Blob Blame History Raw
From 369c5772a722b6e346ec8b41f992112785366778 Mon Sep 17 00:00:00 2001
From: Krutika Dhananjay <kdhananj@redhat.com>
Date: Wed, 8 May 2019 13:00:51 +0530
Subject: [PATCH 189/192] features/shard: Fix block-count accounting upon
 truncate to lower size

    > Upstream: https://review.gluster.org/22681
    > BUG: 1705884
    > Change-Id: I9128a192e9bf8c3c3a959e96b7400879d03d7c53

The way delta_blocks is computed in shard is incorrect, when a file
is truncated to a lower size. The accounting only considers change
in size of the last of the truncated shards.

FIX:

Get the block-count of each shard just before an unlink at posix in
xdata.  Their summation plus the change in size of last shard
(from an actual truncate) is used to compute delta_blocks which is
used in the xattrop for size update.

Change-Id: I9128a192e9bf8c3c3a959e96b7400879d03d7c53
updates: bz#1668001
Signed-off-by: Krutika Dhananjay <kdhananj@redhat.com>
Reviewed-on: https://code.engineering.redhat.com/gerrit/173477
Tested-by: RHGS Build Bot <nigelb@redhat.com>
Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
---
 libglusterfs/src/glusterfs/glusterfs.h      |  2 +
 tests/bugs/shard/bug-1705884.t              | 32 +++++++++++++++
 xlators/features/shard/src/shard.c          | 60 +++++++++++++++++++++++------
 xlators/features/shard/src/shard.h          |  2 +-
 xlators/storage/posix/src/posix-entry-ops.c |  9 +++++
 5 files changed, 92 insertions(+), 13 deletions(-)
 create mode 100644 tests/bugs/shard/bug-1705884.t

diff --git a/libglusterfs/src/glusterfs/glusterfs.h b/libglusterfs/src/glusterfs/glusterfs.h
index 516b497..9ec2365 100644
--- a/libglusterfs/src/glusterfs/glusterfs.h
+++ b/libglusterfs/src/glusterfs/glusterfs.h
@@ -328,6 +328,8 @@ enum gf_internal_fop_indicator {
 #define GF_RESPONSE_LINK_COUNT_XDATA "gf_response_link_count"
 #define GF_REQUEST_LINK_COUNT_XDATA "gf_request_link_count"
 
+#define GF_GET_FILE_BLOCK_COUNT "gf_get_file_block_count"
+
 #define CTR_ATTACH_TIER_LOOKUP "ctr_attach_tier_lookup"
 
 #define CLIENT_CMD_CONNECT "trusted.glusterfs.client-connect"
diff --git a/tests/bugs/shard/bug-1705884.t b/tests/bugs/shard/bug-1705884.t
new file mode 100644
index 0000000..f6e5037
--- /dev/null
+++ b/tests/bugs/shard/bug-1705884.t
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+. $(dirname $0)/../../include.rc
+. $(dirname $0)/../../volume.rc
+. $(dirname $0)/../../fallocate.rc
+
+cleanup
+
+require_fallocate -l 1m $M0/file
+
+TEST glusterd
+TEST pidof glusterd
+TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,2}
+TEST $CLI volume set $V0 features.shard on
+TEST $CLI volume set $V0 performance.write-behind off
+TEST $CLI volume set $V0 performance.stat-prefetch off
+TEST $CLI volume start $V0
+
+TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0
+
+TEST fallocate -l 200M $M0/foo
+EXPECT `echo "$(( ( 200 * 1024 * 1024 ) / 512 ))"`  stat -c %b $M0/foo
+TEST truncate -s 0 $M0/foo
+EXPECT "0" stat -c %b $M0/foo
+TEST fallocate -l 100M $M0/foo
+EXPECT `echo "$(( ( 100 * 1024 * 1024 ) / 512 ))"`  stat -c %b $M0/foo
+
+EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0
+TEST $CLI volume stop $V0
+TEST $CLI volume delete $V0
+
+cleanup
diff --git a/xlators/features/shard/src/shard.c b/xlators/features/shard/src/shard.c
index c1799ad..b248767 100644
--- a/xlators/features/shard/src/shard.c
+++ b/xlators/features/shard/src/shard.c
@@ -1135,6 +1135,7 @@ shard_update_file_size(call_frame_t *frame, xlator_t *this, fd_t *fd,
 {
     int ret = -1;
     int64_t *size_attr = NULL;
+    int64_t delta_blocks = 0;
     inode_t *inode = NULL;
     shard_local_t *local = NULL;
     dict_t *xattr_req = NULL;
@@ -1156,13 +1157,13 @@ shard_update_file_size(call_frame_t *frame, xlator_t *this, fd_t *fd,
 
     /* If both size and block count have not changed, then skip the xattrop.
      */
-    if ((local->delta_size + local->hole_size == 0) &&
-        (local->delta_blocks == 0)) {
+    delta_blocks = GF_ATOMIC_GET(local->delta_blocks);
+    if ((local->delta_size + local->hole_size == 0) && (delta_blocks == 0)) {
         goto out;
     }
 
     ret = shard_set_size_attrs(local->delta_size + local->hole_size,
-                               local->delta_blocks, &size_attr);
+                               delta_blocks, &size_attr);
     if (ret) {
         gf_msg(this->name, GF_LOG_ERROR, 0, SHARD_MSG_SIZE_SET_FAILED,
                "Failed to set size attrs for %s", uuid_utoa(inode->gfid));
@@ -1947,6 +1948,7 @@ shard_truncate_last_shard_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
                               dict_t *xdata)
 {
     inode_t *inode = NULL;
+    int64_t delta_blocks = 0;
     shard_local_t *local = NULL;
 
     local = frame->local;
@@ -1967,14 +1969,15 @@ shard_truncate_last_shard_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
     }
 
     local->postbuf.ia_size = local->offset;
-    local->postbuf.ia_blocks -= (prebuf->ia_blocks - postbuf->ia_blocks);
     /* Let the delta be negative. We want xattrop to do subtraction */
     local->delta_size = local->postbuf.ia_size - local->prebuf.ia_size;
-    local->delta_blocks = postbuf->ia_blocks - prebuf->ia_blocks;
+    delta_blocks = GF_ATOMIC_ADD(local->delta_blocks,
+                                 postbuf->ia_blocks - prebuf->ia_blocks);
+    GF_ASSERT(delta_blocks <= 0);
+    local->postbuf.ia_blocks += delta_blocks;
     local->hole_size = 0;
 
-    shard_inode_ctx_set(inode, this, postbuf, 0, SHARD_MASK_TIMES);
-
+    shard_inode_ctx_set(inode, this, &local->postbuf, 0, SHARD_MASK_TIMES);
     shard_update_file_size(frame, this, NULL, &local->loc,
                            shard_post_update_size_truncate_handler);
     return 0;
@@ -2034,8 +2037,10 @@ shard_truncate_htol_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
                         struct iatt *preparent, struct iatt *postparent,
                         dict_t *xdata)
 {
+    int ret = 0;
     int call_count = 0;
     int shard_block_num = (long)cookie;
+    uint64_t block_count = 0;
     shard_local_t *local = NULL;
 
     local = frame->local;
@@ -2045,6 +2050,16 @@ shard_truncate_htol_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
         local->op_errno = op_errno;
         goto done;
     }
+    ret = dict_get_uint64(xdata, GF_GET_FILE_BLOCK_COUNT, &block_count);
+    if (!ret) {
+        GF_ATOMIC_SUB(local->delta_blocks, block_count);
+    } else {
+        /* dict_get failed possibly due to a heterogeneous cluster? */
+        gf_msg(this->name, GF_LOG_WARNING, 0, SHARD_MSG_DICT_OP_FAILED,
+               "Failed to get key %s from dict during truncate of gfid %s",
+               GF_GET_FILE_BLOCK_COUNT,
+               uuid_utoa(local->resolver_base_inode->gfid));
+    }
 
     shard_unlink_block_inode(local, shard_block_num);
 done:
@@ -2074,6 +2089,7 @@ shard_truncate_htol(call_frame_t *frame, xlator_t *this, inode_t *inode)
     gf_boolean_t wind_failed = _gf_false;
     shard_local_t *local = NULL;
     shard_priv_t *priv = NULL;
+    dict_t *xdata_req = NULL;
 
     local = frame->local;
     priv = this->private;
@@ -2101,7 +2117,7 @@ shard_truncate_htol(call_frame_t *frame, xlator_t *this, inode_t *inode)
         local->postbuf.ia_size = local->offset;
         local->postbuf.ia_blocks = local->prebuf.ia_blocks;
         local->delta_size = local->postbuf.ia_size - local->prebuf.ia_size;
-        local->delta_blocks = 0;
+        GF_ATOMIC_INIT(local->delta_blocks, 0);
         local->hole_size = 0;
         shard_update_file_size(frame, this, local->fd, &local->loc,
                                shard_post_update_size_truncate_handler);
@@ -2110,6 +2126,21 @@ shard_truncate_htol(call_frame_t *frame, xlator_t *this, inode_t *inode)
 
     local->call_count = call_count;
     i = 1;
+    xdata_req = dict_new();
+    if (!xdata_req) {
+        shard_common_failure_unwind(local->fop, frame, -1, ENOMEM);
+        return 0;
+    }
+    ret = dict_set_uint64(xdata_req, GF_GET_FILE_BLOCK_COUNT, 8 * 8);
+    if (ret) {
+        gf_msg(this->name, GF_LOG_WARNING, 0, SHARD_MSG_DICT_OP_FAILED,
+               "Failed to set key %s into dict during truncate of %s",
+               GF_GET_FILE_BLOCK_COUNT,
+               uuid_utoa(local->resolver_base_inode->gfid));
+        dict_unref(xdata_req);
+        shard_common_failure_unwind(local->fop, frame, -1, ENOMEM);
+        return 0;
+    }
 
     SHARD_SET_ROOT_FS_ID(frame, local);
     while (cur_block <= last_block) {
@@ -2148,7 +2179,7 @@ shard_truncate_htol(call_frame_t *frame, xlator_t *this, inode_t *inode)
 
         STACK_WIND_COOKIE(frame, shard_truncate_htol_cbk,
                           (void *)(long)cur_block, FIRST_CHILD(this),
-                          FIRST_CHILD(this)->fops->unlink, &loc, 0, NULL);
+                          FIRST_CHILD(this)->fops->unlink, &loc, 0, xdata_req);
         loc_wipe(&loc);
     next:
         i++;
@@ -2156,6 +2187,7 @@ shard_truncate_htol(call_frame_t *frame, xlator_t *this, inode_t *inode)
         if (!--call_count)
             break;
     }
+    dict_unref(xdata_req);
     return 0;
 }
 
@@ -2608,7 +2640,7 @@ shard_post_lookup_truncate_handler(call_frame_t *frame, xlator_t *this)
          */
         local->hole_size = local->offset - local->prebuf.ia_size;
         local->delta_size = 0;
-        local->delta_blocks = 0;
+        GF_ATOMIC_INIT(local->delta_blocks, 0);
         local->postbuf.ia_size = local->offset;
         tmp_stbuf.ia_size = local->offset;
         shard_inode_ctx_set(local->loc.inode, this, &tmp_stbuf, 0,
@@ -2624,7 +2656,7 @@ shard_post_lookup_truncate_handler(call_frame_t *frame, xlator_t *this)
          */
         local->hole_size = 0;
         local->delta_size = (local->offset - local->prebuf.ia_size);
-        local->delta_blocks = 0;
+        GF_ATOMIC_INIT(local->delta_blocks, 0);
         tmp_stbuf.ia_size = local->offset;
         shard_inode_ctx_set(local->loc.inode, this, &tmp_stbuf, 0,
                             SHARD_INODE_WRITE_MASK);
@@ -2680,6 +2712,7 @@ shard_truncate(call_frame_t *frame, xlator_t *this, loc_t *loc, off_t offset,
     if (!local->xattr_req)
         goto err;
     local->resolver_base_inode = loc->inode;
+    GF_ATOMIC_INIT(local->delta_blocks, 0);
 
     shard_lookup_base_file(frame, this, &local->loc,
                            shard_post_lookup_truncate_handler);
@@ -2735,6 +2768,7 @@ shard_ftruncate(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset,
     local->loc.inode = inode_ref(fd->inode);
     gf_uuid_copy(local->loc.gfid, fd->inode->gfid);
     local->resolver_base_inode = fd->inode;
+    GF_ATOMIC_INIT(local->delta_blocks, 0);
 
     shard_lookup_base_file(frame, this, &local->loc,
                            shard_post_lookup_truncate_handler);
@@ -5295,7 +5329,8 @@ shard_common_inode_write_do_cbk(call_frame_t *frame, void *cookie,
             local->op_errno = op_errno;
         } else {
             local->written_size += op_ret;
-            local->delta_blocks += (post->ia_blocks - pre->ia_blocks);
+            GF_ATOMIC_ADD(local->delta_blocks,
+                          post->ia_blocks - pre->ia_blocks);
             local->delta_size += (post->ia_size - pre->ia_size);
             shard_inode_ctx_set(local->fd->inode, this, post, 0,
                                 SHARD_MASK_TIMES);
@@ -6599,6 +6634,7 @@ shard_common_inode_write_begin(call_frame_t *frame, xlator_t *this,
     local->fd = fd_ref(fd);
     local->block_size = block_size;
     local->resolver_base_inode = local->fd->inode;
+    GF_ATOMIC_INIT(local->delta_blocks, 0);
 
     local->loc.inode = inode_ref(fd->inode);
     gf_uuid_copy(local->loc.gfid, fd->inode->gfid);
diff --git a/xlators/features/shard/src/shard.h b/xlators/features/shard/src/shard.h
index cd6a663..04abd62 100644
--- a/xlators/features/shard/src/shard.h
+++ b/xlators/features/shard/src/shard.h
@@ -275,7 +275,7 @@ typedef struct shard_local {
     size_t req_size;
     size_t readdir_size;
     int64_t delta_size;
-    int64_t delta_blocks;
+    gf_atomic_t delta_blocks;
     loc_t loc;
     loc_t dot_shard_loc;
     loc_t dot_shard_rm_loc;
diff --git a/xlators/storage/posix/src/posix-entry-ops.c b/xlators/storage/posix/src/posix-entry-ops.c
index b24a052..34ee2b8 100644
--- a/xlators/storage/posix/src/posix-entry-ops.c
+++ b/xlators/storage/posix/src/posix-entry-ops.c
@@ -1071,6 +1071,7 @@ posix_unlink(call_frame_t *frame, xlator_t *this, loc_t *loc, int xflag,
     char *real_path = NULL;
     char *par_path = NULL;
     int32_t fd = -1;
+    int ret = -1;
     struct iatt stbuf = {
         0,
     };
@@ -1235,6 +1236,14 @@ posix_unlink(call_frame_t *frame, xlator_t *this, loc_t *loc, int xflag,
         goto out;
     }
 
+    if (xdata && dict_get(xdata, GF_GET_FILE_BLOCK_COUNT)) {
+        ret = dict_set_uint64(unwind_dict, GF_GET_FILE_BLOCK_COUNT,
+                              stbuf.ia_blocks);
+        if (ret)
+            gf_msg(this->name, GF_LOG_WARNING, 0, P_MSG_SET_XDATA_FAIL,
+                   "Failed to set %s in rsp dict", GF_GET_FILE_BLOCK_COUNT);
+    }
+
     if (xdata && dict_get(xdata, GET_LINK_COUNT))
         get_link_count = _gf_true;
     op_ret = posix_unlink_gfid_handle_and_entry(frame, this, real_path, &stbuf,
-- 
1.8.3.1