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