From e893962deaabab8e934813f8a0443a8f94e009f2 Mon Sep 17 00:00:00 2001 From: Kotresh HR Date: Tue, 8 Aug 2017 10:12:14 -0400 Subject: geo-rep: Fix syncing of hardlink of symlink Problem: If there is a hardlink to a symlink on master and if the symlink file is deleted on master, geo-rep fails to sync the hardlink. Typical Usecase: It's easily hit with rsnapshot use case where it uses hardlinks. Example Reproducer: Setup geo-replication between master and slave volume and in master mount point, do the following. 1. mkdir /tmp/symlinkbug 2. ln -f -s /does/not/exist /tmp/symlinkbug/a_symlink 3. rsync -a /tmp/symlinkbug ./ 4. cp -al symlinkbug symlinkbug.0 5. ln -f -s /does/not/exist2 /tmp/symlinkbug/a_symlink 6. rsync -a /tmp/symlinkbug ./ 7. cp -al symlinkbug symlinkbug.1 Cause: If the source was not present while syncing hardlink, it was always packing the blob as regular file. Fix: If the source was not present while syncing hardlink, pack the blob based on the mode. Change-Id: Iaa12d6f99de47b18e0650e7c4eb455f23f8390f2 BUG: 1432046 Signed-off-by: Kotresh HR Reported-by: Christian Lohmaier Reviewed-on: https://review.gluster.org/18011 Smoke: Gluster Build System CentOS-regression: Gluster Build System Reviewed-by: Aravinda VK --- geo-replication/syncdaemon/master.py | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'geo-replication/syncdaemon/master.py') diff --git a/geo-replication/syncdaemon/master.py b/geo-replication/syncdaemon/master.py index 2aae860f5d1..2987bca0601 100644 --- a/geo-replication/syncdaemon/master.py +++ b/geo-replication/syncdaemon/master.py @@ -24,7 +24,7 @@ from datetime import datetime from gconf import gconf from syncdutils import Thread, GsyncdError, boolify, escape_space_newline from syncdutils import unescape_space_newline, gauxpfx, md5hex, selfkill -from syncdutils import lstat, errno_wrap, FreeObject, lf +from syncdutils import lstat, errno_wrap, FreeObject, lf, matching_disk_gfid from syncdutils import NoStimeAvailable, PartialHistoryAvailable URXTIME = (-1, 0) @@ -792,6 +792,10 @@ class GMasterChangelogMixin(GMasterCommon): fix_entry_ops = [] failures1 = [] for failure in failures: + if failure[2]['dst']: + pbname = failure[0]['entry1'] + else: + pbname = failure[0]['entry'] if failure[2]['gfid_mismatch']: slave_gfid = failure[2]['slave_gfid'] st = lstat(os.path.join(pfx, slave_gfid)) @@ -800,7 +804,6 @@ class GMasterChangelogMixin(GMasterCommon): ' the entry', retry_count=retry_count, entry=repr(failure))) #Add deletion to fix_entry_ops list - pbname = failure[0]['entry'] if failure[2]['slave_isdir']: fix_entry_ops.append(edct('RMDIR', gfid=failure[2]['slave_gfid'], @@ -836,7 +839,6 @@ class GMasterChangelogMixin(GMasterCommon): ' Deleting the entry', retry_count=retry_count, entry=repr(failure))) - pbname = failure[0]['entry'] fix_entry_ops.append(edct('UNLINK', gfid=failure[2]['slave_gfid'], entry=pbname)) @@ -1024,15 +1026,27 @@ class GMasterChangelogMixin(GMasterCommon): stat=st, link=rl)) else: # stat() to get mode and other information + if not matching_disk_gfid(gfid, en): + logging.debug(lf('Ignoring entry, purged in the ' + 'interim', file=en, gfid=gfid)) + continue + go = os.path.join(pfx, gfid) st = lstat(go) if isinstance(st, int): - logging.debug(lf('file got purged in the interim', - file=go)) + logging.debug(lf('Ignoring entry, purged in the ' + 'interim', file=en, gfid=gfid)) continue if ty == 'LINK': - entries.append(edct(ty, stat=st, entry=en, gfid=gfid)) + rl = None + if st and stat.S_ISLNK(st.st_mode): + rl = errno_wrap(os.readlink, [en], [ENOENT], + [ESTALE]) + if isinstance(rl, int): + rl = None + entries.append(edct(ty, stat=st, entry=en, gfid=gfid, + link=rl)) elif ty == 'SYMLINK': rl = errno_wrap(os.readlink, [en], [ENOENT], [ESTALE]) if isinstance(rl, int): -- cgit