e3c68b
From 161a039f8088bf8ce7000d8175e3793219525179 Mon Sep 17 00:00:00 2001
e3c68b
From: Kotresh HR <khiremat@redhat.com>
e3c68b
Date: Thu, 28 Mar 2019 07:17:16 -0400
e3c68b
Subject: [PATCH 50/52] geo-rep: Fix syncing multiple rename of symlink
e3c68b
e3c68b
Problem:
e3c68b
Geo-rep fails to sync rename of symlink if it's
e3c68b
renamed multiple times if creation and rename
e3c68b
happened successively
e3c68b
e3c68b
Worker crash at slave:
e3c68b
Traceback (most recent call last):
e3c68b
  File "/usr/libexec/glusterfs/python/syncdaemon/repce.py",  in worker
e3c68b
    res = getattr(self.obj, rmeth)(*in_data[2:])
e3c68b
  File "/usr/libexec/glusterfs/python/syncdaemon/resource.py", in entry_ops
e3c68b
    [ESTALE, EINVAL, EBUSY])
e3c68b
  File "/usr/libexec/glusterfs/python/syncdaemon/syncdutils.py", in errno_wrap
e3c68b
    return call(*arg)
e3c68b
  File "/usr/libexec/glusterfs/python/syncdaemon/libcxattr.py", in lsetxattr
e3c68b
    cls.raise_oserr()
e3c68b
  File "/usr/libexec/glusterfs/python/syncdaemon/libcxattr.py", in raise_oserr
e3c68b
    raise OSError(errn, os.strerror(errn))
e3c68b
OSError: [Errno 12] Cannot allocate memory
e3c68b
e3c68b
Geo-rep Behaviour:
e3c68b
1. SYMLINK doesn't record target path in changelog.
e3c68b
   So while syncing SYMLINK, readlink is done on
e3c68b
   master to get target path.
e3c68b
e3c68b
2. Geo-rep will create destination if source is not
e3c68b
   present while syncing RENAME. Hence while syncing
e3c68b
   RENAME of SYMLINK, target path is collected from
e3c68b
   destination.
e3c68b
e3c68b
Cause:
e3c68b
If symlink is created and renamed multiple times, creation of
e3c68b
symlink is ignored, as it's no longer present on master at
e3c68b
that path. While symlink is renamed multiple times at master,
e3c68b
when syncing first RENAME of SYMLINK, both source and destination
e3c68b
is not present, hence target path is not known.  In this case,
e3c68b
while creating destination directly at slave,  regular file
e3c68b
attributes were encoded into blob instead of symlink,
e3c68b
causing failure in gfid-access translator while decoding
e3c68b
blob.
e3c68b
e3c68b
Solution:
e3c68b
While syncing of RENAME of SYMLINK, when target is not known
e3c68b
and when src and destination is not present on the master,
e3c68b
don't create destination. Ignore the rename. It's ok to ignore.
e3c68b
If it's unliked, it's fine.  If it's renamed to something else,
e3c68b
it will be synced then.
e3c68b
e3c68b
Backport of:
e3c68b
> Patch: https://review.gluster.org/22438
e3c68b
> Change-Id: Ibdfa495513b7c05b5370ab0b89c69a6802338d87
e3c68b
> BUG: 1693648
e3c68b
> Signed-off-by: Kotresh HR <khiremat@redhat.com>
e3c68b
e3c68b
Change-Id: Ibdfa495513b7c05b5370ab0b89c69a6802338d87
e3c68b
fixes: bz#1670429
e3c68b
Signed-off-by: Kotresh HR <khiremat@redhat.com>
e3c68b
Reviewed-on: https://code.engineering.redhat.com/gerrit/167122
e3c68b
Tested-by: RHGS Build Bot <nigelb@redhat.com>
e3c68b
Reviewed-by: Sunil Kumar Heggodu Gopala Acharya <sheggodu@redhat.com>
e3c68b
---
e3c68b
 geo-replication/syncdaemon/resource.py   | 23 ++++++++++++++---------
e3c68b
 tests/00-geo-rep/georep-basic-dr-rsync.t |  1 +
e3c68b
 tests/geo-rep.rc                         | 12 ++++++++++++
e3c68b
 3 files changed, 27 insertions(+), 9 deletions(-)
e3c68b
e3c68b
diff --git a/geo-replication/syncdaemon/resource.py b/geo-replication/syncdaemon/resource.py
e3c68b
index a2d0b16..c290d86 100644
e3c68b
--- a/geo-replication/syncdaemon/resource.py
e3c68b
+++ b/geo-replication/syncdaemon/resource.py
e3c68b
@@ -625,15 +625,20 @@ class Server(object):
e3c68b
                 # exist with different gfid.
e3c68b
                 if not matching_disk_gfid(gfid, entry):
e3c68b
                     if e['stat'] and not stat.S_ISDIR(e['stat']['mode']):
e3c68b
-                        if stat.S_ISLNK(e['stat']['mode']) and \
e3c68b
-                           e['link'] is not None:
e3c68b
-                            st1 = lstat(en)
e3c68b
-                            if isinstance(st1, int):
e3c68b
-                                (pg, bname) = entry2pb(en)
e3c68b
-                                blob = entry_pack_symlink(cls, gfid, bname,
e3c68b
-                                                          e['link'], e['stat'])
e3c68b
-                            elif not matching_disk_gfid(gfid, en):
e3c68b
-                                collect_failure(e, EEXIST, uid, gid, True)
e3c68b
+                        if stat.S_ISLNK(e['stat']['mode']):
e3c68b
+                            # src is not present, so don't sync symlink as
e3c68b
+                            # we don't know target. It's ok to ignore. If
e3c68b
+                            # it's unliked, it's fine. If it's renamed to
e3c68b
+                            # something else, it will be synced then.
e3c68b
+                            if e['link'] is not None:
e3c68b
+                                st1 = lstat(en)
e3c68b
+                                if isinstance(st1, int):
e3c68b
+                                    (pg, bname) = entry2pb(en)
e3c68b
+                                    blob = entry_pack_symlink(cls, gfid, bname,
e3c68b
+                                                              e['link'],
e3c68b
+                                                              e['stat'])
e3c68b
+                                elif not matching_disk_gfid(gfid, en):
e3c68b
+                                    collect_failure(e, EEXIST, uid, gid, True)
e3c68b
                         else:
e3c68b
                             slink = os.path.join(pfx, gfid)
e3c68b
                             st = lstat(slink)
e3c68b
diff --git a/tests/00-geo-rep/georep-basic-dr-rsync.t b/tests/00-geo-rep/georep-basic-dr-rsync.t
e3c68b
index 4a03930..8b64370 100644
e3c68b
--- a/tests/00-geo-rep/georep-basic-dr-rsync.t
e3c68b
+++ b/tests/00-geo-rep/georep-basic-dr-rsync.t
e3c68b
@@ -110,6 +110,7 @@ EXPECT_WITHIN $GEO_REP_TIMEOUT 0 chown_file_ok ${slave_mnt}/hybrid_chown_f1
e3c68b
 #Check History Crawl.
e3c68b
 TEST $GEOREP_CLI $master $slave stop
e3c68b
 TEST create_data "history"
e3c68b
+TEST create_rename_symlink_case
e3c68b
 TEST $GEOREP_CLI $master $slave start
e3c68b
 EXPECT_WITHIN $GEO_REP_TIMEOUT  2 check_status_num_rows "Active"
e3c68b
 EXPECT_WITHIN $GEO_REP_TIMEOUT  2 check_status_num_rows "Passive"
e3c68b
diff --git a/tests/geo-rep.rc b/tests/geo-rep.rc
e3c68b
index 396b4c4..d723129 100644
e3c68b
--- a/tests/geo-rep.rc
e3c68b
+++ b/tests/geo-rep.rc
e3c68b
@@ -19,6 +19,18 @@ function check_common_secret_file()
e3c68b
     echo $?
e3c68b
 }
e3c68b
 
e3c68b
+function create_rename_symlink_case()
e3c68b
+{
e3c68b
+    mkdir ${mastermnt}/MUL_REN_SYMLINK
e3c68b
+    cd ${mastermnt}/MUL_REN_SYMLINK
e3c68b
+    mkdir sym_dir1
e3c68b
+    ln -s "sym_dir1" sym1
e3c68b
+    mv sym1 sym2
e3c68b
+    mv sym2 sym3
e3c68b
+    mv sym3 sym4
e3c68b
+    cd -
e3c68b
+}
e3c68b
+
e3c68b
 function create_data()
e3c68b
 {
e3c68b
     prefix=$1
e3c68b
-- 
e3c68b
1.8.3.1
e3c68b