[ARVADOS] updated: cebc9af013fbe65d83cb4a60813e3d1871f7ca3a

Git user git at public.curoverse.com
Thu Mar 23 18:10:04 EDT 2017


Summary of changes:

  discards  a1fe9aad9d60ab2d61957bf32c0a4989636ad9b0 (commit)
  discards  1c999994ed03a717ea219290072c2dd5681a724e (commit)
  discards  5752685c137c5e37e13845f5328e9a3930fa3100 (commit)
  discards  c733e426aaa4581c266aef15add3cc70c54061dd (commit)
       via  cebc9af013fbe65d83cb4a60813e3d1871f7ca3a (commit)
       via  4e3263eaac83ede993110f1842c557c28be765e1 (commit)
       via  86ec536f01179ecc1bca0f32a4f41ad307b23c7e (commit)

This update added new revisions after undoing existing revisions.  That is
to say, the old revision is not a strict subset of the new revision.  This
situation occurs when you --force push a change and generate a repository
containing something like this:

 * -- * -- B -- O -- O -- O (a1fe9aad9d60ab2d61957bf32c0a4989636ad9b0)
            \
             N -- N -- N (cebc9af013fbe65d83cb4a60813e3d1871f7ca3a)

When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.


commit cebc9af013fbe65d83cb4a60813e3d1871f7ca3a
Author: Tom Clegg <tom at curoverse.com>
Date:   Thu Mar 23 18:06:01 2017 -0400

    11209: Try unmounting at least once even if timeout=0.

diff --git a/services/fuse/arvados_fuse/command.py b/services/fuse/arvados_fuse/command.py
index 883af36..fff0c99 100644
--- a/services/fuse/arvados_fuse/command.py
+++ b/services/fuse/arvados_fuse/command.py
@@ -11,7 +11,6 @@ import sys
 import time
 
 import arvados.commands._util as arv_cmd
-from arvados_fuse import crunchstat
 from arvados_fuse import *
 from arvados_fuse._version import __version__
 
diff --git a/services/fuse/arvados_fuse/unmount.py b/services/fuse/arvados_fuse/unmount.py
index ab5ce4f..7a7464d 100644
--- a/services/fuse/arvados_fuse/unmount.py
+++ b/services/fuse/arvados_fuse/unmount.py
@@ -62,12 +62,13 @@ def unmount(path, timeout=10):
     path = os.path.realpath(path)
 
     was_mounted = False
-    t0 = time.time()
-    delay = 0
-    while True:
-        if timeout and t0 + timeout < time.time():
-            raise Exception("timed out")
+    attempted = False
+    if timeout is None:
+        deadline = None
+    else:
+        deadline = time.time() + timeout
 
+    while True:
         mounted = False
         for m in mountinfo():
             if m.is_fuse:
@@ -81,6 +82,14 @@ def unmount(path, timeout=10):
         if not mounted:
             return was_mounted
 
+        if attempted:
+            delay = 1
+            if deadline:
+                delay = min(delay, deadline - time.time())
+                if delay <= 0:
+                    raise Exception("timed out")
+            time.sleep(delay)
+
         try:
             with open('/sys/fs/fuse/connections/{}/abort'.format(m.minor),
                       'w') as f:
@@ -88,11 +97,9 @@ def unmount(path, timeout=10):
         except OSError as e:
             if e.errno != errno.ENOENT:
                 raise
+
+        attempted = True
         try:
             subprocess.check_call(["fusermount", "-u", "-z", path])
         except subprocess.CalledProcessError:
             pass
-
-        time.sleep(delay)
-        if delay == 0:
-            delay = 1

commit 4e3263eaac83ede993110f1842c557c28be765e1
Author: Tom Clegg <tom at curoverse.com>
Date:   Fri Mar 17 16:32:10 2017 -0400

    11209: "--unmount /path/..." unmounts /path and all fuse mounts below it.

diff --git a/services/fuse/arvados_fuse/command.py b/services/fuse/arvados_fuse/command.py
index c9a090c..883af36 100644
--- a/services/fuse/arvados_fuse/command.py
+++ b/services/fuse/arvados_fuse/command.py
@@ -91,9 +91,9 @@ class ArgumentParser(argparse.ArgumentParser):
         self.add_argument('--crunchstat-interval', type=float, help="Write stats to stderr every N seconds (default disabled)", default=0)
 
         self.add_argument('--unmount', action='store_true', default=False,
-                          help="Forcefully unmount the specified mountpoint (if it's a fuse mount) and exit")
+                          help="Forcefully unmount the specified mountpoint (if it's a fuse mount) and exit. Use /path/... to unmount all fuse mounts below /path as well as /path itself.")
         self.add_argument('--replace', action='store_true', default=False,
-                          help="Forcefully unmount any existing fuse mount before mounting")
+                          help="If a fuse mount is already present at mountpoint, forcefully unmount it before mounting")
         self.add_argument('--unmount-timeout',
                           type=float, default=2.0,
                           help="Time to wait for graceful shutdown after --exec program exits and filesystem is unmounted")
@@ -146,7 +146,7 @@ class Mount(object):
 
     def run(self):
         if self.args.unmount:
-            unmount(self.args.mountpoint, timeout=self.args.unmount_timeout)
+            unmount_all(self.args.mountpoint, timeout=self.args.unmount_timeout)
         elif self.args.exec_args:
             self._run_exec()
         else:
diff --git a/services/fuse/arvados_fuse/unmount.py b/services/fuse/arvados_fuse/unmount.py
index 8be549e..ab5ce4f 100644
--- a/services/fuse/arvados_fuse/unmount.py
+++ b/services/fuse/arvados_fuse/unmount.py
@@ -1,8 +1,49 @@
+import collections
 import errno
 import os
 import subprocess
 import time
 
+
+MountInfo = collections.namedtuple(
+    'MountInfo', ['is_fuse', 'major', 'minor', 'mnttype', 'path'])
+
+
+def mountinfo():
+    mi = []
+    with open('/proc/self/mountinfo') as f:
+        for m in f.readlines():
+            mntid, pmntid, dev, root, path, extra = m.split(" ", 5)
+            mnttype = extra.split(" - ")[1].split(" ", 1)[0]
+            major, minor = dev.split(":")
+            mi.append(MountInfo(
+                is_fuse=(mnttype == "fuse" or mnttype.startswith("fuse.")),
+                major=major,
+                minor=minor,
+                mnttype=mnttype,
+                path=path,
+            ))
+    return mi
+
+
+def unmount_all(path, timeout=10):
+    if not path.endswith("/..."):
+        return unmount(path, timeout=timeout)
+    root = os.path.realpath(path[:-4])
+
+    paths = []
+    for m in mountinfo():
+        if m.path == root or m.path.startswith(root+"/"):
+            paths.append(m.path)
+            if not m.is_fuse:
+                raise Exception(
+                    "cannot unmount {}: non-fuse mountpoint {}".format(
+                        path, m))
+    for path in sorted(paths, key=len, reverse=True):
+        unmount(path, timeout=timeout)
+    return len(paths) > 0
+
+
 def unmount(path, timeout=10):
     """Unmount the fuse mount at path.
 
@@ -28,14 +69,10 @@ def unmount(path, timeout=10):
             raise Exception("timed out")
 
         mounted = False
-        with open('/proc/self/mountinfo') as mi:
-            for m in mi.readlines():
-                mntid, pmntid, dev, root, mnt, extra = m.split(" ", 5)
-                mnttype = extra.split(" - ")[1].split(" ")[0]
-                if not (mnttype == "fuse" or mnttype.startswith("fuse.")):
-                    continue
+        for m in mountinfo():
+            if m.is_fuse:
                 try:
-                    if os.path.realpath(mnt) == path:
+                    if os.path.realpath(m.path) == path:
                         was_mounted = True
                         mounted = True
                         break
@@ -44,9 +81,9 @@ def unmount(path, timeout=10):
         if not mounted:
             return was_mounted
 
-        major, minor = dev.split(":")
         try:
-            with open('/sys/fs/fuse/connections/'+str(minor)+'/abort', 'w') as f:
+            with open('/sys/fs/fuse/connections/{}/abort'.format(m.minor),
+                      'w') as f:
                 f.write("1")
         except OSError as e:
             if e.errno != errno.ENOENT:

commit 86ec536f01179ecc1bca0f32a4f41ad307b23c7e
Author: Tom Clegg <tom at curoverse.com>
Date:   Thu Mar 16 16:49:49 2017 -0400

    11209: Add arv-mount --unmount and --replace flags

diff --git a/services/fuse/arvados_fuse/command.py b/services/fuse/arvados_fuse/command.py
index 66f8a4d..c9a090c 100644
--- a/services/fuse/arvados_fuse/command.py
+++ b/services/fuse/arvados_fuse/command.py
@@ -90,6 +90,10 @@ class ArgumentParser(argparse.ArgumentParser):
 
         self.add_argument('--crunchstat-interval', type=float, help="Write stats to stderr every N seconds (default disabled)", default=0)
 
+        self.add_argument('--unmount', action='store_true', default=False,
+                          help="Forcefully unmount the specified mountpoint (if it's a fuse mount) and exit")
+        self.add_argument('--replace', action='store_true', default=False,
+                          help="Forcefully unmount any existing fuse mount before mounting")
         self.add_argument('--unmount-timeout',
                           type=float, default=2.0,
                           help="Time to wait for graceful shutdown after --exec program exits and filesystem is unmounted")
@@ -118,6 +122,8 @@ class Mount(object):
             exit(1)
 
     def __enter__(self):
+        if self.args.replace:
+            unmount(self.args.mountpoint, timeout=self.args.unmount_timeout)
         llfuse.init(self.operations, self.args.mountpoint, self._fuse_options())
         if self.listen_for_events and not self.args.disable_event_listening:
             self.operations.listen_for_events()
@@ -139,7 +145,9 @@ class Mount(object):
                                 self.args.unmount_timeout)
 
     def run(self):
-        if self.args.exec_args:
+        if self.args.unmount:
+            unmount(self.args.mountpoint, timeout=self.args.unmount_timeout)
+        elif self.args.exec_args:
             self._run_exec()
         else:
             self._run_standalone()
diff --git a/services/fuse/arvados_fuse/unmount.py b/services/fuse/arvados_fuse/unmount.py
new file mode 100644
index 0000000..8be549e
--- /dev/null
+++ b/services/fuse/arvados_fuse/unmount.py
@@ -0,0 +1,61 @@
+import errno
+import os
+import subprocess
+import time
+
+def unmount(path, timeout=10):
+    """Unmount the fuse mount at path.
+
+    Unmounting is done by writing 1 to the "abort" control file in
+    sysfs to kill the fuse driver process, then executing "fusermount
+    -u -z" to detach the mount point, and repeating these steps until
+    the mount is no longer listed in /proc/self/mountinfo.
+
+    This procedure should enable a non-root user to reliably unmount
+    their own fuse filesystem without risk of deadlock.
+
+    Returns True if unmounting was successful, False if it wasn't a
+    fuse mount at all. Raises an exception if it cannot be unmounted.
+    """
+
+    path = os.path.realpath(path)
+
+    was_mounted = False
+    t0 = time.time()
+    delay = 0
+    while True:
+        if timeout and t0 + timeout < time.time():
+            raise Exception("timed out")
+
+        mounted = False
+        with open('/proc/self/mountinfo') as mi:
+            for m in mi.readlines():
+                mntid, pmntid, dev, root, mnt, extra = m.split(" ", 5)
+                mnttype = extra.split(" - ")[1].split(" ")[0]
+                if not (mnttype == "fuse" or mnttype.startswith("fuse.")):
+                    continue
+                try:
+                    if os.path.realpath(mnt) == path:
+                        was_mounted = True
+                        mounted = True
+                        break
+                except OSError:
+                    continue
+        if not mounted:
+            return was_mounted
+
+        major, minor = dev.split(":")
+        try:
+            with open('/sys/fs/fuse/connections/'+str(minor)+'/abort', 'w') as f:
+                f.write("1")
+        except OSError as e:
+            if e.errno != errno.ENOENT:
+                raise
+        try:
+            subprocess.check_call(["fusermount", "-u", "-z", path])
+        except subprocess.CalledProcessError:
+            pass
+
+        time.sleep(delay)
+        if delay == 0:
+            delay = 1

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list