#!@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 # # Copy out a list from , merge them with the system nfs lock # list, and send them out as 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 " 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 # # Send the contents of 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 /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 }