9f5ccc
From 4097a748cbb7616d78886b35e3360177d570b7a6 Mon Sep 17 00:00:00 2001
9f5ccc
From: Krutika Dhananjay <kdhananj@redhat.com>
9f5ccc
Date: Fri, 22 May 2020 13:25:26 +0530
9f5ccc
Subject: [PATCH 382/382] features/shard: Aggregate file size, block-count
9f5ccc
 before unwinding removexattr
9f5ccc
9f5ccc
Posix translator returns pre and postbufs in the dict in {F}REMOVEXATTR fops.
9f5ccc
These iatts are further cached at layers like md-cache.
9f5ccc
Shard translator, in its current state, simply returns these values without
9f5ccc
updating the aggregated file size and block-count.
9f5ccc
9f5ccc
This patch fixes this problem.
9f5ccc
9f5ccc
Upstream patch:
9f5ccc
> Upstream patch link: https://review.gluster.org/c/glusterfs/+/24480
9f5ccc
> Change-Id: I4b2dd41ede472c5829af80a67401ec5a6376d872
9f5ccc
> Fixes: #1243
9f5ccc
> Signed-off-by: Krutika Dhananjay <kdhananj@redhat.com>
9f5ccc
9f5ccc
Change-Id: I4b2dd41ede472c5829af80a67401ec5a6376d872
9f5ccc
BUG: 1823423
9f5ccc
Signed-off-by: Xavi Hernandez <xhernandez@redhat.com>
9f5ccc
Reviewed-on: https://code.engineering.redhat.com/gerrit/201456
9f5ccc
Tested-by: RHGS Build Bot <nigelb@redhat.com>
9f5ccc
Reviewed-by: Sunil Kumar Heggodu Gopala Acharya <sheggodu@redhat.com>
9f5ccc
---
9f5ccc
 tests/bugs/shard/issue-1243.t      |  12 ++
9f5ccc
 xlators/features/shard/src/shard.c | 293 ++++++++++++++++++++++++++-----------
9f5ccc
 xlators/features/shard/src/shard.h |   1 +
9f5ccc
 3 files changed, 224 insertions(+), 82 deletions(-)
9f5ccc
9f5ccc
diff --git a/tests/bugs/shard/issue-1243.t b/tests/bugs/shard/issue-1243.t
9f5ccc
index b0c092c..ba22d2b 100644
9f5ccc
--- a/tests/bugs/shard/issue-1243.t
9f5ccc
+++ b/tests/bugs/shard/issue-1243.t
9f5ccc
@@ -1,6 +1,7 @@
9f5ccc
 #!/bin/bash
9f5ccc
 
9f5ccc
 . $(dirname $0)/../../include.rc
9f5ccc
+. $(dirname $0)/../../volume.rc
9f5ccc
 
9f5ccc
 cleanup;
9f5ccc
 
9f5ccc
@@ -22,10 +23,21 @@ TEST $CLI volume set $V0 md-cache-timeout 10
9f5ccc
 # Write data into a file such that its size crosses shard-block-size
9f5ccc
 TEST dd if=/dev/zero of=$M0/foo bs=1048576 count=8 oflag=direct
9f5ccc
 
9f5ccc
+EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0
9f5ccc
+TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0
9f5ccc
+
9f5ccc
 # Execute a setxattr on the file.
9f5ccc
 TEST setfattr -n trusted.libvirt -v some-value $M0/foo
9f5ccc
 
9f5ccc
 # Size of the file should be the aggregated size, not the shard-block-size
9f5ccc
 EXPECT '8388608' stat -c %s $M0/foo
9f5ccc
 
9f5ccc
+EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0
9f5ccc
+TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0
9f5ccc
+
9f5ccc
+# Execute a removexattr on the file.
9f5ccc
+TEST setfattr -x trusted.libvirt $M0/foo
9f5ccc
+
9f5ccc
+# Size of the file should be the aggregated size, not the shard-block-size
9f5ccc
+EXPECT '8388608' stat -c %s $M0/foo
9f5ccc
 cleanup
9f5ccc
diff --git a/xlators/features/shard/src/shard.c b/xlators/features/shard/src/shard.c
9f5ccc
index 6ae4c41..2e2ef5d 100644
9f5ccc
--- a/xlators/features/shard/src/shard.c
9f5ccc
+++ b/xlators/features/shard/src/shard.c
9f5ccc
@@ -442,6 +442,9 @@ void shard_local_wipe(shard_local_t *local) {
9f5ccc
   loc_wipe(&local->int_entrylk.loc);
9f5ccc
   loc_wipe(&local->newloc);
9f5ccc
 
9f5ccc
+  if (local->name)
9f5ccc
+    GF_FREE(local->name);
9f5ccc
+
9f5ccc
   if (local->int_entrylk.basename)
9f5ccc
     GF_FREE(local->int_entrylk.basename);
9f5ccc
   if (local->fd)
9f5ccc
@@ -5819,46 +5822,216 @@ int32_t shard_readdirp(call_frame_t *frame, xlator_t *this, fd_t *fd,
9f5ccc
   return 0;
9f5ccc
 }
9f5ccc
 
9f5ccc
-int32_t shard_removexattr(call_frame_t *frame, xlator_t *this, loc_t *loc,
9f5ccc
-                          const char *name, dict_t *xdata) {
9f5ccc
-  int op_errno = EINVAL;
9f5ccc
+int32_t
9f5ccc
+shard_modify_and_set_iatt_in_dict(dict_t *xdata, shard_local_t *local,
9f5ccc
+                                  char *key)
9f5ccc
+{
9f5ccc
+    int ret = 0;
9f5ccc
+    struct iatt *tmpbuf = NULL;
9f5ccc
+    struct iatt *stbuf = NULL;
9f5ccc
+    data_t *data = NULL;
9f5ccc
 
9f5ccc
-  if (frame->root->pid != GF_CLIENT_PID_GSYNCD) {
9f5ccc
-    GF_IF_NATIVE_XATTR_GOTO(SHARD_XATTR_PREFIX "*", name, op_errno, out);
9f5ccc
-  }
9f5ccc
+    if (!xdata)
9f5ccc
+        return 0;
9f5ccc
 
9f5ccc
-  if (xdata && (frame->root->pid != GF_CLIENT_PID_GSYNCD)) {
9f5ccc
-    dict_del(xdata, GF_XATTR_SHARD_BLOCK_SIZE);
9f5ccc
-    dict_del(xdata, GF_XATTR_SHARD_FILE_SIZE);
9f5ccc
-  }
9f5ccc
+    data = dict_get(xdata, key);
9f5ccc
+    if (!data)
9f5ccc
+        return 0;
9f5ccc
 
9f5ccc
-  STACK_WIND_TAIL(frame, FIRST_CHILD(this),
9f5ccc
-                  FIRST_CHILD(this)->fops->removexattr, loc, name, xdata);
9f5ccc
-  return 0;
9f5ccc
-out:
9f5ccc
-  shard_common_failure_unwind(GF_FOP_REMOVEXATTR, frame, -1, op_errno);
9f5ccc
-  return 0;
9f5ccc
+    tmpbuf = data_to_iatt(data, key);
9f5ccc
+    stbuf = GF_MALLOC(sizeof(struct iatt), gf_common_mt_char);
9f5ccc
+    if (stbuf == NULL) {
9f5ccc
+        local->op_ret = -1;
9f5ccc
+        local->op_errno = ENOMEM;
9f5ccc
+        goto err;
9f5ccc
+    }
9f5ccc
+    *stbuf = *tmpbuf;
9f5ccc
+    stbuf->ia_size = local->prebuf.ia_size;
9f5ccc
+    stbuf->ia_blocks = local->prebuf.ia_blocks;
9f5ccc
+    ret = dict_set_iatt(xdata, key, stbuf, false);
9f5ccc
+    if (ret < 0) {
9f5ccc
+        local->op_ret = -1;
9f5ccc
+        local->op_errno = ENOMEM;
9f5ccc
+        goto err;
9f5ccc
+    }
9f5ccc
+    return 0;
9f5ccc
+
9f5ccc
+err:
9f5ccc
+    GF_FREE(stbuf);
9f5ccc
+    return -1;
9f5ccc
 }
9f5ccc
 
9f5ccc
-int32_t shard_fremovexattr(call_frame_t *frame, xlator_t *this, fd_t *fd,
9f5ccc
-                           const char *name, dict_t *xdata) {
9f5ccc
-  int op_errno = EINVAL;
9f5ccc
+int32_t
9f5ccc
+shard_common_remove_xattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
9f5ccc
+                              int32_t op_ret, int32_t op_errno, dict_t *xdata)
9f5ccc
+{
9f5ccc
+    int ret = -1;
9f5ccc
+    shard_local_t *local = NULL;
9f5ccc
 
9f5ccc
-  if (frame->root->pid != GF_CLIENT_PID_GSYNCD) {
9f5ccc
-    GF_IF_NATIVE_XATTR_GOTO(SHARD_XATTR_PREFIX "*", name, op_errno, out);
9f5ccc
-  }
9f5ccc
+    local = frame->local;
9f5ccc
 
9f5ccc
-  if (xdata && (frame->root->pid != GF_CLIENT_PID_GSYNCD)) {
9f5ccc
-    dict_del(xdata, GF_XATTR_SHARD_BLOCK_SIZE);
9f5ccc
-    dict_del(xdata, GF_XATTR_SHARD_FILE_SIZE);
9f5ccc
-  }
9f5ccc
+    if (op_ret < 0) {
9f5ccc
+        local->op_ret = op_ret;
9f5ccc
+        local->op_errno = op_errno;
9f5ccc
+        goto err;
9f5ccc
+    }
9f5ccc
 
9f5ccc
-  STACK_WIND_TAIL(frame, FIRST_CHILD(this),
9f5ccc
-                  FIRST_CHILD(this)->fops->fremovexattr, fd, name, xdata);
9f5ccc
-  return 0;
9f5ccc
-out:
9f5ccc
-  shard_common_failure_unwind(GF_FOP_FREMOVEXATTR, frame, -1, op_errno);
9f5ccc
-  return 0;
9f5ccc
+    ret = shard_modify_and_set_iatt_in_dict(xdata, local, GF_PRESTAT);
9f5ccc
+    if (ret < 0)
9f5ccc
+        goto err;
9f5ccc
+
9f5ccc
+    ret = shard_modify_and_set_iatt_in_dict(xdata, local, GF_POSTSTAT);
9f5ccc
+    if (ret < 0)
9f5ccc
+        goto err;
9f5ccc
+
9f5ccc
+    if (local->fd)
9f5ccc
+        SHARD_STACK_UNWIND(fremovexattr, frame, local->op_ret, local->op_errno,
9f5ccc
+                           xdata);
9f5ccc
+    else
9f5ccc
+        SHARD_STACK_UNWIND(removexattr, frame, local->op_ret, local->op_errno,
9f5ccc
+                           xdata);
9f5ccc
+    return 0;
9f5ccc
+
9f5ccc
+err:
9f5ccc
+    shard_common_failure_unwind(local->fop, frame, local->op_ret,
9f5ccc
+                                local->op_errno);
9f5ccc
+    return 0;
9f5ccc
+}
9f5ccc
+
9f5ccc
+int32_t
9f5ccc
+shard_post_lookup_remove_xattr_handler(call_frame_t *frame, xlator_t *this)
9f5ccc
+{
9f5ccc
+    shard_local_t *local = NULL;
9f5ccc
+
9f5ccc
+    local = frame->local;
9f5ccc
+
9f5ccc
+    if (local->op_ret < 0) {
9f5ccc
+        shard_common_failure_unwind(local->fop, frame, local->op_ret,
9f5ccc
+                                    local->op_errno);
9f5ccc
+        return 0;
9f5ccc
+    }
9f5ccc
+
9f5ccc
+    if (local->fd)
9f5ccc
+        STACK_WIND(frame, shard_common_remove_xattr_cbk, FIRST_CHILD(this),
9f5ccc
+                   FIRST_CHILD(this)->fops->fremovexattr, local->fd,
9f5ccc
+                   local->name, local->xattr_req);
9f5ccc
+    else
9f5ccc
+        STACK_WIND(frame, shard_common_remove_xattr_cbk, FIRST_CHILD(this),
9f5ccc
+                   FIRST_CHILD(this)->fops->removexattr, &local->loc,
9f5ccc
+                   local->name, local->xattr_req);
9f5ccc
+    return 0;
9f5ccc
+}
9f5ccc
+
9f5ccc
+int32_t
9f5ccc
+shard_common_remove_xattr(call_frame_t *frame, xlator_t *this,
9f5ccc
+                          glusterfs_fop_t fop, loc_t *loc, fd_t *fd,
9f5ccc
+                          const char *name, dict_t *xdata)
9f5ccc
+{
9f5ccc
+    int ret = -1;
9f5ccc
+    int op_errno = ENOMEM;
9f5ccc
+    uint64_t block_size = 0;
9f5ccc
+    shard_local_t *local = NULL;
9f5ccc
+    inode_t *inode = loc ? loc->inode : fd->inode;
9f5ccc
+
9f5ccc
+    if ((IA_ISDIR(inode->ia_type)) || (IA_ISLNK(inode->ia_type))) {
9f5ccc
+        if (loc)
9f5ccc
+            STACK_WIND_TAIL(frame, FIRST_CHILD(this),
9f5ccc
+                            FIRST_CHILD(this)->fops->removexattr, loc, name,
9f5ccc
+                            xdata);
9f5ccc
+        else
9f5ccc
+            STACK_WIND_TAIL(frame, FIRST_CHILD(this),
9f5ccc
+                            FIRST_CHILD(this)->fops->fremovexattr, fd, name,
9f5ccc
+                            xdata);
9f5ccc
+        return 0;
9f5ccc
+    }
9f5ccc
+
9f5ccc
+    /* If shard's special xattrs are attempted to be removed,
9f5ccc
+     * fail the fop with EPERM (except if the client is gsyncd).
9f5ccc
+     */
9f5ccc
+    if (frame->root->pid != GF_CLIENT_PID_GSYNCD) {
9f5ccc
+        GF_IF_NATIVE_XATTR_GOTO(SHARD_XATTR_PREFIX "*", name, op_errno, err);
9f5ccc
+    }
9f5ccc
+
9f5ccc
+    /* Repeat the same check for bulk-removexattr */
9f5ccc
+    if (xdata && (frame->root->pid != GF_CLIENT_PID_GSYNCD)) {
9f5ccc
+        dict_del(xdata, GF_XATTR_SHARD_BLOCK_SIZE);
9f5ccc
+        dict_del(xdata, GF_XATTR_SHARD_FILE_SIZE);
9f5ccc
+    }
9f5ccc
+
9f5ccc
+    ret = shard_inode_ctx_get_block_size(inode, this, &block_size);
9f5ccc
+    if (ret) {
9f5ccc
+        gf_msg(this->name, GF_LOG_ERROR, 0, SHARD_MSG_INODE_CTX_GET_FAILED,
9f5ccc
+               "Failed to get block size from inode ctx of %s",
9f5ccc
+               uuid_utoa(inode->gfid));
9f5ccc
+        goto err;
9f5ccc
+    }
9f5ccc
+
9f5ccc
+    if (!block_size || frame->root->pid == GF_CLIENT_PID_GSYNCD) {
9f5ccc
+        if (loc)
9f5ccc
+            STACK_WIND_TAIL(frame, FIRST_CHILD(this),
9f5ccc
+                            FIRST_CHILD(this)->fops->removexattr, loc, name,
9f5ccc
+                            xdata);
9f5ccc
+        else
9f5ccc
+            STACK_WIND_TAIL(frame, FIRST_CHILD(this),
9f5ccc
+                            FIRST_CHILD(this)->fops->fremovexattr, fd, name,
9f5ccc
+                            xdata);
9f5ccc
+        return 0;
9f5ccc
+    }
9f5ccc
+
9f5ccc
+    local = mem_get0(this->local_pool);
9f5ccc
+    if (!local)
9f5ccc
+        goto err;
9f5ccc
+
9f5ccc
+    frame->local = local;
9f5ccc
+    local->fop = fop;
9f5ccc
+    if (loc) {
9f5ccc
+        if (loc_copy(&local->loc, loc) != 0)
9f5ccc
+            goto err;
9f5ccc
+    }
9f5ccc
+
9f5ccc
+    if (fd) {
9f5ccc
+        local->fd = fd_ref(fd);
9f5ccc
+        local->loc.inode = inode_ref(fd->inode);
9f5ccc
+        gf_uuid_copy(local->loc.gfid, fd->inode->gfid);
9f5ccc
+    }
9f5ccc
+
9f5ccc
+    if (name) {
9f5ccc
+        local->name = gf_strdup(name);
9f5ccc
+        if (!local->name)
9f5ccc
+            goto err;
9f5ccc
+    }
9f5ccc
+
9f5ccc
+    if (xdata)
9f5ccc
+        local->xattr_req = dict_ref(xdata);
9f5ccc
+
9f5ccc
+    /* To-Do: Switch from LOOKUP which is path-based, to FSTAT if the fop is
9f5ccc
+     * on an fd. This comes under a generic class of bugs in shard tracked by
9f5ccc
+     * bz #1782428.
9f5ccc
+     */
9f5ccc
+    shard_lookup_base_file(frame, this, &local->loc,
9f5ccc
+                           shard_post_lookup_remove_xattr_handler);
9f5ccc
+    return 0;
9f5ccc
+err:
9f5ccc
+    shard_common_failure_unwind(fop, frame, -1, op_errno);
9f5ccc
+    return 0;
9f5ccc
+}
9f5ccc
+
9f5ccc
+int32_t
9f5ccc
+shard_removexattr(call_frame_t *frame, xlator_t *this, loc_t *loc,
9f5ccc
+                  const char *name, dict_t *xdata)
9f5ccc
+{
9f5ccc
+    shard_common_remove_xattr(frame, this, GF_FOP_REMOVEXATTR, loc, NULL, name,
9f5ccc
+                              xdata);
9f5ccc
+    return 0;
9f5ccc
+}
9f5ccc
+
9f5ccc
+int32_t
9f5ccc
+shard_fremovexattr(call_frame_t *frame, xlator_t *this, fd_t *fd,
9f5ccc
+                   const char *name, dict_t *xdata)
9f5ccc
+{
9f5ccc
+    shard_common_remove_xattr(frame, this, GF_FOP_FREMOVEXATTR, NULL, fd, name,
9f5ccc
+                              xdata);
9f5ccc
+    return 0;
9f5ccc
 }
9f5ccc
 
9f5ccc
 int32_t shard_fgetxattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
9f5ccc
@@ -5933,10 +6106,6 @@ int32_t shard_common_set_xattr_cbk(call_frame_t *frame, void *cookie,
9f5ccc
                                    xlator_t *this, int32_t op_ret,
9f5ccc
                                    int32_t op_errno, dict_t *xdata) {
9f5ccc
     int ret = -1;
9f5ccc
-    struct iatt *prebuf = NULL;
9f5ccc
-    struct iatt *postbuf = NULL;
9f5ccc
-    struct iatt *stbuf = NULL;
9f5ccc
-    data_t *data = NULL;
9f5ccc
     shard_local_t *local = NULL;
9f5ccc
 
9f5ccc
     local = frame->local;
9f5ccc
@@ -5947,52 +6116,14 @@ int32_t shard_common_set_xattr_cbk(call_frame_t *frame, void *cookie,
9f5ccc
         goto err;
9f5ccc
     }
9f5ccc
 
9f5ccc
-    if (!xdata)
9f5ccc
-        goto unwind;
9f5ccc
-
9f5ccc
-    data = dict_get(xdata, GF_PRESTAT);
9f5ccc
-    if (data) {
9f5ccc
-        stbuf = data_to_iatt(data, GF_PRESTAT);
9f5ccc
-        prebuf = GF_MALLOC(sizeof(struct iatt), gf_common_mt_char);
9f5ccc
-        if (prebuf == NULL) {
9f5ccc
-            local->op_ret = -1;
9f5ccc
-            local->op_errno = ENOMEM;
9f5ccc
-            goto err;
9f5ccc
-        }
9f5ccc
-        *prebuf = *stbuf;
9f5ccc
-        prebuf->ia_size = local->prebuf.ia_size;
9f5ccc
-        prebuf->ia_blocks = local->prebuf.ia_blocks;
9f5ccc
-        ret = dict_set_iatt(xdata, GF_PRESTAT, prebuf, false);
9f5ccc
-        if (ret < 0) {
9f5ccc
-            local->op_ret = -1;
9f5ccc
-            local->op_errno = ENOMEM;
9f5ccc
-            goto err;
9f5ccc
-        }
9f5ccc
-        prebuf = NULL;
9f5ccc
-    }
9f5ccc
+    ret = shard_modify_and_set_iatt_in_dict(xdata, local, GF_PRESTAT);
9f5ccc
+    if (ret < 0)
9f5ccc
+        goto err;
9f5ccc
 
9f5ccc
-    data = dict_get(xdata, GF_POSTSTAT);
9f5ccc
-    if (data) {
9f5ccc
-        stbuf = data_to_iatt(data, GF_POSTSTAT);
9f5ccc
-        postbuf = GF_MALLOC(sizeof(struct iatt), gf_common_mt_char);
9f5ccc
-        if (postbuf == NULL) {
9f5ccc
-            local->op_ret = -1;
9f5ccc
-            local->op_errno = ENOMEM;
9f5ccc
-            goto err;
9f5ccc
-        }
9f5ccc
-        *postbuf = *stbuf;
9f5ccc
-        postbuf->ia_size = local->prebuf.ia_size;
9f5ccc
-        postbuf->ia_blocks = local->prebuf.ia_blocks;
9f5ccc
-        ret = dict_set_iatt(xdata, GF_POSTSTAT, postbuf, false);
9f5ccc
-        if (ret < 0) {
9f5ccc
-            local->op_ret = -1;
9f5ccc
-            local->op_errno = ENOMEM;
9f5ccc
-            goto err;
9f5ccc
-        }
9f5ccc
-        postbuf = NULL;
9f5ccc
-    }
9f5ccc
+    ret = shard_modify_and_set_iatt_in_dict(xdata, local, GF_POSTSTAT);
9f5ccc
+    if (ret < 0)
9f5ccc
+        goto err;
9f5ccc
 
9f5ccc
-unwind:
9f5ccc
     if (local->fd)
9f5ccc
         SHARD_STACK_UNWIND(fsetxattr, frame, local->op_ret, local->op_errno,
9f5ccc
                            xdata);
9f5ccc
@@ -6002,8 +6133,6 @@ unwind:
9f5ccc
     return 0;
9f5ccc
 
9f5ccc
 err:
9f5ccc
-    GF_FREE(prebuf);
9f5ccc
-    GF_FREE(postbuf);
9f5ccc
     shard_common_failure_unwind(local->fop, frame, local->op_ret,
9f5ccc
                                 local->op_errno);
9f5ccc
     return 0;
9f5ccc
diff --git a/xlators/features/shard/src/shard.h b/xlators/features/shard/src/shard.h
9f5ccc
index 04abd62..1721417 100644
9f5ccc
--- a/xlators/features/shard/src/shard.h
9f5ccc
+++ b/xlators/features/shard/src/shard.h
9f5ccc
@@ -318,6 +318,7 @@ typedef struct shard_local {
9f5ccc
     uint32_t deletion_rate;
9f5ccc
     gf_boolean_t cleanup_required;
9f5ccc
     uuid_t base_gfid;
9f5ccc
+    char *name;
9f5ccc
 } shard_local_t;
9f5ccc
 
9f5ccc
 typedef struct shard_inode_ctx {
9f5ccc
-- 
9f5ccc
1.8.3.1
9f5ccc