diff options
author | Richard W.M. Jones <rjones@redhat.com> | 2012-07-10 18:59:35 +0100 |
---|---|---|
committer | Richard W.M. Jones <rjones@redhat.com> | 2012-07-10 19:03:19 +0100 |
commit | ec0c7e0a1aafd145309ab53749d910ad837d8745 (patch) | |
tree | 0e7b52cf6056f07929e6c66cc474c4bef8444e28 /fuse | |
parent | f883e4d8d3ea65c5cd4c2dc5d557989c00aafc56 (diff) | |
download | libguestfs-ec0c7e0a1aafd145309ab53749d910ad837d8745.tar.gz libguestfs-ec0c7e0a1aafd145309ab53749d910ad837d8745.tar.xz libguestfs-ec0c7e0a1aafd145309ab53749d910ad837d8745.zip |
fuse: Cleaner code and documentation for safe cleanups.
Diffstat (limited to 'fuse')
-rw-r--r-- | fuse/guestmount.pod | 42 | ||||
-rwxr-xr-x | fuse/test-fuse-umount-race.sh | 15 |
2 files changed, 50 insertions, 7 deletions
diff --git a/fuse/guestmount.pod b/fuse/guestmount.pod index fdcf1337..a9da457b 100644 --- a/fuse/guestmount.pod +++ b/fuse/guestmount.pod @@ -99,7 +99,19 @@ programs. The popular workaround for this problem is to retry the C<fusermount -u> command a few times until it works. Unfortunately this isn't a reliable fix if (for example) the mounted filesystem is -particularly large and the intruding program is persistent. +particularly large and the intruding program particularly persistent. + + timeout=10 + + count=$timeout + while ! fusermount -u $mountpoint && [ $count -gt 0 ]; do + sleep 1 + ((count--)) + done + if [ $count -eq 0 ]; then + echo "$0: fusermount failed after $timeout seconds" + exit 1 + fi A proper fix is to use a private mountpoint by creating a new mount namespace using the Linux-specific L<clone(2)>/L<unshare(2)> flag @@ -118,12 +130,38 @@ condition: guestmount -a disk.img -i /mnt # copy things into /mnt fusermount -u /mnt - # immediately try to use 'disk.img' <-- UNSAFE + # immediately try to use 'disk.img' ** UNSAFE ** The solution is to use the I<--pid-file> option to write the guestmount PID to a file, then after fusermount spin waiting for this PID to exit. + guestmount -a disk.img -i --pid-file guestmount.pid /mnt + + # ... + # ... + + # Save the PID of guestmount *before* calling fusermount. + pid="$(cat guestmount.pid)" + + timeout=10 + + # fusermount retry code, see above + # ... + # ... + + count=$timeout + while kill -0 "$pid" 2>/dev/null && [ $count -gt 0 ]; do + sleep 1 + ((count--)) + done + if [ $count -eq 0 ]; then + echo "$0: wait for guestmount to exit failed after $timeout seconds" + exit 1 + fi + + # Now it is safe to use the disk image. + Note that if you use the C<guestfs_mount_local> API directly (see L<guestfs(3)/MOUNT LOCAL>) then it is much easier to write a safe, race-free program. diff --git a/fuse/test-fuse-umount-race.sh b/fuse/test-fuse-umount-race.sh index a5a6e21d..c4ff2e9a 100755 --- a/fuse/test-fuse-umount-race.sh +++ b/fuse/test-fuse-umount-race.sh @@ -43,24 +43,29 @@ mkdir mp ./guestmount -a test.qcow2 -m /dev/VG/Root --pid-file test.pid mp cp $0 mp/test-umount -count=10 +# Save the PID of guestmount. +pid="$(cat test.pid)" + +timeout=10 + +count=$timeout while ! fusermount -u mp && [ $count -gt 0 ]; do sleep 1 ((count--)) done if [ $count -eq 0 ]; then - echo "$0: fusermount failed after 10 attempts" + echo "$0: fusermount failed after $timeout seconds" exit 1 fi # Wait for guestmount to exit. -count=10 -while kill -0 `cat test.pid` 2>/dev/null && [ $count -gt 0 ]; do +count=$timeout +while kill -0 "$pid" 2>/dev/null && [ $count -gt 0 ]; do sleep 1 ((count--)) done if [ $count -eq 0 ]; then - echo "$0: wait for guestmount to exit failed after 10 seconds" + echo "$0: wait for guestmount to exit failed after $timeout seconds" exit 1 fi |