summaryrefslogtreecommitdiffstats
path: root/fuse
diff options
context:
space:
mode:
authorRichard W.M. Jones <rjones@redhat.com>2012-07-10 18:59:35 +0100
committerRichard W.M. Jones <rjones@redhat.com>2012-07-10 19:03:19 +0100
commitec0c7e0a1aafd145309ab53749d910ad837d8745 (patch)
tree0e7b52cf6056f07929e6c66cc474c4bef8444e28 /fuse
parentf883e4d8d3ea65c5cd4c2dc5d557989c00aafc56 (diff)
downloadlibguestfs-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.pod42
-rwxr-xr-xfuse/test-fuse-umount-race.sh15
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