Merge branch 'test_suite' into ronnie_target
[vlendec/samba-autobuild/.git] / ctdb / config / statd-callout
1 #!/bin/sh
2
3 # this script needs to be installed so that statd points to it with the -H 
4 # command line argument. The easiest way to do that is to put something like this in 
5 # /etc/sysconfig/nfs:
6 #   STATD_HOSTNAME="myhostname -H /etc/ctdb/statd-callout"
7
8 [ -z "$CTDB_BASE" ] && {
9     export CTDB_BASE="/etc/ctdb"
10 }
11
12 . $CTDB_BASE/functions
13 loadconfig ctdb
14 loadconfig nfs
15
16 [ -z $NFS_HOSTNAME ] && {
17         echo NFS_HOSTNAME is not configured. statd-callout failed.
18         exit 0
19 }
20
21 case "$1" in
22   add-client)
23         # the callout does not tell us to which ip the client connected
24         # so we must add it to all the ips that we serve
25         PNN=`ctdb xpnn | sed -e "s/.*://"`
26         ctdb ip -Y | while read LINE; do
27                 NODE=`echo $LINE | cut -f3 -d:`
28                 [ "$NODE" = "$PNN" ] || {
29                         # not us
30                         continue
31                 } 
32                 IP=`echo $LINE | cut -f2 -d:`
33                 mkdir -p $CTDB_VARDIR/state/statd/ip/$IP
34                 touch $CTDB_VARDIR/state/statd/ip/$IP/$2
35         done
36         ;;
37   del-client)
38         # the callout does not tell us to which ip the client disconnected
39         # so we must remove it from all the ips that we serve
40         PNN=`ctdb xpnn | sed -e "s/.*://"`
41         ctdb ip -Y | while read LINE; do
42                 NODE=`echo $LINE | cut -f3 -d:`
43                 [ "$NODE" = "$PNN" ] || {
44                         # not us
45                         continue
46                 } 
47                 IP=`echo $LINE | cut -f2 -d:`
48                 mkdir -p $CTDB_VARDIR/state/statd/ip/$IP
49                 rm -f $CTDB_VARDIR/state/statd/ip/$IP/$2
50         done
51         ;;
52   updatelocal)
53         # For all IPs we serve, collect info and push to the config database
54         PNN=`ctdb xpnn | sed -e "s/.*://"`
55         ctdb ip -Y | tail -n +2 | while read LINE; do
56                 NODE=`echo $LINE | cut -f3 -d:`
57                 [ "$NODE" = "$PNN" ] || {
58                         continue
59                 } 
60                 IP=`echo $LINE | cut -f2 -d:`
61
62                 mkdir -p $CTDB_VARDIR/state/statd/ip/$IP
63
64                 rm -f $CTDB_VARDIR/state/statd/ip/$IP.tar
65                 tar cfP $CTDB_VARDIR/state/statd/ip/$IP.tar $CTDB_VARDIR/state/statd/ip/$IP
66
67                 rm -f $CTDB_VARDIR/state/statd/ip/$IP.rec
68                 ctdb pfetch ctdb.tdb statd-state:$IP $CTDB_VARDIR/state/statd/ip/$IP.rec 2>/dev/null
69                 [ "$?" = "0" ] || {
70                         # something went wrong,  try storing this data
71                         echo No record. Store STATD state data for $IP
72                         ctdb pstore ctdb.tdb statd-state:$IP $CTDB_VARDIR/state/statd/ip/$IP.tar 2>/dev/null
73                         continue
74                 }
75
76                 cmp $CTDB_VARDIR/state/statd/ip/$IP.tar $CTDB_VARDIR/state/statd/ip/$IP.rec >/dev/null 2>/dev/null
77                 [ "$?" = "0" ] || {
78                         # something went wrong,  try storing this data
79                         echo Updated record. Store STATD state data for $IP
80                         ctdb pstore ctdb.tdb statd-state:$IP $CTDB_VARDIR/state/statd/ip/$IP.tar 2>/dev/null
81                         continue
82                 }
83         done
84         ;;
85
86   updateremote)
87         # For all IPs we dont serve, pull the state from the database
88         PNN=`ctdb xpnn | sed -e "s/.*://"`
89         ctdb ip -Y | tail -n +2 | while read LINE; do
90                 NODE=`echo $LINE | cut -f3 -d:`
91                 [ "$NODE" = "$PNN" ] && {
92                         continue
93                 } 
94                 IP=`echo $LINE | cut -f2 -d:`
95
96                 mkdir -p $CTDB_VARDIR/state/statd/ip/$IP
97
98                 rm -f $CTDB_VARDIR/state/statd/ip/$IP.rec
99                 ctdb pfetch ctdb.tdb statd-state:$IP $CTDB_VARDIR/state/statd/ip/$IP.rec 2>/dev/null
100                 [ "$?" = "0" ] || {
101                         continue
102                 }
103
104                 rm -f $CTDB_VARDIR/state/statd/ip/$IP/*
105                 tar xfP $CTDB_VARDIR/state/statd/ip/$IP.rec
106         done
107         ;;
108
109   notify)
110         # we must restart the lockmanager (on all nodes) so that we get
111         # a clusterwide grace period (so other clients dont take out
112         # conflicting locks through other nodes before all locks have been
113         # reclaimed)
114
115         # we need these settings to make sure that no tcp connections survive
116         # across a very fast failover/failback
117         #echo 10 > /proc/sys/net/ipv4/tcp_fin_timeout
118         #echo 0 > /proc/sys/net/ipv4/tcp_max_tw_buckets
119         #echo 0 > /proc/sys/net/ipv4/tcp_max_orphans
120
121         # Delete the notification list for statd, we dont want it to 
122         # ping any clients
123         rm -f /var/lib/nfs/statd/sm/*
124         rm -f /var/lib/nfs/statd/sm.bak/*
125
126         # we must keep a monotonically increasing state variable for the entire
127         # cluster  so state always increases when ip addresses fail from one
128         # node to another
129         # We use epoch and hope the nodes are close enough in clock.
130         # Even numbers mean service is shut down, odd numbers mean
131         # service is started.
132         STATE=`date +"%s"`
133         STATE=`expr "$STATE" "/" "2"`
134
135
136         # we must also let some time pass between stopping and restarting the
137         # lockmanager since othervise there is a window where the lockmanager
138         # will respond "strangely" immediately after restarting it, which
139         # causes clients to fail to reclaim the locks.
140         # 
141         startstop_nfslock stop > /dev/null 2>&1
142         sleep 2
143
144         # now start lockmanager again with the new state directory.
145         startstop_nfslock start > /dev/null 2>&1
146
147         # we now need to send out additional statd notifications to ensure
148         # that clients understand that the lockmanager has restarted.
149         # we have three cases:
150         # 1, clients that ignore the ip address the stat notification came from
151         #    and ONLY care about the 'name' in the notify packet.
152         #    these clients ONLY work with lock failover IFF that name
153         #    can be resolved into an ipaddress that matches the one used
154         #    to mount the share.  (==linux clients)
155         #    This is handled when starting lockmanager above,  but those
156         #    packets are sent from the "wrong" ip address, something linux
157         #    clients are ok with, buth other clients will barf at.
158         # 2, Some clients only accept statd packets IFF they come from the
159         #    'correct' ip address.
160         # 2a,Send out the notification using the 'correct' ip address and also
161         #    specify the 'correct' hostname in the statd packet.
162         #    Some clients require both the correct source address and also the
163         #    correct name. (these clients also ONLY work if the ip addresses
164         #    used to map the share can be resolved into the name returned in
165         #    the notify packet.)
166         # 2b,Other clients require that the source ip address of the notify
167         #    packet matches the ip address used to take out the lock.
168         #    I.e. that the correct source address is used.
169         #    These clients also require that the statd notify packet contains
170         #    the name as the ip address used when the lock was taken out.
171         #
172         # Both 2a and 2b are commonly used in lockmanagers since they maximize
173         # probability that the client will accept the statd notify packet and
174         # not just ignore it.
175         # For all IPs we serve, collect info and push to the config database
176         PNN=`ctdb xpnn | sed -e "s/.*://"`
177         ctdb ip -Y | tail -n +2 | while read LINE; do
178                 NODE=`echo $LINE | cut -f3 -d:`
179                 [ "$NODE" = "$PNN" ] || {
180                         continue
181                 } 
182                 IP=`echo $LINE | cut -f2 -d:`
183
184                 ls $CTDB_VARDIR/state/statd/ip/$IP | while read CLIENT; do
185                         rm $CTDB_VARDIR/state/statd/ip/$IP/$CLIENT
186                         smnotify --client=$CLIENT --ip=$IP --server=$ip --stateval=$STATE
187                         smnotify --client=$CLIENT --ip=$IP --server=$NFS_HOSTNAME --stateval=$STATE
188                         STATE=`expr "$STATE" "+" "1"`
189                         smnotify --client=$CLIENT --ip=$IP --server=$ip --stateval=$STATE
190                         smnotify --client=$CLIENT --ip=$IP --server=$NFS_HOSTNAME --stateval=$STATE
191                 done
192         done
193         ;;
194 esac