Blob Blame History Raw
From 57c794e31c0333f508ada740227c9afa1889f8ae Mon Sep 17 00:00:00 2001
From: karthik-us <ksubrahm@redhat.com>
Date: Thu, 15 Apr 2021 11:27:57 +0530
Subject: [PATCH 581/584] afr: don't reopen fds on which POSIX locks are held

When client.strict-locks is enabled on a volume and there are POSIX
locks held on the files, after disconnect and reconnection of the
clients do not re-open such fds which might lead to multiple clients
acquiring the locks and cause data corruption.

> Upstream patch: https://github.com/gluster/glusterfs/pull/1980/commits/56bde56c2741c5eac59937a6cf951a14f2878460
> Change-Id: I8777ffbc2cc8d15ab57b58b72b56eb67521787c5
> Fixes: #1977
> Signed-off-by: karthik-us <ksubrahm@redhat.com>

BUG: 1689375
Change-Id: I8777ffbc2cc8d15ab57b58b72b56eb67521787c5
Signed-off-by: karthik-us <ksubrahm@redhat.com>
Reviewed-on: https://code.engineering.redhat.com/gerrit/c/rhs-glusterfs/+/245414
Tested-by: RHGS Build Bot <nigelb@redhat.com>
Reviewed-by: Sunil Kumar Heggodu Gopala Acharya <sheggodu@redhat.com>
Reviewed-by: Ravishankar Narayanankutty <ravishankar@redhat.com>
---
 rpc/rpc-lib/src/protocol-common.h                |   6 +
 tests/bugs/replicate/do-not-reopen-fd.t          | 206 +++++++++++++++++
 xlators/cluster/afr/src/afr-common.c             |  15 +-
 xlators/cluster/afr/src/afr-open.c               | 280 +++++++++++++++++++----
 xlators/cluster/afr/src/afr.h                    |   3 +
 xlators/protocol/client/src/client-common.c      | 148 ++++++++----
 xlators/protocol/client/src/client-common.h      |   4 +
 xlators/protocol/client/src/client-helpers.c     |  22 +-
 xlators/protocol/client/src/client-rpc-fops.c    |  23 +-
 xlators/protocol/client/src/client-rpc-fops_v2.c |  25 +-
 xlators/protocol/client/src/client.c             |  21 +-
 xlators/protocol/client/src/client.h             |   8 +-
 12 files changed, 654 insertions(+), 107 deletions(-)
 create mode 100644 tests/bugs/replicate/do-not-reopen-fd.t

diff --git a/rpc/rpc-lib/src/protocol-common.h b/rpc/rpc-lib/src/protocol-common.h
index 779878f..f56aaaa 100644
--- a/rpc/rpc-lib/src/protocol-common.h
+++ b/rpc/rpc-lib/src/protocol-common.h
@@ -312,6 +312,12 @@ enum glusterd_mgmt_v3_procnum {
     GLUSTERD_MGMT_V3_MAXVALUE,
 };
 
+enum gf_fd_reopen_status {
+    FD_REOPEN_ALLOWED = 0,
+    FD_REOPEN_NOT_ALLOWED,
+    FD_BAD,
+};
+
 typedef struct gf_gsync_detailed_status_ gf_gsync_status_t;
 
 enum gf_get_volume_info_type {
diff --git a/tests/bugs/replicate/do-not-reopen-fd.t b/tests/bugs/replicate/do-not-reopen-fd.t
new file mode 100644
index 0000000..76d8e70
--- /dev/null
+++ b/tests/bugs/replicate/do-not-reopen-fd.t
@@ -0,0 +1,206 @@
+#!/bin/bash
+
+. $(dirname $0)/../../include.rc
+. $(dirname $0)/../../volume.rc
+. $(dirname $0)/../../fileio.rc
+
+cleanup;
+
+TEST glusterd;
+TEST pidof glusterd
+
+TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,2}
+TEST $CLI volume set $V0 performance.write-behind off
+TEST $CLI volume set $V0 performance.open-behind off
+TEST $CLI volume set $V0 client.strict-locks on
+TEST $CLI volume heal $V0 disable
+TEST $CLI volume start $V0
+EXPECT 'Started' volinfo_field $V0 'Status';
+TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M0
+TEST $GFS --volfile-id=/$V0 --volfile-server=$H0 $M1
+
+TEST touch $M0/a
+
+# Kill one brick and take lock on the fd and do a write.
+TEST kill_brick $V0 $H0 $B0/${V0}0
+EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "0" afr_child_up_status_meta $M0 $V0-replicate-0 0
+TEST fd1=`fd_available`
+TEST fd_open $fd1 'rw' $M0/a
+
+TEST flock -x $fd1
+TEST fd_write $fd1 "data-1"
+
+# Restart the brick and then write. Now fd should not get re-opened but write
+# should still succeed as there were no quorum disconnects.
+TEST $CLI volume start $V0 force
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^1$" brick_up_status $V0 $H0 $B0/${V0}0
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status_meta $M0 $V0-replicate-0 0
+TEST fd_write $fd1 "data-2"
+EXPECT "" cat $B0/${V0}0/a
+EXPECT "data-2" cat $B0/${V0}1/a
+EXPECT "data-2" cat $B0/${V0}2/a
+
+# Check there is no fd opened on the 1st brick by checking for the gfid inside
+# /proc/pid-of-brick/fd/ directory
+gfid_a=$(gf_get_gfid_xattr $B0/${V0}0/a)
+gfid_str_a=$(gf_gfid_xattr_to_str $gfid_a)
+
+EXPECT "N" gf_check_file_opened_in_brick $V0 $H0 $B0/${V0}0 $gfid_str_a
+EXPECT "Y" gf_check_file_opened_in_brick $V0 $H0 $B0/${V0}1 $gfid_str_a
+EXPECT "Y" gf_check_file_opened_in_brick $V0 $H0 $B0/${V0}2 $gfid_str_a
+
+TEST fd2=`fd_available`
+TEST fd_open $fd2 'rw' $M1/a
+
+# Kill 2nd brick and try writing to the file. The write should fail due to
+# quorum failure.
+TEST kill_brick $V0 $H0 $B0/${V0}1
+EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "0" afr_child_up_status_meta $M0 $V0-replicate-0 1
+TEST ! fd_write $fd1 "data-3"
+TEST ! fd_cat $fd1
+
+# Restart the bricks and try writing to the file. This should fail as two bricks
+# which were down previously, will return EBADFD now.
+TEST $CLI volume start $V0 force
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^1$" brick_up_status $V0 $H0 $B0/${V0}1
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status_meta $M0 $V0-replicate-0 1
+TEST ! fd_write $fd1 "data-4"
+TEST ! fd_cat $fd1
+
+# Enable heal and check the files will have same content on all the bricks after
+# the heal is completed.
+EXPECT_WITHIN $HEAL_TIMEOUT "^2$" get_pending_heal_count $V0
+TEST $CLI volume heal $V0 enable
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 2
+
+TEST $CLI volume heal $V0
+EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0
+EXPECT "data-4" cat $B0/${V0}0/a
+EXPECT "data-4" cat $B0/${V0}1/a
+EXPECT "data-4" cat $B0/${V0}2/a
+TEST $CLI volume heal $V0 disable
+
+# Try writing to the file again on the same fd, which should fail again, since
+# it is not yet re-opened.
+TEST ! fd_write $fd1 "data-5"
+
+# At this point only one brick will have the lock. Try taking the lock again on
+# the bad fd, which should also fail with EBADFD.
+TEST ! flock -x $fd1
+
+# Kill the only brick that is having lock and try taking lock on another client
+# which should succeed.
+TEST kill_brick $V0 $H0 $B0/${V0}2
+EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "0" afr_child_up_status_meta $M0 $V0-replicate-0 2
+TEST flock -x $fd2
+TEST fd_write $fd2 "data-6"
+
+# Bring the brick up and try writing & reading on the old fd, which should still
+# fail and operations on the 2nd fd should succeed.
+TEST $CLI volume start $V0 force
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^1$" brick_up_status $V0 $H0 $B0/${V0}2
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status_meta $M0 $V0-replicate-0 2
+TEST ! fd_write $fd1 "data-7"
+
+TEST ! fd_cat $fd1
+TEST fd_cat $fd2
+
+# Close both the fds which will release the locks and then re-open and take lock
+# on the old fd. Operations on that fd should succeed afterwards.
+TEST fd_close $fd1
+TEST fd_close $fd2
+
+TEST ! ls /proc/$$/fd/$fd1
+TEST ! ls /proc/$$/fd/$fd2
+EXPECT_WITHIN $REOPEN_TIMEOUT "N" gf_check_file_opened_in_brick $V0 $H0 $B0/${V0}0 $gfid_str_a
+EXPECT_WITHIN $REOPEN_TIMEOUT "N" gf_check_file_opened_in_brick $V0 $H0 $B0/${V0}1 $gfid_str_a
+EXPECT_WITHIN $REOPEN_TIMEOUT "N" gf_check_file_opened_in_brick $V0 $H0 $B0/${V0}2 $gfid_str_a
+
+TEST fd1=`fd_available`
+TEST fd_open $fd1 'rw' $M0/a
+EXPECT_WITHIN $REOPEN_TIMEOUT "Y" gf_check_file_opened_in_brick $V0 $H0 $B0/${V0}0 $gfid_str_a
+EXPECT_WITHIN $REOPEN_TIMEOUT "Y" gf_check_file_opened_in_brick $V0 $H0 $B0/${V0}1 $gfid_str_a
+EXPECT_WITHIN $REOPEN_TIMEOUT "Y" gf_check_file_opened_in_brick $V0 $H0 $B0/${V0}2 $gfid_str_a
+
+TEST flock -x $fd1
+TEST fd_write $fd1 "data-8"
+TEST fd_cat $fd1
+
+EXPECT "data-8" head -n 1 $B0/${V0}0/a
+EXPECT "data-8" head -n 1 $B0/${V0}1/a
+EXPECT "data-8" head -n 1 $B0/${V0}2/a
+
+TEST fd_close $fd1
+
+# Heal the volume
+TEST $CLI volume heal $V0 enable
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 2
+
+TEST $CLI volume heal $V0
+EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0
+TEST $CLI volume heal $V0 disable
+
+# Kill one brick and open a fd.
+TEST kill_brick $V0 $H0 $B0/${V0}0
+EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "0" afr_child_up_status_meta $M0 $V0-replicate-0 0
+TEST fd1=`fd_available`
+TEST fd_open $fd1 'rw' $M0/a
+
+EXPECT "N" gf_check_file_opened_in_brick $V0 $H0 $B0/${V0}0 $gfid_str_a
+EXPECT "Y" gf_check_file_opened_in_brick $V0 $H0 $B0/${V0}1 $gfid_str_a
+EXPECT "Y" gf_check_file_opened_in_brick $V0 $H0 $B0/${V0}2 $gfid_str_a
+
+# Restart the brick and then write. Now fd should get re-opened and write should
+# succeed on the previously down brick as well since there are no locks held on
+# any of the bricks.
+TEST $CLI volume start $V0 force
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^1$" brick_up_status $V0 $H0 $B0/${V0}0
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status_meta $M0 $V0-replicate-0 0
+TEST fd_write $fd1 "data-10"
+EXPECT "Y" gf_check_file_opened_in_brick $V0 $H0 $B0/${V0}0 $gfid_str_a
+
+EXPECT "data-10" head -n 1 $B0/${V0}0/a
+EXPECT "data-10" head -n 1 $B0/${V0}1/a
+EXPECT "data-10" head -n 1 $B0/${V0}2/a
+TEST fd_close $fd1
+
+# Kill one brick, open and take lock on a fd.
+TEST kill_brick $V0 $H0 $B0/${V0}0
+EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "0" afr_child_up_status_meta $M0 $V0-replicate-0 0
+TEST fd1=`fd_available`
+TEST fd_open $fd1 'rw' $M0/a
+TEST flock -x $fd1
+
+EXPECT "N" gf_check_file_opened_in_brick $V0 $H0 $B0/${V0}0 $gfid_str_a
+EXPECT "Y" gf_check_file_opened_in_brick $V0 $H0 $B0/${V0}1 $gfid_str_a
+EXPECT "Y" gf_check_file_opened_in_brick $V0 $H0 $B0/${V0}2 $gfid_str_a
+
+# Kill & restart another brick so that it will return EBADFD
+TEST kill_brick $V0 $H0 $B0/${V0}1
+EXPECT_WITHIN $PROCESS_DOWN_TIMEOUT "0" brick_up_status $V0 $H0 $B0/${V0}1
+
+# Restart the bricks and then write. Now fd should not get re-opened since lock
+# is still held on one brick and write should also fail as there is no quorum.
+
+TEST $CLI volume start $V0 force
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^1$" brick_up_status $V0 $H0 $B0/${V0}0
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "^1$" brick_up_status $V0 $H0 $B0/${V0}1
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status_meta $M0 $V0-replicate-0 0
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status_meta $M0 $V0-replicate-0 1
+TEST ! fd_write $fd1 "data-11"
+EXPECT "N" gf_check_file_opened_in_brick $V0 $H0 $B0/${V0}0 $gfid_str_a
+EXPECT "N" gf_check_file_opened_in_brick $V0 $H0 $B0/${V0}1 $gfid_str_a
+EXPECT "Y" gf_check_file_opened_in_brick $V0 $H0 $B0/${V0}2 $gfid_str_a
+
+EXPECT "data-10" head -n 1 $B0/${V0}0/a
+EXPECT "data-10" head -n 1 $B0/${V0}1/a
+EXPECT "data-11" head -n 1 $B0/${V0}2/a
+
+TEST fd_close $fd1
+cleanup
diff --git a/xlators/cluster/afr/src/afr-common.c b/xlators/cluster/afr/src/afr-common.c
index 416012c..bd46e59 100644
--- a/xlators/cluster/afr/src/afr-common.c
+++ b/xlators/cluster/afr/src/afr-common.c
@@ -2067,6 +2067,8 @@ afr_local_cleanup(afr_local_t *local, xlator_t *this)
             dict_unref(local->cont.entrylk.xdata);
     }
 
+    GF_FREE(local->need_open);
+
     if (local->xdata_req)
         dict_unref(local->xdata_req);
 
@@ -5689,6 +5691,14 @@ afr_local_init(afr_local_t *local, afr_private_t *priv, int32_t *op_errno)
     }
     local->is_new_entry = _gf_false;
 
+    local->need_open = GF_CALLOC(priv->child_count, sizeof(*local->need_open),
+                                 gf_afr_mt_char);
+    if (!local->need_open) {
+        if (op_errno)
+            *op_errno = ENOMEM;
+        goto out;
+    }
+
     INIT_LIST_HEAD(&local->healer);
     return 0;
 out:
@@ -6124,9 +6134,8 @@ afr_get_heal_info(call_frame_t *frame, xlator_t *this, loc_t *loc)
     char *substr = NULL;
     char *status = NULL;
 
-    ret = afr_lockless_inspect(frame, this, loc->gfid, &inode,
-                               &entry_selfheal, &data_selfheal,
-                               &metadata_selfheal, &pending);
+    ret = afr_lockless_inspect(frame, this, loc->gfid, &inode, &entry_selfheal,
+                               &data_selfheal, &metadata_selfheal, &pending);
 
     if (ret == -ENOMEM) {
         ret = -1;
diff --git a/xlators/cluster/afr/src/afr-open.c b/xlators/cluster/afr/src/afr-open.c
index ff72c73..73c1552 100644
--- a/xlators/cluster/afr/src/afr-open.c
+++ b/xlators/cluster/afr/src/afr-open.c
@@ -35,6 +35,8 @@
 #include "afr-dir-read.h"
 #include "afr-dir-write.h"
 #include "afr-transaction.h"
+#include "afr-self-heal.h"
+#include "protocol-common.h"
 
 gf_boolean_t
 afr_is_fd_fixable(fd_t *fd)
@@ -239,8 +241,32 @@ afr_openfd_fix_open_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
     return 0;
 }
 
+static void
+afr_fd_ctx_reset_need_open(fd_t *fd, xlator_t *this, unsigned char *need_open)
+{
+    afr_fd_ctx_t *fd_ctx = NULL;
+    afr_private_t *priv = NULL;
+    int i = 0;
+
+    priv = this->private;
+    fd_ctx = afr_fd_ctx_get(fd, this);
+    if (!fd_ctx)
+        return;
+
+    LOCK(&fd->lock);
+    {
+        for (i = 0; i < priv->child_count; i++) {
+            if (fd_ctx->opened_on[i] == AFR_FD_OPENING && need_open[i]) {
+                fd_ctx->opened_on[i] = AFR_FD_NOT_OPENED;
+                need_open[i] = 0;
+            }
+        }
+    }
+    UNLOCK(&fd->lock);
+}
+
 static int
-afr_fd_ctx_need_open(fd_t *fd, xlator_t *this, unsigned char *need_open)
+afr_fd_ctx_set_need_open(fd_t *fd, xlator_t *this, unsigned char *need_open)
 {
     afr_fd_ctx_t *fd_ctx = NULL;
     afr_private_t *priv = NULL;
@@ -248,7 +274,6 @@ afr_fd_ctx_need_open(fd_t *fd, xlator_t *this, unsigned char *need_open)
     int count = 0;
 
     priv = this->private;
-
     fd_ctx = afr_fd_ctx_get(fd, this);
     if (!fd_ctx)
         return 0;
@@ -271,21 +296,217 @@ afr_fd_ctx_need_open(fd_t *fd, xlator_t *this, unsigned char *need_open)
     return count;
 }
 
+static int
+afr_do_fix_open(call_frame_t *frame, xlator_t *this)
+{
+    afr_local_t *local = frame->local;
+    afr_private_t *priv = NULL;
+    int i = 0;
+    int need_open_count = 0;
+
+    priv = this->private;
+
+    need_open_count = AFR_COUNT(local->need_open, priv->child_count);
+    if (!need_open_count) {
+        goto out;
+    }
+    gf_msg_debug(this->name, 0, "need open count: %d", need_open_count);
+    local->call_count = need_open_count;
+
+    for (i = 0; i < priv->child_count; i++) {
+        if (!local->need_open[i])
+            continue;
+
+        if (IA_IFDIR == local->fd->inode->ia_type) {
+            gf_msg_debug(this->name, 0, "opening fd for dir %s on subvolume %s",
+                         local->loc.path, priv->children[i]->name);
+            STACK_WIND_COOKIE(frame, afr_openfd_fix_open_cbk, (void *)(long)i,
+                              priv->children[i],
+                              priv->children[i]->fops->opendir, &local->loc,
+                              local->fd, NULL);
+        } else {
+            gf_msg_debug(this->name, 0,
+                         "opening fd for file %s on subvolume %s",
+                         local->loc.path, priv->children[i]->name);
+
+            STACK_WIND_COOKIE(
+                frame, afr_openfd_fix_open_cbk, (void *)(long)i,
+                priv->children[i], priv->children[i]->fops->open, &local->loc,
+                local->fd_ctx->flags & ~(O_CREAT | O_EXCL | O_TRUNC), local->fd,
+                NULL);
+        }
+        if (!--need_open_count)
+            break;
+    }
+    return 0;
+
+out:
+    afr_fd_ctx_reset_need_open(local->fd, this, local->need_open);
+    AFR_STACK_DESTROY(frame);
+    return 0;
+}
+
+static int
+afr_is_reopen_allowed_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
+                          int32_t op_ret, int32_t op_errno,
+                          struct gf_flock *lock, dict_t *xdata)
+{
+    afr_local_t *local = frame->local;
+    afr_private_t *priv = NULL;
+    int ret = -1;
+    int call_count = 0;
+    int i = (long)cookie;
+    int32_t fd_reopen_status = -1;
+    int32_t final_reopen_status = -1;
+
+    priv = this->private;
+    local->replies[i].valid = 1;
+    local->replies[i].op_ret = op_ret;
+    local->replies[i].op_errno = op_errno;
+    if (op_ret != 0) {
+        gf_msg(this->name, GF_LOG_ERROR, op_errno, AFR_MSG_DICT_GET_FAILED,
+               "Failed getlk for %s", uuid_utoa(local->fd->inode->gfid));
+    }
+
+    if (xdata)
+        local->replies[i].xdata = dict_ref(xdata);
+
+    call_count = afr_frame_return(frame);
+
+    if (call_count)
+        return 0;
+
+    /* Currently we get 3 values from the lower layer (protocol/client) in the
+     * getlk_cbk.
+     *  FD_REOPEN_ALLOWED : No conflicting locks are held and reopen is allowed
+     *  FD_REOPEN_NOT_ALLOWED : Conflicting locks are held and reopen is not
+     *                          allowed
+     *  FD_BAD : FD is not valid
+     *
+     * - If we get FD_REOPEN_NOT_ALLOWED from any of the bricks, will block the
+     *   reopen taking this as high priority.
+     * - If we get FD_BAD from all the replies, we will not reopen since we do
+     *   not know the correct status.
+     * - If we get FD_BAD from few brick and FD_REOPEN_NOT_ALLOWED from one or
+     *   more bricks, then we will block reopen.
+     * - If we get FD_BAD from few bricks and FD_REOPEN_ALLOWED from one or
+     *   more bricks, then we will allow the reopen.
+     *
+     *   We will update the final_reopen_status only when the value returned
+     *   from lower layer is >= FD_REOPEN_ALLOWED and < FD_BAD. We will not set
+     *   FD_BAD in final_reopen_status, since it can lead to unexpected
+     *   behaviours.
+     *
+     *   At the end of this loop, if we still have final_reopen_status as -1
+     *   i.e., the init value, it means we failed to get the fd status from any
+     *   of the bricks or we do not have a valid fd on any of the bricks. We
+     *   will not reopen the fd in this case as well.
+     */
+
+    for (i = 0; i < priv->child_count; i++) {
+        if (final_reopen_status != FD_REOPEN_NOT_ALLOWED &&
+            local->replies[i].xdata) {
+            ret = dict_get_int32(xdata, "fd-reopen-status", &fd_reopen_status);
+            if (ret) {
+                gf_msg(this->name, GF_LOG_ERROR, -ret, AFR_MSG_DICT_GET_FAILED,
+                       "Failed to get whether reopen is allowed or not on fd "
+                       "for file %s on subvolume %s.",
+                       local->loc.path, priv->children[i]->name);
+            } else if (fd_reopen_status >= FD_REOPEN_ALLOWED &&
+                       fd_reopen_status < FD_BAD) {
+                final_reopen_status = fd_reopen_status;
+            }
+        }
+
+        if (final_reopen_status == FD_REOPEN_NOT_ALLOWED)
+            break;
+    }
+
+    if (final_reopen_status == FD_REOPEN_NOT_ALLOWED) {
+        gf_log(this->name, GF_LOG_INFO,
+               "Conflicting locks held on file %s. FD reopen is not allowed.",
+               local->loc.path);
+    } else if (final_reopen_status == -1) {
+        gf_log(this->name, GF_LOG_INFO,
+               "Failed to get the lock information "
+               "on file %s. FD reopen is not allowed.",
+               local->loc.path);
+    } else {
+        afr_local_replies_wipe(local, priv);
+        afr_do_fix_open(frame, this);
+        return 0;
+    }
+
+    afr_fd_ctx_reset_need_open(local->fd, this, local->need_open);
+    AFR_STACK_DESTROY(frame);
+    return 0;
+}
+
 void
-afr_fix_open(fd_t *fd, xlator_t *this)
+afr_is_reopen_allowed(xlator_t *this, call_frame_t *frame)
 {
     afr_private_t *priv = NULL;
+    afr_local_t *local = NULL;
+    dict_t *xdata = NULL;
     int i = 0;
+    int call_count = 0;
+    struct gf_flock flock = {
+        0,
+    };
+
+    local = frame->local;
+    priv = this->private;
+
+    flock.l_type = F_WRLCK;
+    afr_set_lk_owner(frame, this, frame->root);
+    lk_owner_copy(&flock.l_owner, &frame->root->lk_owner);
+
+    call_count = AFR_COUNT(local->child_up, priv->child_count);
+    if (!call_count)
+        goto out;
+    local->call_count = call_count;
+
+    xdata = dict_new();
+    if (xdata == NULL)
+        goto out;
+
+    if (dict_set_int32(xdata, "fd-reopen-status", -1))
+        goto out;
+
+    for (i = 0; i < priv->child_count; i++) {
+        if (local->child_up[i]) {
+            STACK_WIND_COOKIE(frame, afr_is_reopen_allowed_cbk, (void *)(long)i,
+                              priv->children[i], priv->children[i]->fops->lk,
+                              local->fd, F_GETLK, &flock, xdata);
+        } else {
+            continue;
+        }
+
+        if (!--call_count)
+            break;
+    }
+
+    dict_unref(xdata);
+    return;
+
+out:
+    if (xdata)
+        dict_unref(xdata);
+    afr_fd_ctx_reset_need_open(local->fd, this, local->need_open);
+    AFR_STACK_DESTROY(frame);
+    return;
+}
+
+void
+afr_fix_open(fd_t *fd, xlator_t *this)
+{
     call_frame_t *frame = NULL;
     afr_local_t *local = NULL;
     int ret = -1;
     int32_t op_errno = 0;
     afr_fd_ctx_t *fd_ctx = NULL;
-    unsigned char *need_open = NULL;
     int call_count = 0;
 
-    priv = this->private;
-
     if (!afr_is_fd_fixable(fd))
         goto out;
 
@@ -293,12 +514,6 @@ afr_fix_open(fd_t *fd, xlator_t *this)
     if (!fd_ctx)
         goto out;
 
-    need_open = alloca0(priv->child_count);
-
-    call_count = afr_fd_ctx_need_open(fd, this, need_open);
-    if (!call_count)
-        goto out;
-
     frame = create_frame(this, this->ctx->pool);
     if (!frame)
         goto out;
@@ -307,47 +522,24 @@ afr_fix_open(fd_t *fd, xlator_t *this)
     if (!local)
         goto out;
 
+    call_count = afr_fd_ctx_set_need_open(fd, this, local->need_open);
+    if (!call_count)
+        goto out;
+
     local->loc.inode = inode_ref(fd->inode);
     ret = loc_path(&local->loc, NULL);
     if (ret < 0)
         goto out;
-
     local->fd = fd_ref(fd);
     local->fd_ctx = fd_ctx;
 
-    local->call_count = call_count;
-
-    gf_msg_debug(this->name, 0, "need open count: %d", call_count);
-
-    for (i = 0; i < priv->child_count; i++) {
-        if (!need_open[i])
-            continue;
-
-        if (IA_IFDIR == fd->inode->ia_type) {
-            gf_msg_debug(this->name, 0, "opening fd for dir %s on subvolume %s",
-                         local->loc.path, priv->children[i]->name);
-
-            STACK_WIND_COOKIE(frame, afr_openfd_fix_open_cbk, (void *)(long)i,
-                              priv->children[i],
-                              priv->children[i]->fops->opendir, &local->loc,
-                              local->fd, NULL);
-        } else {
-            gf_msg_debug(this->name, 0,
-                         "opening fd for file %s on subvolume %s",
-                         local->loc.path, priv->children[i]->name);
-
-            STACK_WIND_COOKIE(frame, afr_openfd_fix_open_cbk, (void *)(long)i,
-                              priv->children[i], priv->children[i]->fops->open,
-                              &local->loc, fd_ctx->flags & (~O_TRUNC),
-                              local->fd, NULL);
-        }
-
-        if (!--call_count)
-            break;
-    }
-
+    afr_is_reopen_allowed(this, frame);
     return;
+
 out:
+    if (call_count)
+        afr_fd_ctx_reset_need_open(fd, this, local->need_open);
     if (frame)
         AFR_STACK_DESTROY(frame);
+    return;
 }
diff --git a/xlators/cluster/afr/src/afr.h b/xlators/cluster/afr/src/afr.h
index 6a9a763..ffc7317 100644
--- a/xlators/cluster/afr/src/afr.h
+++ b/xlators/cluster/afr/src/afr.h
@@ -895,6 +895,9 @@ typedef struct _afr_local {
     afr_ta_fop_state_t fop_state;
     int ta_failed_subvol;
     gf_boolean_t is_new_entry;
+
+    /* For fix_open */
+    unsigned char *need_open;
 } afr_local_t;
 
 typedef struct afr_spbc_timeout {
diff --git a/xlators/protocol/client/src/client-common.c b/xlators/protocol/client/src/client-common.c
index 1417a60..92cda12 100644
--- a/xlators/protocol/client/src/client-common.c
+++ b/xlators/protocol/client/src/client-common.c
@@ -343,7 +343,7 @@ client_pre_readv(xlator_t *this, gfs3_read_req *req, fd_t *fd, size_t size,
     int op_errno = ESTALE;
 
     CLIENT_GET_REMOTE_FD(this, fd, FALLBACK_TO_ANON_FD, remote_fd, op_errno,
-                         out);
+                         GFS3_OP_READ, out);
 
     req->size = size;
     req->offset = offset;
@@ -368,7 +368,7 @@ client_pre_writev(xlator_t *this, gfs3_write_req *req, fd_t *fd, size_t size,
     int op_errno = ESTALE;
 
     CLIENT_GET_REMOTE_FD(this, fd, FALLBACK_TO_ANON_FD, remote_fd, op_errno,
-                         out);
+                         GFS3_OP_WRITE, out);
 
     req->size = size;
     req->offset = offset;
@@ -429,7 +429,8 @@ client_pre_flush(xlator_t *this, gfs3_flush_req *req, fd_t *fd, dict_t *xdata)
     int64_t remote_fd = -1;
     int op_errno = ESTALE;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_FLUSH, out);
 
     req->fd = remote_fd;
     memcpy(req->gfid, fd->inode->gfid, 16);
@@ -450,7 +451,7 @@ client_pre_fsync(xlator_t *this, gfs3_fsync_req *req, fd_t *fd, int32_t flags,
     int op_errno = 0;
 
     CLIENT_GET_REMOTE_FD(this, fd, FALLBACK_TO_ANON_FD, remote_fd, op_errno,
-                         out);
+                         GFS3_OP_FSYNC, out);
 
     req->fd = remote_fd;
     req->data = flags;
@@ -591,7 +592,8 @@ client_pre_fsyncdir(xlator_t *this, gfs3_fsyncdir_req *req, fd_t *fd,
     int32_t op_errno = ESTALE;
     int64_t remote_fd = -1;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_FSYNCDIR, out);
 
     req->fd = remote_fd;
     req->data = flags;
@@ -668,7 +670,8 @@ client_pre_ftruncate(xlator_t *this, gfs3_ftruncate_req *req, fd_t *fd,
     int64_t remote_fd = -1;
     int op_errno = EINVAL;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_FTRUNCATE, out);
 
     req->offset = offset;
     req->fd = remote_fd;
@@ -687,7 +690,8 @@ client_pre_fstat(xlator_t *this, gfs3_fstat_req *req, fd_t *fd, dict_t *xdata)
     int64_t remote_fd = -1;
     int op_errno = ESTALE;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_FSTAT, out);
 
     req->fd = remote_fd;
     memcpy(req->gfid, fd->inode->gfid, 16);
@@ -710,7 +714,8 @@ client_pre_lk(xlator_t *this, gfs3_lk_req *req, int32_t cmd,
     int32_t gf_type = 0;
     int ret = 0;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_LK, out);
 
     ret = client_cmd_to_gf_cmd(cmd, &gf_cmd);
     if (ret) {
@@ -787,7 +792,8 @@ client_pre_readdir(xlator_t *this, gfs3_readdir_req *req, fd_t *fd, size_t size,
     int64_t remote_fd = -1;
     int op_errno = ESTALE;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_READDIR, out);
 
     req->size = size;
     req->offset = offset;
@@ -869,7 +875,7 @@ client_pre_finodelk(xlator_t *this, gfs3_finodelk_req *req, fd_t *fd, int cmd,
     int32_t gf_cmd = 0;
 
     CLIENT_GET_REMOTE_FD(this, fd, FALLBACK_TO_ANON_FD, remote_fd, op_errno,
-                         out);
+                         GFS3_OP_FINODELK, out);
 
     if (cmd == F_GETLK || cmd == F_GETLK64)
         gf_cmd = GF_LK_GETLK;
@@ -952,7 +958,8 @@ client_pre_fentrylk(xlator_t *this, gfs3_fentrylk_req *req, fd_t *fd,
     int64_t remote_fd = -1;
     int op_errno = ESTALE;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_FENTRYLK, out);
 
     req->fd = remote_fd;
     req->cmd = cmd_entrylk;
@@ -1013,7 +1020,7 @@ client_pre_fxattrop(xlator_t *this, gfs3_fxattrop_req *req, fd_t *fd,
     int64_t remote_fd = -1;
 
     CLIENT_GET_REMOTE_FD(this, fd, FALLBACK_TO_ANON_FD, remote_fd, op_errno,
-                         out);
+                         GFS3_OP_FXATTROP, out);
 
     req->fd = remote_fd;
     req->flags = flags;
@@ -1039,7 +1046,8 @@ client_pre_fgetxattr(xlator_t *this, gfs3_fgetxattr_req *req, fd_t *fd,
     int64_t remote_fd = -1;
     int op_errno = ESTALE;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_FGETXATTR, out);
 
     req->namelen = 1; /* Use it as a flag */
     req->fd = remote_fd;
@@ -1065,7 +1073,8 @@ client_pre_fsetxattr(xlator_t *this, gfs3_fsetxattr_req *req, fd_t *fd,
     int64_t remote_fd = -1;
     int op_errno = ESTALE;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_FSETXATTR, out);
 
     req->fd = remote_fd;
     req->flags = flags;
@@ -1091,7 +1100,8 @@ client_pre_rchecksum(xlator_t *this, gfs3_rchecksum_req *req, fd_t *fd,
     int64_t remote_fd = -1;
     int op_errno = ESTALE;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_RCHECKSUM, out);
 
     req->len = len;
     req->offset = offset;
@@ -1141,7 +1151,8 @@ client_pre_fsetattr(xlator_t *this, gfs3_fsetattr_req *req, fd_t *fd,
     int op_errno = ESTALE;
     int64_t remote_fd = -1;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_FSETATTR, out);
 
     req->fd = remote_fd;
     req->valid = valid;
@@ -1161,7 +1172,8 @@ client_pre_readdirp(xlator_t *this, gfs3_readdirp_req *req, fd_t *fd,
     int op_errno = ESTALE;
     int64_t remote_fd = -1;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_READDIRP, out);
 
     req->size = size;
     req->offset = offset;
@@ -1187,7 +1199,8 @@ client_pre_fremovexattr(xlator_t *this, gfs3_fremovexattr_req *req, fd_t *fd,
     if (!(fd && fd->inode))
         goto out;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_FREMOVEXATTR, out);
 
     memcpy(req->gfid, fd->inode->gfid, 16);
     req->name = (char *)name;
@@ -1208,7 +1221,8 @@ client_pre_fallocate(xlator_t *this, gfs3_fallocate_req *req, fd_t *fd,
     int op_errno = ESTALE;
     int64_t remote_fd = -1;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_FALLOCATE, out);
 
     req->fd = remote_fd;
     req->flags = flags;
@@ -1230,7 +1244,8 @@ client_pre_discard(xlator_t *this, gfs3_discard_req *req, fd_t *fd,
     int op_errno = ESTALE;
     int64_t remote_fd = -1;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_DISCARD, out);
 
     req->fd = remote_fd;
     req->offset = offset;
@@ -1251,7 +1266,8 @@ client_pre_zerofill(xlator_t *this, gfs3_zerofill_req *req, fd_t *fd,
     int op_errno = ESTALE;
     int64_t remote_fd = -1;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_ZEROFILL, out);
 
     req->fd = remote_fd;
     req->offset = offset;
@@ -1286,7 +1302,8 @@ client_pre_seek(xlator_t *this, gfs3_seek_req *req, fd_t *fd, off_t offset,
     int64_t remote_fd = -1;
     int op_errno = ESTALE;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_SEEK, out);
 
     memcpy(req->gfid, fd->inode->gfid, 16);
     req->fd = remote_fd;
@@ -2508,7 +2525,7 @@ client_pre_readv_v2(xlator_t *this, gfx_read_req *req, fd_t *fd, size_t size,
     int op_errno = ESTALE;
 
     CLIENT_GET_REMOTE_FD(this, fd, FALLBACK_TO_ANON_FD, remote_fd, op_errno,
-                         out);
+                         GFS3_OP_READ, out);
 
     req->size = size;
     req->offset = offset;
@@ -2532,7 +2549,7 @@ client_pre_writev_v2(xlator_t *this, gfx_write_req *req, fd_t *fd, size_t size,
     int op_errno = ESTALE;
 
     CLIENT_GET_REMOTE_FD(this, fd, FALLBACK_TO_ANON_FD, remote_fd, op_errno,
-                         out);
+                         GFS3_OP_WRITE, out);
 
     req->size = size;
     req->offset = offset;
@@ -2567,10 +2584,10 @@ client_pre_copy_file_range_v2(xlator_t *this, gfx_copy_file_range_req *req,
     int op_errno = ESTALE;
 
     CLIENT_GET_REMOTE_FD(this, fd_in, FALLBACK_TO_ANON_FD, remote_fd_in,
-                         op_errno, out);
+                         op_errno, GFS3_OP_COPY_FILE_RANGE, out);
 
     CLIENT_GET_REMOTE_FD(this, fd_out, FALLBACK_TO_ANON_FD, remote_fd_out,
-                         op_errno, out);
+                         op_errno, GFS3_OP_COPY_FILE_RANGE, out);
     req->size = size;
     req->off_in = off_in;
     req->off_out = off_out;
@@ -2623,7 +2640,8 @@ client_pre_flush_v2(xlator_t *this, gfx_flush_req *req, fd_t *fd, dict_t *xdata)
     int64_t remote_fd = -1;
     int op_errno = ESTALE;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_FLUSH, out);
 
     req->fd = remote_fd;
     memcpy(req->gfid, fd->inode->gfid, 16);
@@ -2643,7 +2661,7 @@ client_pre_fsync_v2(xlator_t *this, gfx_fsync_req *req, fd_t *fd, int32_t flags,
     int op_errno = 0;
 
     CLIENT_GET_REMOTE_FD(this, fd, FALLBACK_TO_ANON_FD, remote_fd, op_errno,
-                         out);
+                         GFS3_OP_FSYNC, out);
 
     req->fd = remote_fd;
     req->data = flags;
@@ -2778,7 +2796,8 @@ client_pre_fsyncdir_v2(xlator_t *this, gfx_fsyncdir_req *req, fd_t *fd,
     int32_t op_errno = ESTALE;
     int64_t remote_fd = -1;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_FSYNCDIR, out);
 
     req->fd = remote_fd;
     req->data = flags;
@@ -2852,7 +2871,8 @@ client_pre_ftruncate_v2(xlator_t *this, gfx_ftruncate_req *req, fd_t *fd,
     int64_t remote_fd = -1;
     int op_errno = EINVAL;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_FTRUNCATE, out);
 
     req->offset = offset;
     req->fd = remote_fd;
@@ -2870,7 +2890,8 @@ client_pre_fstat_v2(xlator_t *this, gfx_fstat_req *req, fd_t *fd, dict_t *xdata)
     int64_t remote_fd = -1;
     int op_errno = ESTALE;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_FSTAT, out);
 
     req->fd = remote_fd;
     memcpy(req->gfid, fd->inode->gfid, 16);
@@ -2892,7 +2913,8 @@ client_pre_lk_v2(xlator_t *this, gfx_lk_req *req, int32_t cmd,
     int32_t gf_type = 0;
     int ret = 0;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_LK, out);
 
     ret = client_cmd_to_gf_cmd(cmd, &gf_cmd);
     if (ret) {
@@ -2967,7 +2989,8 @@ client_pre_readdir_v2(xlator_t *this, gfx_readdir_req *req, fd_t *fd,
     int64_t remote_fd = -1;
     int op_errno = ESTALE;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_READDIR, out);
 
     req->size = size;
     req->offset = offset;
@@ -3048,7 +3071,7 @@ client_pre_finodelk_v2(xlator_t *this, gfx_finodelk_req *req, fd_t *fd, int cmd,
     int32_t gf_cmd = 0;
 
     CLIENT_GET_REMOTE_FD(this, fd, FALLBACK_TO_ANON_FD, remote_fd, op_errno,
-                         out);
+                         GFS3_OP_FINODELK, out);
 
     if (cmd == F_GETLK || cmd == F_GETLK64)
         gf_cmd = GF_LK_GETLK;
@@ -3129,7 +3152,8 @@ client_pre_fentrylk_v2(xlator_t *this, gfx_fentrylk_req *req, fd_t *fd,
     int64_t remote_fd = -1;
     int op_errno = ESTALE;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_FENTRYLK, out);
 
     req->fd = remote_fd;
     req->cmd = cmd_entrylk;
@@ -3185,7 +3209,7 @@ client_pre_fxattrop_v2(xlator_t *this, gfx_fxattrop_req *req, fd_t *fd,
     int64_t remote_fd = -1;
 
     CLIENT_GET_REMOTE_FD(this, fd, FALLBACK_TO_ANON_FD, remote_fd, op_errno,
-                         out);
+                         GFS3_OP_FXATTROP, out);
 
     req->fd = remote_fd;
     req->flags = flags;
@@ -3207,7 +3231,8 @@ client_pre_fgetxattr_v2(xlator_t *this, gfx_fgetxattr_req *req, fd_t *fd,
     int64_t remote_fd = -1;
     int op_errno = ESTALE;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_FGETXATTR, out);
 
     req->namelen = 1; /* Use it as a flag */
     req->fd = remote_fd;
@@ -3232,7 +3257,8 @@ client_pre_fsetxattr_v2(xlator_t *this, gfx_fsetxattr_req *req, fd_t *fd,
     int64_t remote_fd = -1;
     int op_errno = ESTALE;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_FSETXATTR, out);
 
     req->fd = remote_fd;
     req->flags = flags;
@@ -3256,7 +3282,8 @@ client_pre_rchecksum_v2(xlator_t *this, gfx_rchecksum_req *req, fd_t *fd,
     int64_t remote_fd = -1;
     int op_errno = ESTALE;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_RCHECKSUM, out);
 
     req->len = len;
     req->offset = offset;
@@ -3304,7 +3331,8 @@ client_pre_fsetattr_v2(xlator_t *this, gfx_fsetattr_req *req, fd_t *fd,
     int op_errno = ESTALE;
     int64_t remote_fd = -1;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_FSETATTR, out);
 
     memcpy(req->gfid, fd->inode->gfid, 16);
     req->fd = remote_fd;
@@ -3324,7 +3352,8 @@ client_pre_readdirp_v2(xlator_t *this, gfx_readdirp_req *req, fd_t *fd,
     int op_errno = ESTALE;
     int64_t remote_fd = -1;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_READDIRP, out);
 
     req->size = size;
     req->offset = offset;
@@ -3349,7 +3378,8 @@ client_pre_fremovexattr_v2(xlator_t *this, gfx_fremovexattr_req *req, fd_t *fd,
     if (!(fd && fd->inode))
         goto out;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_FREMOVEXATTR, out);
 
     memcpy(req->gfid, fd->inode->gfid, 16);
     req->name = (char *)name;
@@ -3369,7 +3399,8 @@ client_pre_fallocate_v2(xlator_t *this, gfx_fallocate_req *req, fd_t *fd,
     int op_errno = ESTALE;
     int64_t remote_fd = -1;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_FALLOCATE, out);
 
     req->fd = remote_fd;
     req->flags = flags;
@@ -3390,7 +3421,8 @@ client_pre_discard_v2(xlator_t *this, gfx_discard_req *req, fd_t *fd,
     int op_errno = ESTALE;
     int64_t remote_fd = -1;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_DISCARD, out);
 
     req->fd = remote_fd;
     req->offset = offset;
@@ -3410,7 +3442,8 @@ client_pre_zerofill_v2(xlator_t *this, gfx_zerofill_req *req, fd_t *fd,
     int op_errno = ESTALE;
     int64_t remote_fd = -1;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_ZEROFILL, out);
 
     req->fd = remote_fd;
     req->offset = offset;
@@ -3439,7 +3472,8 @@ client_pre_seek_v2(xlator_t *this, gfx_seek_req *req, fd_t *fd, off_t offset,
     int64_t remote_fd = -1;
     int op_errno = ESTALE;
 
-    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno, out);
+    CLIENT_GET_REMOTE_FD(this, fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
+                         GFS3_OP_SEEK, out);
 
     memcpy(req->gfid, fd->inode->gfid, 16);
     req->fd = remote_fd;
@@ -3587,3 +3621,25 @@ client_post_rename_v2(xlator_t *this, gfx_rename_rsp *rsp, struct iatt *stbuf,
 
     return xdr_to_dict(&rsp->xdata, xdata);
 }
+
+void
+set_fd_reopen_status(xlator_t *this, dict_t *xdata,
+                     enum gf_fd_reopen_status fd_reopen_status)
+{
+    clnt_conf_t *conf = NULL;
+
+    conf = this->private;
+    if (!conf) {
+        gf_msg_debug(this->name, ENOMEM, "Failed to get client conf");
+        return;
+    }
+
+    if (!conf->strict_locks)
+        fd_reopen_status = FD_REOPEN_ALLOWED;
+
+    if (dict_set_int32(xdata, "fd-reopen-status", fd_reopen_status))
+        gf_msg(this->name, GF_LOG_WARNING, ENOMEM, PC_MSG_DICT_SET_FAILED,
+               NULL);
+
+    return;
+}
diff --git a/xlators/protocol/client/src/client-common.h b/xlators/protocol/client/src/client-common.h
index a2043d8..16fb167 100644
--- a/xlators/protocol/client/src/client-common.h
+++ b/xlators/protocol/client/src/client-common.h
@@ -627,4 +627,8 @@ client_pre_copy_file_range_v2(xlator_t *this, gfx_copy_file_range_req *req,
                               off64_t off_out, size_t size, int32_t flags,
                               dict_t **xdata);
 
+void
+set_fd_reopen_status(xlator_t *this, dict_t *xdata,
+                     enum gf_fd_reopen_status fd_reopen_allowed);
+
 #endif /* __CLIENT_COMMON_H__ */
diff --git a/xlators/protocol/client/src/client-helpers.c b/xlators/protocol/client/src/client-helpers.c
index 6543100..48b6448 100644
--- a/xlators/protocol/client/src/client-helpers.c
+++ b/xlators/protocol/client/src/client-helpers.c
@@ -406,11 +406,12 @@ clnt_readdir_rsp_cleanup_v2(gfx_readdir_rsp *rsp)
 }
 
 int
-client_get_remote_fd(xlator_t *this, fd_t *fd, int flags, int64_t *remote_fd)
+client_get_remote_fd(xlator_t *this, fd_t *fd, int flags, int64_t *remote_fd,
+                     enum gf_fop_procnum fop)
 {
     clnt_fd_ctx_t *fdctx = NULL;
     clnt_conf_t *conf = NULL;
-    gf_boolean_t locks_held = _gf_false;
+    gf_boolean_t locks_involved = _gf_false;
 
     GF_VALIDATE_OR_GOTO(this->name, fd, out);
     GF_VALIDATE_OR_GOTO(this->name, remote_fd, out);
@@ -423,23 +424,32 @@ client_get_remote_fd(xlator_t *this, fd_t *fd, int flags, int64_t *remote_fd)
             if (fd->anonymous) {
                 *remote_fd = GF_ANON_FD_NO;
             } else {
+                if (conf->strict_locks &&
+                    (fop == GFS3_OP_WRITE || fop == GFS3_OP_FTRUNCATE ||
+                     fop == GFS3_OP_FALLOCATE || fop == GFS3_OP_ZEROFILL ||
+                     fop == GFS3_OP_DISCARD)) {
+                    locks_involved = _gf_true;
+                }
                 *remote_fd = -1;
                 gf_msg_debug(this->name, EBADF, "not a valid fd for gfid: %s",
                              uuid_utoa(fd->inode->gfid));
             }
         } else {
-            if (__is_fd_reopen_in_progress(fdctx))
+            if (__is_fd_reopen_in_progress(fdctx)) {
                 *remote_fd = -1;
-            else
+            } else {
                 *remote_fd = fdctx->remote_fd;
+            }
 
-            locks_held = !list_empty(&fdctx->lock_list);
+            locks_involved = !list_empty(&fdctx->lock_list);
         }
     }
     pthread_spin_unlock(&conf->fd_lock);
 
-    if ((flags & FALLBACK_TO_ANON_FD) && (*remote_fd == -1) && (!locks_held))
+    if ((flags & FALLBACK_TO_ANON_FD) && (*remote_fd == -1) &&
+        (!locks_involved)) {
         *remote_fd = GF_ANON_FD_NO;
+    }
 
     return 0;
 out:
diff --git a/xlators/protocol/client/src/client-rpc-fops.c b/xlators/protocol/client/src/client-rpc-fops.c
index 3110c78..46ac544 100644
--- a/xlators/protocol/client/src/client-rpc-fops.c
+++ b/xlators/protocol/client/src/client-rpc-fops.c
@@ -2439,6 +2439,13 @@ client3_3_lk_cbk(struct rpc_req *req, struct iovec *iov, int count,
         }
     }
 
+    if (local->check_reopen) {
+        if (lock.l_type == F_WRLCK)
+            set_fd_reopen_status(this, xdata, FD_REOPEN_NOT_ALLOWED);
+        else
+            set_fd_reopen_status(this, xdata, FD_REOPEN_ALLOWED);
+    }
+
 out:
     if ((rsp.op_ret == -1) && (EAGAIN != gf_error_to_errno(rsp.op_errno))) {
         gf_msg(this->name, GF_LOG_WARNING, gf_error_to_errno(rsp.op_errno),
@@ -5198,6 +5205,7 @@ client3_3_lk(call_frame_t *frame, xlator_t *this, void *data)
             0,
         },
     };
+    dict_t *xdata = NULL;
     int32_t gf_cmd = 0;
     clnt_local_t *local = NULL;
     clnt_conf_t *conf = NULL;
@@ -5224,6 +5232,10 @@ client3_3_lk(call_frame_t *frame, xlator_t *this, void *data)
         goto unwind;
     }
 
+    ret = dict_get_int32(args->xdata, "fd-reopen-status", &local->check_reopen);
+    if (ret)
+        local->check_reopen = 0;
+
     local->owner = frame->root->lk_owner;
     local->cmd = args->cmd;
     local->fd = fd_ref(args->fd);
@@ -5237,6 +5249,13 @@ client3_3_lk(call_frame_t *frame, xlator_t *this, void *data)
             client_is_setlk(local->cmd)) {
             client_add_lock_for_recovery(local->fd, args->flock, &local->owner,
                                          local->cmd);
+        } else if (local->check_reopen) {
+            xdata = dict_new();
+            if (xdata == NULL) {
+                op_errno = ENOMEM;
+                goto unwind;
+            }
+            set_fd_reopen_status(this, xdata, FD_BAD);
         }
 
         goto unwind;
@@ -5254,8 +5273,10 @@ client3_3_lk(call_frame_t *frame, xlator_t *this, void *data)
 
     return 0;
 unwind:
-    CLIENT_STACK_UNWIND(lk, frame, -1, op_errno, NULL, NULL);
+    CLIENT_STACK_UNWIND(lk, frame, -1, op_errno, NULL, xdata);
     GF_FREE(req.xdata.xdata_val);
+    if (xdata)
+        dict_unref(xdata);
 
     return 0;
 }
diff --git a/xlators/protocol/client/src/client-rpc-fops_v2.c b/xlators/protocol/client/src/client-rpc-fops_v2.c
index 954fc58..d0055e9 100644
--- a/xlators/protocol/client/src/client-rpc-fops_v2.c
+++ b/xlators/protocol/client/src/client-rpc-fops_v2.c
@@ -2234,6 +2234,13 @@ client4_0_lk_cbk(struct rpc_req *req, struct iovec *iov, int count,
         }
     }
 
+    if (local->check_reopen) {
+        if (lock.l_type == F_WRLCK)
+            set_fd_reopen_status(this, xdata, FD_REOPEN_NOT_ALLOWED);
+        else
+            set_fd_reopen_status(this, xdata, FD_REOPEN_ALLOWED);
+    }
+
 out:
     if ((rsp.op_ret == -1) && (EAGAIN != gf_error_to_errno(rsp.op_errno))) {
         gf_msg(this->name, GF_LOG_WARNING, gf_error_to_errno(rsp.op_errno),
@@ -4759,6 +4766,7 @@ client4_0_lk(call_frame_t *frame, xlator_t *this, void *data)
             0,
         },
     };
+    dict_t *xdata = NULL;
     int32_t gf_cmd = 0;
     clnt_local_t *local = NULL;
     clnt_conf_t *conf = NULL;
@@ -4785,6 +4793,10 @@ client4_0_lk(call_frame_t *frame, xlator_t *this, void *data)
         goto unwind;
     }
 
+    ret = dict_get_int32(args->xdata, "fd-reopen-status", &local->check_reopen);
+    if (ret)
+        local->check_reopen = 0;
+
     local->owner = frame->root->lk_owner;
     local->cmd = args->cmd;
     local->fd = fd_ref(args->fd);
@@ -4798,6 +4810,13 @@ client4_0_lk(call_frame_t *frame, xlator_t *this, void *data)
             client_is_setlk(local->cmd)) {
             client_add_lock_for_recovery(local->fd, args->flock, &local->owner,
                                          local->cmd);
+        } else if (local->check_reopen) {
+            xdata = dict_new();
+            if (xdata == NULL) {
+                op_errno = ENOMEM;
+                goto unwind;
+            }
+            set_fd_reopen_status(this, xdata, FD_BAD);
         }
 
         goto unwind;
@@ -4815,8 +4834,10 @@ client4_0_lk(call_frame_t *frame, xlator_t *this, void *data)
 
     return 0;
 unwind:
-    CLIENT_STACK_UNWIND(lk, frame, -1, op_errno, NULL, NULL);
+    CLIENT_STACK_UNWIND(lk, frame, -1, op_errno, NULL, xdata);
     GF_FREE(req.xdata.pairs.pairs_val);
+    if (xdata)
+        dict_unref(xdata);
 
     return 0;
 }
@@ -6094,7 +6115,7 @@ client4_0_rchecksum(call_frame_t *frame, xlator_t *this, void *data)
     conf = this->private;
 
     CLIENT_GET_REMOTE_FD(this, args->fd, DEFAULT_REMOTE_FD, remote_fd, op_errno,
-                         unwind);
+                         GFS3_OP_RCHECKSUM, unwind);
 
     req.len = args->len;
     req.offset = args->offset;
diff --git a/xlators/protocol/client/src/client.c b/xlators/protocol/client/src/client.c
index 63c90ea..35a5340 100644
--- a/xlators/protocol/client/src/client.c
+++ b/xlators/protocol/client/src/client.c
@@ -864,9 +864,11 @@ int32_t
 client_open(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags,
             fd_t *fd, dict_t *xdata)
 {
-    int ret = -1;
+    int ret = 0;
+    int op_errno = ENOTCONN;
     clnt_conf_t *conf = NULL;
     rpc_clnt_procedure_t *proc = NULL;
+    clnt_fd_ctx_t *fdctx = NULL;
     clnt_args_t args = {
         0,
     };
@@ -875,6 +877,21 @@ client_open(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags,
     if (!conf || !conf->fops)
         goto out;
 
+    if (conf->strict_locks) {
+        pthread_spin_lock(&conf->fd_lock);
+        {
+            fdctx = this_fd_get_ctx(fd, this);
+            if (fdctx && !list_empty(&fdctx->lock_list)) {
+                ret = -1;
+                op_errno = EBADFD;
+            }
+        }
+        pthread_spin_unlock(&conf->fd_lock);
+
+        if (ret)
+            goto out;
+    }
+
     args.loc = loc;
     args.fd = fd;
     args.xdata = xdata;
@@ -888,7 +905,7 @@ client_open(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags,
 
 out:
     if (ret)
-        STACK_UNWIND_STRICT(open, frame, -1, ENOTCONN, NULL, NULL);
+        STACK_UNWIND_STRICT(open, frame, -1, op_errno, NULL, NULL);
 
     return 0;
 }
diff --git a/xlators/protocol/client/src/client.h b/xlators/protocol/client/src/client.h
index bde3d1a..2a50625 100644
--- a/xlators/protocol/client/src/client.h
+++ b/xlators/protocol/client/src/client.h
@@ -98,10 +98,10 @@ typedef enum {
         free(_this_rsp->xdata.xdata_val);                                      \
     } while (0)
 
-#define CLIENT_GET_REMOTE_FD(xl, fd, flags, remote_fd, op_errno, label)        \
+#define CLIENT_GET_REMOTE_FD(xl, fd, flags, remote_fd, op_errno, fop, label)   \
     do {                                                                       \
         int _ret = 0;                                                          \
-        _ret = client_get_remote_fd(xl, fd, flags, &remote_fd);                \
+        _ret = client_get_remote_fd(xl, fd, flags, &remote_fd, fop);           \
         if (_ret < 0) {                                                        \
             op_errno = errno;                                                  \
             goto label;                                                        \
@@ -286,6 +286,7 @@ typedef struct client_local {
     client_posix_lock_t *client_lock;
     gf_lkowner_t owner;
     int32_t cmd;
+    int32_t check_reopen;
     struct list_head lock_list;
     pthread_mutex_t mutex;
     char *name;
@@ -435,7 +436,8 @@ client_default_reopen_done(clnt_fd_ctx_t *fdctx, int64_t rfd, xlator_t *this);
 void
 client_attempt_reopen(fd_t *fd, xlator_t *this);
 int
-client_get_remote_fd(xlator_t *this, fd_t *fd, int flags, int64_t *remote_fd);
+client_get_remote_fd(xlator_t *this, fd_t *fd, int flags, int64_t *remote_fd,
+                     enum gf_fop_procnum fop);
 int
 client_fd_fop_prepare_local(call_frame_t *frame, fd_t *fd, int64_t remote_fd);
 gf_boolean_t
-- 
1.8.3.1