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