e7a346
From 737d077a44899f6222822408c400fcd91939ca5b Mon Sep 17 00:00:00 2001
e7a346
From: Kotresh HR <khiremat@redhat.com>
e7a346
Date: Thu, 12 Jul 2018 04:31:01 -0400
e7a346
Subject: [PATCH 321/325] geo-rep: Fix symlink rename syncing issue
e7a346
e7a346
Problem:
e7a346
   Geo-rep sometimes fails to sync the rename of symlink
e7a346
if the I/O is as follows
e7a346
e7a346
  1. touch file1
e7a346
  2. ln -s "./file1" sym_400
e7a346
  3. mv sym_400 renamed_sym_400
e7a346
  4. mkdir sym_400
e7a346
e7a346
 The file 'renamed_sym_400' failed to sync to slave
e7a346
e7a346
Cause:
e7a346
  Assume there are three distribute subvolume (brick1, brick2, brick3).
e7a346
  The changelogs are recorded as follows for above I/O pattern.
e7a346
  Note that the MKDIR is recorded on all bricks.
e7a346
e7a346
  1. brick1:
e7a346
     -------
e7a346
e7a346
     CREATE file1
e7a346
     SYMLINK sym_400
e7a346
     RENAME sym_400 renamed_sym_400
e7a346
     MKDIR sym_400
e7a346
e7a346
  2. brick2:
e7a346
     -------
e7a346
e7a346
     MKDIR sym_400
e7a346
e7a346
  3. brick3:
e7a346
     -------
e7a346
e7a346
     MKDIR sym_400
e7a346
e7a346
  The operations on 'brick1' should be processed sequentially. But
e7a346
  since MKDIR is recorded on all the bricks, The brick 'brick2/brick3'
e7a346
  processed MKDIR first before 'brick1' causing out of order syncing
e7a346
  and created directory sym_400 first.
e7a346
e7a346
  Now 'brick1' processed it's changelog.
e7a346
e7a346
     CREATE file1 -> succeeds
e7a346
     SYMLINK sym_400 -> No longer present in master. Ignored
e7a346
     RENAME sym_400 renamed_sym_400
e7a346
            While processing RENAME, if source('sym_400') doesn't
e7a346
            present, destination('renamed_sym_400') is created. But
e7a346
            geo-rep stats the name 'sym_400' to confirm source file's
e7a346
            presence. In this race, since source name 'sym_400' is
e7a346
            present as directory, it doesn't create destination.
e7a346
            Hence RENAME is ignored.
e7a346
e7a346
Fix:
e7a346
  The fix is not rely only on stat of source name during RENAME.
e7a346
  It should stat the name and if the name is present, gfid should
e7a346
  be same. Only then it can conclude the presence of source.
e7a346
e7a346
>upstream patch : https://review.gluster.org/#/c/20496/
e7a346
e7a346
Backport of:
e7a346
 > BUG: 1600405
e7a346
 > Change-Id: I9fbec4f13ca6a182798a7f81b356fe2003aff969
e7a346
 > Signed-off-by: Kotresh HR <khiremat@redhat.com>
e7a346
e7a346
BUG: 1601314
e7a346
Change-Id: I9fbec4f13ca6a182798a7f81b356fe2003aff969
e7a346
Signed-off-by: Kotresh HR <khiremat@redhat.com>
e7a346
Reviewed-on: https://code.engineering.redhat.com/gerrit/144104
e7a346
Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
e7a346
Tested-by: RHGS Build Bot <nigelb@redhat.com>
e7a346
---
e7a346
 geo-replication/syncdaemon/resource.py | 11 +++++++++--
e7a346
 1 file changed, 9 insertions(+), 2 deletions(-)
e7a346
e7a346
diff --git a/geo-replication/syncdaemon/resource.py b/geo-replication/syncdaemon/resource.py
e7a346
index 00e62b7..0d5462a 100644
e7a346
--- a/geo-replication/syncdaemon/resource.py
e7a346
+++ b/geo-replication/syncdaemon/resource.py
e7a346
@@ -674,8 +674,14 @@ class Server(object):
e7a346
                     collect_failure(e, EEXIST)
e7a346
             elif op == 'RENAME':
e7a346
                 en = e['entry1']
e7a346
-                st = lstat(entry)
e7a346
-                if isinstance(st, int):
e7a346
+                # The matching disk gfid check validates two things
e7a346
+                #  1. Validates name is present, return false otherwise
e7a346
+                #  2. Validates gfid is same, returns false otherwise
e7a346
+                # So both validations are necessary to decide src doesn't
e7a346
+                # exist. We can't rely on only gfid stat as hardlink could
e7a346
+                # be present and we can't rely only on name as name could
e7a346
+                # exist with differnt gfid.
e7a346
+                if not matching_disk_gfid(gfid, entry):
e7a346
                     if e['stat'] and not stat.S_ISDIR(e['stat']['mode']):
e7a346
                         if stat.S_ISLNK(e['stat']['mode']) and \
e7a346
                            e['link'] is not None:
e7a346
@@ -699,6 +705,7 @@ class Server(object):
e7a346
                                                     [ENOENT, EEXIST], [ESTALE])
e7a346
                                 collect_failure(e, cmd_ret)
e7a346
                 else:
e7a346
+                    st = lstat(entry)
e7a346
                     st1 = lstat(en)
e7a346
                     if isinstance(st1, int):
e7a346
                         rename_with_disk_gfid_confirmation(gfid, entry, en)
e7a346
-- 
e7a346
1.8.3.1
e7a346