diff options
author | Csaba Henk <csaba@redhat.com> | 2012-05-14 17:07:28 +0530 |
---|---|---|
committer | Anand Avati <avati@redhat.com> | 2012-05-21 13:47:09 -0700 |
commit | 439d0426dd60ef6c1f4af13fcbbe73f1d206acc6 (patch) | |
tree | ab9b7637bd223bf7862e2861dd562faa541687eb /contrib/fuse-util | |
parent | a2b7f11f279b9acc74c1a3b6d893fda7c160683d (diff) |
fuse, glusterfsd: mount logic fixes
Commit 7d0397c2 introduced two issues:
i) broke the libfuse derived mount logic (details below)
ii) in case of a daemonized glusterfs client is ran as daemon, parent
process can return earlier than the mount is in place, which breaks
agents that programmatically do a gluster mount via a direct call to
glusterfs (ie. not via mount(8)).
This patch fixes these issues by a refactor that merges the approaches
sported by commits
7d0397c2 fuse: allow requests during mount (needed for SELinux labels)
c5d781e0 upon daemonizing, wait on mtab update to terminate in parent
Original daemonized libfuse event flow is as follows:
try:
fd = open("/dev/fuse")
mount("-oopts,fd=%s" % fd ...)
mount(8) -f # manipulate mtab
except:
sp = socketpair()
env _FUSE_COMMFD=sp fusermount -oopts
fd = receive_fd(sp)
where fusermount(1) does:
fd = open("/dev/fuse")
mount("-oopts,fd=%d" % fd ...)
sp = atoi(getenv("_FUSE_COMMFD"))
send_fd(sp, fd)
daemonize(
# in child
fuse_loop(fd)
)
# in parent
exit()
As of 013850c9 (instead of adopting FUSE's 47e61004¹), we went for async
mtab manipulation, and as of c5d781e0, still wanted keep that in sync
with termination of daemon parent, so we changed it to:
try:
fd = open("/dev/fuse")
mount("-oopts,fd=%s" % fd ...)
pid = fork(
# in child
mount(8) -f
)
except:
sp = socketpair()
env _FUSE_COMMFD=sp fusermount -oopts
fd = receive_fd(sp)
daemonize(
fuse_loop(fd)
)
waitpid(pid)
exit()
(Note the new approch came only to direct [privileged] mount, so fusermount
based mounting was already partially broken.)
As of 7d0397c2, with the purpose of facilitating async mount, the event flow
was practically reduced to:
fd = open("/dev/fuse")
fork(
mount("-oopts,fd=%s" % fd ...)
fork(
mount(8) -n
)
)
daemonize(
fuse_loop(fd)
)
exit()
Thus fusermount based mounting become defunct; however, the dead
code was still kept around. So, we should either drop it or fix
it. Also, the mtab manipulator is forked into yet another child
with no purpose, while syncing with it in daemon parent is broken.
mount(2) is neither synced with parent.
Now we are coming to the following scheme:
fd = open("/dev/fuse")
pid = fork(
try:
mount("-oopts,fd=%s" % fd ...)
mount(8) -n
except:
env _FUSE_DEVFD=fd fusermount -oopts
)
where fusermount(1) does:
fd = getenv("_FUSE_DEVFD")
mount("-oopts,fd=%s" % fd ...)
daemonize(
fuse_loop(fd)
)
waitpid(pid)
exit()
Nb.:
- We can't help losing compatibility with upstream fusermount,
as it sends back the fd only when mount(2) is completed,
thus defeating the async mount approach. The
'getenv("_FUSE_DEVFD")' mechanism is specfic to glusterfs'
fusermount (at the moment -- sure we can talk about it with
upstream)
- fusermount opens /dev/fuse at same privilege level as of
original process², so we can bravely go on with doing the open
unconditionally in original process
- Original mounting code actually tries to mount through
fusermount _twice_: if first attempt fails, then, assuming
subtype support is missing in kernel, it tries again subtype
stripped. However, this is redundant, as fusermount internally
also performs the subtype check³. Therefore we simplified the
logic to have just a single fusermount call.
- we revert the changes to mount.glusterfs as of 7d0397c2, as
now there is no issue with glusterfs to work around in that scope
¹ http://fuse.git.sourceforge.net/git/gitweb.cgi?p=fuse/fuse;a=blobdiff;f=ChangeLog;h=47e61004;hb=4c3d9b19;hpb=e61b775a
² http://fuse.git.sourceforge.net/git/gitweb.cgi?p=fuse/fuse;a=blob;f=util/fusermount.c;h=b2e87d95#l1023
³ http://fuse.git.sourceforge.net/git/gitweb.cgi?p=fuse/fuse;a=blob;f=util/fusermount.c;h=b2e87d95#l839
Change-Id: I0c4ab70e0c5ad7b27337228749b266bcd0ba941d
BUG: 811217
Signed-off-by: Csaba Henk <csaba@redhat.com>
Reviewed-on: http://review.gluster.com/3341
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Jeff Darcy <jdarcy@redhat.com>
Reviewed-by: Anand Avati <avati@redhat.com>
Diffstat (limited to 'contrib/fuse-util')
-rw-r--r-- | contrib/fuse-util/fusermount.c | 60 |
1 files changed, 48 insertions, 12 deletions
diff --git a/contrib/fuse-util/fusermount.c b/contrib/fuse-util/fusermount.c index 39da9b6a0b6..4e7e4f9501c 100644 --- a/contrib/fuse-util/fusermount.c +++ b/contrib/fuse-util/fusermount.c @@ -19,6 +19,7 @@ #include <errno.h> #include <fcntl.h> #include <pwd.h> +#include <limits.h> #include <mntent.h> #include <sys/wait.h> #include <sys/stat.h> @@ -28,6 +29,7 @@ #include <sys/utsname.h> #include <sched.h> +#define FUSE_DEVFD_ENV "_FUSE_DEVFD" #define FUSE_COMMFD_ENV "_FUSE_COMMFD" #define FUSE_DEV_OLD "/proc/fs/fuse/dev" @@ -1016,8 +1018,36 @@ static int open_fuse_device(char **devp) return -1; } +static int check_fuse_device(char *devfd, char **devp) +{ + int res; + char *devlink; + + res = asprintf(&devlink, "/proc/self/fd/%s", devfd); + if (res == -1) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + return -1; + } + + *devp = (char *) calloc(1, PATH_MAX + 1); + if (!*devp) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + free(devlink); + return -1; + } + + res = readlink (devlink, *devp, PATH_MAX); + free (devlink); + if (res == -1) { + fprintf(stderr, "%s: specified fuse fd is invalid\n", + progname); + return -1; + } + + return atoi(devfd); +} -static int mount_fuse(const char *mnt, const char *opts) +static int mount_fuse(const char *mnt, const char *opts, char *devfd) { int res; int fd; @@ -1030,7 +1060,7 @@ static int mount_fuse(const char *mnt, const char *opts) int currdir_fd = -1; int mountpoint_fd = -1; - fd = open_fuse_device(&dev); + fd = devfd ? check_fuse_device(devfd, &dev) : open_fuse_device(&dev); if (fd == -1) return -1; @@ -1154,6 +1184,7 @@ int main(int argc, char *argv[]) static int unmount = 0; static int lazy = 0; static int quiet = 0; + char *devfd; char *commfd; int cfd; const char *opts = ""; @@ -1242,21 +1273,26 @@ int main(int argc, char *argv[]) return 0; } - commfd = getenv(FUSE_COMMFD_ENV); - if (commfd == NULL) { - fprintf(stderr, "%s: old style mounting not supported\n", - progname); - exit(1); + devfd = getenv(FUSE_DEVFD_ENV); + if (devfd == NULL) { + commfd = getenv(FUSE_COMMFD_ENV); + if (commfd == NULL) { + fprintf(stderr, "%s: old style mounting not supported\n", + progname); + exit(1); + } } - fd = mount_fuse(mnt, opts); + fd = mount_fuse(mnt, opts, devfd); if (fd == -1) exit(1); - cfd = atoi(commfd); - res = send_fd(cfd, fd); - if (res == -1) - exit(1); + if (devfd == NULL) { + cfd = atoi(commfd); + res = send_fd(cfd, fd); + if (res == -1) + exit(1); + } return 0; } |