d2787b
From cb0d240004e6d40f8d7f30d177d5970ebc8e25fb Mon Sep 17 00:00:00 2001
d2787b
From: Vinayak hariharmath <65405035+VHariharmath-rh@users.noreply.github.com>
d2787b
Date: Wed, 3 Feb 2021 17:04:25 +0530
d2787b
Subject: [PATCH 574/584] features/shard: delay unlink of a file that has
d2787b
 fd_count > 0
d2787b
d2787b
When there are multiple processes working on a file and if any
d2787b
process unlinks that file then unlink operation shouldn't harm
d2787b
other processes working on it. This is a posix a compliant
d2787b
behavior and this should be supported when shard feature is
d2787b
enabled also.
d2787b
d2787b
Problem description:
d2787b
Let's consider 2 clients C1 and C2 working on a file F1 with 5
d2787b
shards on gluster mount and gluster server has 4 bricks
d2787b
B1, B2, B3, B4.
d2787b
d2787b
Assume that base file/shard is present on B1, 1st, 2nd shards
d2787b
on B2, 3rd and 4th shards on B3 and 5th shard falls on B4 C1
d2787b
has opened the F1 in append mode and is writing to it. The
d2787b
write FOP goes to 5th shard in this case. So the
d2787b
inode->fd_count = 1 on B1(base file) and B4 (5th shard).
d2787b
d2787b
C2 at the same time issued unlink to F1. On the server, the
d2787b
base file has fd_count = 1 (since C1 has opened the file),
d2787b
the base file is renamed under .glusterfs/unlink and
d2787b
returned to C2. Then unlink will be sent to shards on all
d2787b
bricks and shards on B2 and B3 will be deleted which have
d2787b
no open reference yet. C1 starts getting errors while
d2787b
accessing the remaining shards though it has open references
d2787b
for the file.
d2787b
d2787b
This is one such undefined behavior. Likewise we will
d2787b
encounter many such undefined behaviors as we dont have one
d2787b
global lock to access all shards as one. Of Course having such
d2787b
global lock will lead to performance hit as it reduces window
d2787b
for parallel access of shards.
d2787b
d2787b
Solution:
d2787b
The above undefined behavior can be addressed by delaying the
d2787b
unlink of a file when there are open references on it.
d2787b
File unlink happens in 2 steps.
d2787b
step 1: client creates marker file under .shard/remove_me and
d2787b
sends unlink on base file to the server
d2787b
step 2: on return from the server, the associated shards will
d2787b
be cleaned up and finally marker file will be removed.
d2787b
d2787b
In step 2, the back ground deletion process does nameless
d2787b
lookup using marker file name (marker file is named after the
d2787b
gfid of the base file) in glusterfs/unlink dir. If the nameless
d2787b
look up is successful then that means the gfid still has open
d2787b
fds and deletion of shards has to be delayed. If nameless
d2787b
lookup fails then that indicates the gfid is unlinked and no
d2787b
open fds on that file (the gfid path is unlinked during final
d2787b
close on the file). The shards on which deletion is delayed
d2787b
are unlinked one the all open fds are closed and this is
d2787b
done through a thread which wakes up every 10 mins.
d2787b
d2787b
Also removed active_fd_count from inode structure and
d2787b
referring fd_count wherever active_fd_count was used.
d2787b
d2787b
Backport of:
d2787b
> Upstream-patch: https://github.com/gluster/glusterfs/pull/1563
d2787b
> Fixes: #1358
d2787b
> Change-Id: I8985093386e26215e0b0dce294c534a66f6ca11c
d2787b
> Signed-off-by: Vinayakswami Hariharmath <vharihar@redhat.com>
d2787b
d2787b
BUG: 1782428
d2787b
Change-Id: I8985093386e26215e0b0dce294c534a66f6ca11c
d2787b
Signed-off-by: Vinayakswami Hariharmath <vharihar@redhat.com>
d2787b
Reviewed-on: https://code.engineering.redhat.com/gerrit/c/rhs-glusterfs/+/244967
d2787b
Tested-by: RHGS Build Bot <nigelb@redhat.com>
d2787b
Reviewed-by: Sunil Kumar Heggodu Gopala Acharya <sheggodu@redhat.com>
d2787b
---
d2787b
 libglusterfs/src/glusterfs/glusterfs.h         |   1 +
d2787b
 tests/bugs/shard/issue-1358.t                  | 100 +++++++++++++
d2787b
 tests/bugs/shard/unlinks-and-renames.t         |   5 +
d2787b
 xlators/features/shard/src/shard.c             | 199 ++++++++++++++++++++++++-
d2787b
 xlators/features/shard/src/shard.h             |  11 ++
d2787b
 xlators/storage/posix/src/posix-entry-ops.c    |  36 +++++
d2787b
 xlators/storage/posix/src/posix-inode-fd-ops.c |  64 +++++---
d2787b
 7 files changed, 391 insertions(+), 25 deletions(-)
d2787b
 create mode 100644 tests/bugs/shard/issue-1358.t
d2787b
d2787b
diff --git a/libglusterfs/src/glusterfs/glusterfs.h b/libglusterfs/src/glusterfs/glusterfs.h
d2787b
index d3400bf..4401cf6 100644
d2787b
--- a/libglusterfs/src/glusterfs/glusterfs.h
d2787b
+++ b/libglusterfs/src/glusterfs/glusterfs.h
d2787b
@@ -261,6 +261,7 @@ enum gf_internal_fop_indicator {
d2787b
 #define GF_XATTROP_PURGE_INDEX "glusterfs.xattrop-purge-index"
d2787b
 
d2787b
 #define GF_GFIDLESS_LOOKUP "gfidless-lookup"
d2787b
+#define GF_UNLINKED_LOOKUP "unlinked-lookup"
d2787b
 /* replace-brick and pump related internal xattrs */
d2787b
 #define RB_PUMP_CMD_START "glusterfs.pump.start"
d2787b
 #define RB_PUMP_CMD_PAUSE "glusterfs.pump.pause"
d2787b
diff --git a/tests/bugs/shard/issue-1358.t b/tests/bugs/shard/issue-1358.t
d2787b
new file mode 100644
d2787b
index 0000000..1838e06
d2787b
--- /dev/null
d2787b
+++ b/tests/bugs/shard/issue-1358.t
d2787b
@@ -0,0 +1,100 @@
d2787b
+#!/bin/bash
d2787b
+
d2787b
+. $(dirname $0)/../../include.rc
d2787b
+. $(dirname $0)/../../volume.rc
d2787b
+
d2787b
+cleanup;
d2787b
+
d2787b
+FILE_COUNT_TIME=5
d2787b
+
d2787b
+function get_file_count {
d2787b
+    ls $1* | wc -l
d2787b
+}
d2787b
+
d2787b
+TEST glusterd
d2787b
+TEST pidof glusterd
d2787b
+TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1}
d2787b
+TEST $CLI volume set $V0 features.shard on
d2787b
+TEST $CLI volume set $V0 features.shard-block-size 4MB
d2787b
+TEST $CLI volume set $V0 performance.quick-read off
d2787b
+TEST $CLI volume set $V0 performance.io-cache off
d2787b
+TEST $CLI volume set $V0 performance.read-ahead off
d2787b
+TEST $CLI volume set $V0 performance.write-behind off
d2787b
+TEST $CLI volume start $V0
d2787b
+
d2787b
+TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0
d2787b
+
d2787b
+TEST mkdir $M0/dir
d2787b
+TEST dd if=/dev/urandom of=$M0/dir/foo bs=4M count=5
d2787b
+gfid_new=$(get_gfid_string $M0/dir/foo)
d2787b
+
d2787b
+# Ensure its shards dir is created now.
d2787b
+TEST stat $B0/${V0}0/.shard/$gfid_new.1
d2787b
+TEST stat $B0/${V0}1/.shard/$gfid_new.1
d2787b
+TEST stat $B0/${V0}0/.shard/$gfid_new.2
d2787b
+TEST stat $B0/${V0}1/.shard/$gfid_new.2
d2787b
+
d2787b
+# Open a file and store descriptor in fd = 5
d2787b
+exec 5>$M0/dir/foo
d2787b
+
d2787b
+# Write something on the file using the open fd = 5
d2787b
+echo "issue-1358" >&5
d2787b
+
d2787b
+# Write on the descriptor should be succesful
d2787b
+EXPECT 0 echo $?
d2787b
+
d2787b
+# Unlink the same file which is opened in prev step
d2787b
+TEST unlink $M0/dir/foo
d2787b
+
d2787b
+# Check the base file
d2787b
+TEST ! stat $M0/dir/foo
d2787b
+TEST ! stat $B0/${V0}0/foo
d2787b
+TEST ! stat $B0/${V0}1/foo
d2787b
+
d2787b
+# Write something on the file using the open fd = 5
d2787b
+echo "issue-1281" >&5
d2787b
+
d2787b
+# Write on the descriptor should be succesful
d2787b
+EXPECT 0 echo $?
d2787b
+
d2787b
+# Check ".shard/.remove_me"
d2787b
+EXPECT_WITHIN $FILE_COUNT_TIME 1 get_file_count $B0/${V0}0/.shard/.remove_me/$gfid_new
d2787b
+EXPECT_WITHIN $FILE_COUNT_TIME 1 get_file_count $B0/${V0}1/.shard/.remove_me/$gfid_new
d2787b
+
d2787b
+# Close the fd = 5
d2787b
+exec 5>&-
d2787b
+
d2787b
+###### To see the shards deleted, wait for 10 mins or repeat the same steps i.e open a file #####
d2787b
+###### write something to it, unlink it and close it. This will wake up the thread that is ######
d2787b
+###### responsible to delete the shards
d2787b
+
d2787b
+TEST touch $M0/dir/new
d2787b
+exec 6>$M0/dir/new
d2787b
+echo "issue-1358" >&6
d2787b
+EXPECT 0 echo $?
d2787b
+TEST unlink $M0/dir/new
d2787b
+exec 6>&-
d2787b
+
d2787b
+# Now check the ".shard/remove_me" and the gfid will not be there
d2787b
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}0/.shard/.remove_me/$gfid_new
d2787b
+EXPECT_WITHIN $FILE_COUNT_TIME 0 get_file_count $B0/${V0}1/.shard/.remove_me/$gfid_new
d2787b
+
d2787b
+# check for the absence of shards
d2787b
+TEST ! stat $B0/${V0}0/.shard/$gfid_new.1
d2787b
+TEST ! stat $B0/${V0}1/.shard/$gfid_new.1
d2787b
+TEST ! stat $B0/${V0}0/.shard/$gfid_new.2
d2787b
+TEST ! stat $B0/${V0}1/.shard/$gfid_new.2
d2787b
+
d2787b
+#### Create the file with same name and check creation and deletion works fine ######
d2787b
+TEST dd if=/dev/urandom of=$M0/dir/foo bs=4M count=5
d2787b
+gfid_new=$(get_gfid_string $M0/dir/foo)
d2787b
+
d2787b
+# Ensure its shards dir is created now.
d2787b
+TEST stat $B0/${V0}0/.shard/$gfid_new.1
d2787b
+TEST stat $B0/${V0}1/.shard/$gfid_new.1
d2787b
+TEST stat $B0/${V0}0/.shard/$gfid_new.2
d2787b
+TEST stat $B0/${V0}1/.shard/$gfid_new.2
d2787b
+
d2787b
+TEST unlink $M0/dir/foo
d2787b
+cleanup
d2787b
+
d2787b
diff --git a/tests/bugs/shard/unlinks-and-renames.t b/tests/bugs/shard/unlinks-and-renames.t
d2787b
index 990ca69..3280fcb 100644
d2787b
--- a/tests/bugs/shard/unlinks-and-renames.t
d2787b
+++ b/tests/bugs/shard/unlinks-and-renames.t
d2787b
@@ -24,6 +24,11 @@ TEST pidof glusterd
d2787b
 TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1}
d2787b
 TEST $CLI volume set $V0 features.shard on
d2787b
 TEST $CLI volume set $V0 features.shard-block-size 4MB
d2787b
+TEST $CLI volume set $V0 performance.quick-read off
d2787b
+TEST $CLI volume set $V0 performance.io-cache off
d2787b
+TEST $CLI volume set $V0 performance.read-ahead off
d2787b
+TEST $CLI volume set $V0 performance.write-behind off
d2787b
+
d2787b
 TEST $CLI volume start $V0
d2787b
 TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 $M0
d2787b
 
d2787b
diff --git a/xlators/features/shard/src/shard.c b/xlators/features/shard/src/shard.c
d2787b
index 8d4a970..b828ff9 100644
d2787b
--- a/xlators/features/shard/src/shard.c
d2787b
+++ b/xlators/features/shard/src/shard.c
d2787b
@@ -1242,7 +1242,8 @@ out:
d2787b
 
d2787b
 static inode_t *
d2787b
 shard_link_internal_dir_inode(shard_local_t *local, inode_t *inode,
d2787b
-                              struct iatt *buf, shard_internal_dir_type_t type)
d2787b
+                              xlator_t *this, struct iatt *buf,
d2787b
+                              shard_internal_dir_type_t type)
d2787b
 {
d2787b
     inode_t *linked_inode = NULL;
d2787b
     shard_priv_t *priv = NULL;
d2787b
@@ -1250,7 +1251,7 @@ shard_link_internal_dir_inode(shard_local_t *local, inode_t *inode,
d2787b
     inode_t **priv_inode = NULL;
d2787b
     inode_t *parent = NULL;
d2787b
 
d2787b
-    priv = THIS->private;
d2787b
+    priv = this->private;
d2787b
 
d2787b
     switch (type) {
d2787b
         case SHARD_INTERNAL_DIR_DOT_SHARD:
d2787b
@@ -1294,7 +1295,7 @@ shard_refresh_internal_dir_cbk(call_frame_t *frame, void *cookie,
d2787b
     /* To-Do: Fix refcount increment per call to
d2787b
      * shard_link_internal_dir_inode().
d2787b
      */
d2787b
-    linked_inode = shard_link_internal_dir_inode(local, inode, buf, type);
d2787b
+    linked_inode = shard_link_internal_dir_inode(local, inode, this, buf, type);
d2787b
     shard_inode_ctx_mark_dir_refreshed(linked_inode, this);
d2787b
 out:
d2787b
     shard_common_resolve_shards(frame, this, local->post_res_handler);
d2787b
@@ -1383,7 +1384,7 @@ shard_lookup_internal_dir_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
d2787b
         goto unwind;
d2787b
     }
d2787b
 
d2787b
-    link_inode = shard_link_internal_dir_inode(local, inode, buf, type);
d2787b
+    link_inode = shard_link_internal_dir_inode(local, inode, this, buf, type);
d2787b
     if (link_inode != inode) {
d2787b
         shard_refresh_internal_dir(frame, this, type);
d2787b
     } else {
d2787b
@@ -3586,7 +3587,8 @@ shard_resolve_internal_dir(xlator_t *this, shard_local_t *local,
d2787b
                        "Lookup on %s failed, exiting", bname);
d2787b
             goto err;
d2787b
         } else {
d2787b
-            shard_link_internal_dir_inode(local, loc->inode, &stbuf, type);
d2787b
+            shard_link_internal_dir_inode(local, loc->inode, this, &stbuf,
d2787b
+                                          type);
d2787b
         }
d2787b
     }
d2787b
     ret = 0;
d2787b
@@ -3633,6 +3635,45 @@ err:
d2787b
     return ret;
d2787b
 }
d2787b
 
d2787b
+static int
d2787b
+shard_nameless_lookup_base_file(xlator_t *this, char *gfid)
d2787b
+{
d2787b
+    int ret = 0;
d2787b
+    loc_t loc = {
d2787b
+        0,
d2787b
+    };
d2787b
+    dict_t *xattr_req = dict_new();
d2787b
+    if (!xattr_req) {
d2787b
+        ret = -1;
d2787b
+        goto out;
d2787b
+    }
d2787b
+
d2787b
+    loc.inode = inode_new(this->itable);
d2787b
+    if (loc.inode == NULL) {
d2787b
+        ret = -1;
d2787b
+        goto out;
d2787b
+    }
d2787b
+
d2787b
+    ret = gf_uuid_parse(gfid, loc.gfid);
d2787b
+    if (ret < 0)
d2787b
+        goto out;
d2787b
+
d2787b
+    ret = dict_set_uint32(xattr_req, GF_UNLINKED_LOOKUP, 1);
d2787b
+    if (ret < 0)
d2787b
+        goto out;
d2787b
+
d2787b
+    ret = syncop_lookup(FIRST_CHILD(this), &loc, NULL, NULL, xattr_req, NULL);
d2787b
+    if (ret < 0)
d2787b
+        goto out;
d2787b
+
d2787b
+out:
d2787b
+    if (xattr_req)
d2787b
+        dict_unref(xattr_req);
d2787b
+    loc_wipe(&loc;;
d2787b
+
d2787b
+    return ret;
d2787b
+}
d2787b
+
d2787b
 int
d2787b
 shard_delete_shards(void *opaque)
d2787b
 {
d2787b
@@ -3734,6 +3775,11 @@ shard_delete_shards(void *opaque)
d2787b
                     if (ret < 0)
d2787b
                         continue;
d2787b
                 }
d2787b
+
d2787b
+                ret = shard_nameless_lookup_base_file(this, entry->d_name);
d2787b
+                if (!ret)
d2787b
+                    continue;
d2787b
+
d2787b
                 link_inode = inode_link(entry->inode, local->fd->inode,
d2787b
                                         entry->d_name, &entry->d_stat);
d2787b
 
d2787b
@@ -4105,6 +4151,9 @@ err:
d2787b
 int
d2787b
 shard_unlock_entrylk(call_frame_t *frame, xlator_t *this);
d2787b
 
d2787b
+static int
d2787b
+shard_unlink_handler_spawn(xlator_t *this);
d2787b
+
d2787b
 int
d2787b
 shard_unlink_base_file_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
d2787b
                            int32_t op_ret, int32_t op_errno,
d2787b
@@ -4126,7 +4175,7 @@ shard_unlink_base_file_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
d2787b
         if (xdata)
d2787b
             local->xattr_rsp = dict_ref(xdata);
d2787b
         if (local->cleanup_required)
d2787b
-            shard_start_background_deletion(this);
d2787b
+            shard_unlink_handler_spawn(this);
d2787b
     }
d2787b
 
d2787b
     if (local->entrylk_frame) {
d2787b
@@ -5785,7 +5834,7 @@ shard_mkdir_internal_dir_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
d2787b
         }
d2787b
     }
d2787b
 
d2787b
-    link_inode = shard_link_internal_dir_inode(local, inode, buf, type);
d2787b
+    link_inode = shard_link_internal_dir_inode(local, inode, this, buf, type);
d2787b
     if (link_inode != inode) {
d2787b
         shard_refresh_internal_dir(frame, this, type);
d2787b
     } else {
d2787b
@@ -7098,6 +7147,132 @@ shard_seek(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset,
d2787b
     return 0;
d2787b
 }
d2787b
 
d2787b
+static void
d2787b
+shard_unlink_wait(shard_unlink_thread_t *ti)
d2787b
+{
d2787b
+    struct timespec wait_till = {
d2787b
+        0,
d2787b
+    };
d2787b
+
d2787b
+    pthread_mutex_lock(&ti->mutex);
d2787b
+    {
d2787b
+        /* shard_unlink_handler() runs every 10 mins of interval */
d2787b
+        wait_till.tv_sec = time(NULL) + 600;
d2787b
+
d2787b
+        while (!ti->rerun) {
d2787b
+            if (pthread_cond_timedwait(&ti->cond, &ti->mutex, &wait_till) ==
d2787b
+                ETIMEDOUT)
d2787b
+                break;
d2787b
+        }
d2787b
+        ti->rerun = _gf_false;
d2787b
+    }
d2787b
+    pthread_mutex_unlock(&ti->mutex);
d2787b
+}
d2787b
+
d2787b
+static void *
d2787b
+shard_unlink_handler(void *data)
d2787b
+{
d2787b
+    shard_unlink_thread_t *ti = data;
d2787b
+    xlator_t *this = ti->this;
d2787b
+
d2787b
+    THIS = this;
d2787b
+
d2787b
+    while (!ti->stop) {
d2787b
+        shard_start_background_deletion(this);
d2787b
+        shard_unlink_wait(ti);
d2787b
+    }
d2787b
+    return NULL;
d2787b
+}
d2787b
+
d2787b
+static int
d2787b
+shard_unlink_handler_spawn(xlator_t *this)
d2787b
+{
d2787b
+    int ret = 0;
d2787b
+    shard_priv_t *priv = this->private;
d2787b
+    shard_unlink_thread_t *ti = &priv->thread_info;
d2787b
+
d2787b
+    ti->this = this;
d2787b
+
d2787b
+    pthread_mutex_lock(&ti->mutex);
d2787b
+    {
d2787b
+        if (ti->running) {
d2787b
+            pthread_cond_signal(&ti->cond);
d2787b
+        } else {
d2787b
+            ret = gf_thread_create(&ti->thread, NULL, shard_unlink_handler, ti,
d2787b
+                                   "shard_unlink");
d2787b
+            if (ret < 0) {
d2787b
+                gf_log(this->name, GF_LOG_ERROR,
d2787b
+                       "Failed to create \"shard_unlink\" thread");
d2787b
+                goto unlock;
d2787b
+            }
d2787b
+            ti->running = _gf_true;
d2787b
+        }
d2787b
+
d2787b
+        ti->rerun = _gf_true;
d2787b
+    }
d2787b
+unlock:
d2787b
+    pthread_mutex_unlock(&ti->mutex);
d2787b
+    return ret;
d2787b
+}
d2787b
+
d2787b
+static int
d2787b
+shard_unlink_handler_init(shard_unlink_thread_t *ti)
d2787b
+{
d2787b
+    int ret = 0;
d2787b
+    xlator_t *this = THIS;
d2787b
+
d2787b
+    ret = pthread_mutex_init(&ti->mutex, NULL);
d2787b
+    if (ret) {
d2787b
+        gf_log(this->name, GF_LOG_ERROR,
d2787b
+               "Failed to init mutex for \"shard_unlink\" thread");
d2787b
+        goto out;
d2787b
+    }
d2787b
+
d2787b
+    ret = pthread_cond_init(&ti->cond, NULL);
d2787b
+    if (ret) {
d2787b
+        gf_log(this->name, GF_LOG_ERROR,
d2787b
+               "Failed to init cond var for \"shard_unlink\" thread");
d2787b
+        pthread_mutex_destroy(&ti->mutex);
d2787b
+        goto out;
d2787b
+    }
d2787b
+
d2787b
+    ti->running = _gf_false;
d2787b
+    ti->rerun = _gf_false;
d2787b
+    ti->stop = _gf_false;
d2787b
+
d2787b
+out:
d2787b
+    return -ret;
d2787b
+}
d2787b
+
d2787b
+static void
d2787b
+shard_unlink_handler_fini(shard_unlink_thread_t *ti)
d2787b
+{
d2787b
+    int ret = 0;
d2787b
+    xlator_t *this = THIS;
d2787b
+    if (!ti)
d2787b
+        return;
d2787b
+
d2787b
+    pthread_mutex_lock(&ti->mutex);
d2787b
+    if (ti->running) {
d2787b
+        ti->rerun = _gf_true;
d2787b
+        ti->stop = _gf_true;
d2787b
+        pthread_cond_signal(&ti->cond);
d2787b
+    }
d2787b
+    pthread_mutex_unlock(&ti->mutex);
d2787b
+
d2787b
+    if (ti->running) {
d2787b
+        ret = pthread_join(ti->thread, NULL);
d2787b
+        if (ret)
d2787b
+            gf_msg(this->name, GF_LOG_WARNING, 0, 0,
d2787b
+                   "Failed to clean up shard unlink thread.");
d2787b
+        ti->running = _gf_false;
d2787b
+    }
d2787b
+    ti->thread = 0;
d2787b
+
d2787b
+    pthread_cond_destroy(&ti->cond);
d2787b
+    pthread_mutex_destroy(&ti->mutex);
d2787b
+}
d2787b
+
d2787b
 int32_t
d2787b
 mem_acct_init(xlator_t *this)
d2787b
 {
d2787b
@@ -7164,6 +7339,14 @@ init(xlator_t *this)
d2787b
     this->private = priv;
d2787b
     LOCK_INIT(&priv->lock);
d2787b
     INIT_LIST_HEAD(&priv->ilist_head);
d2787b
+
d2787b
+    ret = shard_unlink_handler_init(&priv->thread_info);
d2787b
+    if (ret) {
d2787b
+        gf_log(this->name, GF_LOG_ERROR,
d2787b
+               "Failed to initialize resources for \"shard_unlink\" thread");
d2787b
+        goto out;
d2787b
+    }
d2787b
+
d2787b
     ret = 0;
d2787b
 out:
d2787b
     if (ret) {
d2787b
@@ -7188,6 +7371,8 @@ fini(xlator_t *this)
d2787b
     if (!priv)
d2787b
         goto out;
d2787b
 
d2787b
+    shard_unlink_handler_fini(&priv->thread_info);
d2787b
+
d2787b
     this->private = NULL;
d2787b
     LOCK_DESTROY(&priv->lock);
d2787b
     GF_FREE(priv);
d2787b
diff --git a/xlators/features/shard/src/shard.h b/xlators/features/shard/src/shard.h
d2787b
index 4fe181b..3dcb112 100644
d2787b
--- a/xlators/features/shard/src/shard.h
d2787b
+++ b/xlators/features/shard/src/shard.h
d2787b
@@ -207,6 +207,16 @@ typedef enum {
d2787b
 
d2787b
 /* rm = "remove me" */
d2787b
 
d2787b
+typedef struct shard_unlink_thread {
d2787b
+    pthread_mutex_t mutex;
d2787b
+    pthread_cond_t cond;
d2787b
+    pthread_t thread;
d2787b
+    gf_boolean_t running;
d2787b
+    gf_boolean_t rerun;
d2787b
+    gf_boolean_t stop;
d2787b
+    xlator_t *this;
d2787b
+} shard_unlink_thread_t;
d2787b
+
d2787b
 typedef struct shard_priv {
d2787b
     uint64_t block_size;
d2787b
     uuid_t dot_shard_gfid;
d2787b
@@ -220,6 +230,7 @@ typedef struct shard_priv {
d2787b
     shard_bg_deletion_state_t bg_del_state;
d2787b
     gf_boolean_t first_lookup_done;
d2787b
     uint64_t lru_limit;
d2787b
+    shard_unlink_thread_t thread_info;
d2787b
 } shard_priv_t;
d2787b
 
d2787b
 typedef struct {
d2787b
diff --git a/xlators/storage/posix/src/posix-entry-ops.c b/xlators/storage/posix/src/posix-entry-ops.c
d2787b
index b3a5381..1511e68 100644
d2787b
--- a/xlators/storage/posix/src/posix-entry-ops.c
d2787b
+++ b/xlators/storage/posix/src/posix-entry-ops.c
d2787b
@@ -183,6 +183,11 @@ posix_lookup(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata)
d2787b
     struct posix_private *priv = NULL;
d2787b
     posix_inode_ctx_t *ctx = NULL;
d2787b
     int ret = 0;
d2787b
+    uint32_t lookup_unlink_dir = 0;
d2787b
+    char *unlink_path = NULL;
d2787b
+    struct stat lstatbuf = {
d2787b
+        0,
d2787b
+    };
d2787b
 
d2787b
     VALIDATE_OR_GOTO(frame, out);
d2787b
     VALIDATE_OR_GOTO(this, out);
d2787b
@@ -208,7 +213,36 @@ posix_lookup(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata)
d2787b
     op_ret = -1;
d2787b
     if (gf_uuid_is_null(loc->pargfid) || (loc->name == NULL)) {
d2787b
         /* nameless lookup */
d2787b
+        op_ret = op_errno = errno = 0;
d2787b
         MAKE_INODE_HANDLE(real_path, this, loc, &buf;;
d2787b
+
d2787b
+        /* The gfid will be renamed to ".glusterfs/unlink" in case
d2787b
+         * there are any open fds on the file in posix_unlink path.
d2787b
+         * So client can request server to do nameless lookup with
d2787b
+         * xdata = GF_UNLINKED_LOOKUP in ".glusterfs/unlink"
d2787b
+         * dir if a client wants to know the status of the all open fds
d2787b
+         * on the unlinked file. If the file still present in the
d2787b
+         * ".glusterfs/unlink" dir then it indicates there still
d2787b
+         * open fds present on the file and the file is still under
d2787b
+         * unlink process */
d2787b
+        if (op_ret < 0 && errno == ENOENT) {
d2787b
+            ret = dict_get_uint32(xdata, GF_UNLINKED_LOOKUP,
d2787b
+                                  &lookup_unlink_dir);
d2787b
+            if (!ret && lookup_unlink_dir) {
d2787b
+                op_ret = op_errno = errno = 0;
d2787b
+                POSIX_GET_FILE_UNLINK_PATH(priv->base_path, loc->gfid,
d2787b
+                                           unlink_path);
d2787b
+                ret = sys_lstat(unlink_path, &lstatbuf);
d2787b
+                if (ret) {
d2787b
+                    op_ret = -1;
d2787b
+                    op_errno = errno;
d2787b
+                } else {
d2787b
+                    iatt_from_stat(&buf, &lstatbuf);
d2787b
+                    buf.ia_nlink = 0;
d2787b
+                }
d2787b
+                goto nameless_lookup_unlink_dir_out;
d2787b
+            }
d2787b
+        }
d2787b
     } else {
d2787b
         MAKE_ENTRY_HANDLE(real_path, par_path, this, loc, &buf;;
d2787b
         if (!real_path || !par_path) {
d2787b
@@ -328,6 +362,8 @@ out:
d2787b
 
d2787b
     if (op_ret == 0)
d2787b
         op_errno = 0;
d2787b
+
d2787b
+nameless_lookup_unlink_dir_out:
d2787b
     STACK_UNWIND_STRICT(lookup, frame, op_ret, op_errno,
d2787b
                         (loc) ? loc->inode : NULL, &buf, xattr, &postparent);
d2787b
 
d2787b
diff --git a/xlators/storage/posix/src/posix-inode-fd-ops.c b/xlators/storage/posix/src/posix-inode-fd-ops.c
d2787b
index 761e018..4c2983a 100644
d2787b
--- a/xlators/storage/posix/src/posix-inode-fd-ops.c
d2787b
+++ b/xlators/storage/posix/src/posix-inode-fd-ops.c
d2787b
@@ -2504,6 +2504,39 @@ out:
d2787b
     return 0;
d2787b
 }
d2787b
 
d2787b
+static int
d2787b
+posix_unlink_renamed_file(xlator_t *this, inode_t *inode)
d2787b
+{
d2787b
+    int ret = 0;
d2787b
+    char *unlink_path = NULL;
d2787b
+    uint64_t ctx_uint = 0;
d2787b
+    posix_inode_ctx_t *ctx = NULL;
d2787b
+    struct posix_private *priv = this->private;
d2787b
+
d2787b
+    ret = inode_ctx_get(inode, this, &ctx_uint);
d2787b
+
d2787b
+    if (ret < 0)
d2787b
+        goto out;
d2787b
+
d2787b
+    ctx = (posix_inode_ctx_t *)(uintptr_t)ctx_uint;
d2787b
+
d2787b
+    if (ctx->unlink_flag == GF_UNLINK_TRUE) {
d2787b
+        POSIX_GET_FILE_UNLINK_PATH(priv->base_path, inode->gfid, unlink_path);
d2787b
+        if (!unlink_path) {
d2787b
+            gf_msg(this->name, GF_LOG_ERROR, ENOMEM, P_MSG_UNLINK_FAILED,
d2787b
+                   "Failed to remove gfid :%s", uuid_utoa(inode->gfid));
d2787b
+            ret = -1;
d2787b
+        } else {
d2787b
+            ret = sys_unlink(unlink_path);
d2787b
+            if (!ret)
d2787b
+                ctx->unlink_flag = GF_UNLINK_FALSE;
d2787b
+        }
d2787b
+    }
d2787b
+
d2787b
+out:
d2787b
+    return ret;
d2787b
+}
d2787b
+
d2787b
 int32_t
d2787b
 posix_release(xlator_t *this, fd_t *fd)
d2787b
 {
d2787b
@@ -2514,6 +2547,9 @@ posix_release(xlator_t *this, fd_t *fd)
d2787b
     VALIDATE_OR_GOTO(this, out);
d2787b
     VALIDATE_OR_GOTO(fd, out);
d2787b
 
d2787b
+    if (fd->inode->active_fd_count == 0)
d2787b
+        posix_unlink_renamed_file(this, fd->inode);
d2787b
+
d2787b
     ret = fd_ctx_del(fd, this, &tmp_pfd);
d2787b
     if (ret < 0) {
d2787b
         gf_msg(this->name, GF_LOG_WARNING, 0, P_MSG_PFD_NULL,
d2787b
@@ -5881,41 +5917,33 @@ posix_forget(xlator_t *this, inode_t *inode)
d2787b
     uint64_t ctx_uint1 = 0;
d2787b
     uint64_t ctx_uint2 = 0;
d2787b
     posix_inode_ctx_t *ctx = NULL;
d2787b
-    posix_mdata_t *mdata = NULL;
d2787b
-    struct posix_private *priv_posix = NULL;
d2787b
-
d2787b
-    priv_posix = (struct posix_private *)this->private;
d2787b
-    if (!priv_posix)
d2787b
-        return 0;
d2787b
+    struct posix_private *priv = this->private;
d2787b
 
d2787b
     ret = inode_ctx_del2(inode, this, &ctx_uint1, &ctx_uint2);
d2787b
+
d2787b
+    if (ctx_uint2)
d2787b
+        GF_FREE((posix_mdata_t *)(uintptr_t)ctx_uint2);
d2787b
+
d2787b
     if (!ctx_uint1)
d2787b
-        goto check_ctx2;
d2787b
+        return 0;
d2787b
 
d2787b
     ctx = (posix_inode_ctx_t *)(uintptr_t)ctx_uint1;
d2787b
 
d2787b
     if (ctx->unlink_flag == GF_UNLINK_TRUE) {
d2787b
-        POSIX_GET_FILE_UNLINK_PATH(priv_posix->base_path, inode->gfid,
d2787b
-                                   unlink_path);
d2787b
+        POSIX_GET_FILE_UNLINK_PATH(priv->base_path, inode->gfid, unlink_path);
d2787b
         if (!unlink_path) {
d2787b
             gf_msg(this->name, GF_LOG_ERROR, ENOMEM, P_MSG_UNLINK_FAILED,
d2787b
                    "Failed to remove gfid :%s", uuid_utoa(inode->gfid));
d2787b
             ret = -1;
d2787b
-            goto ctx_free;
d2787b
+        } else {
d2787b
+            ret = sys_unlink(unlink_path);
d2787b
         }
d2787b
-        ret = sys_unlink(unlink_path);
d2787b
     }
d2787b
-ctx_free:
d2787b
+
d2787b
     pthread_mutex_destroy(&ctx->xattrop_lock);
d2787b
     pthread_mutex_destroy(&ctx->write_atomic_lock);
d2787b
     pthread_mutex_destroy(&ctx->pgfid_lock);
d2787b
     GF_FREE(ctx);
d2787b
 
d2787b
-check_ctx2:
d2787b
-    if (ctx_uint2) {
d2787b
-        mdata = (posix_mdata_t *)(uintptr_t)ctx_uint2;
d2787b
-    }
d2787b
-
d2787b
-    GF_FREE(mdata);
d2787b
     return ret;
d2787b
 }
d2787b
-- 
d2787b
1.8.3.1
d2787b