diff options
| author | Kotresh HR <khiremat@redhat.com> | 2017-08-08 10:12:14 -0400 | 
|---|---|---|
| committer | Aravinda VK <avishwan@redhat.com> | 2017-08-24 03:13:47 +0000 | 
| commit | e893962deaabab8e934813f8a0443a8f94e009f2 (patch) | |
| tree | 9d5a894168a81d0a195ae97ab88dc7a772c77226 /geo-replication/syncdaemon/syncdutils.py | |
| parent | ee3d9ac7f2db3a4aa9186e08b5a1db62c3270188 (diff) | |
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 <khiremat@redhat.com>
Reported-by: Christian Lohmaier <lohmaier+rhbz@gmail.com>
Reviewed-on: https://review.gluster.org/18011
Smoke: Gluster Build System <jenkins@build.gluster.org>
CentOS-regression: Gluster Build System <jenkins@build.gluster.org>
Reviewed-by: Aravinda VK <avishwan@redhat.com>
Diffstat (limited to 'geo-replication/syncdaemon/syncdutils.py')
| -rw-r--r-- | geo-replication/syncdaemon/syncdutils.py | 46 | 
1 files changed, 46 insertions, 0 deletions
diff --git a/geo-replication/syncdaemon/syncdutils.py b/geo-replication/syncdaemon/syncdutils.py index 43b21668a46..2187ecd226b 100644 --- a/geo-replication/syncdaemon/syncdutils.py +++ b/geo-replication/syncdaemon/syncdutils.py @@ -66,6 +66,8 @@ except ImportError:  _CL_AUX_GFID_PFX = ".gfid/"  GF_OP_RETRIES = 10 +GX_GFID_CANONICAL_LEN = 37  # canonical gfid len + '\0' +  CHANGELOG_AGENT_SERVER_VERSION = 1.0  CHANGELOG_AGENT_CLIENT_VERSION = 1.0  NodeID = None @@ -371,6 +373,33 @@ class GsyncdError(Exception):      pass +class _MetaXattr(object): + +    """singleton class, a lazy wrapper around the +    libcxattr module + +    libcxattr (a heavy import due to ctypes) is +    loaded only when when the single +    instance is tried to be used. + +    This reduces runtime for those invocations +    which do not need filesystem manipulation +    (eg. for config, url parsing) +    """ + +    def __getattr__(self, meth): +        from libcxattr import Xattr as LXattr +        xmeth = [m for m in dir(LXattr) if m[0] != '_'] +        if meth not in xmeth: +            return +        for m in xmeth: +            setattr(self, m, getattr(LXattr, m)) +        return getattr(self, meth) + + +Xattr = _MetaXattr() + +  def getusername(uid=None):      if uid is None:          uid = os.geteuid() @@ -524,6 +553,23 @@ def lstat(e):      return errno_wrap(os.lstat, [e], [ENOENT], [ESTALE, EBUSY]) +def get_gfid_from_mnt(gfidpath): +    return errno_wrap(Xattr.lgetxattr, +                      [gfidpath, 'glusterfs.gfid.string', +                       GX_GFID_CANONICAL_LEN], [ENOENT], [ESTALE]) + + +def matching_disk_gfid(gfid, entry): +    disk_gfid = get_gfid_from_mnt(entry) +    if isinstance(disk_gfid, int): +        return False + +    if not gfid == disk_gfid: +        return False + +    return True + +  class NoStimeAvailable(Exception):      pass  | 
