summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2009-12-23 12:51:40 +0000
committerMiklos Szeredi <miklos@szeredi.hu>2009-12-23 12:51:40 +0000
commit4c3d9b19576c228e1a3c6eab9a6942d9431f6ce4 (patch)
tree28babd13dc0472ebb7ce251544329eeda32b98ec
parente61b775a5ae3ac4c3d4b6edb9a4401d39d288cb5 (diff)
downloadfuse-4c3d9b19576c228e1a3c6eab9a6942d9431f6ce4.tar.gz
* Use '--no-canonicalize' option of mount(8) (available in
util-linux-ng version 2.17 or greater) to avoid calling readling(2) on the newly mounted filesystem before the mount procedure is finished. This has caused a deadlock if audit was enabled in the kernel. Also use '--no-canonicalize' for umount to avoid touching the mounted filesystem.
-rw-r--r--ChangeLog9
-rw-r--r--lib/mount_util.c121
2 files changed, 116 insertions, 14 deletions
diff --git a/ChangeLog b/ChangeLog
index 1711026..47e6100 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2009-12-17 Miklos Szeredi <miklos@szeredi.hu>
+
+ * Use '--no-canonicalize' option of mount(8) (available in
+ util-linux-ng version 2.17 or greater) to avoid calling
+ readling(2) on the newly mounted filesystem before the mount
+ procedure is finished. This has caused a deadlock if "audit" was
+ enabled in the kernel. Also use '--no-canonicalize' for umount to
+ avoid touching the mounted filesystem.
+
2009-09-11 Miklos Szeredi <miklos@szeredi.hu>
* Released 2.8.1
diff --git a/lib/mount_util.c b/lib/mount_util.c
index e78b482..3b6e771 100644
--- a/lib/mount_util.c
+++ b/lib/mount_util.c
@@ -13,6 +13,7 @@
#include <string.h>
#include <dirent.h>
#include <errno.h>
+#include <fcntl.h>
#include <limits.h>
#include <mntent.h>
#include <sys/stat.h>
@@ -53,17 +54,14 @@ static int mtab_needs_update(const char *mnt)
return 1;
}
-int fuse_mnt_add_mount(const char *progname, const char *fsname,
- const char *mnt, const char *type, const char *opts)
+static int add_mount_legacy(const char *progname, const char *fsname,
+ const char *mnt, const char *type, const char *opts)
{
int res;
int status;
sigset_t blockmask;
sigset_t oldmask;
- if (!mtab_needs_update(mnt))
- return 0;
-
sigemptyset(&blockmask);
sigaddset(&blockmask, SIGCHLD);
res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
@@ -116,23 +114,83 @@ int fuse_mnt_add_mount(const char *progname, const char *fsname,
out_restore:
sigprocmask(SIG_SETMASK, &oldmask, NULL);
+
return res;
}
-int fuse_mnt_umount(const char *progname, const char *mnt, int lazy)
+static int add_mount(const char *progname, const char *fsname,
+ const char *mnt, const char *type, const char *opts)
{
int res;
int status;
sigset_t blockmask;
sigset_t oldmask;
- if (!mtab_needs_update(mnt)) {
- res = umount2(mnt, lazy ? 2 : 0);
- if (res == -1)
- fprintf(stderr, "%s: failed to unmount %s: %s\n",
- progname, mnt, strerror(errno));
- return res;
+ sigemptyset(&blockmask);
+ sigaddset(&blockmask, SIGCHLD);
+ res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
+ if (res == -1) {
+ fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
+ return -1;
+ }
+
+ res = fork();
+ if (res == -1) {
+ fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
+ goto out_restore;
}
+ if (res == 0) {
+ /*
+ * Hide output, because old versions don't support
+ * --no-canonicalize
+ */
+ int fd = open("/dev/null", O_RDONLY);
+ dup2(fd, 1);
+ dup2(fd, 2);
+
+ sigprocmask(SIG_SETMASK, &oldmask, NULL);
+ setuid(geteuid());
+ execl("/bin/mount", "/bin/mount", "--no-canonicalize", "-i",
+ "-f", "-t", type, "-o", opts, fsname, mnt, NULL);
+ fprintf(stderr, "%s: failed to execute /bin/mount: %s\n",
+ progname, strerror(errno));
+ exit(1);
+ }
+ res = waitpid(res, &status, 0);
+ if (res == -1)
+ fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
+
+ if (status != 0)
+ res = -1;
+
+ out_restore:
+ sigprocmask(SIG_SETMASK, &oldmask, NULL);
+
+ return res;
+}
+
+int fuse_mnt_add_mount(const char *progname, const char *fsname,
+ const char *mnt, const char *type, const char *opts)
+{
+ int res;
+
+ if (!mtab_needs_update(mnt))
+ return 0;
+
+ res = add_mount(progname, fsname, mnt, type, opts);
+ if (res == -1)
+ res = add_mount_legacy(progname, fsname, mnt, type, opts);
+
+ return res;
+}
+
+static int exec_umount(const char *progname, const char *mnt, int lazy,
+ int legacy)
+{
+ int res;
+ int status;
+ sigset_t blockmask;
+ sigset_t oldmask;
sigemptyset(&blockmask);
sigaddset(&blockmask, SIGCHLD);
@@ -148,10 +206,25 @@ int fuse_mnt_umount(const char *progname, const char *mnt, int lazy)
goto out_restore;
}
if (res == 0) {
+ /*
+ * Hide output, because old versions don't support
+ * --no-canonicalize
+ */
+ if (!legacy) {
+ int fd = open("/dev/null", O_RDONLY);
+ dup2(fd, 1);
+ dup2(fd, 2);
+ }
+
sigprocmask(SIG_SETMASK, &oldmask, NULL);
setuid(geteuid());
- execl("/bin/umount", "/bin/umount", "-i", mnt,
- lazy ? "-l" : NULL, NULL);
+ if (legacy) {
+ execl("/bin/umount", "/bin/umount", "-i", mnt,
+ lazy ? "-l" : NULL, NULL);
+ } else {
+ execl("/bin/umount", "/bin/umount", "--no-canonicalize",
+ "-i", mnt, lazy ? "-l" : NULL, NULL);
+ }
fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
progname, strerror(errno));
exit(1);
@@ -166,6 +239,26 @@ int fuse_mnt_umount(const char *progname, const char *mnt, int lazy)
out_restore:
sigprocmask(SIG_SETMASK, &oldmask, NULL);
return res;
+
+}
+
+int fuse_mnt_umount(const char *progname, const char *mnt, int lazy)
+{
+ int res;
+
+ if (!mtab_needs_update(mnt)) {
+ res = umount2(mnt, lazy ? 2 : 0);
+ if (res == -1)
+ fprintf(stderr, "%s: failed to unmount %s: %s\n",
+ progname, mnt, strerror(errno));
+ return res;
+ }
+
+ res = exec_umount(progname, mnt, lazy, 0);
+ if (res == -1)
+ res = exec_umount(progname, mnt, lazy, 1);
+
+ return res;
}
char *fuse_mnt_resolve_path(const char *progname, const char *orig)