#!/bin/sh # # # Support: linux-ha@lists.linux-ha.org # License: GNU General Public License (GPL) # # Filesystem # Description: Manages a Filesystem on a shared storage medium. # Original Author: Eric Z. Ayers (eric.ayers@compgen.com) # Original Release: 25 Oct 2000 # Modified by: Martin Fick, 11/30/2006 # to: unmount safely even when an NFS share somewhere on the # system is not responding # # usage: ./Filesystem {start|stop|status|monitor|validate-all|meta-data} # # OCF parameters are as below: # OCF_RESKEY_device # OCF_RESKEY_directory # OCF_RESKEY_fstype # OCF_RESKEY_options # #OCF_RESKEY_device : name of block device for the filesystem. e.g. /dev/sda1, /dev/md0 # Or a -U or -L option for mount, or an NFS mount specification #OCF_RESKEY_directory : the mount point for the filesystem #OCF_RESKEY_fstype : optional name of the filesystem type. e.g. ext2 #OCF_RESKEY_options : options to be given to the mount command via -o # # # An example usage in /etc/ha.d/haresources: # node1 10.0.0.170 Filesystem::/dev/sda1::/data1::ext2 # or # node1 10.0.0.170 Filesystem::-Ldata1::/data1::ext2 # or # node1 10.0.0.170 Filesystem::server:/data1::/data1::nfs::ro # # This assumes you want to manage a filesystem on a shared (scsi) bus. # Do not put this filesystem in /etc/fstab. This script manages all of # that for you. # # If you are interested in High Availability, you will probably also want # some sort of external hardware RAID controller in front of the actual # disks. I don't mean a RAID controller embedded in the host controller - # it has to be an external controller. # # It can also be an internal RAID controller if the controller supports # failover. IBM's ServeRAID controller does this, and it automatically # prohibits concurrent access too, so it's pretty cool in this application. # # There is a script for software RAID-1 included in this directory. Right # now, I wouldn't recommend using software RAID (see notes in the Raid1 script) # # NOTE: There is no locking (such as a SCSI reservation) being done here. # I would if the SCSI driver could properly maintain the reservation, # which it cannot, even with the 'scsi reservation' patch submitted # earlier this year by James Bottomley. The patch minimizes the # bus resets caused by a RESERVATION_CONFLICT return, and helps the # reservation stay when 2 nodes contend for a reservation, # but it does not attempt to recover the reservation in the # case of a bus reset. # # What all this means is that if 2 nodes mount the same file system # read-write, the filesystem is going to become corrupted. # # As a result, you should use this together with the stonith option # and redundant, independent communications paths. # # If you don't do this, don't blame us when you scramble your disk. # # Note: the ServeRAID controller does prohibit concurrent acess # In this case, you don't actually need STONITH, but redundant comm is # still an excellent idea. # ####################################################################### # Initialization: . /usr/lib/heartbeat/ocf-shellfuncs ####################################################################### # Utilities used by this script MODPROBE=/sbin/modprobe FSCK=/sbin/fsck FUSER=/bin/fuser MOUNT=/bin/mount UMOUNT=/bin/umount BLOCKDEV=/sbin/blockdev check_util () { if [ ! -x "$1" ] ; then ocf_log err "Setup problem: Couldn't find utility $1" exit $OCF_ERR_GENERIC fi } usage() { cat <<-EOT usage: $0 {start|stop|status|monitor|validate-all|meta-data} $Id: Filesystem.in,v 1.15 2006/02/11 13:40:42 xunsun Exp $ EOT } meta_data() { cat < 1.0 Resource script for Filesystem. It manages a Filesystem on a shared storage medium. Filesystem resource agent The name of block device for the filesystem, or -U, -L options for mount, or NFS mount specification. block device The mount point for the filesystem. mount point The optional type of filesystem to be mounted. filesystem type Any extra options to be given as -o options to mount. options END } # # Make sure the kernel does the right thing with the FS buffers # This function should be called after unmounting and before mounting # It may not be necessary in 2.4 and later kernels, but it shouldn't hurt # anything either... # # It's really a bug that you have to do this at all... # flushbufs() { if [ "$BLOCKDEV" != "" -a -x "$BLOCKDEV" ] then case $1 in -*|[^/]*:/*|//[^/]*/*) # -U, -L options to mount, or NFS mount point, # or samba mount point ;; *) $BLOCKDEV --flushbufs $1 return $? ;; esac fi return 0 } # # START: Start up the filesystem # Filesystem_start() { # See if the device is already mounted. Filesystem_status >/dev/null 2>&1 if [ $? -eq $OCF_SUCCESS ] ; then ocf_log info "Filesystem $MOUNTPOINT is already mounted." return $OCF_SUCCESS fi # Insert SCSI module $MODPROBE scsi_hostadapter >/dev/null 2>&1 if [ -z $FSTYPE ]; then : No $FSTYPE specified, rely on the system has the right file-system support already else # Insert Filesystem module $MODPROBE $FSTYPE >/dev/null 2>&1 grep -e "$FSTYPE"'$' /proc/filesystems >/dev/null if [ $? != 0 ] ; then ocf_log err "Couldn't find filesystem $FSTYPE in /proc/filesystems" return $OCF_ERR_ARGS fi fi # Check the filesystem & auto repair. # NOTE: Some filesystem types don't need this step... Please modify # accordingly if [ $blockdevice = "yes" ]; then if [ ! -b "$DEVICE" ] ; then ocf_log err "Couldn't find device [$DEVICE]. Expected /dev/??? to exist" exit $OCF_ERR_ARGS fi if case $FSTYPE in ext3|reiserfs|xfs|jfs|vfat|fat|nfs|cifs|smbfs) false;; *) true;; esac then ocf_log info "Starting filesystem check on $DEVICE" if [ -z $FSTYPE ]; then $FSCK -a $DEVICE else $FSCK -t $FSTYPE -a $DEVICE fi # NOTE: if any errors at all are detected, it returns non-zero # if the error is >= 4 then there is a big problem if [ $? -ge 4 ] then ocf_log err "Couldn't sucessfully fsck filesystem for $DEVICE" return $OCF_ERR_GENERIC fi fi fi if [ ! -d "$MOUNTPOINT" ] ; then ocf_log err "Couldn't find directory [$MOUNTPOINT] to use as a mount point" exit $OCF_ERR_ARGS fi flushbufs $DEVICE # Mount the filesystem. if [ -z $FSTYPE ]; then $MOUNT $options $DEVICE $MOUNTPOINT else $MOUNT -t $FSTYPE $options $DEVICE $MOUNTPOINT fi if [ $? -ne 0 ]; then ocf_log err "Couldn't mount filesystem $DEVICE on $MOUNTPOINT" return $OCF_ERR_GENERIC fi return $? } # end of Filesystem_start fuser_dave() { # MNT typeset IDS SIG MOUNTPOINT="$1" SYSTYPE="`uname -s 2>/dev/null`" if [ "$SYSTYPE" = Linux ]; then # fuser hangs on files open to inaccessible nfs-mounted # filesystems so instead find processes that have open # files by looking in /proc. Try first to kill with # signal 15 and if that doesn't work try signal 9. for SIG in 15 9 LOG; do IDS="`find /proc -type l -printf "%p -> %l/\n" 2>/dev/null| \ grep "> $MOUNTPOINT/"|cut -d/ -f3|sort -u`" if [ -n "$IDS" ]; then IDS="`echo $IDS`" # get rid of newlines if [ "$SIG" = "LOG" ]; then ha_log "Process(es) $IDS weren't killed, attempting to continue" else ha_log "kill -$SIG $IDS" kill -$SIG $IDS sleep 1 fi fi done else # only do default signal because option to change # the signal number isn't portable $FUSER -mk $MOUNTPOINT fi } # # STOP: Unmount the filesystem # Filesystem_stop() { # See if the device is currently mounted if Filesystem_status >/dev/null 2>&1 then # Umount all sub-filesystems mounted under $MOUNTPOINT/ # (e.g. /proc in chroots) for SUB in `$MOUNT | grep "on $MOUNTPOINT/" | cut -d' ' -f3 | tac` ; do fuser_dave $SUB $UMOUNT $SUB done if [ $blockdevice = "yes" ]; then fuser_dave $DEVICE else fuser_dave $MOUNTPOINT fi if [ $blockdevice = "yes" ]; then $UMOUNT $DEVICE DEV=$DEVICE else # Get the current real device name... # (specified devname could be -L or -U...) DEV=`$MOUNT | grep "on $MOUNTPOINT " | cut -d' ' -f1` # Unmount the filesystem $UMOUNT $MOUNTPOINT fi if [ $? -ne 0 ] ; then ocf_log err "Couldn't unmount $MOUNTPOINT" return $OCF_ERR_GENERIC fi flushbufs $DEV else : $MOUNTPOINT Not mounted. No problema! fi return $? } # end of Filesystem_stop # # STATUS: is the filesystem mounted or not? # Filesystem_status() { if [ $blockdevice = "yes" ] then greppat="^$DEVICE $MOUNTPOINT " else greppat=" $MOUNTPOINT " fi if grep -q -e "${greppat}" /proc/mounts >/dev/null 2>&1 then rc=$OCF_SUCCESS msg="$MOUNTPOINT is mounted (running)" else rc=$OCF_NOT_RUNNING msg="$MOUNTPOINT is unmounted (stopped)" fi case "$OP" in status) ocf_log info "$msg";; esac return $rc } # end of Filesystem_status # # VALIDATE_ALL: Are the instance parameters valid? # FIXME!! The only part that's useful is the return code. # This code always returns $OCF_SUCCESS (!) # Filesystem_validate_all() { if [ -n $MOUNTPOINT -a ! -d $MOUNTPOINT ]; then ocf_log warn "Mountpoint $MOUNTPOINT does not exist" fi # Check if the $FSTYPE is workable # NOTE: Without inserting the $FSTYPE module, this step may be imprecise if [ ! -z $FSTYPE ]; then cut -f2 /proc/filesystems |grep -q ^$FSTYPE$ if [ $? -ne 0 ]; then modpath=/lib/modules/`uname -r` moddep=$modpath/modules.dep # Do we have $FSTYPE in modules.dep? cut -d' ' -f1 $moddep |grep -q "^$modpath.*$FSTYPE\.k\?o:$" if [ $? -ne 0 ]; then ocf_log info "It seems we do not have $FSTYPE support" fi fi fi #TODO: How to check the $options ? return $OCF_SUCCESS } # Check the arguments passed to this script if [ $# -ne 1 ] then usage exit $OCF_ERR_ARGS fi # Check the OCF_RESKEY_ environment variables... DEVICE=$OCF_RESKEY_device FSTYPE=$OCF_RESKEY_fstype if [ ! -z "$OCF_RESKEY_options" ]; then options="-o $OCF_RESKEY_options" fi OP=$1 # These operations do not require instance parameters case $OP in meta-data) meta_data exit $OCF_SUCCESS ;; usage) usage exit $OCF_SUCCESS ;; esac blockdevice=no case $DEVICE in "") ocf_log err "Please set OCF_RESKEY_device to the device to be managed" exit $OCF_ERR_ARGS ;; -*) # Oh... An option to mount instead... Typically -U or -L ;; [^/]*:/*) # An NFS filesystem specification... ;; //[^/]*/*) # An SMB filesystem specification... ;; *) if [ ! -b "$DEVICE" -a "X$OP" != Xstart ] ; then ocf_log warn "Couldn't find device [$DEVICE]. Expected /dev/??? to exist" fi blockdevice=yes ;; esac # It is possible that OCF_RESKEY_directory has one or even multiple trailing "/". # But the output of `mount` and /proc/mounts do not. if [ -z $OCF_RESKEY_directory ]; then if [ X$OP = "Xstart" -o $blockdevice = "no" ]; then ocf_log err "Please specify the directory" exit $OCF_ERR_ARGS fi else MOUNTPOINT=$(echo $OCF_RESKEY_directory | sed 's/\/*$//') : ${MOUNTPOINT:=/} # At this stage, $MOUNTPOINT does not contain trailing "/" unless it is "/" fi # Check to make sure the utilites are found check_util $MODPROBE check_util $FSCK check_util $FUSER check_util $MOUNT check_util $UMOUNT case $OP in start) Filesystem_start ;; stop) Filesystem_stop ;; status|monitor) Filesystem_status ;; validate-all) Filesystem_validate_all ;; *) usage exit $OCF_ERR_UNIMPLEMENTED ;; esac exit $?