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