From: Csaba Henk Date: Sun, 6 Jan 2008 15:34:10 +0000 (+0000) Subject: lib/mount_bsd.c: fix up/refine device closing vs. unmount X-Git-Tag: fuse_2_8_start~8 X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=97bedd898976db5ac53812be5399869fba92e2cd;p=qemu-gpiodev%2Flibfuse.git lib/mount_bsd.c: fix up/refine device closing vs. unmount --- diff --git a/lib/Makefile.am b/lib/Makefile.am index 4d14ef4..48986bb 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -36,6 +36,9 @@ libfuse_la_SOURCES = \ libfuse_la_LDFLAGS = @libfuse_libs@ -version-number 2:7:2 \ -Wl,--version-script,$(srcdir)/fuse_versionscript +if BSD +libfuse_la_LDFLAGS += -lkvm +endif libulockmgr_la_SOURCES = ulockmgr.c libulockmgr_la_LDFLAGS = -version-number 1:0:1 diff --git a/lib/mount_bsd.c b/lib/mount_bsd.c index 09611c1..d7f0f33 100644 --- a/lib/mount_bsd.c +++ b/lib/mount_bsd.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -21,9 +22,12 @@ #include #include #include +#include +#include #define FUSERMOUNT_PROG "mount_fusefs" #define FUSE_DEV_TRUNK "/dev/fuse" +#define FUSE_ANS_WCHAN "fu_ans" enum { KEY_ALLOW_ROOT, @@ -206,13 +210,83 @@ void fuse_unmount_compat22(const char *mountpoint) return; asprintf(&umount_cmd, "/sbin/umount %s", dev); - close(fd); system(umount_cmd); } +static void do_unmount(char *dev, int fd) +{ + char *device_path; + const char *argv[3]; + const char umount_cmd[] = "/sbin/umount"; + pid_t pid, rpid = 0; + + asprintf(&device_path, _PATH_DEV "%s", dev); + + argv[0] = umount_cmd; + argv[1] = device_path; + argv[2] = NULL; + + pid = fork(); + + if (pid == -1) + return; + + /* + * We don't simply close the device fd, because that's what + * guarantees us exclusive access to the device. + * + * OTOH, unmount(2) might get stuck if the device is kept + * open. + * + * So after we have spawn the umount process, we monitor it + * using the kvm(3) interface, and if we see it's waiting + * for an answer from us -- which implies the umount process + * still keeps the device occupied, regardless of the fd -- + * _then_ we close the device, interrupting thus unmount(2) + * in its futile waiting. + */ + if (pid) { + kvm_t *kd; + struct kinfo_proc *kp; + char errbuf[_POSIX2_LINE_MAX]; + int nentries; + + kd = kvm_openfiles(_PATH_DEVNULL, _PATH_DEVNULL, NULL, + O_RDONLY, errbuf); + if (!kd) + goto out; + + for (;;) { + kp = kvm_getprocs(kd, KERN_PROC_PID, pid, &nentries); + + if (kp && nentries == 1 && + strcmp(kp->ki_wmesg, FUSE_ANS_WCHAN) == 0) { + close(fd); + + break; + } + + rpid = waitpid(pid, NULL, WNOHANG); + if (rpid) + break; + usleep(10000); + } + + kvm_close(kd); + } else { + close(fd); + execvp(umount_cmd, (char **)argv); + exit(1); + } + +out: + if (!rpid) + waitpid(pid, NULL, 0); +} + void fuse_kern_unmount(const char *mountpoint, int fd) { - char *ep, *umount_cmd, dev[128]; + char *ep, dev[128]; struct stat sbuf; (void)mountpoint; @@ -229,9 +303,7 @@ void fuse_kern_unmount(const char *mountpoint, int fd) if (*ep != '\0') return; - asprintf(&umount_cmd, "/sbin/umount " _PATH_DEV "%s", dev); - close(fd); - system(umount_cmd); + do_unmount(dev, fd); } /* Check if kernel is doing init in background */