Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/rgmanager/src/resources/netfs.sh b/rgmanager/src/resources/netfs.sh
index 93f977397..b67932827 100755
--- a/rgmanager/src/resources/netfs.sh
+++ b/rgmanager/src/resources/netfs.sh
@@ -1,408 +1,481 @@
#!/bin/bash
#
# NFS/CIFS file system mount/umount/etc. agent
#
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
. $(dirname $0)/utils/fs-lib.sh
do_metadata()
{
cat <<EOT
<?xml version="1.0" ?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1-modified.dtd">
<resource-agent name="netfs" version="rgmanager 2.0">
<version>1.0</version>
<longdesc lang="en">
This defines an NFS/CIFS mount for use by cluster services.
</longdesc>
<shortdesc lang="en">
Defines an NFS/CIFS file system mount.
</shortdesc>
<parameters>
<parameter name="name" primary="1">
<longdesc lang="en">
Symbolic name for this file system.
</longdesc>
<shortdesc lang="en">
File System Name
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="mountpoint" unique="1" required="1">
<longdesc lang="en">
Path in file system heirarchy to mount this file system.
</longdesc>
<shortdesc lang="en">
Mount Point
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="host" required="1">
<longdesc lang="en">
Server IP address or hostname
</longdesc>
<shortdesc lang="en">
IP or Host
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="export" required="1">
<longdesc lang="en">
NFS Export directory name or CIFS share
</longdesc>
<shortdesc lang="en">
Export
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="fstype" required="0">
<longdesc lang="en">
File System type (nfs, nfs4 or cifs)
</longdesc>
<shortdesc lang="en">
File System Type
</shortdesc>
<content type="string"/>
</parameter>
<parameter name="no_unmount" required="0">
<longdesc lang="en">
Do not unmount the filesystem during a stop or relocation operation
</longdesc>
<shortdesc lang="en">
Skip unmount opration
</shortdesc>
<content type="boolean"/>
</parameter>
<parameter name="force_unmount">
<longdesc lang="en">
If set, the cluster will kill all processes using
this file system when the resource group is
stopped. Otherwise, the unmount will fail, and
the resource group will be restarted.
</longdesc>
<shortdesc lang="en">
Force Unmount
</shortdesc>
<content type="boolean"/>
</parameter>
<parameter name="self_fence">
<longdesc lang="en">
If set and unmounting the file system fails, the node will
immediately reboot. Generally, this is used in conjunction
with force_unmount support, but it is not required.
</longdesc>
<shortdesc lang="en">
Seppuku Unmount
</shortdesc>
<content type="boolean"/>
</parameter>
<parameter name="options">
<longdesc lang="en">
Provides a list of mount options. If none are specified,
the NFS file system is mounted -o sync.
</longdesc>
<shortdesc lang="en">
Mount Options
</shortdesc>
<content type="string"/>
</parameter>
</parameters>
<actions>
<action name="start" timeout="900"/>
<action name="stop" timeout="30"/>
<!-- Recovery isn't possible; we don't know if resources are using
the file system. -->
<!-- Checks to see if it's mounted in the right place -->
<action name="status" interval="1m" timeout="10"/>
<action name="monitor" interval="1m" timeout="10"/>
<!-- Checks to see if we can read from the mountpoint -->
<action name="status" depth="10" timeout="30" interval="5m"/>
<action name="monitor" depth="10" timeout="30" interval="5m"/>
<!-- Checks to see if we can write to the mountpoint (if !ROFS) -->
<action name="status" depth="20" timeout="30" interval="10m"/>
<action name="monitor" depth="20" timeout="30" interval="10m"/>
<action name="meta-data" timeout="5"/>
<action name="validate-all" timeout="5"/>
</actions>
<special tag="rgmanager">
<child type="nfsexport" forbid="1"/>
<child type="nfsclient" forbid="1"/>
</special>
</resource-agent>
EOT
}
verify_host()
{
if [ -z "$OCF_RESKEY_host" ]; then
ocf_log err "No server hostname or IP address specified."
return 1
fi
host $OCF_RESKEY_host 2>&1 | grep -vq "not found"
if [ $? -eq 0 ]; then
return 0
fi
ocf_log err "Hostname or IP address \"$OCF_RESKEY_host\" not valid"
return $OCF_ERR_ARGS
}
verify_fstype()
{
# Auto detect?
[ -z "$OCF_RESKEY_fstype" ] && return 0
case $OCF_RESKEY_fstype in
nfs|nfs4|cifs)
return 0
;;
*)
ocf_log err "File system type $OCF_RESKEY_fstype not supported"
return $OCF_ERR_ARGS
;;
esac
}
verify_options()
{
declare -i ret=0
#
# From mount(1)
#
for o in `echo $OCF_RESKEY_options | sed -e s/,/\ /g`; do
case $o in
async|atime|auto|defaults|dev|exec|_netdev|noatime)
continue
;;
noauto|nodev|noexec|nosuid|nouser|ro|rw|suid|sync)
continue
;;
dirsync|user|users)
continue
;;
esac
case $OCF_RESKEY_fstype in
cifs)
continue
;;
nfs|nfs4)
case $o in
#
# NFS / NFS4 common
#
rsize=*|wsize=*|timeo=*|retrans=*|acregmin=*)
continue
;;
acregmax=*|acdirmin=*|acdirmax=*|actimeo=*)
continue
;;
retry=*|port=*|bg|fg|soft|hard|intr|cto|ac|noac)
continue
;;
esac
#
# NFS v2/v3 only
#
if [ "$OCF_RESKEY_fstype" = "nfs" ]; then
case $o in
mountport=*|mounthost=*)
continue
;;
mountprog=*|mountvers=*|nfsprog=*|nfsvers=*)
continue
;;
namelen=*)
continue
;;
tcp|udp|lock|nolock)
continue
;;
esac
fi
#
# NFS4 only
#
if [ "$OCF_RESKEY_fstype" = "nfs4" ]; then
case $o in
proto=*|clientaddr=*|sec=*)
continue
;;
esac
fi
;;
esac
ocf_log err "Option $o not supported for $OCF_RESKEY_fstype"
ret=$OCF_ERR_ARGS
done
return $ret
}
do_validate()
{
verify_name || return $OCF_ERR_ARGS
verify_fstype|| return $OCF_ERR_ARGS
verify_host || return $OCF_ERR_ARGS
verify_mountpoint || return $OCF_ERR_ARGS
verify_options || return $OCF_ERR_ARGS
# verify_target || return $OCF_ERR_ARGS
}
#
# Override real_device to use fs-lib's functions for start/stop_filesystem
#
real_device() {
export REAL_DEVICE="$1"
}
#
# do_mount - nfs / cifs are mounted differently than blockdevs
#
do_mount() {
declare opts=""
declare mount_options=""
declare ret_val
declare mp="$OCF_RESKEY_mountpoint"
#
# Get the filesystem type, if specified.
#
fstype_option=""
fstype=${OCF_RESKEY_fstype}
case "$fstype" in
""|"[ ]*")
fstype=""
;;
*) # found it
fstype_option="-t $fstype"
;;
esac
#
# Get the mount options, if they exist.
#
mount_options=""
opts=${OCF_RESKEY_options}
case "$opts" in
""|"[ ]*")
opts=""
;;
*) # found it
mount_options="-o $opts"
;;
esac
case $OCF_RESKEY_fstype in
nfs|nfs4)
mount -t $OCF_RESKEY_fstype $mount_options $OCF_RESKEY_host:"$OCF_RESKEY_export" "$mp"
;;
cifs)
mount -t $OCF_RESKEY_fstype $mount_options //$OCF_RESKEY_host/"$OCF_RESKEY_export" "$mp"
;;
esac
ret_val=$?
if [ $ret_val -ne 0 ]; then
ocf_log err "\
'mount $fstype_option $mount_options $OCF_RESKEY_host:$OCF_RESKEY_export $mp' failed, error=$ret_val"
return 1
fi
return 0
}
+do_nfs_rpc_check() {
+ # see man nfs TRANSPORT PROTOCOL section for defaults
+ local nfsproto=tcp
+ local nfsmountproto=udp
+
+ # follow the same logic as mount.nfs option parser.
+ # the rightmost option wins over previous ones, so don't break when
+ # we find something.
+
+ for o in $(echo ${OCF_RESKEY_options} | sed -e s/,/\ /g); do
+ if echo $o | grep -q "^proto=" ; then
+ nfsproto="$(echo $o | cut -d "=" -f 2)"
+ fi
+ if echo $o | grep -q "^mountproto=" ; then
+ nfsmountproto="$(echo $o | cut -d "=" -f 2)"
+ fi
+ case $o in
+ tcp) nfsproto=tcp;;
+ udp) nfsproto=udp;;
+ rdma) nfsproto=rdma;;
+ esac
+ done
+
+ ocf_log debug "Testing generic rpc access on server ${OCF_RESKEY_host} with protocol $nfsproto"
+ if ! rpcinfo -T $nfsproto ${OCF_RESKEY_host} > /dev/null 2>&1; then
+ ocf_log alert "RPC server on ${OCF_RESKEY_host} with $nfsproto is not responding"
+ return 1
+ fi
+
+ ocf_log debug "Testing nfs rcp access on server ${OCF_RESKEY_host} with protocol $nfsproto"
+ if ! rpcinfo -T $nfsproto ${OCF_RESKEY_host} nfs > /dev/null 2>&1; then
+ ocf_log alert "NFS server on ${OCF_RESKEY_host} with $nfsproto is not responding"
+ return 1
+ fi
+
+ if [ "$OCF_RESKEY_fstype" = nfs ]; then
+ ocf_log debug "Testing mountd rpc access on server ${OCF_RESKEY_host} with protocol $nfsmountproto"
+ if ! rpcinfo -T $nfsmountproto ${OCF_RESKEY_host} mountd; then
+ ocf_log alert "MOUNTD server on ${OCF_RESKEY_host} with $nfsmountproto is not responding"
+ return 1
+ fi
+ fi
+
+ return 0
+}
+
+do_pre_unmount() {
+ case $OCF_RESKEY_fstype in
+ nfs|nfs4)
+ if [ "$self_fence" != $YES ]; then
+ ocf_log debug "Skipping pre unmount checks: self_fence is disabled"
+ return 0
+ fi
+
+ is_mounted "$dev" "$mp"
+ case $? in
+ $NO)
+ ocf_log debug "Skipping pre unmount checks: device is not mounted"
+ return 0
+ ;;
+ esac
+
+ ocf_log info "pre unmount: checking if nfs server ${OCF_RESKEY_host} is alive"
+ if ! do_nfs_rpc_check; then
+ ocf_log alert "NFS server not responding - REBOOTING"
+ sleep 2
+ reboot -fn
+ fi
+ ;;
+ esac
+
+ return 0
+}
do_force_unmount() {
case $OCF_RESKEY_fstype in
nfs|nfs4)
ocf_log warning "Calling 'umount -f $mp'"
umount -f "$OCF_RESKEY_mountpoint"
return $?
;;
*)
;;
esac
return 1 # Returning 1 lets stop_filesystem do add'l checks
}
populate_defaults()
{
if [ -z "$OCF_RESKEY_fstype" ]; then
export OCF_RESKEY_fstype=nfs
fi
case $OCF_RESKEY_fstype in
nfs|nfs4)
export OCF_RESKEY_device="$OCF_RESKEY_host:$OCF_RESKEY_export"
if [ -z "$OCF_RESKEY_options" ]; then
export OCF_RESKEY_options=sync,soft,noac
fi
;;
cifs)
export OCF_RESKEY_device="//$OCF_RESKEY_host/$OCF_RESKEY_export"
if [ -z "$OCF_RESKEY_options" ]; then
export OCF_RESKEY_options=guest
fi
;;
esac
}
#
# Main...
#
populate_defaults
main $*
diff --git a/rgmanager/src/resources/utils/fs-lib.sh b/rgmanager/src/resources/utils/fs-lib.sh
index c78b143da..e3ead2205 100644
--- a/rgmanager/src/resources/utils/fs-lib.sh
+++ b/rgmanager/src/resources/utils/fs-lib.sh
@@ -1,1166 +1,1170 @@
#!/bin/bash
#
# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
#
# File system common functions
#
LC_ALL=C
LANG=C
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export LC_ALL LANG PATH
# Private return codes
FAIL=2
NO=1
YES=0
YES_STR="yes"
[ -z "$OCF_RESOURCE_INSTANCE" ] && export OCF_RESOURCE_INSTANCE="filesystem:$OCF_RESKEY_name"
#
# Using a global to contain the return value saves
# clone() operations. This is important to reduce
# resource consumption during status checks.
#
# There is no way to return a string from a function
# in bash without cloning the process, which is exactly
# what we are trying to avoid. So, we have to resort
# to using a dedicated global variables.
declare REAL_DEVICE
declare STRIP_SLASHES=""
declare FINDMNT_OUTPUT=""
#
# Stub ocf_log function for when we are using
# quick_status, since ocf_log generally forks (and
# sourcing ocf-shellfuncs forks -a lot-).
#
ocf_log()
{
echo $*
}
#
# Assume NFS_TRICKS are not available until we are
# proved otherwise.
#
export NFS_TRICKS=1
#
# Quick status doesn't fork() or clone() when using
# device files directly. (i.e. not symlinks, LABEL= or
# UUID=
#
if [ "$1" = "status" -o "$1" = "monitor" ] &&
[ "$OCF_RESKEY_quick_status" = "1" ]; then
echo Using Quick Status
# XXX maybe we can make ocf-shellfuncs have a 'quick' mode too?
export OCF_SUCCESS=0
export OCF_ERR_GENERIC=1
else
#
# Grab nfs lock tricks if available
#
if [ -f "$(dirname $0)/svclib_nfslock" ]; then
. $(dirname $0)/svclib_nfslock
NFS_TRICKS=0
fi
. $(dirname $0)/ocf-shellfuncs
fi
verify_name()
{
if [ -z "$OCF_RESKEY_name" ]; then
ocf_log err "No file system name specified."
return $OCF_ERR_ARGS
fi
return $OCF_SUCCESS
}
verify_mountpoint()
{
if [ -z "$OCF_RESKEY_mountpoint" ]; then
ocf_log err "No mount point specified."
return $OCF_ERR_ARGS
fi
if ! [ -e "$OCF_RESKEY_mountpoint" ]; then
ocf_log info "Mount point $OCF_RESKEY_mountpoint will be "\
"created at mount time."
return $OCF_SUCCESS
fi
[ -d "$OCF_RESKEY_mountpoint" ] && return $OCF_SUCCESS
ocf_log err "$OCF_RESKEY_mountpoint exists but is not a directory."
return $OCF_ERR_ARGS
}
#
# This used to be called using $(...), but doing this causes bash
# to set up a pipe and clone(). So, the output of this function is
# stored in the global variable REAL_DEVICE, declared previously.
#
real_device()
{
declare dev="$1"
declare realdev
REAL_DEVICE=""
[ -z "$dev" ] && return $OCF_ERR_ARGS
# Oops, we have a link. Sorry, this is going to fork.
if [ -h "$dev" ]; then
realdev=$(readlink -f $dev)
if [ $? -ne 0 ]; then
return $OCF_ERR_ARGS
fi
REAL_DEVICE="$realdev"
return $OCF_SUCCESS
fi
# If our provided blockdev is a device, we are done
if [ -b "$dev" ]; then
REAL_DEVICE="$dev"
return $OCF_SUCCESS
fi
# It's not a link, it's not a block device. If it also
# does not match UUID= or LABEL=, then findfs is not
# going to find anything useful, so we should quit now.
if [ "${dev/UUID=/}" = "$dev" ] &&
[ "${dev/LABEL=/}" = "$dev" ]; then
return $OCF_ERR_GENERIC
fi
# When using LABEL= or UUID=, we can't save a fork.
realdev=$(findfs "$dev" 2> /dev/null)
if [ -n "$realdev" ] && [ -b "$realdev" ]; then
REAL_DEVICE="$realdev"
return $OCF_SUCCESS
fi
return $OCF_ERR_GENERIC
}
verify_device()
{
declare realdev
if [ -z "$OCF_RESKEY_device" ]; then
ocf_log err "No device or label specified."
return $OCF_ERR_ARGS
fi
real_device "$OCF_RESKEY_device"
realdev="$REAL_DEVICE"
if [ -n "$realdev" ]; then
if [ "$realdev" != "$OCF_RESKEY_device" ]; then
ocf_log info "Specified $OCF_RESKEY_device maps to $realdev"
fi
return $OCF_SUCCESS
fi
ocf_log err "Device or label \"$OCF_RESKEY_device\" not valid"
return $OCF_ERR_ARGS
}
##
# Tries to use findmnt util to return list
# of mountpoints for a device
#
# Global variables are used to reduce forking when capturing stdout.
#
# Return values
# 0 - device mount points found, mountpoint list returned to FINDMNT_OUTPUT global variable
# 1 - device mount not found
# 2 - findmnt tool isn't found
#
##
try_findmnt()
{
FINDMNT_OUTPUT=""
which findmnt > /dev/null 2>&1
if [ $? -eq 0 ]; then
FINDMNT_OUTPUT=$(findmnt -o TARGET --noheadings $1)
if [ $? -ne 0 ]; then
return 1
else
return 0
fi
fi
return 2
}
##
# Returns result in global variable to reduce forking
##
strip_trailing_slashes()
{
local tmp=$1
while [ "${tmp#${tmp%?}}" = "/" ]
do
tmp="${tmp%/}"
done
STRIP_SLASHES="$tmp"
}
#
# kill_procs_using_mount mount_point [signal]
#
# Kill any processes using the specified mountpoint, using the optional
# specified signal. This is used in place of fuser to avoid it becoming
# blocked while following symlinks to an unresponsive file system.
# Defaults to SIGKILL if no signal specified.
#
kill_procs_using_mount () {
declare mp
declare procs
if [ $# -lt 1 -o -z "$1" ]; then
ocf_log err "Usage: kill_procs_using_mount mount_point [signal]"
return $FAIL
fi
strip_trailing_slashes "$1"
mp="$STRIP_SLASHES"
if [ -z "$mp" ]; then
ocf_log err "Usage: kill_procs_using_mount mount_point [signal]"
return $FAIL
fi
# anything held open in mount point after the slash
procs=$(find /proc/[0-9]*/fd/ -type l -lname "${mp}/*" -or -lname "${mp}" 2>/dev/null | awk -F/ '{print $3}' | uniq)
for pid in $procs; do
if [ -n "$2" ]; then
kill -s $2 $pid
else
kill -s KILL $pid
fi
done
return $SUCCESS
}
#
# mount_in_use device mount_point
#
# Check to see if either the device or mount point are in use anywhere on
# the system. It is not required that the device be mounted on the named
# moint point, just if either are in use.
#
mount_in_use () {
declare mp tmp_mp
declare dev tmp_dev
declare junka junkb junkc junkd
declare res=$FAIL
declare findmnt_res=2
if [ $# -ne 2 ]; then
ocf_log err "Usage: mount_in_use device mount_point".
return $FAIL
fi
dev="$1"
mp="$2"
# First try and find out if the device has a mount point by
# attempting to use the findmnt tool. It is much faster than
# iterating through /proc/mounts
try_findmnt $dev
findmnt_res=$?
if [ $findmnt_res -eq 0 ]; then
case $OCF_RESKEY_fstype in
cifs|nfs|nfs4)
# -r means to include '/' character and not treat it as escape character
while read -r tmp_mp
do
if [ "$tmp_mp" = "$mp" ]; then
return $YES
fi
done < <(echo $FINDMNT_OUTPUT)
;;
*)
return $YES
;;
esac
fi
while read -r tmp_dev tmp_mp junka junkb junkc junkd; do
# Does the device match? We might have already tried findmnt
# which is why this could get skipped
if [ $findmnt_res -eq 2 ]; then
if [ "${tmp_dev:0:1}" != "-" ]; then
# XXX fork/clone warning XXX
tmp_dev="$(printf "$tmp_dev")"
fi
strip_trailing_slashes "$tmp_dev"
tmp_dev="$STRIP_SLASHES"
if [ -n "$tmp_dev" -a "$tmp_dev" = "$dev" ]; then
case $OCF_RESKEY_fstype in
cifs|nfs|nfs4)
;;
*)
return $YES
;;
esac
fi
fi
# Mountpoint from /proc/mounts containing spaces will
# have spaces represented in octal. printf takes care
# of this for us.
tmp_mp="$(printf "$tmp_mp")"
if [ -n "$tmp_mp" -a "$tmp_mp" = "$mp" ]; then
return $YES
fi
done < <(cat /proc/mounts)
return $NO
}
##
# Returns whether or not the device is mounted.
# If the mountpoint does not match the one provided, the
# mount point found is printed to stdout.
##
real_mountpoint()
{
declare dev=$1
declare mp=$2
declare ret=$NO
declare tmp_mp
declare tmp_dev
declare found=1
declare poss_mp=""
try_findmnt $dev
case $? in
0) #findmnt found mount points, loop through them to find a match
# -r means to include '/' character and not treat it as escape character
while read -r tmp_mp
do
ret=$YES
if [ "$tmp_mp" != "$mp" ]; then
poss_mp=$tmp_mp
else
found=0
break
fi
done < <(echo $FINDMNT_OUTPUT)
;;
1)
# findmnt found no mount points for the device
return $NO
;;
2) # findmnt tool could not be used.
# Using slow method reading /proc/mounts dir.
while read -r tmp_dev tmp_mp junk_a junk_b junk_c junk_d
do
if [ "${tmp_dev:0:1}" != "-" ]; then
# XXX fork/clone warning XXX
tmp_dev="$(printf "$tmp_dev")"
fi
# CIFS mounts can sometimes have trailing slashes
# in their first field in /proc/mounts, so strip them.
strip_trailing_slashes "$tmp_dev"
tmp_dev="$STRIP_SLASHES"
real_device "$tmp_dev"
tmp_dev="$REAL_DEVICE"
# XXX fork/clone warning XXX
# Mountpoint from /proc/mounts containing spaces will
# have spaces represented in octal. printf takes care
# of this for us.
tmp_mp="$(printf "$tmp_mp")"
if [ -n "$tmp_dev" -a "$tmp_dev" = "$dev" ]; then
ret=$YES
#
# Check to see if its mounted in the right
# place
#
if [ -n "$tmp_mp" ]; then
if [ "$tmp_mp" != "$mp" ]; then
poss_mp=$tmp_mp
else
found=0
break
fi
fi
fi
done < <(cat /proc/mounts)
esac
if [ $found -ne 0 ]; then
echo "$poss_mp"
fi
return $ret
}
#
# is_mounted device mount_point
#
# Check to see if the device is mounted. Print a warning if its not
# mounted on the directory we expect it to be mounted on.
#
is_mounted () {
declare mp
declare dev
declare ret=$FAIL
declare poss_mp
if [ $# -ne 2 ]; then
ocf_log err "Usage: is_mounted device mount_point"
return $FAIL
fi
real_device "$1"
dev="$REAL_DEVICE"
if [ -z "$dev" ]; then
ocf_log err "$OCF_RESOURCE_INSTANCE: is_mounted: Could not match $1 with a real device"
return $OCF_ERR_ARGS
fi
if [ -h "$2" ]; then
mp="$(readlink -f $2)"
else
mp="$2"
fi
# This bash glyph simply removes a trailing slash
# if one exists. /a/b/ -> /a/b; /a/b -> /a/b.
mp="${mp%/}"
poss_mp=$(real_mountpoint "$dev" "$mp")
ret=$?
if [ $ret -eq $YES ] && [ -n "$poss_mp" ]; then
# if we made it here, then the device is mounted, but not where
# we expected it to be
case $OCF_RESKEY_fstype in
cifs|nfs|nfs4)
ret=$NO
;;
*)
ocf_log warn "Device $dev is mounted on $poss_mp instead of $mp"
;;
esac
fi
return $ret
}
#
# is_alive mount_point
#
# Check to see if mount_point is alive (testing read/write)
#
is_alive()
{
declare errcode
declare mount_point="$1"
declare file
declare rw
if [ $# -ne 1 ]; then
ocf_log err "Usage: is_alive mount_point"
return $FAIL
fi
[ -z "$OCF_CHECK_LEVEL" ] && export OCF_CHECK_LEVEL=0
test -d "$mount_point"
if [ $? -ne 0 ]; then
ocf_log err "${OCF_RESOURCE_INSTANCE}: is_alive: $mount_point is not a directory"
return $FAIL
fi
[ $OCF_CHECK_LEVEL -lt 10 ] && return $YES
# depth 10 test (read test)
ls "$mount_point" > /dev/null 2> /dev/null
errcode=$?
if [ $errcode -ne 0 ]; then
ocf_log err "${OCF_RESOURCE_INSTANCE}: is_alive: failed read test on [$mount_point]. Return code: $errcode"
return $NO
fi
[ $OCF_CHECK_LEVEL -lt 20 ] && return $YES
# depth 20 check (write test)
rw=$YES
for o in `echo $OCF_RESKEY_options | sed -e s/,/\ /g`; do
if [ "$o" = "ro" ]; then
rw=$NO
fi
done
if [ $rw -eq $YES ]; then
file=$(mktemp "$mount_point/.check_writable.$(hostname).XXXXXX")
if [ ! -e $file ]; then
ocf_log err "${OCF_RESOURCE_INSTANCE}: is_alive: failed write test on [$mount_point]. Return code: $errcode"
return $NO
fi
rm -f $file > /dev/null 2> /dev/null
fi
return $YES
}
#
# Decide which quota options are enabled and return a string
# which we can pass to quotaon
#
quota_opts()
{
declare quotaopts=""
declare opts="$1"
declare mopt
for mopt in `echo $opts | sed -e s/,/\ /g`; do
case $mopt in
quota)
quotaopts="gu"
break
;;
usrquota)
quotaopts="u$quotaopts"
continue
;;
grpquota)
quotaopts="g$quotaopts"
continue
;;
noquota)
quotaopts=""
return 0
;;
esac
done
echo $quotaopts
return 0
}
#
# Enable quotas on the mount point if the user requested them
#
enable_fs_quotas()
{
declare -i need_check=0
declare -i rv
declare quotaopts=""
declare mopt
declare opts="$1"
declare mp="$2"
if ! type quotaon &> /dev/null; then
ocf_log err "quotaon not found in $PATH"
return $OCF_ERR_GENERIC
fi
quotaopts=$(quota_opts $opts)
[ -z "$quotaopts" ] && return 0
ocf_log debug "quotaopts = $quotaopts"
# Ok, create quota files if they don't exist
for f in quota.user aquota.user quota.group aquota.group; do
if ! [ -f "$mp/$f" ]; then
ocf_log info "$mp/$f was missing - creating"
touch "$mp/$f"
chmod 600 "$mp/$f"
need_check=1
fi
done
if [ $need_check -eq 1 ]; then
ocf_log info "Checking quota info in $mp"
quotacheck -$quotaopts "$mp"
fi
ocf_log info "Enabling Quotas on $mp"
ocf_log debug "quotaon -$quotaopts \"$mp\""
quotaon -$quotaopts "$mp"
rv=$?
if [ $rv -ne 0 ]; then
# Just a warning
ocf_log warn "Unable to turn on quotas for $mp; return = $rv"
fi
return $rv
}
# Agent-specific actions to take before mounting
# (if required). Typically things like fsck.
do_pre_mount() {
return 0
}
# Default mount handler - for block devices
#
do_mount() {
declare dev="$1"
declare mp="$2"
declare mount_options=""
declare fstype_option=""
declare fstype
#
# Get the filesystem type, if specified.
#
fstype_option=""
fstype=${OCF_RESKEY_fstype}
case "$fstype" in
""|"[ ]*")
fstype=""
;;
*) # found it
fstype_option="-t $fstype"
;;
esac
#
# Get the mount options, if they exist.
#
mount_options=""
opts=${OCF_RESKEY_options}
case "$opts" in
""|"[ ]*")
opts=""
;;
*) # found it
mount_options="-o $opts"
;;
esac
#
# Mount the device
#
ocf_log info "mounting $dev on $mp"
ocf_log err "mount $fstype_option $mount_options $dev $mp"
mount $fstype_option $mount_options "$dev" "$mp"
ret_val=$?
if [ $ret_val -ne 0 ]; then
ocf_log err "\
'mount $fstype_option $mount_options $dev $mp' failed, error=$ret_val"
return 1
fi
return 0
}
# Agent-specific actions to take after mounting
# (if required).
do_post_mount() {
return 0
}
# Agent-specific actions to take before unmounting
# (if required)
do_pre_unmount() {
return 0
}
# Agent-specific actions to take after umount succeeds
# (if required)
do_post_unmount() {
return 0
}
# Agent-specific force unmount logic, if required
# return = nonzero if successful, or 0 if unsuccessful
# (unsuccessful = try harder)
do_force_unmount() {
return 1
}
#
# start_filesystem
#
start_filesystem() {
declare -i ret_val=$OCF_SUCCESS
declare mp="${OCF_RESKEY_mountpoint}"
declare dev="" # device
declare fstype=""
declare opts=""
declare mount_options=""
#
# Check if mount point was specified. If not, no need to continue.
#
case "$mp" in
""|"[ ]*") # nothing to mount
return $OCF_SUCCESS
;;
/*) # found it
;;
*) # invalid format
ocf_log err \
"start_filesystem: Invalid mount point format (must begin with a '/'): \'$mp\'"
return $OCF_ERR_ARGS
;;
esac
#
# Get the device
#
real_device "$OCF_RESKEY_device"
dev="$REAL_DEVICE"
if [ -z "$dev" ]; then
ocf_log err "\
start_filesystem: Could not match $OCF_RESKEY_device with a real device"
return $OCF_ERR_ARGS
fi
#
# Ensure we've got a valid directory
#
if [ -e "$mp" ]; then
if ! [ -d "$mp" ]; then
ocf_log err"\
start_filesystem: Mount point $mp exists but is not a directory"
return $OCF_ERR_ARGS
fi
else
ocf_log err "\
start_filesystem: Creating mount point $mp for device $dev"
mkdir -p "$mp"
ret_val=$?
if [ $ret_val -ne 0 ]; then
ocf_log err "\
start_filesystem: Unable to create $mp. Error code: $ret_val"
return $OCF_ERR_GENERIC
fi
fi
#
# See if the device is already mounted.
#
is_mounted "$dev" "$mp"
case $? in
$YES) # already mounted
ocf_log debug "$dev already mounted"
return $OCF_SUCCESS
;;
$NO) # not mounted, continue
;;
*)
return $FAIL
;;
esac
#
# Make sure that neither the device nor the mount point are mounted
# (i.e. they may be mounted in a different location). The'mount_in_use'
# function checks to see if either the device or mount point are in
# use somewhere else on the system.
#
mount_in_use "$dev" "$mp"
case $? in
$YES) # uh oh, someone is using the device or mount point
ocf_log err "\
Cannot mount $dev on $mp, the device or mount point is already in use!"
return $FAIL
;;
$NO) # good, no one else is using it
;;
$FAIL)
return $FAIL
;;
*)
ocf_log err "Unknown return from mount_in_use"
return $FAIL
;;
esac
do_pre_mount
case $? in
0)
;;
1)
return $OCF_ERR_GENERIC
;;
2)
return $OCF_SUCCESS
;;
esac
do_mount "$dev" "$mp"
case $? in
0)
;;
1)
return $OCF_ERR_GENERIC
;;
2)
return $OCF_SUCCESS
;;
esac
do_post_mount
case $? in
0)
;;
1)
return $OCF_ERR_GENERIC
;;
2)
return $OCF_SUCCESS
;;
esac
enable_fs_quotas "$opts" "$mp"
return $OCF_SUCCESS
}
#
# stop_filesystem - unmount a file system; calls out to
#
stop_filesystem() {
declare -i ret_val=0
declare -i try
declare -i sleep_time=5 # time between each umount failure
declare umount_failed=""
declare force_umount=""
declare self_fence=""
declare quotaopts=""
#
# Get the mount point, if it exists. If not, no need to continue.
#
mp=${OCF_RESKEY_mountpoint}
case "$mp" in
""|"[ ]*") # nothing to mount
return $OCF_SUCCESS
;;
/*) # found it
;;
*) # invalid format
ocf_log err \
"stop_filesystem: Invalid mount point format (must begin with a '/'): \'$mp\'"
return $FAIL
;;
esac
#
# Get the device
#
real_device "$OCF_RESKEY_device"
dev="$REAL_DEVICE"
if [ -z "$dev" ]; then
ocf_log err "\
stop: Could not match $OCF_RESKEY_device with a real device"
return $OCF_ERR_INSTALLED
fi
#
# Get the force unmount setting if there is a mount point.
#
case ${OCF_RESKEY_force_unmount} in
$YES_STR) force_umount=$YES ;;
on) force_umount=$YES ;;
true) force_umount=$YES ;;
1) force_umount=$YES ;;
*) force_umount="" ;;
esac
+ #
+ # self_fence _MUST_ be initialized before calling do_pre_unmount
+ # The netfs agent depends on the self_fence variable.
+ #
case ${OCF_RESKEY_self_fence} in
$YES_STR) self_fence=$YES ;;
on) self_fence=$YES ;;
true) self_fence=$YES ;;
1) self_fence=$YES ;;
*) self_fence="" ;;
esac
do_pre_unmount
case $? in
0)
;;
1)
return $OCF_ERR_GENERIC
;;
2)
return $OCF_SUCCESS
;;
esac
#
# Preparations: sync, turn off quotas
#
sync
quotaopts=$(quota_opts $OCF_RESKEY_options)
if [ -n "$quotaopts" ]; then
ocf_log debug "Turning off quotas for $mp"
quotaoff -$quotaopts "$mp" &> /dev/null
fi
#
# Unmount the device.
#
for try in 1 2 3; do
if [ $try -ne 1 ]; then
sleep $sleep_time
fi
is_mounted "$dev" "$mp"
case $? in
$NO)
ocf_log info "$dev is not mounted"
umount_failed=
break
;;
$YES) # fallthrough
;;
*)
return $FAIL
;;
esac
case ${OCF_RESKEY_no_unmount} in
yes|YES|true|TRUE|YES|on|ON|1)
ocf_log debug "Skipping umount on stop because of 'no_unmount' option"
return $OCF_SUCCESS
;;
*) : ;;
esac
ocf_log info "unmounting $mp"
umount "$mp"
ret_val=$?
# some versions of umount will exit with status 16 iff
# the umount(2) succeeded but /etc/mtab could not be written.
if [ $ret_val -eq 0 -o $ret_val -eq 16 ]; then
umount_failed=
break
fi
ocf_log debug "umount failed: $ret_val"
umount_failed=yes
if [ -z "$force_umount" ]; then
continue
fi
# Force unmount: try #1: send SIGTERM
if [ $try -eq 1 ]; then
# Try fs-specific force unmount, if provided
do_force_unmount
if [ $? -eq 0 ]; then
# if this succeeds, we should be done
continue
fi
ocf_log warning "Sending SIGTERM to processes on $mp"
kill_procs_using_mount "$mp" "TERM"
continue
else
ocf_log warning "Sending SIGKILL to processes on $mp"
kill_procs_using_mount "$mp"
if [ $? -eq 0 ]; then
# someone is still accessing the mount, We've already sent
# SIGTERM, now we've sent SIGKILL and are trying umount again.
continue
fi
# mount has failed, and no one is accessing it. There's
# nothing left for us to try.
break
fi
done # for
do_post_unmount
case $? in
0)
;;
1)
return $OCF_ERR_GENERIC
;;
2)
return $OCF_SUCCESS
;;
esac
if [ -n "$umount_failed" ]; then
ocf_log err "'umount $mp' failed, error=$ret_val"
if [ "$self_fence" ]; then
ocf_log alert "umount failed - REBOOTING"
sync
reboot -fn
fi
return $OCF_ERR_GENERIC
fi
return $OCF_SUCCESS
}
do_start() {
declare tries=0
declare rv
while [ $tries -lt 3 ]; do
start_filesystem
rv=$?
if [ $rv -eq 0 ]; then
return 0
fi
((tries++))
sleep 3
done
return $rv
}
do_stop() {
stop_filesystem
return $?
}
do_monitor() {
ocf_log debug "Checking fs \"$OCF_RESKEY_name\", Level $OCF_CHECK_LEVEL"
#
# Get the device
#
real_device "$OCF_RESKEY_device"
dev="$REAL_DEVICE"
if [ -z "$dev" ]; then
ocf_log err "\
start_filesystem: Could not match $OCF_RESKEY_device with a real device"
return $OCF_NOT_RUNNING
fi
is_mounted "$dev" "${OCF_RESKEY_mountpoint}"
if [ $? -ne $YES ]; then
ocf_log err "${OCF_RESOURCE_INSTANCE}: ${OCF_RESKEY_device} is not mounted on ${OCF_RESKEY_mountpoint}"
return $OCF_NOT_RUNNING
fi
if [ "$OCF_RESKEY_quick_status" = "1" ]; then
return 0
fi
is_alive "${OCF_RESKEY_mountpoint}"
[ $? -eq $YES ] && return 0
ocf_log err "fs:${OCF_RESKEY_name}: Mount point is not accessible!"
return $OCF_ERR_GENERIC
}
do_restart() {
stop_filesystem
if [ $? -ne 0 ]; then
return $OCF_ERR_GENERIC
fi
start_filesystem
if [ $? -ne 0 ]; then
return $OCF_ERR_GENERIC
fi
return 0
}
# MUST BE OVERRIDDEN
do_metadata() {
return 1
}
do_validate() {
return 1
}
main() {
case $1 in
start)
do_start
exit $?
;;
stop)
do_stop
exit $?
;;
status|monitor)
do_monitor
exit $?
;;
restart)
do_restart
exit $?
;;
meta-data)
do_metadata
exit $?
;;
validate-all)
do_validate
;;
*)
echo "usage: $0 {start|stop|status|monitor|restart|meta-data|validate-all}"
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
exit 0
}

File Metadata

Mime Type
text/x-diff
Expires
Thu, Feb 27, 2:41 AM (1 d, 3 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1463235
Default Alt Text
(35 KB)

Event Timeline