14f8ab
From 369c5772a722b6e346ec8b41f992112785366778 Mon Sep 17 00:00:00 2001
14f8ab
From: Krutika Dhananjay <kdhananj@redhat.com>
14f8ab
Date: Wed, 8 May 2019 13:00:51 +0530
14f8ab
Subject: [PATCH 189/192] features/shard: Fix block-count accounting upon
14f8ab
 truncate to lower size
14f8ab
14f8ab
    > Upstream: https://review.gluster.org/22681
14f8ab
    > BUG: 1705884
14f8ab
    > Change-Id: I9128a192e9bf8c3c3a959e96b7400879d03d7c53
14f8ab
14f8ab
The way delta_blocks is computed in shard is incorrect, when a file
14f8ab
is truncated to a lower size. The accounting only considers change
14f8ab
in size of the last of the truncated shards.
14f8ab
14f8ab
FIX:
14f8ab
14f8ab
Get the block-count of each shard just before an unlink at posix in
14f8ab
xdata.  Their summation plus the change in size of last shard
14f8ab
(from an actual truncate) is used to compute delta_blocks which is
14f8ab
used in the xattrop for size update.
14f8ab
14f8ab
Change-Id: I9128a192e9bf8c3c3a959e96b7400879d03d7c53
14f8ab
updates: bz#1668001
14f8ab
Signed-off-by: Krutika Dhananjay <kdhananj@redhat.com>
14f8ab
Reviewed-on: https://code.engineering.redhat.com/gerrit/173477
14f8ab
Tested-by: RHGS Build Bot <nigelb@redhat.com>
14f8ab
Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
14f8ab
---
14f8ab
 libglusterfs/src/glusterfs/glusterfs.h      |  2 +
14f8ab
 tests/bugs/shard/bug-1705884.t              | 32 +++++++++++++++
14f8ab
 xlators/features/shard/src/shard.c          | 60 +++++++++++++++++++++++------
14f8ab
 xlators/features/shard/src/shard.h          |  2 +-
14f8ab
 xlators/storage/posix/src/posix-entry-ops.c |  9 +++++
14f8ab
 5 files changed, 92 insertions(+), 13 deletions(-)
14f8ab
 create mode 100644 tests/bugs/shard/bug-1705884.t
14f8ab
14f8ab
diff --git a/libglusterfs/src/glusterfs/glusterfs.h b/libglusterfs/src/glusterfs/glusterfs.h
14f8ab
index 516b497..9ec2365 100644
14f8ab
--- a/libglusterfs/src/glusterfs/glusterfs.h
14f8ab
+++ b/libglusterfs/src/glusterfs/glusterfs.h
14f8ab
@@ -328,6 +328,8 @@ enum gf_internal_fop_indicator {
14f8ab
 #define GF_RESPONSE_LINK_COUNT_XDATA "gf_response_link_count"
14f8ab
 #define GF_REQUEST_LINK_COUNT_XDATA "gf_request_link_count"
14f8ab
 
14f8ab
+#define GF_GET_FILE_BLOCK_COUNT "gf_get_file_block_count"
14f8ab
+
14f8ab
 #define CTR_ATTACH_TIER_LOOKUP "ctr_attach_tier_lookup"
14f8ab
 
14f8ab
 #define CLIENT_CMD_CONNECT "trusted.glusterfs.client-connect"
14f8ab
diff --git a/tests/bugs/shard/bug-1705884.t b/tests/bugs/shard/bug-1705884.t
14f8ab
new file mode 100644
14f8ab
index 0000000..f6e5037
14f8ab
--- /dev/null
14f8ab
+++ b/tests/bugs/shard/bug-1705884.t
14f8ab
@@ -0,0 +1,32 @@
14f8ab
+#!/bin/bash
14f8ab
+
14f8ab
+. $(dirname $0)/../../include.rc
14f8ab
+. $(dirname $0)/../../volume.rc
14f8ab
+. $(dirname $0)/../../fallocate.rc
14f8ab
+
14f8ab
+cleanup
14f8ab
+
14f8ab
+require_fallocate -l 1m $M0/file
14f8ab
+
14f8ab
+TEST glusterd
14f8ab
+TEST pidof glusterd
14f8ab
+TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,2}
14f8ab
+TEST $CLI volume set $V0 features.shard on
14f8ab
+TEST $CLI volume set $V0 performance.write-behind off
14f8ab
+TEST $CLI volume set $V0 performance.stat-prefetch off
14f8ab
+TEST $CLI volume start $V0
14f8ab
+
14f8ab
+TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0
14f8ab
+
14f8ab
+TEST fallocate -l 200M $M0/foo
14f8ab
+EXPECT `echo "$(( ( 200 * 1024 * 1024 ) / 512 ))"`  stat -c %b $M0/foo
14f8ab
+TEST truncate -s 0 $M0/foo
14f8ab
+EXPECT "0" stat -c %b $M0/foo
14f8ab
+TEST fallocate -l 100M $M0/foo
14f8ab
+EXPECT `echo "$(( ( 100 * 1024 * 1024 ) / 512 ))"`  stat -c %b $M0/foo
14f8ab
+
14f8ab
+EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0
14f8ab
+TEST $CLI volume stop $V0
14f8ab
+TEST $CLI volume delete $V0
14f8ab
+
14f8ab
+cleanup
14f8ab
diff --git a/xlators/features/shard/src/shard.c b/xlators/features/shard/src/shard.c
14f8ab
index c1799ad..b248767 100644
14f8ab
--- a/xlators/features/shard/src/shard.c
14f8ab
+++ b/xlators/features/shard/src/shard.c
14f8ab
@@ -1135,6 +1135,7 @@ shard_update_file_size(call_frame_t *frame, xlator_t *this, fd_t *fd,
14f8ab
 {
14f8ab
     int ret = -1;
14f8ab
     int64_t *size_attr = NULL;
14f8ab
+    int64_t delta_blocks = 0;
14f8ab
     inode_t *inode = NULL;
14f8ab
     shard_local_t *local = NULL;
14f8ab
     dict_t *xattr_req = NULL;
14f8ab
@@ -1156,13 +1157,13 @@ shard_update_file_size(call_frame_t *frame, xlator_t *this, fd_t *fd,
14f8ab
 
14f8ab
     /* If both size and block count have not changed, then skip the xattrop.
14f8ab
      */
14f8ab
-    if ((local->delta_size + local->hole_size == 0) &&
14f8ab
-        (local->delta_blocks == 0)) {
14f8ab
+    delta_blocks = GF_ATOMIC_GET(local->delta_blocks);
14f8ab
+    if ((local->delta_size + local->hole_size == 0) && (delta_blocks == 0)) {
14f8ab
         goto out;
14f8ab
     }
14f8ab
 
14f8ab
     ret = shard_set_size_attrs(local->delta_size + local->hole_size,
14f8ab
-                               local->delta_blocks, &size_attr);
14f8ab
+                               delta_blocks, &size_attr);
14f8ab
     if (ret) {
14f8ab
         gf_msg(this->name, GF_LOG_ERROR, 0, SHARD_MSG_SIZE_SET_FAILED,
14f8ab
                "Failed to set size attrs for %s", uuid_utoa(inode->gfid));
14f8ab
@@ -1947,6 +1948,7 @@ shard_truncate_last_shard_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
14f8ab
                               dict_t *xdata)
14f8ab
 {
14f8ab
     inode_t *inode = NULL;
14f8ab
+    int64_t delta_blocks = 0;
14f8ab
     shard_local_t *local = NULL;
14f8ab
 
14f8ab
     local = frame->local;
14f8ab
@@ -1967,14 +1969,15 @@ shard_truncate_last_shard_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
14f8ab
     }
14f8ab
 
14f8ab
     local->postbuf.ia_size = local->offset;
14f8ab
-    local->postbuf.ia_blocks -= (prebuf->ia_blocks - postbuf->ia_blocks);
14f8ab
     /* Let the delta be negative. We want xattrop to do subtraction */
14f8ab
     local->delta_size = local->postbuf.ia_size - local->prebuf.ia_size;
14f8ab
-    local->delta_blocks = postbuf->ia_blocks - prebuf->ia_blocks;
14f8ab
+    delta_blocks = GF_ATOMIC_ADD(local->delta_blocks,
14f8ab
+                                 postbuf->ia_blocks - prebuf->ia_blocks);
14f8ab
+    GF_ASSERT(delta_blocks <= 0);
14f8ab
+    local->postbuf.ia_blocks += delta_blocks;
14f8ab
     local->hole_size = 0;
14f8ab
 
14f8ab
-    shard_inode_ctx_set(inode, this, postbuf, 0, SHARD_MASK_TIMES);
14f8ab
-
14f8ab
+    shard_inode_ctx_set(inode, this, &local->postbuf, 0, SHARD_MASK_TIMES);
14f8ab
     shard_update_file_size(frame, this, NULL, &local->loc,
14f8ab
                            shard_post_update_size_truncate_handler);
14f8ab
     return 0;
14f8ab
@@ -2034,8 +2037,10 @@ shard_truncate_htol_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
14f8ab
                         struct iatt *preparent, struct iatt *postparent,
14f8ab
                         dict_t *xdata)
14f8ab
 {
14f8ab
+    int ret = 0;
14f8ab
     int call_count = 0;
14f8ab
     int shard_block_num = (long)cookie;
14f8ab
+    uint64_t block_count = 0;
14f8ab
     shard_local_t *local = NULL;
14f8ab
 
14f8ab
     local = frame->local;
14f8ab
@@ -2045,6 +2050,16 @@ shard_truncate_htol_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
14f8ab
         local->op_errno = op_errno;
14f8ab
         goto done;
14f8ab
     }
14f8ab
+    ret = dict_get_uint64(xdata, GF_GET_FILE_BLOCK_COUNT, &block_count);
14f8ab
+    if (!ret) {
14f8ab
+        GF_ATOMIC_SUB(local->delta_blocks, block_count);
14f8ab
+    } else {
14f8ab
+        /* dict_get failed possibly due to a heterogeneous cluster? */
14f8ab
+        gf_msg(this->name, GF_LOG_WARNING, 0, SHARD_MSG_DICT_OP_FAILED,
14f8ab
+               "Failed to get key %s from dict during truncate of gfid %s",
14f8ab
+               GF_GET_FILE_BLOCK_COUNT,
14f8ab
+               uuid_utoa(local->resolver_base_inode->gfid));
14f8ab
+    }
14f8ab
 
14f8ab
     shard_unlink_block_inode(local, shard_block_num);
14f8ab
 done:
14f8ab
@@ -2074,6 +2089,7 @@ shard_truncate_htol(call_frame_t *frame, xlator_t *this, inode_t *inode)
14f8ab
     gf_boolean_t wind_failed = _gf_false;
14f8ab
     shard_local_t *local = NULL;
14f8ab
     shard_priv_t *priv = NULL;
14f8ab
+    dict_t *xdata_req = NULL;
14f8ab
 
14f8ab
     local = frame->local;
14f8ab
     priv = this->private;
14f8ab
@@ -2101,7 +2117,7 @@ shard_truncate_htol(call_frame_t *frame, xlator_t *this, inode_t *inode)
14f8ab
         local->postbuf.ia_size = local->offset;
14f8ab
         local->postbuf.ia_blocks = local->prebuf.ia_blocks;
14f8ab
         local->delta_size = local->postbuf.ia_size - local->prebuf.ia_size;
14f8ab
-        local->delta_blocks = 0;
14f8ab
+        GF_ATOMIC_INIT(local->delta_blocks, 0);
14f8ab
         local->hole_size = 0;
14f8ab
         shard_update_file_size(frame, this, local->fd, &local->loc,
14f8ab
                                shard_post_update_size_truncate_handler);
14f8ab
@@ -2110,6 +2126,21 @@ shard_truncate_htol(call_frame_t *frame, xlator_t *this, inode_t *inode)
14f8ab
 
14f8ab
     local->call_count = call_count;
14f8ab
     i = 1;
14f8ab
+    xdata_req = dict_new();
14f8ab
+    if (!xdata_req) {
14f8ab
+        shard_common_failure_unwind(local->fop, frame, -1, ENOMEM);
14f8ab
+        return 0;
14f8ab
+    }
14f8ab
+    ret = dict_set_uint64(xdata_req, GF_GET_FILE_BLOCK_COUNT, 8 * 8);
14f8ab
+    if (ret) {
14f8ab
+        gf_msg(this->name, GF_LOG_WARNING, 0, SHARD_MSG_DICT_OP_FAILED,
14f8ab
+               "Failed to set key %s into dict during truncate of %s",
14f8ab
+               GF_GET_FILE_BLOCK_COUNT,
14f8ab
+               uuid_utoa(local->resolver_base_inode->gfid));
14f8ab
+        dict_unref(xdata_req);
14f8ab
+        shard_common_failure_unwind(local->fop, frame, -1, ENOMEM);
14f8ab
+        return 0;
14f8ab
+    }
14f8ab
 
14f8ab
     SHARD_SET_ROOT_FS_ID(frame, local);
14f8ab
     while (cur_block <= last_block) {
14f8ab
@@ -2148,7 +2179,7 @@ shard_truncate_htol(call_frame_t *frame, xlator_t *this, inode_t *inode)
14f8ab
 
14f8ab
         STACK_WIND_COOKIE(frame, shard_truncate_htol_cbk,
14f8ab
                           (void *)(long)cur_block, FIRST_CHILD(this),
14f8ab
-                          FIRST_CHILD(this)->fops->unlink, &loc, 0, NULL);
14f8ab
+                          FIRST_CHILD(this)->fops->unlink, &loc, 0, xdata_req);
14f8ab
         loc_wipe(&loc;;
14f8ab
     next:
14f8ab
         i++;
14f8ab
@@ -2156,6 +2187,7 @@ shard_truncate_htol(call_frame_t *frame, xlator_t *this, inode_t *inode)
14f8ab
         if (!--call_count)
14f8ab
             break;
14f8ab
     }
14f8ab
+    dict_unref(xdata_req);
14f8ab
     return 0;
14f8ab
 }
14f8ab
 
14f8ab
@@ -2608,7 +2640,7 @@ shard_post_lookup_truncate_handler(call_frame_t *frame, xlator_t *this)
14f8ab
          */
14f8ab
         local->hole_size = local->offset - local->prebuf.ia_size;
14f8ab
         local->delta_size = 0;
14f8ab
-        local->delta_blocks = 0;
14f8ab
+        GF_ATOMIC_INIT(local->delta_blocks, 0);
14f8ab
         local->postbuf.ia_size = local->offset;
14f8ab
         tmp_stbuf.ia_size = local->offset;
14f8ab
         shard_inode_ctx_set(local->loc.inode, this, &tmp_stbuf, 0,
14f8ab
@@ -2624,7 +2656,7 @@ shard_post_lookup_truncate_handler(call_frame_t *frame, xlator_t *this)
14f8ab
          */
14f8ab
         local->hole_size = 0;
14f8ab
         local->delta_size = (local->offset - local->prebuf.ia_size);
14f8ab
-        local->delta_blocks = 0;
14f8ab
+        GF_ATOMIC_INIT(local->delta_blocks, 0);
14f8ab
         tmp_stbuf.ia_size = local->offset;
14f8ab
         shard_inode_ctx_set(local->loc.inode, this, &tmp_stbuf, 0,
14f8ab
                             SHARD_INODE_WRITE_MASK);
14f8ab
@@ -2680,6 +2712,7 @@ shard_truncate(call_frame_t *frame, xlator_t *this, loc_t *loc, off_t offset,
14f8ab
     if (!local->xattr_req)
14f8ab
         goto err;
14f8ab
     local->resolver_base_inode = loc->inode;
14f8ab
+    GF_ATOMIC_INIT(local->delta_blocks, 0);
14f8ab
 
14f8ab
     shard_lookup_base_file(frame, this, &local->loc,
14f8ab
                            shard_post_lookup_truncate_handler);
14f8ab
@@ -2735,6 +2768,7 @@ shard_ftruncate(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset,
14f8ab
     local->loc.inode = inode_ref(fd->inode);
14f8ab
     gf_uuid_copy(local->loc.gfid, fd->inode->gfid);
14f8ab
     local->resolver_base_inode = fd->inode;
14f8ab
+    GF_ATOMIC_INIT(local->delta_blocks, 0);
14f8ab
 
14f8ab
     shard_lookup_base_file(frame, this, &local->loc,
14f8ab
                            shard_post_lookup_truncate_handler);
14f8ab
@@ -5295,7 +5329,8 @@ shard_common_inode_write_do_cbk(call_frame_t *frame, void *cookie,
14f8ab
             local->op_errno = op_errno;
14f8ab
         } else {
14f8ab
             local->written_size += op_ret;
14f8ab
-            local->delta_blocks += (post->ia_blocks - pre->ia_blocks);
14f8ab
+            GF_ATOMIC_ADD(local->delta_blocks,
14f8ab
+                          post->ia_blocks - pre->ia_blocks);
14f8ab
             local->delta_size += (post->ia_size - pre->ia_size);
14f8ab
             shard_inode_ctx_set(local->fd->inode, this, post, 0,
14f8ab
                                 SHARD_MASK_TIMES);
14f8ab
@@ -6599,6 +6634,7 @@ shard_common_inode_write_begin(call_frame_t *frame, xlator_t *this,
14f8ab
     local->fd = fd_ref(fd);
14f8ab
     local->block_size = block_size;
14f8ab
     local->resolver_base_inode = local->fd->inode;
14f8ab
+    GF_ATOMIC_INIT(local->delta_blocks, 0);
14f8ab
 
14f8ab
     local->loc.inode = inode_ref(fd->inode);
14f8ab
     gf_uuid_copy(local->loc.gfid, fd->inode->gfid);
14f8ab
diff --git a/xlators/features/shard/src/shard.h b/xlators/features/shard/src/shard.h
14f8ab
index cd6a663..04abd62 100644
14f8ab
--- a/xlators/features/shard/src/shard.h
14f8ab
+++ b/xlators/features/shard/src/shard.h
14f8ab
@@ -275,7 +275,7 @@ typedef struct shard_local {
14f8ab
     size_t req_size;
14f8ab
     size_t readdir_size;
14f8ab
     int64_t delta_size;
14f8ab
-    int64_t delta_blocks;
14f8ab
+    gf_atomic_t delta_blocks;
14f8ab
     loc_t loc;
14f8ab
     loc_t dot_shard_loc;
14f8ab
     loc_t dot_shard_rm_loc;
14f8ab
diff --git a/xlators/storage/posix/src/posix-entry-ops.c b/xlators/storage/posix/src/posix-entry-ops.c
14f8ab
index b24a052..34ee2b8 100644
14f8ab
--- a/xlators/storage/posix/src/posix-entry-ops.c
14f8ab
+++ b/xlators/storage/posix/src/posix-entry-ops.c
14f8ab
@@ -1071,6 +1071,7 @@ posix_unlink(call_frame_t *frame, xlator_t *this, loc_t *loc, int xflag,
14f8ab
     char *real_path = NULL;
14f8ab
     char *par_path = NULL;
14f8ab
     int32_t fd = -1;
14f8ab
+    int ret = -1;
14f8ab
     struct iatt stbuf = {
14f8ab
         0,
14f8ab
     };
14f8ab
@@ -1235,6 +1236,14 @@ posix_unlink(call_frame_t *frame, xlator_t *this, loc_t *loc, int xflag,
14f8ab
         goto out;
14f8ab
     }
14f8ab
 
14f8ab
+    if (xdata && dict_get(xdata, GF_GET_FILE_BLOCK_COUNT)) {
14f8ab
+        ret = dict_set_uint64(unwind_dict, GF_GET_FILE_BLOCK_COUNT,
14f8ab
+                              stbuf.ia_blocks);
14f8ab
+        if (ret)
14f8ab
+            gf_msg(this->name, GF_LOG_WARNING, 0, P_MSG_SET_XDATA_FAIL,
14f8ab
+                   "Failed to set %s in rsp dict", GF_GET_FILE_BLOCK_COUNT);
14f8ab
+    }
14f8ab
+
14f8ab
     if (xdata && dict_get(xdata, GET_LINK_COUNT))
14f8ab
         get_link_count = _gf_true;
14f8ab
     op_ret = posix_unlink_gfid_handle_and_entry(frame, this, real_path, &stbuf,
14f8ab
-- 
14f8ab
1.8.3.1
14f8ab