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=/var/run/xen-hotplug 23 24_setlockfd() 25{ 26 local i 27 for ((i = 0; i < ${#_lockdict}; i++)) 28 do [ -z "${_lockdict[$i]}" -o "${_lockdict[$i]}" = "$1" ] && break 29 done 30 _lockdict[$i]="$1" 31 let _lockfd=200+i 32 _lockfile="$LOCK_BASEDIR/$1" 33} 34 35 36claim_lock() 37{ 38 mkdir -p "$LOCK_BASEDIR" 39 _setlockfd $1 40 # The locking strategy is identical to that from with-lock-ex(1) 41 # from chiark-utils, except using flock. It has the benefit of 42 # it being possible to safely remove the lockfile when done. 43 # See below for a correctness proof. 44 local rightfile 45 while true; do 46 eval "exec $_lockfd<>$_lockfile" 47 flock -x $_lockfd || return $? 48 # We can't just stat /dev/stdin or /proc/self/fd/$_lockfd or 49 # use bash's test -ef because those all go through what is 50 # actually a synthetic symlink in /proc and we aren't 51 # guaranteed that our stat(2) won't lose the race with an 52 # rm(1) between reading the synthetic link and traversing the 53 # file system to find the inum. Perl is very fast so use that. 54 rightfile=$( perl -e ' 55 open STDIN, "<&'$_lockfd'" or die $!; 56 my $fd_inum = (stat STDIN)[1]; die $! unless defined $fd_inum; 57 my $file_inum = (stat $ARGV[0])[1]; 58 print "y\n" if $fd_inum eq $file_inum; 59 ' "$_lockfile" ) 60 if [ x$rightfile = xy ]; then break; fi 61 # Some versions of bash appear to be buggy if the same 62 # $_lockfile is opened repeatedly. Close the current fd here. 63 eval "exec $_lockfd<&-" 64 done 65} 66 67 68release_lock() 69{ 70 _setlockfd $1 71 rm "$_lockfile" 72} 73 74# Protocol and correctness proof: 75# 76# * The lock is owned not by a process but by an open-file (informally 77# an fd). Any process with an fd onto this open-file is a 78# lockholder and may perform the various operations; such a process 79# should only do so when its co-lockholder processes expect. Ie, we 80# will treat all processes holding fds onto the open-file as acting 81# in concert and not distinguish between them. 82# 83# * You are a lockholder if 84# - You have an fd onto an open-file which 85# currently holds an exclusive flock lock on its inum 86# - and that inum is currently linked at the lockfile path 87# 88# * The rules are: 89# - No-one but a lockholder may unlink the lockfile path 90# (or otherwise cause it to stop referring to a file it 91# refers to). 92# - Anyone may open the lockfile with O_CREAT 93# 94# * The protocol for locking is: 95# - Open the file (O_CREAT) 96# - flock it 97# - fstat the fd you have open 98# - stat the lockfile path 99# - if both are equal you have the lock, otherwise try again. 100# 101# * Informal proof of exclusivity: 102# - No two open-files can hold an fcntl lock onto the same file 103# at the same time 104# - No two files can have the same name at the same time 105# 106# * Informal proof of correctness of locking protocol: 107# - After you call flock successfully no-one other than you 108# (someone with the same open-file) can stop you having 109# that flock lock. 110# - Obviously the inum you get from the fstat is fixed 111# - At the point where you call stat there are two 112# possibilities: 113# (i) the lockfile path referred to some other inum 114# in which case you have failed 115# (ii) the lockfile path referred to the same file 116# in which case at that point you were the 117# lockholder (by definition). 118# 119# * Informal proof that no-one else can steal the lock: 120# - After you call flock successfully no-one other than you 121# can stop you having that flock lock 122# - No-one other than the lockholder is permitted to stop 123# the path referring to a particular inum. So if you 124# hold the lock then only you are allowed to stop the 125# path referring to the file whose flock you hold; so 126# it will continue to refer to that file. 127# That's both the conditions for being the lockholder. 128# 129# Thus once you hold the lock at any instant, you will 130# continue to do so until you voluntarily stop doing so 131# (eg by unlinking the lockfile or closing the fd). 132