diff options
Diffstat (limited to 'rgmanager/src/resources/svclib_nfslock.in')
-rw-r--r-- | rgmanager/src/resources/svclib_nfslock.in | 281 |
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 +} + |