From 1c094d1dc70dbc5d08181ef64fb300c95f331aec Mon Sep 17 00:00:00 2001 From: Krutika Dhananjay Date: Wed, 6 Dec 2017 16:55:33 +0530 Subject: [PATCH 171/180] features/shard: Upon FSYNC from upper layers, wind fsync on all changed shards > Upstream: https://review.gluster.org/19566 > BUG: 1468483 > Change-Id: Ib74354f57a18569762ad45a51f182822a2537421 Change-Id: I93797a60e3449d02413d171babfb8e4292e3f2f6 BUG: 1493085 Signed-off-by: Krutika Dhananjay Reviewed-on: https://code.engineering.redhat.com/gerrit/131737 Reviewed-by: Atin Mukherjee Tested-by: RHGS Build Bot Reviewed-by: Pranith Kumar Karampuri --- tests/bugs/shard/bug-1468483.t | 58 +++ tests/bugs/shard/shard-inode-refcount-test.t | 2 +- xlators/features/shard/src/shard-messages.h | 9 +- xlators/features/shard/src/shard.c | 533 +++++++++++++++++++++++++-- xlators/features/shard/src/shard.h | 6 + 5 files changed, 569 insertions(+), 39 deletions(-) create mode 100644 tests/bugs/shard/bug-1468483.t diff --git a/tests/bugs/shard/bug-1468483.t b/tests/bugs/shard/bug-1468483.t new file mode 100644 index 0000000..e462b8d --- /dev/null +++ b/tests/bugs/shard/bug-1468483.t @@ -0,0 +1,58 @@ +#!/bin/bash + +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +. $(dirname $0)/../../common-utils.rc + +cleanup + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 $H0:$B0/${V0}0 +TEST $CLI volume set $V0 performance.write-behind off +TEST $CLI volume set $V0 features.shard on +TEST $CLI volume set $V0 features.shard-block-size 16MB +TEST $CLI volume start $V0 +TEST $CLI volume profile $V0 start + +TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0 +TEST dd if=/dev/zero conv=fsync of=$M0/foo bs=1M count=100 + +#This should ensure /.shard is created on the bricks. +TEST stat $B0/${V0}0/.shard + +gfid_foo=$(get_gfid_string $M0/foo) + +TEST stat $B0/${V0}0/.shard/$gfid_foo.1 +TEST stat $B0/${V0}0/.shard/$gfid_foo.2 +TEST stat $B0/${V0}0/.shard/$gfid_foo.3 +TEST stat $B0/${V0}0/.shard/$gfid_foo.4 +TEST stat $B0/${V0}0/.shard/$gfid_foo.5 +TEST stat $B0/${V0}0/.shard/$gfid_foo.6 + +# For a file with 7 shards, there should be 7 fsyncs on the brick. Without this +# fix, I was seeing only 1 fsync (on the base shard alone). + +EXPECT "7" echo `$CLI volume profile $V0 info incremental | grep -w FSYNC | awk '{print $8}'` + +useradd -M test_user 2>/dev/null + +TEST touch $M0/bar + +# Change ownership to non-root on bar. +TEST chown test_user:test_user $M0/bar + +TEST $CLI volume profile $V0 stop +TEST $CLI volume profile $V0 start + +# Write 100M of data on bar as non-root. +TEST run_cmd_as_user test_user "dd if=/dev/zero conv=fsync of=$M0/bar bs=1M count=100" + +EXPECT "7" echo `$CLI volume profile $V0 info incremental | grep -w FSYNC | awk '{print $8}'` + +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0 +userdel test_user +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0 + +cleanup diff --git a/tests/bugs/shard/shard-inode-refcount-test.t b/tests/bugs/shard/shard-inode-refcount-test.t index 6358097..03e0cc9 100644 --- a/tests/bugs/shard/shard-inode-refcount-test.t +++ b/tests/bugs/shard/shard-inode-refcount-test.t @@ -14,7 +14,7 @@ TEST $CLI volume start $V0 TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 $M0 -TEST dd if=/dev/zero of=$M0/one-plus-five-shards bs=1M count=23 +TEST dd if=/dev/zero conv=fsync of=$M0/one-plus-five-shards bs=1M count=23 ACTIVE_INODES_BEFORE=$(get_mount_active_size_value $V0) TEST rm -f $M0/one-plus-five-shards diff --git a/xlators/features/shard/src/shard-messages.h b/xlators/features/shard/src/shard-messages.h index 588cb68..8e61630 100644 --- a/xlators/features/shard/src/shard-messages.h +++ b/xlators/features/shard/src/shard-messages.h @@ -40,7 +40,7 @@ */ #define GLFS_COMP_BASE_SHARD GLFS_MSGID_COMP_SHARD -#define GLFS_NUM_MESSAGES 18 +#define GLFS_NUM_MESSAGES 19 #define GLFS_MSGID_END (GLFS_COMP_BASE_SHARD + GLFS_NUM_MESSAGES + 1) #define glfs_msg_start_x GLFS_COMP_BASE_SHARD, "Invalid: Start of messages" @@ -180,5 +180,12 @@ */ #define SHARD_MSG_INVALID_FOP (GLFS_COMP_BASE_SHARD + 18) +/*! + * @messageid 133019 + * @diagnosis + * @recommendedaction +*/ +#define SHARD_MSG_MEMALLOC_FAILED (GLFS_COMP_BASE_SHARD + 19) + #define glfs_msg_end_x GLFS_MSGID_END, "Invalid: End of messages" #endif /* !_SHARD_MESSAGES_H_ */ diff --git a/xlators/features/shard/src/shard.c b/xlators/features/shard/src/shard.c index 49cf04a..a661345 100644 --- a/xlators/features/shard/src/shard.c +++ b/xlators/features/shard/src/shard.c @@ -76,6 +76,7 @@ __shard_inode_ctx_get (inode_t *inode, xlator_t *this, shard_inode_ctx_t **ctx) return ret; INIT_LIST_HEAD (&ctx_p->ilist); + INIT_LIST_HEAD (&ctx_p->to_fsync_list); ret = __inode_ctx_set (inode, this, (uint64_t *)&ctx_p); if (ret < 0) { @@ -205,6 +206,65 @@ shard_inode_ctx_set_refreshed_flag (inode_t *inode, xlator_t *this) return ret; } +int +__shard_inode_ctx_add_to_fsync_list (inode_t *base_inode, xlator_t *this, + inode_t *shard_inode) +{ + int ret = -1; + shard_inode_ctx_t *base_ictx = NULL; + shard_inode_ctx_t *shard_ictx = NULL; + + ret = __shard_inode_ctx_get (base_inode, this, &base_ictx); + if (ret) + return ret; + + ret = __shard_inode_ctx_get (shard_inode, this, &shard_ictx); + if (ret) + return ret; + + if (shard_ictx->fsync_needed) { + shard_ictx->fsync_needed++; + return 1; + } + + list_add_tail (&shard_ictx->to_fsync_list, &base_ictx->to_fsync_list); + shard_ictx->inode = shard_inode; + shard_ictx->fsync_needed++; + base_ictx->fsync_count++; + shard_ictx->base_inode = base_inode; + + return 0; +} + +int +shard_inode_ctx_add_to_fsync_list (inode_t *base_inode, xlator_t *this, + inode_t *shard_inode) +{ + int ret = -1; + + /* This ref acts as a refkeepr on the base inode. We + * need to keep this inode alive as it holds the head + * of the to_fsync_list. + */ + inode_ref (base_inode); + + LOCK (&base_inode->lock); + LOCK (&shard_inode->lock); + { + ret = __shard_inode_ctx_add_to_fsync_list (base_inode, this, + shard_inode); + } + UNLOCK (&shard_inode->lock); + UNLOCK (&base_inode->lock); + + /* Unref the base inode corresponding to the ref above, if the shard is + * found to be already part of the fsync list. + */ + if (ret != 0) + inode_unref (base_inode); + return ret; +} + gf_boolean_t __shard_inode_ctx_needs_lookup (inode_t *inode, xlator_t *this) { @@ -301,6 +361,40 @@ shard_inode_ctx_get_block_size (inode_t *inode, xlator_t *this, } int +__shard_inode_ctx_get_fsync_count (inode_t *inode, xlator_t *this, + int *fsync_count) +{ + int ret = -1; + uint64_t ctx_uint = 0; + shard_inode_ctx_t *ctx = NULL; + + ret = __inode_ctx_get (inode, this, &ctx_uint); + if (ret < 0) + return ret; + + ctx = (shard_inode_ctx_t *) ctx_uint; + + *fsync_count = ctx->fsync_needed; + + return 0; +} + +int +shard_inode_ctx_get_fsync_count (inode_t *inode, xlator_t *this, + int *fsync_count) +{ + int ret = -1; + + LOCK (&inode->lock); + { + ret = __shard_inode_ctx_get_fsync_count (inode, this, + fsync_count); + } + UNLOCK (&inode->lock); + + return ret; +} +int __shard_inode_ctx_get_all (inode_t *inode, xlator_t *this, shard_inode_ctx_t *ctx_out) { @@ -482,15 +576,19 @@ out: return ret; } -void +inode_t * __shard_update_shards_inode_list (inode_t *linked_inode, xlator_t *this, inode_t *base_inode, int block_num) { - char block_bname[256] = {0,}; - inode_t *lru_inode = NULL; - shard_priv_t *priv = NULL; - shard_inode_ctx_t *ctx = NULL; - shard_inode_ctx_t *lru_inode_ctx = NULL; + char block_bname[256] = {0,}; + inode_t *lru_inode = NULL; + shard_priv_t *priv = NULL; + shard_inode_ctx_t *ctx = NULL; + shard_inode_ctx_t *lru_inode_ctx = NULL; + shard_inode_ctx_t *lru_base_inode_ctx = NULL; + inode_t *fsync_inode = NULL; + inode_t *lru_base_inode = NULL; + gf_boolean_t do_fsync = _gf_false; priv = this->private; @@ -510,6 +608,7 @@ __shard_update_shards_inode_list (inode_t *linked_inode, xlator_t *this, ctx->block_num = block_num; list_add_tail (&ctx->ilist, &priv->ilist_head); priv->inode_count++; + ctx->base_inode = base_inode; } else { /*If on the other hand there is no available slot for this inode * in the list, delete the lru inode from the head of the list, @@ -519,30 +618,56 @@ __shard_update_shards_inode_list (inode_t *linked_inode, xlator_t *this, shard_inode_ctx_t, ilist); GF_ASSERT (lru_inode_ctx->block_num > 0); + lru_base_inode = lru_inode_ctx->base_inode; list_del_init (&lru_inode_ctx->ilist); lru_inode = inode_find (linked_inode->table, lru_inode_ctx->stat.ia_gfid); - shard_make_block_bname (lru_inode_ctx->block_num, - lru_inode_ctx->base_gfid, - block_bname, - sizeof (block_bname)); - inode_unlink (lru_inode, priv->dot_shard_inode, - block_bname); - /* The following unref corresponds to the ref held by - * inode_find() above. + /* If the lru inode was part of the pending-fsync list, + * the base inode needs to be unref'd, the lru inode + * deleted from fsync list and fsync'd in a new frame, + * and then unlinked in memory and forgotten. */ - inode_unref (lru_inode); + LOCK (&lru_base_inode->lock); + LOCK (&lru_inode->lock); + { + if (!list_empty(&lru_inode_ctx->to_fsync_list)) { + list_del_init (&lru_inode_ctx->to_fsync_list); + lru_inode_ctx->fsync_needed = 0; + do_fsync = _gf_true; + __shard_inode_ctx_get (lru_base_inode, this, &lru_base_inode_ctx); + lru_base_inode_ctx->fsync_count--; + } + } + UNLOCK (&lru_inode->lock); + UNLOCK (&lru_base_inode->lock); + + if (!do_fsync) { + shard_make_block_bname (lru_inode_ctx->block_num, + lru_inode_ctx->base_gfid, + block_bname, + sizeof (block_bname)); /* The following unref corresponds to the ref held at - * the time the shard was created or looked up + * the time the shard was added to the lru list. + */ + inode_unref (lru_inode); + inode_unlink (lru_inode, priv->dot_shard_inode, + block_bname); + inode_forget (lru_inode, 0); + } else { + fsync_inode = lru_inode; + inode_unref (lru_base_inode); + } + /* The following unref corresponds to the ref + * held by inode_find() above. */ inode_unref (lru_inode); - inode_forget (lru_inode, 0); /* For as long as an inode is in lru list, we try to * keep it alive by holding a ref on it. */ inode_ref (linked_inode); gf_uuid_copy (ctx->base_gfid, base_inode->gfid); ctx->block_num = block_num; + ctx->base_inode = base_inode; list_add_tail (&ctx->ilist, &priv->ilist_head); } } else { @@ -551,6 +676,7 @@ __shard_update_shards_inode_list (inode_t *linked_inode, xlator_t *this, */ list_move_tail (&ctx->ilist, &priv->ilist_head); } + return fsync_inode; } int @@ -617,6 +743,85 @@ shard_common_inode_write_success_unwind (glusterfs_fop_t fop, } int +shard_evicted_inode_fsync_cbk (call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, int32_t op_errno, + struct iatt *prebuf, struct iatt *postbuf, + dict_t *xdata) +{ + char block_bname[256] = {0,}; + fd_t *anon_fd = cookie; + inode_t *shard_inode = NULL; + shard_inode_ctx_t *ctx = NULL; + shard_priv_t *priv = NULL; + + priv = this->private; + shard_inode = anon_fd->inode; + + if (op_ret < 0) { + gf_msg (this->name, GF_LOG_WARNING, op_errno, + SHARD_MSG_MEMALLOC_FAILED, "fsync failed on shard"); + goto out; + } + + LOCK (&priv->lock); + LOCK(&shard_inode->lock); + { + __shard_inode_ctx_get (shard_inode, this, &ctx); + if ((list_empty(&ctx->to_fsync_list)) && + (list_empty(&ctx->ilist))) { + shard_make_block_bname (ctx->block_num, + shard_inode->gfid, block_bname, + sizeof (block_bname)); + inode_unlink (shard_inode, priv->dot_shard_inode, + block_bname); + /* The following unref corresponds to the ref held by + * inode_link() at the time the shard was created or + * looked up + */ + inode_unref (shard_inode); + inode_forget (shard_inode, 0); + } + } + UNLOCK(&shard_inode->lock); + UNLOCK(&priv->lock); + +out: + if (anon_fd) + fd_unref (anon_fd); + STACK_DESTROY (frame->root); + return 0; +} + +int +shard_initiate_evicted_inode_fsync (xlator_t *this, inode_t *inode) +{ + fd_t *anon_fd = NULL; + call_frame_t *fsync_frame = NULL; + + fsync_frame = create_frame (this, this->ctx->pool); + if (!fsync_frame) { + gf_msg (this->name, GF_LOG_WARNING, ENOMEM, + SHARD_MSG_MEMALLOC_FAILED, "Failed to create new frame " + "to fsync shard"); + return -1; + } + + anon_fd = fd_anonymous (inode); + if (!anon_fd) { + gf_msg (this->name, GF_LOG_WARNING, ENOMEM, + SHARD_MSG_MEMALLOC_FAILED, "Failed to create anon fd to" + " fsync shard"); + STACK_DESTROY (fsync_frame->root); + return -1; + } + + STACK_WIND_COOKIE (fsync_frame, shard_evicted_inode_fsync_cbk, anon_fd, + FIRST_CHILD(this), FIRST_CHILD(this)->fops->fsync, + anon_fd, 1, NULL); + return 0; +} + +int shard_common_resolve_shards (call_frame_t *frame, xlator_t *this, shard_post_resolve_fop_handler_t post_res_handler) { @@ -625,6 +830,7 @@ shard_common_resolve_shards (call_frame_t *frame, xlator_t *this, char path[PATH_MAX] = {0,}; inode_t *inode = NULL; inode_t *res_inode = NULL; + inode_t *fsync_inode = NULL; shard_priv_t *priv = NULL; shard_local_t *local = NULL; @@ -661,20 +867,22 @@ shard_common_resolve_shards (call_frame_t *frame, xlator_t *this, */ LOCK(&priv->lock); { - __shard_update_shards_inode_list (inode, this, + fsync_inode = __shard_update_shards_inode_list (inode, + this, res_inode, shard_idx_iter); } UNLOCK(&priv->lock); shard_idx_iter++; - + if (fsync_inode) + shard_initiate_evicted_inode_fsync (this, + fsync_inode); continue; } else { local->call_count++; shard_idx_iter++; } } - out: post_res_handler (frame, this); return 0; @@ -1657,6 +1865,7 @@ shard_link_block_inode (shard_local_t *local, int block_num, inode_t *inode, char block_bname[256] = {0,}; inode_t *linked_inode = NULL; xlator_t *this = NULL; + inode_t *fsync_inode = NULL; shard_priv_t *priv = NULL; this = THIS; @@ -1674,10 +1883,14 @@ shard_link_block_inode (shard_local_t *local, int block_num, inode_t *inode, LOCK(&priv->lock); { - __shard_update_shards_inode_list (linked_inode, this, - local->loc.inode, block_num); + fsync_inode = __shard_update_shards_inode_list (linked_inode, + this, + local->loc.inode, + block_num); } UNLOCK(&priv->lock); + if (fsync_inode) + shard_initiate_evicted_inode_fsync (this, fsync_inode); } int @@ -2120,6 +2333,7 @@ shard_truncate (call_frame_t *frame, xlator_t *this, loc_t *loc, off_t offset, local->xattr_req = (xdata) ? dict_ref (xdata) : dict_new (); if (!local->xattr_req) goto err; + local->resolver_base_inode = loc->inode; shard_lookup_base_file (frame, this, &local->loc, shard_post_lookup_truncate_handler); @@ -2172,6 +2386,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; shard_lookup_base_file (frame, this, &local->loc, shard_post_lookup_truncate_handler); @@ -2509,32 +2724,48 @@ shard_unlink_block_inode (shard_local_t *local, int shard_block_num) { char block_bname[256] = {0,}; inode_t *inode = NULL; + inode_t *base_inode = NULL; xlator_t *this = NULL; shard_priv_t *priv = NULL; shard_inode_ctx_t *ctx = NULL; + shard_inode_ctx_t *base_ictx = NULL; + gf_boolean_t unlink_unref_forget = _gf_false; this = THIS; priv = this->private; inode = local->inode_list[shard_block_num - local->first_block]; + base_inode = local->resolver_base_inode; shard_make_block_bname (shard_block_num, (local->loc.inode)->gfid, block_bname, sizeof (block_bname)); LOCK(&priv->lock); + LOCK(&base_inode->lock); + LOCK(&inode->lock); { - shard_inode_ctx_get (inode, this, &ctx); + __shard_inode_ctx_get (inode, this, &ctx); if (!list_empty (&ctx->ilist)) { list_del_init (&ctx->ilist); priv->inode_count--; GF_ASSERT (priv->inode_count >= 0); - inode_unlink (inode, priv->dot_shard_inode, block_bname); - inode_unref (inode); - inode_forget (inode, 0); + unlink_unref_forget = _gf_true; + } + if (ctx->fsync_needed) { + inode_unref (base_inode); + list_del_init (&ctx->to_fsync_list); + __shard_inode_ctx_get (base_inode, this, &base_ictx); + base_ictx->fsync_count--; } } + UNLOCK(&inode->lock); + UNLOCK(&base_inode->lock); + if (unlink_unref_forget) { + inode_unlink (inode, priv->dot_shard_inode, block_bname); + inode_unref (inode); + inode_forget (inode, 0); + } UNLOCK(&priv->lock); - } int @@ -2752,6 +2983,7 @@ shard_unlink (call_frame_t *frame, xlator_t *this, loc_t *loc, int xflag, local->xflag = xflag; local->xattr_req = (xdata) ? dict_ref (xdata) : dict_new (); local->block_size = block_size; + local->resolver_base_inode = loc->inode; local->fop = GF_FOP_UNLINK; if (!this->itable) this->itable = (local->loc.inode)->table; @@ -2988,6 +3220,7 @@ shard_rename (call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc, frame->local = local; loc_copy (&local->loc, oldloc); loc_copy (&local->loc2, newloc); + local->resolver_base_inode = newloc->inode; local->fop = GF_FOP_RENAME; local->xattr_req = (xdata) ? dict_ref (xdata) : dict_new(); if (!local->xattr_req) @@ -3754,6 +3987,10 @@ shard_common_inode_write_do_cbk (call_frame_t *frame, void *cookie, local->delta_size += (post->ia_size - pre->ia_size); shard_inode_ctx_set (local->fd->inode, this, post, 0, SHARD_MASK_TIMES); + if (local->fd->inode != anon_fd->inode) + shard_inode_ctx_add_to_fsync_list (local->fd->inode, + this, + anon_fd->inode); } } UNLOCK (&frame->lock); @@ -4204,18 +4441,198 @@ shard_flush (call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *xdata) } int -shard_fsync_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno, struct iatt *prebuf, - struct iatt *postbuf, dict_t *xdata) +__shard_get_timestamps_from_inode_ctx (shard_local_t *local, inode_t *inode, + xlator_t *this) { - if (op_ret < 0) + int ret = -1; + uint64_t ctx_uint = 0; + shard_inode_ctx_t *ctx = NULL; + + ret = __inode_ctx_get (inode, this, &ctx_uint); + if (ret < 0) + return ret; + + ctx = (shard_inode_ctx_t *) ctx_uint; + + local->postbuf.ia_ctime = ctx->stat.ia_ctime; + local->postbuf.ia_ctime_nsec = ctx->stat.ia_ctime_nsec; + local->postbuf.ia_atime = ctx->stat.ia_atime; + local->postbuf.ia_atime_nsec = ctx->stat.ia_atime_nsec; + local->postbuf.ia_mtime = ctx->stat.ia_mtime; + local->postbuf.ia_mtime_nsec = ctx->stat.ia_mtime_nsec; + + return 0; +} + +int +shard_get_timestamps_from_inode_ctx (shard_local_t *local, inode_t *inode, + xlator_t *this) +{ + int ret = 0; + + LOCK (&inode->lock); + { + ret = __shard_get_timestamps_from_inode_ctx (local, inode, + this); + } + UNLOCK (&inode->lock); + + return ret; +} + +int +shard_fsync_shards_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata) +{ + int call_count = 0; + uint64_t fsync_count = 0; + fd_t *anon_fd = cookie; + shard_local_t *local = NULL; + shard_inode_ctx_t *ctx = NULL; + shard_inode_ctx_t *base_ictx = NULL; + inode_t *base_inode = NULL; + + local = frame->local; + base_inode = local->fd->inode; + + if (local->op_ret < 0) goto out; - /* To-Do: Wind fsync on all shards of the file */ - postbuf->ia_ctime = 0; + LOCK (&frame->lock); + { + if (op_ret < 0) { + local->op_ret = op_ret; + local->op_errno = op_errno; + goto out; + } + shard_inode_ctx_set (local->fd->inode, this, postbuf, 0, + SHARD_MASK_TIMES); + } + UNLOCK (&frame->lock); + fd_ctx_get (anon_fd, this, &fsync_count); out: - SHARD_STACK_UNWIND (fsync, frame, op_ret, op_errno, prebuf, postbuf, - xdata); + if (base_inode != anon_fd->inode) { + LOCK (&base_inode->lock); + LOCK (&anon_fd->inode->lock); + { + __shard_inode_ctx_get (anon_fd->inode, this, &ctx); + __shard_inode_ctx_get (base_inode, this, &base_ictx); + if (op_ret == 0) + ctx->fsync_needed -= fsync_count; + GF_ASSERT (ctx->fsync_needed >= 0); + list_del_init (&ctx->to_fsync_list); + if (ctx->fsync_needed != 0) { + list_add_tail (&ctx->to_fsync_list, + &base_ictx->to_fsync_list); + base_ictx->fsync_count++; + } + } + UNLOCK (&anon_fd->inode->lock); + UNLOCK (&base_inode->lock); + } + if (anon_fd) + fd_unref (anon_fd); + + call_count = shard_call_count_return (frame); + if (call_count != 0) + return 0; + + if (local->op_ret < 0) { + SHARD_STACK_UNWIND (fsync, frame, local->op_ret, + local->op_errno, NULL, NULL, NULL); + } else { + shard_get_timestamps_from_inode_ctx (local, base_inode, this); + SHARD_STACK_UNWIND (fsync, frame, local->op_ret, + local->op_errno, &local->prebuf, + &local->postbuf, local->xattr_rsp); + } + return 0; +} + +int +shard_post_lookup_fsync_handler (call_frame_t *frame, xlator_t *this) +{ + int ret = 0; + int call_count = 0; + int fsync_count = 0; + fd_t *anon_fd = NULL; + inode_t *base_inode = NULL; + shard_local_t *local = NULL; + shard_inode_ctx_t *ctx = NULL; + shard_inode_ctx_t *iter = NULL; + struct list_head copy = {0,}; + shard_inode_ctx_t *tmp = NULL; + + local = frame->local; + base_inode = local->fd->inode; + local->postbuf = local->prebuf; + INIT_LIST_HEAD (©); + + if (local->op_ret < 0) { + SHARD_STACK_UNWIND (fsync, frame, local->op_ret, + local->op_errno, NULL, NULL, NULL); + return 0; + } + + LOCK (&base_inode->lock); + { + __shard_inode_ctx_get (base_inode, this, &ctx); + list_splice_init (&ctx->to_fsync_list, ©); + call_count = ctx->fsync_count; + ctx->fsync_count = 0; + } + UNLOCK (&base_inode->lock); + + local->call_count = ++call_count; + + /* Send fsync() on the base shard first */ + anon_fd = fd_ref (local->fd); + STACK_WIND_COOKIE (frame, shard_fsync_shards_cbk, anon_fd, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->fsync, anon_fd, + local->datasync, local->xattr_req); + call_count--; + anon_fd = NULL; + + list_for_each_entry_safe (iter, tmp, ©, to_fsync_list) { + fsync_count = 0; + shard_inode_ctx_get_fsync_count (iter->inode, this, + &fsync_count); + GF_ASSERT (fsync_count > 0); + anon_fd = fd_anonymous (iter->inode); + if (!anon_fd) { + local->op_ret = -1; + local->op_errno = ENOMEM; + gf_msg (this->name, GF_LOG_WARNING, ENOMEM, + SHARD_MSG_MEMALLOC_FAILED, "Failed to create " + "anon fd to fsync shard"); + shard_fsync_shards_cbk (frame, (void *) (long) anon_fd, + this, -1, ENOMEM, NULL, NULL, + NULL); + continue; + } + + ret = fd_ctx_set (anon_fd, this, fsync_count); + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, 0, + SHARD_MSG_FD_CTX_SET_FAILED, "Failed to set fd " + "ctx for shard inode gfid=%s", + uuid_utoa (iter->inode->gfid)); + local->op_ret = -1; + local->op_errno = ENOMEM; + shard_fsync_shards_cbk (frame, (void *) (long) anon_fd, + this, -1, ENOMEM, NULL, NULL, + NULL); + continue; + } + STACK_WIND_COOKIE (frame, shard_fsync_shards_cbk, anon_fd, + FIRST_CHILD(this), + FIRST_CHILD(this)->fops->fsync, anon_fd, + local->datasync, local->xattr_req); + call_count--; + } + return 0; } @@ -4223,8 +4640,50 @@ int shard_fsync (call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t datasync, dict_t *xdata) { - STACK_WIND (frame, shard_fsync_cbk, FIRST_CHILD(this), - FIRST_CHILD(this)->fops->fsync, fd, datasync, xdata); + int ret = 0; + uint64_t block_size = 0; + shard_local_t *local = NULL; + + ret = shard_inode_ctx_get_block_size (fd->inode, this, &block_size); + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, 0, + SHARD_MSG_INODE_CTX_GET_FAILED, "Failed to get block " + "size for %s from its inode ctx", + uuid_utoa (fd->inode->gfid)); + goto err; + } + + if (!block_size || frame->root->pid == GF_CLIENT_PID_GSYNCD) { + STACK_WIND (frame, default_fsync_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->fsync, fd, datasync, + xdata); + return 0; + } + + if (!this->itable) + this->itable = fd->inode->table; + + local = mem_get0 (this->local_pool); + if (!local) + goto err; + + frame->local = local; + + local->fd = fd_ref (fd); + local->fop = GF_FOP_FSYNC; + local->datasync = datasync; + local->xattr_req = (xdata) ? dict_ref (xdata) : dict_new (); + if (!local->xattr_req) + goto err; + + local->loc.inode = inode_ref (fd->inode); + gf_uuid_copy (local->loc.gfid, fd->inode->gfid); + + shard_lookup_base_file (frame, this, &local->loc, + shard_post_lookup_fsync_handler); + return 0; +err: + SHARD_STACK_UNWIND (fsync, frame, -1, ENOMEM, NULL, NULL, NULL); return 0; } diff --git a/xlators/features/shard/src/shard.h b/xlators/features/shard/src/shard.h index 7319598..75d39a1 100644 --- a/xlators/features/shard/src/shard.h +++ b/xlators/features/shard/src/shard.h @@ -215,6 +215,7 @@ typedef struct shard_local { uint32_t gid; uint64_t block_size; uint64_t dst_block_size; + int32_t datasync; off_t offset; size_t total_size; size_t written_size; @@ -270,6 +271,11 @@ typedef struct shard_inode_ctx { uuid_t base_gfid; int block_num; gf_boolean_t refreshed; + struct list_head to_fsync_list; + int fsync_needed; + inode_t *inode; + int fsync_count; + inode_t *base_inode; } shard_inode_ctx_t; #endif /* __SHARD_H__ */ -- 1.8.3.1