diff options
-rw-r--r-- | libglusterfs/src/glusterfs/glusterfs.h | 2 | ||||
-rw-r--r-- | tests/bugs/shard/bug-1705884.t | 32 | ||||
-rw-r--r-- | xlators/features/shard/src/shard.c | 60 | ||||
-rw-r--r-- | xlators/features/shard/src/shard.h | 2 | ||||
-rw-r--r-- | xlators/storage/posix/src/posix-entry-ops.c | 9 |
5 files changed, 92 insertions, 13 deletions
diff --git a/libglusterfs/src/glusterfs/glusterfs.h b/libglusterfs/src/glusterfs/glusterfs.h index 4e5669c6dae..930d83cdfe6 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 00000000000..f6e50376a58 --- /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 b8f5a31742e..2249cefc5ab 100644 --- a/xlators/features/shard/src/shard.c +++ b/xlators/features/shard/src/shard.c @@ -1137,6 +1137,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; @@ -1158,13 +1159,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)); @@ -1949,6 +1950,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; @@ -1969,14 +1971,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; @@ -2035,8 +2038,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; @@ -2046,6 +2051,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: @@ -2075,6 +2090,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; @@ -2102,7 +2118,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); @@ -2111,6 +2127,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) { @@ -2149,7 +2180,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++; @@ -2157,6 +2188,7 @@ shard_truncate_htol(call_frame_t *frame, xlator_t *this, inode_t *inode) if (!--call_count) break; } + dict_unref(xdata_req); return 0; } @@ -2609,7 +2641,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, @@ -2625,7 +2657,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); @@ -2681,6 +2713,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); @@ -2736,6 +2769,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); @@ -5296,7 +5330,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); @@ -6600,6 +6635,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 cd6a663c03b..04abd62c21c 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 240f237a39a..0b612dcc99c 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, |