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