1# 2# Copyright (c) 2005 XenSource Ltd. 3# Copyright (c) 2007 Red Hat 4# 5# This library is free software; you can redistribute it and/or 6# modify it under the terms of version 2.1 of the GNU Lesser General Public 7# License as published by the Free Software Foundation. 8# 9# This library is distributed in the hope that it will be useful, 10# but WITHOUT ANY WARRANTY; without even the implied warranty of 11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12# Lesser General Public License for more details. 13# 14# You should have received a copy of the GNU Lesser General Public 15# License along with this library; If not, see <http://www.gnu.org/licenses/>. 16# 17 18# 19# Serialisation 20# 21 22LOCK_BASEDIR=$XEN_LOCK_DIR/xen-hotplug 23 24_setlockfd() 25{ 26 _lockfd=9 27 _lockfile="$LOCK_BASEDIR/$1" 28} 29 30 31claim_lock() 32{ 33 mkdir -p "$LOCK_BASEDIR" 34 _setlockfd $1 35 # The locking strategy is identical to that from with-lock-ex(1) 36 # from chiark-utils, except using flock. It has the benefit of 37 # it being possible to safely remove the lockfile when done. 38 # See below for a correctness proof. 39 local stat 40 while true; do 41 eval "exec $_lockfd<> $_lockfile" 42 # we can't flock $_lockfd here, as the shell closes it on exec. 43 # Workaround by redirecting to 0 for the command, and flock 0 instead. 44 flock -v -x 0 0<& $_lockfd|| exit 1 45 local file_stat 46 local fd_stat 47 if fd_stat=$(stat -f '%d.%i' 0<&$_lockfd 2>/dev/null) && file_stat=$(stat -f '%d.%i' $_lockfile 2>/dev/null ) 48 then 49 if [ "$fd_stat" = "$file_stat" ] ; then break; fi 50 fi 51 # Some versions of bash appear to be buggy if the same 52 # $_lockfile is opened repeatedly. Close the current fd here. 53 eval "exec $_lockfd<&-" 54 done 55} 56 57 58release_lock() 59{ 60 _setlockfd $1 61 rm "$_lockfile" 62} 63 64# Protocol and correctness proof: 65# 66# * The lock is owned not by a process but by an open-file (informally 67# an fd). Any process with an fd onto this open-file is a 68# lockholder and may perform the various operations; such a process 69# should only do so when its co-lockholder processes expect. Ie, we 70# will treat all processes holding fds onto the open-file as acting 71# in concert and not distinguish between them. 72# 73# * You are a lockholder if 74# - You have an fd onto an open-file which 75# currently holds an exclusive flock lock on its inum 76# - and that inum is currently linked at the lockfile path 77# 78# * The rules are: 79# - No-one but a lockholder may unlink the lockfile path 80# (or otherwise cause it to stop referring to a file it 81# refers to). 82# - Anyone may open the lockfile with O_CREAT 83# 84# * The protocol for locking is: 85# - Open the file (O_CREAT) 86# - flock it 87# - fstat the fd you have open 88# - stat the lockfile path 89# - if both are equal you have the lock, otherwise try again. 90# 91# * Informal proof of exclusivity: 92# - No two open-files can hold an fcntl lock onto the same file 93# at the same time 94# - No two files can have the same name at the same time 95# 96# * Informal proof of correctness of locking protocol: 97# - After you call flock successfully no-one other than you 98# (someone with the same open-file) can stop you having 99# that flock lock. 100# - Obviously the inum you get from the fstat is fixed 101# - At the point where you call stat there are two 102# possibilities: 103# (i) the lockfile path referred to some other inum 104# in which case you have failed 105# (ii) the lockfile path referred to the same file 106# in which case at that point you were the 107# lockholder (by definition). 108# 109# * Informal proof that no-one else can steal the lock: 110# - After you call flock successfully no-one other than you 111# can stop you having that flock lock 112# - No-one other than the lockholder is permitted to stop 113# the path referring to a particular inum. So if you 114# hold the lock then only you are allowed to stop the 115# path referring to the file whose flock you hold; so 116# it will continue to refer to that file. 117# That's both the conditions for being the lockholder. 118# 119# Thus once you hold the lock at any instant, you will 120# continue to do so until you voluntarily stop doing so 121# (eg by unlinking the lockfile or closing the fd). 122