summaryrefslogtreecommitdiffstats
path: root/rgmanager/src/resources/svclib_nfslock.in
diff options
context:
space:
mode:
Diffstat (limited to 'rgmanager/src/resources/svclib_nfslock.in')
-rw-r--r--rgmanager/src/resources/svclib_nfslock.in281
1 files changed, 281 insertions, 0 deletions
diff --git a/rgmanager/src/resources/svclib_nfslock.in b/rgmanager/src/resources/svclib_nfslock.in
new file mode 100644
index 0000000..86efd07
--- /dev/null
+++ b/rgmanager/src/resources/svclib_nfslock.in
@@ -0,0 +1,281 @@
+#!@BASH_SHELL@
+#
+# 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.
+#
+
+# Do reclaim-broadcasts when we kill lockd during shutdown/startup
+# of a cluster service.
+#
+# Exported functions:
+#
+# notify_list_store
+# notify_list_merge
+# notify_list_broadcast
+#
+
+#
+# Usage:
+# statd_notify <directory> <hostname|ip>
+#
+# Copy out a list from <directory>, merge them with the system nfs lock
+# list, and send them out as <hostname|ip> after generating a random
+# state (needed so clients will reclaim their locks)
+#
+nfslock_statd_notify()
+{
+ declare tmpdir
+ declare nl_dir=$1
+ declare nl_ip=$2
+ declare command # Work around bugs in rpc.statd
+ declare pid_xxx # Work around bugs in rpc.statd
+ declare owner
+
+ [ -z "$lockd_pid" ] && return 0
+ if ! [ -d $nl_dir ]; then
+ return 0
+ fi
+
+ if [ -z "`ls $nl_dir/sm/* 2> /dev/null`" ]; then
+ ocf_log debug "No hosts to notify"
+ return 0
+ fi
+
+ tmpdir=$(mktemp -d /tmp/statd-$2.XXXXXX)
+
+ # Ok, copy the HA directory to something we can use.
+ mkdir -p $tmpdir/sm
+
+ # Copy in our specified entries
+ cp -f $nl_dir/sm/* $tmpdir/sm
+
+ # Copy in our global entries
+ # XXX This might be what we just copied.
+
+ if [ -d "/var/lib/nfs/statd/sm" ]; then
+ owner=$(ls -dl /var/lib/nfs/statd/sm | awk '{print $3"."$4}')
+ cp -f /var/lib/nfs/statd/sm/* $tmpdir/sm
+ elif [ -d "/var/lib/nfs/sm" ]; then
+ owner=$(ls -dl /var/lib/nfs/statd/sm | awk '{print $3"."$4}')
+ cp -f /var/lib/nfs/sm/* $tmpdir/sm
+ fi
+
+ #
+ # Generate a random state file. If this ends up being what a client
+ # already has in its list, that's bad, but the chances of this
+ # are small - and relocations should be rare.
+ #
+ dd if=/dev/urandom of=$tmpdir/state bs=1 count=4 &> /dev/null
+
+ #
+ # Make sure we set permissions, or statd will not like it.
+ #
+ chown -R $owner $tmpdir
+
+ #
+ # Tell rpc.statd to notify clients. Don't go into background,
+ # because statd is buggy and won't exit like it's supposed to after
+ # sending the notifications out.
+ #
+ ocf_log info "Sending reclaim notifications via $nl_ip"
+ command="rpc.statd -NFP $tmpdir -n $nl_ip"
+ eval $command 2>&1 &
+ sleep 3 # XXX - the instance of rpc.statd we just spawned is supposed
+ # to exit after it finishes notifying clients.
+ # rpc.statd spawned which is still running handles the actual
+ # new SM_MON requests... we hope 3 seconds is enough time
+ # to get all the SM_NOTIFY messages out. rpc.statd = bugged
+ #
+ # clean up
+ #
+ pid_xxx=`ps auwwx | grep "$command" | grep -v grep | awk '{print $2}'`
+ kill $pid_xxx
+ rm -rf $tmpdir
+
+ return 0
+}
+
+
+#
+# Copy of isSlave from svclib_ip and/or ip.sh
+#
+nfslock_isSlave()
+{
+ declare intf=$1
+ declare line
+
+ if [ -z "$intf" ]; then
+ ocf_log err "usage: isSlave <I/F>"
+ return 1
+ fi
+
+ line=$(/sbin/ip link list dev $intf)
+ if [ $? -ne 0 ]; then
+ ocf_log err "$intf not found"
+ return 1
+ fi
+
+ if [ "$line" = "${line/<*SLAVE*>/}" ]; then
+ return 2
+ fi
+
+ # Yes, it is a slave device. Ignore.
+ return 0
+}
+
+
+#
+# Get all the IPs on the system except loopback IPs
+#
+nfslock_ip_address_list()
+{
+ declare idx dev family ifaddr
+
+ while read idx dev family ifaddr; do
+
+ if [ "$family" != "inet" ] && [ "$family" != "inet6" ]; then
+ continue
+ fi
+
+ if [ "$dev" = "lo" ]; then
+ # Ignore loopback
+ continue
+ fi
+
+ nfslock_isSlave $dev
+ if [ $? -ne 2 ]; then
+ continue
+ fi
+
+ idx=${idx/:/}
+
+ echo $dev $family ${ifaddr/\/*/} ${ifaddr/*\//}
+
+ done < <(/sbin/ip -o addr list | awk '{print $1,$2,$3,$4}')
+
+ return 0
+}
+
+
+#
+# Usage: broadcast_notify <state_directory>
+#
+# Send the contents of <state_directory> out via all IPs on the system.
+#
+notify_list_broadcast()
+{
+ declare dev family addr maskbits ip_name
+ declare lockd_pid=$(pidof lockd)
+ declare nl_dir=$1
+
+ # First of all, send lockd a SIGKILL. We hope nfsd is running.
+ # If it is, this will cause lockd to reset the grace period for
+ # lock reclaiming.
+ if [ -n "$lockd_pid" ]; then
+ ocf_log info "Asking lockd to drop locks (pid $lockd_pid)"
+ kill -9 $lockd_pid
+ else
+ ocf_log warning "lockd not running; cannot notify clients"
+ return 1
+ fi
+
+ while read dev family addr maskbits; do
+ if [ "$family" != "inet" ]; then
+ continue
+ fi
+
+ ip_name=$(clufindhostname -i $addr)
+ if [ -z "$ip_name" ]; then
+ nfslock_statd_notify $nl_dir $addr
+ else
+ nfslock_statd_notify $nl_dir $ip_name
+ fi
+
+ done < <(nfslock_ip_address_list)
+}
+
+
+#
+# Store the lock monitor list from rpc.statd - do this during a teardown
+# after the IP addresses of a service have been taken offline. Note that
+# this should be done by HA-callout programs, but this feature is not in
+# RHEL3.
+#
+notify_list_store()
+{
+ declare nl_dir=$1
+ declare owner
+
+ mkdir -p $nl_dir/sm
+
+ if [ -d "/var/lib/nfs/statd/sm" ]; then
+ if [ -z "`ls /var/lib/nfs/statd/sm/* 2> /dev/null`" ]; then
+ return 1
+ # nothing to do!
+ fi
+
+ owner=$(ls -dl /var/lib/nfs/statd/sm | awk '{print $3"."$4}')
+ cp -Rdpf /var/lib/nfs/statd/sm/* $nl_dir/sm
+ chown -R $owner $nl_dir
+ return 0
+ elif [ -d "/var/lib/nfs/sm" ]; then
+ if [ -z "`ls /var/lib/nfs/sm/* 2> /dev/null`" ]; then
+ return 1
+ # nothing to do!
+ fi
+
+ owner=$(ls -dl /var/lib/nfs/sm | awk '{print $3"."$4}')
+ cp -Rdpf /var/lib/nfs/sm/* $nl_dir/sm
+ chown -R $owner $nl_dir
+ return 0
+ fi
+
+ return 1
+}
+
+
+#
+# Merge the contents of <nl_dir>/sm with the system-wide list
+# Make sure ownership is right, or statd will hiccup. This should not
+# actually ever be needed because statd will, upon getting a SM_MON
+# request, create all the entries in this list. It's mostly for
+# housekeeping for next time we relocate the service.
+#
+notify_list_merge()
+{
+ declare nl_dir=$1
+ declare owner
+
+ if [ -z "`ls $nl_dir/* 2> /dev/null`" ]; then
+ return 1
+ fi
+
+ if [ -d "/var/lib/nfs/statd/sm" ]; then
+ owner=$(ls -dl /var/lib/nfs/statd/sm | awk '{print $3"."$4}')
+ cp -Rdpf $nl_dir/sm/* /var/lib/nfs/statd/sm
+ chown -R $owner $nl_dir
+ return 0
+ elif [ -d "/var/lib/nfs/sm" ]; then
+ owner=$(ls -dl /var/lib/nfs/sm | awk '{print $3"."$4}')
+ cp -Rdpf $nl_dir/sm/* /var/lib/nfs/sm
+ chown -R $owner $nl_dir
+ return 0
+ fi
+
+ return 1
+}
+