1df6c8
From 2cf22e54c8424949607c4a20df84887b838b2702 Mon Sep 17 00:00:00 2001
1df6c8
From: Krutika Dhananjay <kdhananj@redhat.com>
1df6c8
Date: Fri, 15 May 2020 11:29:36 +0530
1df6c8
Subject: [PATCH 380/382] features/shard: Aggregate size, block-count in iatt
1df6c8
 before unwinding setxattr
1df6c8
1df6c8
Backport of:
1df6c8
> Upstream patch - https://review.gluster.org/c/glusterfs/+/24471
1df6c8
> Fixes: #1243
1df6c8
> Change-Id: I4da0eceb4235b91546df79270bcc0af8cd64e9ea
1df6c8
> Signed-off-by: Krutika Dhananjay <kdhananj@redhat.com>
1df6c8
1df6c8
Posix translator returns pre and postbufs in the dict in {F}SETXATTR fops.
1df6c8
These iatts are further cached at layers like md-cache.
1df6c8
Shard translator, in its current state, simply returns these values without
1df6c8
updating the aggregated file size and block-count.
1df6c8
1df6c8
This patch fixes this problem.
1df6c8
1df6c8
Change-Id: I4da0eceb4235b91546df79270bcc0af8cd64e9ea
1df6c8
BUG: 1823423
1df6c8
Signed-off-by: Krutika Dhananjay <kdhananj@redhat.com>
1df6c8
Reviewed-on: https://code.engineering.redhat.com/gerrit/201135
1df6c8
Tested-by: RHGS Build Bot <nigelb@redhat.com>
1df6c8
Reviewed-by: Xavi Hernandez Juan <xhernandez@redhat.com>
1df6c8
---
1df6c8
 tests/bugs/shard/issue-1243.t      |  31 ++++++
1df6c8
 xlators/features/shard/src/shard.c | 218 +++++++++++++++++++++++++++++++++----
1df6c8
 2 files changed, 225 insertions(+), 24 deletions(-)
1df6c8
 create mode 100644 tests/bugs/shard/issue-1243.t
1df6c8
1df6c8
diff --git a/tests/bugs/shard/issue-1243.t b/tests/bugs/shard/issue-1243.t
1df6c8
new file mode 100644
1df6c8
index 0000000..b0c092c
1df6c8
--- /dev/null
1df6c8
+++ b/tests/bugs/shard/issue-1243.t
1df6c8
@@ -0,0 +1,31 @@
1df6c8
+#!/bin/bash
1df6c8
+
1df6c8
+. $(dirname $0)/../../include.rc
1df6c8
+
1df6c8
+cleanup;
1df6c8
+
1df6c8
+TEST glusterd
1df6c8
+TEST pidof glusterd
1df6c8
+TEST $CLI volume create $V0 $H0:$B0/${V0}{0,1}
1df6c8
+TEST $CLI volume set $V0 features.shard on
1df6c8
+TEST $CLI volume set $V0 features.shard-block-size 4MB
1df6c8
+TEST $CLI volume set $V0 performance.quick-read off
1df6c8
+TEST $CLI volume set $V0 performance.io-cache off
1df6c8
+TEST $CLI volume set $V0 performance.read-ahead off
1df6c8
+TEST $CLI volume set $V0 performance.strict-o-direct on
1df6c8
+TEST $CLI volume start $V0
1df6c8
+
1df6c8
+TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0
1df6c8
+
1df6c8
+TEST $CLI volume set $V0 md-cache-timeout 10
1df6c8
+
1df6c8
+# Write data into a file such that its size crosses shard-block-size
1df6c8
+TEST dd if=/dev/zero of=$M0/foo bs=1048576 count=8 oflag=direct
1df6c8
+
1df6c8
+# Execute a setxattr on the file.
1df6c8
+TEST setfattr -n trusted.libvirt -v some-value $M0/foo
1df6c8
+
1df6c8
+# Size of the file should be the aggregated size, not the shard-block-size
1df6c8
+EXPECT '8388608' stat -c %s $M0/foo
1df6c8
+
1df6c8
+cleanup
1df6c8
diff --git a/xlators/features/shard/src/shard.c b/xlators/features/shard/src/shard.c
1df6c8
index ee38ed2..6ae4c41 100644
1df6c8
--- a/xlators/features/shard/src/shard.c
1df6c8
+++ b/xlators/features/shard/src/shard.c
1df6c8
@@ -5929,36 +5929,206 @@ out:
1df6c8
   return 0;
1df6c8
 }
1df6c8
 
1df6c8
-int32_t shard_fsetxattr(call_frame_t *frame, xlator_t *this, fd_t *fd,
1df6c8
-                        dict_t *dict, int32_t flags, dict_t *xdata) {
1df6c8
-  int op_errno = EINVAL;
1df6c8
+int32_t shard_common_set_xattr_cbk(call_frame_t *frame, void *cookie,
1df6c8
+                                   xlator_t *this, int32_t op_ret,
1df6c8
+                                   int32_t op_errno, dict_t *xdata) {
1df6c8
+    int ret = -1;
1df6c8
+    struct iatt *prebuf = NULL;
1df6c8
+    struct iatt *postbuf = NULL;
1df6c8
+    struct iatt *stbuf = NULL;
1df6c8
+    data_t *data = NULL;
1df6c8
+    shard_local_t *local = NULL;
1df6c8
 
1df6c8
-  if (frame->root->pid != GF_CLIENT_PID_GSYNCD) {
1df6c8
-    GF_IF_INTERNAL_XATTR_GOTO(SHARD_XATTR_PREFIX "*", dict, op_errno, out);
1df6c8
-  }
1df6c8
+    local = frame->local;
1df6c8
 
1df6c8
-  STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->fsetxattr,
1df6c8
-                  fd, dict, flags, xdata);
1df6c8
-  return 0;
1df6c8
-out:
1df6c8
-  shard_common_failure_unwind(GF_FOP_FSETXATTR, frame, -1, op_errno);
1df6c8
-  return 0;
1df6c8
+    if (op_ret < 0) {
1df6c8
+        local->op_ret = op_ret;
1df6c8
+        local->op_errno = op_errno;
1df6c8
+        goto err;
1df6c8
+    }
1df6c8
+
1df6c8
+    if (!xdata)
1df6c8
+        goto unwind;
1df6c8
+
1df6c8
+    data = dict_get(xdata, GF_PRESTAT);
1df6c8
+    if (data) {
1df6c8
+        stbuf = data_to_iatt(data, GF_PRESTAT);
1df6c8
+        prebuf = GF_MALLOC(sizeof(struct iatt), gf_common_mt_char);
1df6c8
+        if (prebuf == NULL) {
1df6c8
+            local->op_ret = -1;
1df6c8
+            local->op_errno = ENOMEM;
1df6c8
+            goto err;
1df6c8
+        }
1df6c8
+        *prebuf = *stbuf;
1df6c8
+        prebuf->ia_size = local->prebuf.ia_size;
1df6c8
+        prebuf->ia_blocks = local->prebuf.ia_blocks;
1df6c8
+        ret = dict_set_iatt(xdata, GF_PRESTAT, prebuf, false);
1df6c8
+        if (ret < 0) {
1df6c8
+            local->op_ret = -1;
1df6c8
+            local->op_errno = ENOMEM;
1df6c8
+            goto err;
1df6c8
+        }
1df6c8
+        prebuf = NULL;
1df6c8
+    }
1df6c8
+
1df6c8
+    data = dict_get(xdata, GF_POSTSTAT);
1df6c8
+    if (data) {
1df6c8
+        stbuf = data_to_iatt(data, GF_POSTSTAT);
1df6c8
+        postbuf = GF_MALLOC(sizeof(struct iatt), gf_common_mt_char);
1df6c8
+        if (postbuf == NULL) {
1df6c8
+            local->op_ret = -1;
1df6c8
+            local->op_errno = ENOMEM;
1df6c8
+            goto err;
1df6c8
+        }
1df6c8
+        *postbuf = *stbuf;
1df6c8
+        postbuf->ia_size = local->prebuf.ia_size;
1df6c8
+        postbuf->ia_blocks = local->prebuf.ia_blocks;
1df6c8
+        ret = dict_set_iatt(xdata, GF_POSTSTAT, postbuf, false);
1df6c8
+        if (ret < 0) {
1df6c8
+            local->op_ret = -1;
1df6c8
+            local->op_errno = ENOMEM;
1df6c8
+            goto err;
1df6c8
+        }
1df6c8
+        postbuf = NULL;
1df6c8
+    }
1df6c8
+
1df6c8
+unwind:
1df6c8
+    if (local->fd)
1df6c8
+        SHARD_STACK_UNWIND(fsetxattr, frame, local->op_ret, local->op_errno,
1df6c8
+                           xdata);
1df6c8
+    else
1df6c8
+        SHARD_STACK_UNWIND(setxattr, frame, local->op_ret, local->op_errno,
1df6c8
+                           xdata);
1df6c8
+    return 0;
1df6c8
+
1df6c8
+err:
1df6c8
+    GF_FREE(prebuf);
1df6c8
+    GF_FREE(postbuf);
1df6c8
+    shard_common_failure_unwind(local->fop, frame, local->op_ret,
1df6c8
+                                local->op_errno);
1df6c8
+    return 0;
1df6c8
 }
1df6c8
 
1df6c8
-int32_t shard_setxattr(call_frame_t *frame, xlator_t *this, loc_t *loc,
1df6c8
-                       dict_t *dict, int32_t flags, dict_t *xdata) {
1df6c8
-  int op_errno = EINVAL;
1df6c8
+int32_t shard_post_lookup_set_xattr_handler(call_frame_t *frame,
1df6c8
+                                            xlator_t *this) {
1df6c8
+    shard_local_t *local = NULL;
1df6c8
 
1df6c8
-  if (frame->root->pid != GF_CLIENT_PID_GSYNCD) {
1df6c8
-    GF_IF_INTERNAL_XATTR_GOTO(SHARD_XATTR_PREFIX "*", dict, op_errno, out);
1df6c8
-  }
1df6c8
+    local = frame->local;
1df6c8
 
1df6c8
-  STACK_WIND_TAIL(frame, FIRST_CHILD(this), FIRST_CHILD(this)->fops->setxattr,
1df6c8
-                  loc, dict, flags, xdata);
1df6c8
-  return 0;
1df6c8
-out:
1df6c8
-  shard_common_failure_unwind(GF_FOP_SETXATTR, frame, -1, op_errno);
1df6c8
-  return 0;
1df6c8
+    if (local->op_ret < 0) {
1df6c8
+        shard_common_failure_unwind(local->fop, frame, local->op_ret,
1df6c8
+                                    local->op_errno);
1df6c8
+        return 0;
1df6c8
+    }
1df6c8
+
1df6c8
+    if (local->fd)
1df6c8
+        STACK_WIND(frame, shard_common_set_xattr_cbk, FIRST_CHILD(this),
1df6c8
+                   FIRST_CHILD(this)->fops->fsetxattr, local->fd,
1df6c8
+                   local->xattr_req, local->flags, local->xattr_rsp);
1df6c8
+    else
1df6c8
+        STACK_WIND(frame, shard_common_set_xattr_cbk, FIRST_CHILD(this),
1df6c8
+                   FIRST_CHILD(this)->fops->setxattr, &local->loc,
1df6c8
+                   local->xattr_req, local->flags, local->xattr_rsp);
1df6c8
+    return 0;
1df6c8
+}
1df6c8
+
1df6c8
+int32_t shard_common_set_xattr(call_frame_t *frame, xlator_t *this,
1df6c8
+                               glusterfs_fop_t fop, loc_t *loc, fd_t *fd,
1df6c8
+                               dict_t *dict, int32_t flags, dict_t *xdata) {
1df6c8
+    int ret = -1;
1df6c8
+    int op_errno = ENOMEM;
1df6c8
+    uint64_t block_size = 0;
1df6c8
+    shard_local_t *local = NULL;
1df6c8
+    inode_t *inode = loc ? loc->inode : fd->inode;
1df6c8
+
1df6c8
+    if ((IA_ISDIR(inode->ia_type)) || (IA_ISLNK(inode->ia_type))) {
1df6c8
+        if (loc)
1df6c8
+            STACK_WIND_TAIL(frame, FIRST_CHILD(this),
1df6c8
+                            FIRST_CHILD(this)->fops->setxattr, loc, dict, flags,
1df6c8
+                            xdata);
1df6c8
+        else
1df6c8
+            STACK_WIND_TAIL(frame, FIRST_CHILD(this),
1df6c8
+                            FIRST_CHILD(this)->fops->fsetxattr, fd, dict, flags,
1df6c8
+                            xdata);
1df6c8
+        return 0;
1df6c8
+    }
1df6c8
+
1df6c8
+    /* Sharded or not, if shard's special xattrs are attempted to be set,
1df6c8
+     * fail the fop with EPERM (except if the client is gsyncd.
1df6c8
+     */
1df6c8
+    if (frame->root->pid != GF_CLIENT_PID_GSYNCD) {
1df6c8
+        GF_IF_INTERNAL_XATTR_GOTO(SHARD_XATTR_PREFIX "*", dict, op_errno, err);
1df6c8
+    }
1df6c8
+
1df6c8
+    ret = shard_inode_ctx_get_block_size(inode, this, &block_size);
1df6c8
+    if (ret) {
1df6c8
+        gf_msg(this->name, GF_LOG_ERROR, 0, SHARD_MSG_INODE_CTX_GET_FAILED,
1df6c8
+               "Failed to get block size from inode ctx of %s",
1df6c8
+               uuid_utoa(inode->gfid));
1df6c8
+        goto err;
1df6c8
+    }
1df6c8
+
1df6c8
+    if (!block_size || frame->root->pid == GF_CLIENT_PID_GSYNCD) {
1df6c8
+        if (loc)
1df6c8
+            STACK_WIND_TAIL(frame, FIRST_CHILD(this),
1df6c8
+                            FIRST_CHILD(this)->fops->setxattr, loc, dict, flags,
1df6c8
+                            xdata);
1df6c8
+        else
1df6c8
+            STACK_WIND_TAIL(frame, FIRST_CHILD(this),
1df6c8
+                            FIRST_CHILD(this)->fops->fsetxattr, fd, dict, flags,
1df6c8
+                            xdata);
1df6c8
+        return 0;
1df6c8
+    }
1df6c8
+
1df6c8
+    local = mem_get0(this->local_pool);
1df6c8
+    if (!local)
1df6c8
+        goto err;
1df6c8
+
1df6c8
+    frame->local = local;
1df6c8
+    local->fop = fop;
1df6c8
+    if (loc) {
1df6c8
+        if (loc_copy(&local->loc, loc) != 0)
1df6c8
+            goto err;
1df6c8
+    }
1df6c8
+
1df6c8
+    if (fd) {
1df6c8
+        local->fd = fd_ref(fd);
1df6c8
+        local->loc.inode = inode_ref(fd->inode);
1df6c8
+        gf_uuid_copy(local->loc.gfid, fd->inode->gfid);
1df6c8
+    }
1df6c8
+    local->flags = flags;
1df6c8
+    /* Reusing local->xattr_req and local->xattr_rsp to store the setxattr dict
1df6c8
+     * and the xdata dict
1df6c8
+     */
1df6c8
+    if (dict)
1df6c8
+        local->xattr_req = dict_ref(dict);
1df6c8
+    if (xdata)
1df6c8
+        local->xattr_rsp = dict_ref(xdata);
1df6c8
+
1df6c8
+    /* To-Do: Switch from LOOKUP which is path-based, to FSTAT if the fop is
1df6c8
+     * on an fd. This comes under a generic class of bugs in shard tracked by
1df6c8
+     * bz #1782428.
1df6c8
+     */
1df6c8
+    shard_lookup_base_file(frame, this, &local->loc,
1df6c8
+                           shard_post_lookup_set_xattr_handler);
1df6c8
+    return 0;
1df6c8
+err:
1df6c8
+    shard_common_failure_unwind(fop, frame, -1, op_errno);
1df6c8
+    return 0;
1df6c8
+}
1df6c8
+
1df6c8
+int32_t shard_fsetxattr(call_frame_t *frame, xlator_t *this, fd_t *fd,
1df6c8
+                        dict_t *dict, int32_t flags, dict_t *xdata) {
1df6c8
+    shard_common_set_xattr(frame, this, GF_FOP_FSETXATTR, NULL, fd, dict, flags,
1df6c8
+                           xdata);
1df6c8
+    return 0;
1df6c8
+}
1df6c8
+
1df6c8
+int32_t shard_setxattr(call_frame_t *frame, xlator_t *this, loc_t *loc,
1df6c8
+                       dict_t *dict, int32_t flags, dict_t *xdata) {
1df6c8
+    shard_common_set_xattr(frame, this, GF_FOP_SETXATTR, loc, NULL, dict, flags,
1df6c8
+                           xdata);
1df6c8
+    return 0;
1df6c8
 }
1df6c8
 
1df6c8
 int shard_post_setattr_handler(call_frame_t *frame, xlator_t *this) {
1df6c8
-- 
1df6c8
1.8.3.1
1df6c8