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