d1681e
From 9f4564e55b1e515743a1f80d18989681d5d3b59f Mon Sep 17 00:00:00 2001
d1681e
From: Kotresh HR <khiremat@redhat.com>
d1681e
Date: Thu, 15 Feb 2018 01:46:29 -0500
d1681e
Subject: [PATCH 164/180] geo-rep: Remove lazy umount and use mount namespaces
d1681e
d1681e
Lazy umounting the master volume by worker causes
d1681e
issues with rsync's usage of getcwd. Henc removing
d1681e
the lazy umount and using private mount namespace
d1681e
for the same. On the slave, the lazy umount is
d1681e
retained as we can't use private namespace in non
d1681e
root geo-rep setup because gsyncd is spawned as
d1681e
non-privileged user.
d1681e
d1681e
Backport of https://review.gluster.org/#/c/19544/
d1681e
d1681e
Change-Id: I851e8dc2b8523dc5668a97e87ef619ab70471dfd
d1681e
BUG: 1544382
d1681e
Signed-off-by: Kotresh HR <khiremat@redhat.com>
d1681e
Reviewed-on: https://code.engineering.redhat.com/gerrit/130468
d1681e
Tested-by: RHGS Build Bot <nigelb@redhat.com>
d1681e
Reviewed-by: Aravinda Vishwanathapura Krishna Murthy <avishwan@redhat.com>
d1681e
Reviewed-by: Sunil Kumar Heggodu Gopala Acharya <sheggodu@redhat.com>
d1681e
---
d1681e
 geo-replication/syncdaemon/gconf.py      |  3 +++
d1681e
 geo-replication/syncdaemon/gsyncd.py     | 13 ++++++-----
d1681e
 geo-replication/syncdaemon/monitor.py    | 38 ++++++++++++++++++++------------
d1681e
 geo-replication/syncdaemon/resource.py   | 20 ++++++++++++-----
d1681e
 geo-replication/syncdaemon/syncdutils.py | 12 +++++-----
d1681e
 glusterfs.spec.in                        |  4 ++++
d1681e
 6 files changed, 59 insertions(+), 31 deletions(-)
d1681e
d1681e
diff --git a/geo-replication/syncdaemon/gconf.py b/geo-replication/syncdaemon/gconf.py
d1681e
index 97395b4..2280f44 100644
d1681e
--- a/geo-replication/syncdaemon/gconf.py
d1681e
+++ b/geo-replication/syncdaemon/gconf.py
d1681e
@@ -28,5 +28,8 @@ class GConf(object):
d1681e
     active_earlier = False
d1681e
     passive_earlier = False
d1681e
     mgmt_lock_fd = None
d1681e
+    mountbroker = False
d1681e
+    mount_point = None
d1681e
+    mbr_umount_cmd = []
d1681e
 
d1681e
 gconf = GConf()
d1681e
diff --git a/geo-replication/syncdaemon/gsyncd.py b/geo-replication/syncdaemon/gsyncd.py
d1681e
index d77b90f..629e8b7 100644
d1681e
--- a/geo-replication/syncdaemon/gsyncd.py
d1681e
+++ b/geo-replication/syncdaemon/gsyncd.py
d1681e
@@ -276,6 +276,7 @@ def main_i():
d1681e
     op.add_option('--georep-session-working-dir', metavar='STATF',
d1681e
                   type=str, action='callback', callback=store_abs)
d1681e
     op.add_option('--access-mount', default=False, action='store_true')
d1681e
+    op.add_option('--slave-access-mount', default=False, action='store_true')
d1681e
     op.add_option('--ignore-deletes', default=False, action='store_true')
d1681e
     op.add_option('--isolated-slave', default=False, action='store_true')
d1681e
     op.add_option('--use-rsync-xattrs', default=False, action='store_true')
d1681e
@@ -431,7 +432,7 @@ def main_i():
d1681e
                     o.get_opt_string() not in ('--version', '--help'))]
d1681e
     remote_tunables = ['listen', 'go_daemon', 'timeout',
d1681e
                        'session_owner', 'config_file', 'use_rsync_xattrs',
d1681e
-                       'local_id', 'local_node', 'access_mount']
d1681e
+                       'local_id', 'local_node', 'slave_access_mount']
d1681e
     rq_remote_tunables = {'listen': True}
d1681e
 
d1681e
     # precedence for sources of values: 1) commandline, 2) cfg file, 3)
d1681e
@@ -768,15 +769,15 @@ def main_i():
d1681e
     else:
d1681e
         log_file = gconf.log_file
d1681e
     if be_monitor:
d1681e
-        label = 'monitor'
d1681e
+        gconf.label = 'monitor'
d1681e
     elif be_agent:
d1681e
-        label = gconf.local_path
d1681e
+        gconf.label = gconf.local_path
d1681e
     elif remote:
d1681e
         # master
d1681e
-        label = gconf.local_path
d1681e
+        gconf.label = gconf.local_path
d1681e
     else:
d1681e
-        label = 'slave'
d1681e
-    startup(go_daemon=go_daemon, log_file=log_file, label=label)
d1681e
+        gconf.label = 'slave'
d1681e
+    startup(go_daemon=go_daemon, log_file=log_file, label=gconf.label)
d1681e
     resource.Popen.init_errhandler()
d1681e
 
d1681e
     if be_agent:
d1681e
diff --git a/geo-replication/syncdaemon/monitor.py b/geo-replication/syncdaemon/monitor.py
d1681e
index 4da9330..0f43c4f 100644
d1681e
--- a/geo-replication/syncdaemon/monitor.py
d1681e
+++ b/geo-replication/syncdaemon/monitor.py
d1681e
@@ -24,7 +24,7 @@ import random
d1681e
 from gconf import gconf
d1681e
 from syncdutils import select, waitpid, errno_wrap, lf
d1681e
 from syncdutils import set_term_handler, is_host_local, GsyncdError
d1681e
-from syncdutils import escape, Thread, finalize, memoize
d1681e
+from syncdutils import escape, Thread, finalize, memoize, boolify
d1681e
 from syncdutils import gf_event, EVENT_GEOREP_FAULTY
d1681e
 
d1681e
 from gsyncdstatus import GeorepStatus, set_monitor_status
d1681e
@@ -306,19 +306,29 @@ class Monitor(object):
d1681e
                 os.close(pr)
d1681e
                 os.close(ra)
d1681e
                 os.close(wa)
d1681e
-                os.execv(sys.executable, argv + ['--feedback-fd', str(pw),
d1681e
-                                                 '--local-path', w[0]['dir'],
d1681e
-                                                 '--local-node', w[0]['host'],
d1681e
-                                                 '--local-node-id',
d1681e
-                                                 w[0]['uuid'],
d1681e
-                                                 '--local-id',
d1681e
-                                                 '.' + escape(w[0]['dir']),
d1681e
-                                                 '--rpc-fd',
d1681e
-                                                 ','.join([str(rw), str(ww),
d1681e
-                                                           str(ra), str(wa)]),
d1681e
-                                                 '--subvol-num', str(w[2])] +
d1681e
-                         (['--is-hottier'] if w[3] else []) +
d1681e
-                         ['--resource-remote', remote_host])
d1681e
+                args_to_worker = argv + ['--feedback-fd', str(pw),
d1681e
+                                         '--local-path', w[0]['dir'],
d1681e
+                                         '--local-node', w[0]['host'],
d1681e
+                                         '--local-node-id',
d1681e
+                                         w[0]['uuid'],
d1681e
+                                         '--local-id',
d1681e
+                                         '.' + escape(w[0]['dir']),
d1681e
+                                         '--rpc-fd',
d1681e
+                                         ','.join([str(rw), str(ww),
d1681e
+                                         str(ra), str(wa)]),
d1681e
+                                         '--subvol-num', str(w[2])]
d1681e
+
d1681e
+                if w[3]:
d1681e
+                    args_to_worker.append('--is-hottier')
d1681e
+                args_to_worker += ['--resource-remote', remote_host]
d1681e
+
d1681e
+                access_mount = boolify(gconf.access_mount)
d1681e
+                if access_mount:
d1681e
+                    os.execv(sys.executable, args_to_worker)
d1681e
+                else:
d1681e
+                    unshare_cmd = ['unshare', '-m', '--propagation', 'private']
d1681e
+                    cmd = unshare_cmd + args_to_worker
d1681e
+                    os.execvp("unshare", cmd)
d1681e
 
d1681e
             cpids.add(cpid)
d1681e
             agents.add(apid)
d1681e
diff --git a/geo-replication/syncdaemon/resource.py b/geo-replication/syncdaemon/resource.py
d1681e
index 5ad5b97..4b2a266 100644
d1681e
--- a/geo-replication/syncdaemon/resource.py
d1681e
+++ b/geo-replication/syncdaemon/resource.py
d1681e
@@ -43,7 +43,7 @@ from syncdutils import CHANGELOG_AGENT_CLIENT_VERSION
d1681e
 from syncdutils import GX_GFID_CANONICAL_LEN
d1681e
 from gsyncdstatus import GeorepStatus
d1681e
 from syncdutils import get_master_and_slave_data_from_args
d1681e
-from syncdutils import mntpt_list, lf
d1681e
+from syncdutils import lf
d1681e
 from syncdutils import Xattr, matching_disk_gfid, get_gfid_from_mnt
d1681e
 
d1681e
 UrlRX = re.compile('\A(\w+)://([^ *?[]*)\Z')
d1681e
@@ -1047,8 +1047,8 @@ class SlaveRemote(object):
d1681e
             extra_opts += ['--local-node', ln]
d1681e
         if boolify(gconf.use_rsync_xattrs):
d1681e
             extra_opts.append('--use-rsync-xattrs')
d1681e
-        if boolify(gconf.access_mount):
d1681e
-            extra_opts.append('--access-mount')
d1681e
+        if boolify(gconf.slave_access_mount):
d1681e
+            extra_opts.append('--slave-access-mount')
d1681e
         po = Popen(rargs + gconf.remote_gsyncd.split() + extra_opts +
d1681e
                    ['-N', '--listen', '--timeout', str(gconf.timeout),
d1681e
                     slave],
d1681e
@@ -1333,6 +1333,7 @@ class GLUSTER(AbstractUrl, SlaveLocal, SlaveRemote):
d1681e
         def __init__(self, params):
d1681e
             self.params = params
d1681e
             self.mntpt = None
d1681e
+            self.umount_cmd = []
d1681e
 
d1681e
         @classmethod
d1681e
         def get_glusterprog(cls):
d1681e
@@ -1424,13 +1425,15 @@ class GLUSTER(AbstractUrl, SlaveLocal, SlaveRemote):
d1681e
                         assert(mntdata[-1] == '\0')
d1681e
                         mntpt = mntdata[:-1]
d1681e
                         assert(mntpt)
d1681e
-                        if mounted and not boolify(gconf.access_mount):
d1681e
+                        if mounted and gconf.label == 'slave' \
d1681e
+                           and not boolify(gconf.slave_access_mount):
d1681e
                             po = self.umount_l(mntpt)
d1681e
                             po.terminate_geterr(fail_on_err=False)
d1681e
                             if po.returncode != 0:
d1681e
                                 po.errlog()
d1681e
                                 rv = po.returncode
d1681e
-                        if not boolify(gconf.access_mount):
d1681e
+                        if gconf.label == 'slave' \
d1681e
+                           and not boolify(gconf.slave_access_mount):
d1681e
                             self.cleanup_mntpt(mntpt)
d1681e
                 except:
d1681e
                     logging.exception('mount cleanup failure:')
d1681e
@@ -1451,7 +1454,7 @@ class GLUSTER(AbstractUrl, SlaveLocal, SlaveRemote):
d1681e
 
d1681e
         def make_mount_argv(self):
d1681e
             self.mntpt = tempfile.mkdtemp(prefix='gsyncd-aux-mount-')
d1681e
-            mntpt_list.append(self.mntpt)
d1681e
+            gconf.mount_point = self.mntpt
d1681e
             return [self.get_glusterprog()] + \
d1681e
                 ['--' + p for p in self.params] + [self.mntpt]
d1681e
 
d1681e
@@ -1483,6 +1486,11 @@ class GLUSTER(AbstractUrl, SlaveLocal, SlaveRemote):
d1681e
 
d1681e
         def handle_mounter(self, po):
d1681e
             self.mntpt = po.stdout.readline()[:-1]
d1681e
+            gconf.mount_point = self.mntpt
d1681e
+            gconf.mountbroker = True
d1681e
+            self.umount_cmd = self.make_cli_argv() + ['umount']
d1681e
+            gconf.mbr_umount_cmd = self.umount_cmd
d1681e
+
d1681e
             po.stdout.close()
d1681e
             sup(self, po)
d1681e
             if po.returncode != 0:
d1681e
diff --git a/geo-replication/syncdaemon/syncdutils.py b/geo-replication/syncdaemon/syncdutils.py
d1681e
index 269f301..2b57f83 100644
d1681e
--- a/geo-replication/syncdaemon/syncdutils.py
d1681e
+++ b/geo-replication/syncdaemon/syncdutils.py
d1681e
@@ -23,7 +23,6 @@ from errno import EINTR, ENOENT, EPERM, ESTALE, EBUSY, errorcode
d1681e
 from signal import signal, SIGTERM
d1681e
 import select as oselect
d1681e
 from os import waitpid as owaitpid
d1681e
-import subprocess
d1681e
 
d1681e
 from conf import GLUSTERFS_LIBEXECDIR, UUID_FILE
d1681e
 sys.path.insert(1, GLUSTERFS_LIBEXECDIR)
d1681e
@@ -209,7 +208,6 @@ def grabpidfile(fname=None, setpid=True):
d1681e
 
d1681e
 final_lock = Lock()
d1681e
 
d1681e
-mntpt_list = []
d1681e
 def finalize(*a, **kw):
d1681e
     """all those messy final steps we go trough upon termination
d1681e
 
d1681e
@@ -256,12 +254,16 @@ def finalize(*a, **kw):
d1681e
                 pass
d1681e
 
d1681e
     """ Unmount if not done """
d1681e
-    for mnt in mntpt_list:
d1681e
-        p0 = subprocess.Popen (["umount", "-l", mnt], stderr=subprocess.PIPE)
d1681e
+    if gconf.mount_point:
d1681e
+        if gconf.mountbroker:
d1681e
+            umount_cmd = gconf.mbr_umount_cmd + [gconf.mount_point, 'lazy']
d1681e
+        else:
d1681e
+            umount_cmd = ['umount', '-l', gconf.mount_point]
d1681e
+        p0 = subprocess.Popen(umount_cmd, stderr=subprocess.PIPE)
d1681e
         _, errdata = p0.communicate()
d1681e
         if p0.returncode == 0:
d1681e
             try:
d1681e
-                os.rmdir(mnt)
d1681e
+                os.rmdir(gconf.mount_point)
d1681e
             except OSError:
d1681e
                 pass
d1681e
         else:
d1681e
diff --git a/glusterfs.spec.in b/glusterfs.spec.in
d1681e
index 3181d72..8379f64 100644
d1681e
--- a/glusterfs.spec.in
d1681e
+++ b/glusterfs.spec.in
d1681e
@@ -453,6 +453,7 @@ BuildRequires:    python-ctypes
d1681e
 %endif
d1681e
 Requires:         python2-gluster = %{version}-%{release}
d1681e
 Requires:         rsync
d1681e
+Requires:         util-linux
d1681e
 
d1681e
 %description geo-replication
d1681e
 GlusterFS is a distributed file-system capable of scaling to several
d1681e
@@ -2147,6 +2148,9 @@ fi
d1681e
 %endif
d1681e
 
d1681e
 %changelog
d1681e
+* Thu Feb 22 2018 Kotresh HR <khiremat@redhat.com>
d1681e
+- Added util-linux as dependency to georeplication rpm (#1544382)
d1681e
+
d1681e
 * Wed Jan 17 2018 Milind Changire <mchangir@redhat.com>
d1681e
 - DOWNSTREAM ONLY - Removed pretrans script for glusterfs-ganesha - (#1410719)
d1681e
 
d1681e
-- 
d1681e
1.8.3.1
d1681e