Blob Blame History Raw
From 137b7b034169022540c69a6ace4c108015910b2d Mon Sep 17 00:00:00 2001
From: Amar Tumballi <amarts@redhat.com>
Date: Mon, 29 May 2017 17:26:35 +0530
Subject: [PATCH 318/318] fuse: implement "-oauto_unmount"

libfuse has an auto_unmount option which,
if enabled, ensures that the file system
is unmounted at FUSE server termination
by running a separate monitor process
that performs the unmount when that
occurs. (This feature would probably
better be called "robust auto-unmount",
as FUSE servers usually do try to unmount
their file systems upon termination,
it's just this mechanism is not crash
resilient.)

This change implements that option and
behavior for glusterfs.

Note that "auto unmount" (robust or not) is
a leaky abstraction, as the kernel cannot
guarantee that at the path where the FUSE
fs is mounted is actually the toplevel mount
at the time of the umount(2) call, for
multiple reasons, among others, see:

  fuse-devel: "fuse: feasible to distinguish between umount and abort?"
  http://fuse.996288.n3.nabble.com/fuse-feasible-to-distinguish-between-umount-and-abort-tt14358.html
  https://github.com/libfuse/libfuse/issues/122

> Change-Id: Ia4432580c9fd2c156d9c73c3a44f4bfd42437599
> Signed-off-by: Csaba Henk <csaba@redhat.com>
> Reviewed-on: https://review.gluster.org/17230
> Tested-by: Amar Tumballi <amarts@redhat.com>
> CentOS-regression: Gluster Build System <jenkins@build.gluster.org>
> Smoke: Gluster Build System <jenkins@build.gluster.org>
> Reviewed-by: Amar Tumballi <amarts@redhat.com>
> NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org>

BUG: 1456420
Change-Id: I4bae611254bad749b02abaf18d0ed6f447aec7b8
Signed-off-by: Amar Tumballi <amarts@redhat.com>
Reviewed-on: https://code.engineering.redhat.com/gerrit/107573
Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
---
 contrib/fuse-include/fuse-mount.h           |  1 +
 contrib/fuse-lib/mount.c                    | 46 +++++++++++++++++++++++++++++
 xlators/mount/fuse/src/fuse-bridge.c        | 34 +++++++++++++++++++--
 xlators/mount/fuse/src/fuse-bridge.h        |  3 ++
 xlators/mount/fuse/utils/mount.glusterfs.in |  2 +-
 5 files changed, 82 insertions(+), 4 deletions(-)

diff --git a/contrib/fuse-include/fuse-mount.h b/contrib/fuse-include/fuse-mount.h
index 9358ac8..f2f08e3 100644
--- a/contrib/fuse-include/fuse-mount.h
+++ b/contrib/fuse-include/fuse-mount.h
@@ -8,6 +8,7 @@
 */
 
 void gf_fuse_unmount (const char *mountpoint, int fd);
+int gf_fuse_unmount_daemon (const char *mountpoint, int fd);
 int gf_fuse_mount (const char *mountpoint, char *fsname,
                    unsigned long mountflags, char *mnt_param,
                    pid_t *mtab_pid, int status_fd);
diff --git a/contrib/fuse-lib/mount.c b/contrib/fuse-lib/mount.c
index 5e0b4dd..876ac90 100644
--- a/contrib/fuse-lib/mount.c
+++ b/contrib/fuse-lib/mount.c
@@ -75,6 +75,52 @@ gf_fuse_unmount (const char *mountpoint, int fd)
 
 /* gluster-specific routines */
 
+/* Unmounting in a daemon that lurks 'till main process exits */
+int
+gf_fuse_unmount_daemon (const char *mountpoint, int fd)
+{
+        int   ret = -1;
+        pid_t pid = -1;
+
+        if (fd == -1)
+                return -1;
+
+        int ump[2] = {0,};
+
+        ret = pipe(ump);
+        if (ret == -1) {
+                close (fd);
+                return -1;
+        }
+
+        pid = fork ();
+        switch (pid) {
+                char c = 0;
+                sigset_t sigset;
+        case 0:
+
+                close_fds_except (ump, 1);
+
+                setsid();
+                chdir("/");
+                sigfillset(&sigset);
+                sigprocmask(SIG_BLOCK, &sigset, NULL);
+
+                read (ump[0], &c, 1);
+
+                gf_fuse_unmount (mountpoint, fd);
+                exit (0);
+        case -1:
+                close (fd);
+                fd = -1;
+                ret = -1;
+                close (ump[1]);
+        }
+        close (ump[0]);
+
+        return ret;
+}
+
 static char *
 escape (char *s)
 {
diff --git a/xlators/mount/fuse/src/fuse-bridge.c b/xlators/mount/fuse/src/fuse-bridge.c
index eead33f..60280ef 100644
--- a/xlators/mount/fuse/src/fuse-bridge.c
+++ b/xlators/mount/fuse/src/fuse-bridge.c
@@ -5079,7 +5079,7 @@ fuse_thread_proc (void *data)
                                                      ZR_MOUNTPOINT_OPT));
         if (mount_point) {
                 gf_log (this->name, GF_LOG_INFO,
-                        "unmounting %s", mount_point);
+                        "initating unmount of %s", mount_point);
         }
 
         /* Kill the whole process, not just this thread. */
@@ -5701,6 +5701,24 @@ init (xlator_t *this_xl)
         if (!mnt_args)
                 goto cleanup_exit;
 
+        {
+                char *mnt_tok         = NULL;
+                token_iter_t tit      = {0,};
+                gf_boolean_t iter_end = _gf_false;
+
+                for (mnt_tok = token_iter_init (mnt_args, ',', &tit) ;;) {
+                        iter_end = next_token (&mnt_tok, &tit);
+
+                        if (strcmp (mnt_tok, "auto_unmount") == 0) {
+                                priv->auto_unmount = _gf_true;
+                                drop_token (mnt_tok, &tit);
+                        }
+
+                        if (iter_end)
+                                break;
+                }
+        }
+
         if (pipe(priv->status_pipe) < 0) {
                 gf_log (this_xl->name, GF_LOG_ERROR,
                         "could not create pipe to separate mount process");
@@ -5712,6 +5730,11 @@ init (xlator_t *this_xl)
                                   priv->status_pipe[1]);
         if (priv->fd == -1)
                 goto cleanup_exit;
+        if (priv->auto_unmount) {
+                ret = gf_fuse_unmount_daemon (priv->mount_point, priv->fd);
+                if (ret == -1)
+                        goto cleanup_exit;
+        }
 
         event = eh_new (FUSE_EVENT_HISTORY_SIZE, _gf_false, NULL);
         if (!event) {
@@ -5789,10 +5812,15 @@ fini (xlator_t *this_xl)
                 mount_point = data_to_str (dict_get (this_xl->options,
                                                      ZR_MOUNTPOINT_OPT));
         if (mount_point != NULL) {
+                if (!priv->auto_unmount) {
+                        gf_log (this_xl->name, GF_LOG_INFO,
+                                "Unmounting '%s'.", mount_point);
+                        gf_fuse_unmount (mount_point, priv->fd);
+                }
+
                 gf_log (this_xl->name, GF_LOG_INFO,
-                        "Unmounting '%s'.", mount_point);
+                        "Closing fuse connection to '%s'.", mount_point);
 
-                gf_fuse_unmount (mount_point, priv->fd);
                 sys_close (priv->fuse_dump_fd);
                 dict_del (this_xl->options, ZR_MOUNTPOINT_OPT);
         }
diff --git a/xlators/mount/fuse/src/fuse-bridge.h b/xlators/mount/fuse/src/fuse-bridge.h
index 40bd17b..0c70189 100644
--- a/xlators/mount/fuse/src/fuse-bridge.h
+++ b/xlators/mount/fuse/src/fuse-bridge.h
@@ -134,6 +134,9 @@ struct fuse_private {
 
         /* Enable or disable capability support */
         gf_boolean_t         capability;
+
+        /* whether to run the unmount daemon */
+        gf_boolean_t auto_unmount;
 };
 typedef struct fuse_private fuse_private_t;
 
diff --git a/xlators/mount/fuse/utils/mount.glusterfs.in b/xlators/mount/fuse/utils/mount.glusterfs.in
index 6c4cdfe..2c5e466 100755
--- a/xlators/mount/fuse/utils/mount.glusterfs.in
+++ b/xlators/mount/fuse/utils/mount.glusterfs.in
@@ -538,7 +538,7 @@ without_options()
         "atime"|"noatime"|"diratime"|"nodiratime"|\
         "relatime"|"norelatime"|\
         "strictatime"|"nostrictatime"|"lazyatime"|"nolazyatime"|\
-        "dev"|"nodev"|"exec"|"noexec"|"suid"|"nosuid")
+        "dev"|"nodev"|"exec"|"noexec"|"suid"|"nosuid"|"auto_unmount")
             [ -z "$fuse_mountopts" ] || fuse_mountopts="$fuse_mountopts,"
             fuse_mountopts="${fuse_mountopts}${option}"
             ;;
-- 
1.8.3.1