9ae3f9
From ba23e6d8f4eff11a228816149a8a1ccd6df41146 Mon Sep 17 00:00:00 2001
9ae3f9
From: Susant Palai <spalai@redhat.com>
9ae3f9
Date: Fri, 27 Dec 2019 12:06:19 +0530
9ae3f9
Subject: [PATCH 415/449] dht: Fix stale-layout and create issue
9ae3f9
9ae3f9
Problem: With lookup-optimize set to on by default, a client with
9ae3f9
stale-layout can create a new file on a wrong subvol. This will lead to
9ae3f9
possible duplicate files if two different clients attempt to create the
9ae3f9
same file with two different layouts.
9ae3f9
9ae3f9
Solution: Send in-memory layout to be cross checked at posix before
9ae3f9
commiting a "create". In case of a mismatch, sync the client layout with
9ae3f9
that of the server and attempt the create fop one more time.
9ae3f9
9ae3f9
test: Manual, testcase(attached)
9ae3f9
9ae3f9
(Backport of https://review.gluster.org/#/c/glusterfs/+/23927/)
9ae3f9
9ae3f9
BUG: 1748865
9ae3f9
Change-Id: I6c82c97418654ae8eb3b81ab65f1247aa4002ceb
9ae3f9
Signed-off-by: Susant Palai <spalai@redhat.com>
9ae3f9
Reviewed-on: https://code.engineering.redhat.com/gerrit/202465
9ae3f9
Tested-by: RHGS Build Bot <nigelb@redhat.com>
9ae3f9
Reviewed-by: Mohit Agrawal <moagrawa@redhat.com>
9ae3f9
Reviewed-by: Sunil Kumar Heggodu Gopala Acharya <sheggodu@redhat.com>
9ae3f9
---
9ae3f9
 tests/bugs/distribute/bug-1786679.t              |  69 +++++++++++
9ae3f9
 xlators/cluster/dht/src/dht-common.c             | 147 ++++++++++++++++++++---
9ae3f9
 xlators/cluster/dht/src/dht-common.h             |   6 +
9ae3f9
 xlators/protocol/client/src/client-rpc-fops_v2.c |   9 +-
9ae3f9
 xlators/storage/posix/src/posix-entry-ops.c      |  29 ++++-
9ae3f9
 xlators/storage/posix/src/posix-helpers.c        |  76 ++++++++++++
9ae3f9
 xlators/storage/posix/src/posix.h                |   4 +
9ae3f9
 7 files changed, 321 insertions(+), 19 deletions(-)
9ae3f9
 create mode 100755 tests/bugs/distribute/bug-1786679.t
9ae3f9
9ae3f9
diff --git a/tests/bugs/distribute/bug-1786679.t b/tests/bugs/distribute/bug-1786679.t
9ae3f9
new file mode 100755
9ae3f9
index 0000000..219ce51
9ae3f9
--- /dev/null
9ae3f9
+++ b/tests/bugs/distribute/bug-1786679.t
9ae3f9
@@ -0,0 +1,69 @@
9ae3f9
+#!/bin/bash
9ae3f9
+
9ae3f9
+SCRIPT_TIMEOUT=250
9ae3f9
+
9ae3f9
+. $(dirname $0)/../../include.rc
9ae3f9
+. $(dirname $0)/../../volume.rc
9ae3f9
+. $(dirname $0)/../../dht.rc
9ae3f9
+
9ae3f9
+
9ae3f9
+# create 2 subvols
9ae3f9
+# create a dir
9ae3f9
+# create a file
9ae3f9
+# change layout
9ae3f9
+# remove the file
9ae3f9
+# execute create from a different mount
9ae3f9
+# Without the patch, the file will be present on both of the bricks
9ae3f9
+
9ae3f9
+cleanup
9ae3f9
+
9ae3f9
+function get_layout () {
9ae3f9
+
9ae3f9
+layout=`getfattr -n trusted.glusterfs.dht -e hex $1 2>&1 | grep dht | gawk -F"=" '{print $2}'`
9ae3f9
+
9ae3f9
+echo $layout
9ae3f9
+
9ae3f9
+}
9ae3f9
+
9ae3f9
+function set_layout()
9ae3f9
+{
9ae3f9
+    setfattr -n  "trusted.glusterfs.dht" -v $1 $2
9ae3f9
+}
9ae3f9
+
9ae3f9
+TEST glusterd
9ae3f9
+TEST pidof glusterd
9ae3f9
+
9ae3f9
+BRICK1=$B0/${V0}-0
9ae3f9
+BRICK2=$B0/${V0}-1
9ae3f9
+
9ae3f9
+TEST $CLI volume create $V0 $H0:$BRICK1 $H0:$BRICK2
9ae3f9
+TEST $CLI volume start $V0
9ae3f9
+
9ae3f9
+# Mount FUSE and create symlink
9ae3f9
+TEST glusterfs -s $H0 --volfile-id $V0 $M0
9ae3f9
+TEST mkdir $M0/dir
9ae3f9
+TEST touch $M0/dir/file
9ae3f9
+TEST ! stat "$BRICK1/dir/file"
9ae3f9
+TEST stat "$BRICK2/dir/file"
9ae3f9
+
9ae3f9
+layout1="$(get_layout "$BRICK1/dir")"
9ae3f9
+layout2="$(get_layout "$BRICK2/dir")"
9ae3f9
+
9ae3f9
+TEST set_layout $layout1 "$BRICK2/dir"
9ae3f9
+TEST set_layout $layout2 "$BRICK1/dir"
9ae3f9
+
9ae3f9
+TEST rm $M0/dir/file -f
9ae3f9
+TEST gluster v set $V0 client-log-level DEBUG
9ae3f9
+
9ae3f9
+#Without the patch in place, this client will create the file in $BRICK2
9ae3f9
+#which will lead to two files being on both the bricks when a new client
9ae3f9
+#create the file with the same name
9ae3f9
+TEST touch $M0/dir/file
9ae3f9
+
9ae3f9
+TEST glusterfs -s $H0 --volfile-id $V0 $M1
9ae3f9
+TEST touch $M1/dir/file
9ae3f9
+
9ae3f9
+TEST stat "$BRICK1/dir/file"
9ae3f9
+TEST ! stat "$BRICK2/dir/file"
9ae3f9
+
9ae3f9
+cleanup
9ae3f9
diff --git a/xlators/cluster/dht/src/dht-common.c b/xlators/cluster/dht/src/dht-common.c
9ae3f9
index 7890e7a..6aa18f3 100644
9ae3f9
--- a/xlators/cluster/dht/src/dht-common.c
9ae3f9
+++ b/xlators/cluster/dht/src/dht-common.c
9ae3f9
@@ -8262,6 +8262,11 @@ dht_create_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int op_ret,
9ae3f9
     xlator_t *prev = NULL;
9ae3f9
     int ret = -1;
9ae3f9
     dht_local_t *local = NULL;
9ae3f9
+    gf_boolean_t parent_layout_changed = _gf_false;
9ae3f9
+    char pgfid[GF_UUID_BUF_SIZE] = {0};
9ae3f9
+    xlator_t *subvol = NULL;
9ae3f9
+
9ae3f9
+    local = frame->local;
9ae3f9
 
9ae3f9
     local = frame->local;
9ae3f9
     if (!local) {
9ae3f9
@@ -8270,8 +8275,69 @@ dht_create_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int op_ret,
9ae3f9
         goto out;
9ae3f9
     }
9ae3f9
 
9ae3f9
-    if (op_ret == -1)
9ae3f9
+    if (op_ret == -1) {
9ae3f9
+        local->op_errno = op_errno;
9ae3f9
+        parent_layout_changed = (xdata &&
9ae3f9
+                                 dict_get(xdata, GF_PREOP_CHECK_FAILED))
9ae3f9
+                                    ? _gf_true
9ae3f9
+                                    : _gf_false;
9ae3f9
+
9ae3f9
+        if (parent_layout_changed) {
9ae3f9
+            if (local && local->lock[0].layout.parent_layout.locks) {
9ae3f9
+                /* Returning failure as the layout could not be fixed even under
9ae3f9
+                 * the lock */
9ae3f9
+                goto out;
9ae3f9
+            }
9ae3f9
+
9ae3f9
+            gf_uuid_unparse(local->loc.parent->gfid, pgfid);
9ae3f9
+            gf_msg(this->name, GF_LOG_INFO, 0, DHT_MSG_PARENT_LAYOUT_CHANGED,
9ae3f9
+                   "create (%s/%s) (path: %s): parent layout "
9ae3f9
+                   "changed. Attempting a layout refresh and then a "
9ae3f9
+                   "retry",
9ae3f9
+                   pgfid, local->loc.name, local->loc.path);
9ae3f9
+
9ae3f9
+            /*
9ae3f9
+              dht_refresh_layout needs directory info in local->loc.Hence,
9ae3f9
+              storing the parent_loc in local->loc and storing the create
9ae3f9
+              context in local->loc2. We will restore this information in
9ae3f9
+              dht_creation_do.
9ae3f9
+             */
9ae3f9
+
9ae3f9
+            loc_wipe(&local->loc2);
9ae3f9
+
9ae3f9
+            ret = loc_copy(&local->loc2, &local->loc);
9ae3f9
+            if (ret) {
9ae3f9
+                gf_msg(this->name, GF_LOG_ERROR, ENOMEM, DHT_MSG_NO_MEMORY,
9ae3f9
+                       "loc_copy failed %s", local->loc.path);
9ae3f9
+
9ae3f9
+                goto out;
9ae3f9
+            }
9ae3f9
+
9ae3f9
+            loc_wipe(&local->loc);
9ae3f9
+
9ae3f9
+            ret = dht_build_parent_loc(this, &local->loc, &local->loc2,
9ae3f9
+                                       &op_errno);
9ae3f9
+
9ae3f9
+            if (ret) {
9ae3f9
+                gf_msg(this->name, GF_LOG_ERROR, ENOMEM, DHT_MSG_LOC_FAILED,
9ae3f9
+                       "parent loc build failed");
9ae3f9
+                goto out;
9ae3f9
+            }
9ae3f9
+
9ae3f9
+            subvol = dht_subvol_get_hashed(this, &local->loc2);
9ae3f9
+
9ae3f9
+            ret = dht_create_lock(frame, subvol);
9ae3f9
+            if (ret < 0) {
9ae3f9
+                gf_msg(this->name, GF_LOG_ERROR, 0, DHT_MSG_INODE_LK_ERROR,
9ae3f9
+                       "locking parent failed");
9ae3f9
+                goto out;
9ae3f9
+            }
9ae3f9
+
9ae3f9
+            return 0;
9ae3f9
+        }
9ae3f9
+
9ae3f9
         goto out;
9ae3f9
+    }
9ae3f9
 
9ae3f9
     prev = cookie;
9ae3f9
 
9ae3f9
@@ -8392,6 +8458,8 @@ dht_create_wind_to_avail_subvol(call_frame_t *frame, xlator_t *this,
9ae3f9
         gf_msg_debug(this->name, 0, "creating %s on %s", loc->path,
9ae3f9
                      subvol->name);
9ae3f9
 
9ae3f9
+        dht_set_parent_layout_in_dict(loc, this, local);
9ae3f9
+
9ae3f9
         STACK_WIND_COOKIE(frame, dht_create_cbk, subvol, subvol,
9ae3f9
                           subvol->fops->create, loc, flags, mode, umask, fd,
9ae3f9
                           params);
9ae3f9
@@ -8400,10 +8468,6 @@ dht_create_wind_to_avail_subvol(call_frame_t *frame, xlator_t *this,
9ae3f9
         avail_subvol = dht_free_disk_available_subvol(this, subvol, local);
9ae3f9
 
9ae3f9
         if (avail_subvol != subvol) {
9ae3f9
-            local->params = dict_ref(params);
9ae3f9
-            local->flags = flags;
9ae3f9
-            local->mode = mode;
9ae3f9
-            local->umask = umask;
9ae3f9
             local->cached_subvol = avail_subvol;
9ae3f9
             local->hashed_subvol = subvol;
9ae3f9
 
9ae3f9
@@ -8419,6 +8483,8 @@ dht_create_wind_to_avail_subvol(call_frame_t *frame, xlator_t *this,
9ae3f9
         gf_msg_debug(this->name, 0, "creating %s on %s", loc->path,
9ae3f9
                      subvol->name);
9ae3f9
 
9ae3f9
+        dht_set_parent_layout_in_dict(loc, this, local);
9ae3f9
+
9ae3f9
         STACK_WIND_COOKIE(frame, dht_create_cbk, subvol, subvol,
9ae3f9
                           subvol->fops->create, loc, flags, mode, umask, fd,
9ae3f9
                           params);
9ae3f9
@@ -8680,6 +8746,60 @@ err:
9ae3f9
 }
9ae3f9
 
9ae3f9
 int
9ae3f9
+dht_set_parent_layout_in_dict(loc_t *loc, xlator_t *this, dht_local_t *local)
9ae3f9
+{
9ae3f9
+    dht_conf_t *conf = this->private;
9ae3f9
+    dht_layout_t *parent_layout = NULL;
9ae3f9
+    int *parent_disk_layout = NULL;
9ae3f9
+    xlator_t *hashed_subvol = NULL;
9ae3f9
+    char pgfid[GF_UUID_BUF_SIZE] = {0};
9ae3f9
+    int ret = 0;
9ae3f9
+
9ae3f9
+    gf_uuid_unparse(loc->parent->gfid, pgfid);
9ae3f9
+
9ae3f9
+    parent_layout = dht_layout_get(this, loc->parent);
9ae3f9
+    hashed_subvol = dht_subvol_get_hashed(this, loc);
9ae3f9
+
9ae3f9
+    ret = dht_disk_layout_extract_for_subvol(this, parent_layout, hashed_subvol,
9ae3f9
+                                             &parent_disk_layout);
9ae3f9
+    if (ret == -1) {
9ae3f9
+        gf_msg(this->name, GF_LOG_WARNING, local->op_errno,
9ae3f9
+               DHT_MSG_PARENT_LAYOUT_CHANGED,
9ae3f9
+               "%s (%s/%s) (path: %s): "
9ae3f9
+               "extracting in-memory layout of parent failed. ",
9ae3f9
+               gf_fop_list[local->fop], pgfid, loc->name, loc->path);
9ae3f9
+        goto err;
9ae3f9
+    }
9ae3f9
+
9ae3f9
+    ret = dict_set_str_sizen(local->params, GF_PREOP_PARENT_KEY,
9ae3f9
+                             conf->xattr_name);
9ae3f9
+    if (ret < 0) {
9ae3f9
+        gf_msg(this->name, GF_LOG_WARNING, local->op_errno,
9ae3f9
+               DHT_MSG_PARENT_LAYOUT_CHANGED,
9ae3f9
+               "%s (%s/%s) (path: %s): "
9ae3f9
+               "setting %s key in params dictionary failed. ",
9ae3f9
+               gf_fop_list[local->fop], pgfid, loc->name, loc->path,
9ae3f9
+               GF_PREOP_PARENT_KEY);
9ae3f9
+        goto err;
9ae3f9
+    }
9ae3f9
+
9ae3f9
+    ret = dict_set_bin(local->params, conf->xattr_name, parent_disk_layout,
9ae3f9
+                       4 * 4);
9ae3f9
+    if (ret < 0) {
9ae3f9
+        gf_msg(this->name, GF_LOG_WARNING, local->op_errno,
9ae3f9
+               DHT_MSG_PARENT_LAYOUT_CHANGED,
9ae3f9
+               "%s (%s/%s) (path: %s): "
9ae3f9
+               "setting parent-layout in params dictionary failed. ",
9ae3f9
+               gf_fop_list[local->fop], pgfid, loc->name, loc->path);
9ae3f9
+        goto err;
9ae3f9
+    }
9ae3f9
+
9ae3f9
+err:
9ae3f9
+    dht_layout_unref(this, parent_layout);
9ae3f9
+    return ret;
9ae3f9
+}
9ae3f9
+
9ae3f9
+int
9ae3f9
 dht_create(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags,
9ae3f9
            mode_t mode, mode_t umask, fd_t *fd, dict_t *params)
9ae3f9
 {
9ae3f9
@@ -8705,6 +8825,11 @@ dht_create(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags,
9ae3f9
         goto err;
9ae3f9
     }
9ae3f9
 
9ae3f9
+    local->params = dict_ref(params);
9ae3f9
+    local->flags = flags;
9ae3f9
+    local->mode = mode;
9ae3f9
+    local->umask = umask;
9ae3f9
+
9ae3f9
     if (dht_filter_loc_subvol_key(this, loc, &local->loc, &subvol)) {
9ae3f9
         gf_msg(this->name, GF_LOG_INFO, 0, DHT_MSG_SUBVOL_INFO,
9ae3f9
                "creating %s on %s (got create on %s)", local->loc.path,
9ae3f9
@@ -8720,10 +8845,6 @@ dht_create(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags,
9ae3f9
 
9ae3f9
         if (hashed_subvol && (hashed_subvol != subvol)) {
9ae3f9
             /* Create the linkto file and then the data file */
9ae3f9
-            local->params = dict_ref(params);
9ae3f9
-            local->flags = flags;
9ae3f9
-            local->mode = mode;
9ae3f9
-            local->umask = umask;
9ae3f9
             local->cached_subvol = subvol;
9ae3f9
             local->hashed_subvol = hashed_subvol;
9ae3f9
 
9ae3f9
@@ -8736,6 +8857,9 @@ dht_create(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags,
9ae3f9
          * file as we expect a lookup everywhere if there are problems
9ae3f9
          * with the parent layout
9ae3f9
          */
9ae3f9
+
9ae3f9
+        dht_set_parent_layout_in_dict(loc, this, local);
9ae3f9
+
9ae3f9
         STACK_WIND_COOKIE(frame, dht_create_cbk, subvol, subvol,
9ae3f9
                           subvol->fops->create, &local->loc, flags, mode, umask,
9ae3f9
                           fd, params);
9ae3f9
@@ -8787,11 +8911,6 @@ dht_create(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags,
9ae3f9
                     goto err;
9ae3f9
                 }
9ae3f9
 
9ae3f9
-                local->params = dict_ref(params);
9ae3f9
-                local->flags = flags;
9ae3f9
-                local->mode = mode;
9ae3f9
-                local->umask = umask;
9ae3f9
-
9ae3f9
                 loc_wipe(&local->loc);
9ae3f9
 
9ae3f9
                 ret = dht_build_parent_loc(this, &local->loc, loc, &op_errno);
9ae3f9
diff --git a/xlators/cluster/dht/src/dht-common.h b/xlators/cluster/dht/src/dht-common.h
9ae3f9
index 8e65111..1b3e826 100644
9ae3f9
--- a/xlators/cluster/dht/src/dht-common.h
9ae3f9
+++ b/xlators/cluster/dht/src/dht-common.h
9ae3f9
@@ -1549,4 +1549,10 @@ dht_check_remote_fd_failed_error(dht_local_t *local, int op_ret, int op_errno);
9ae3f9
 int
9ae3f9
 dht_dir_layout_error_check(xlator_t *this, inode_t *inode);
9ae3f9
 
9ae3f9
+int32_t
9ae3f9
+dht_create_lock(call_frame_t *frame, xlator_t *subvol);
9ae3f9
+
9ae3f9
+int
9ae3f9
+dht_set_parent_layout_in_dict(loc_t *loc, xlator_t *this, dht_local_t *local);
9ae3f9
+
9ae3f9
 #endif /* _DHT_H */
9ae3f9
diff --git a/xlators/protocol/client/src/client-rpc-fops_v2.c b/xlators/protocol/client/src/client-rpc-fops_v2.c
9ae3f9
index 2673b6e..613dda8 100644
9ae3f9
--- a/xlators/protocol/client/src/client-rpc-fops_v2.c
9ae3f9
+++ b/xlators/protocol/client/src/client-rpc-fops_v2.c
9ae3f9
@@ -2094,11 +2094,12 @@ client4_0_create_cbk(struct rpc_req *req, struct iovec *iov, int count,
9ae3f9
         goto out;
9ae3f9
     }
9ae3f9
 
9ae3f9
+    ret = client_post_create_v2(this, &rsp, &stbuf, &preparent, &postparent,
9ae3f9
+                                local, &xdata);
9ae3f9
+    if (ret < 0)
9ae3f9
+        goto out;
9ae3f9
+
9ae3f9
     if (-1 != rsp.op_ret) {
9ae3f9
-        ret = client_post_create_v2(this, &rsp, &stbuf, &preparent, &postparent,
9ae3f9
-                                    local, &xdata);
9ae3f9
-        if (ret < 0)
9ae3f9
-            goto out;
9ae3f9
         ret = client_add_fd_to_saved_fds(frame->this, fd, &local->loc,
9ae3f9
                                          local->flags, rsp.fd, 0);
9ae3f9
         if (ret) {
9ae3f9
diff --git a/xlators/storage/posix/src/posix-entry-ops.c b/xlators/storage/posix/src/posix-entry-ops.c
9ae3f9
index bea0bbf..65650b3 100644
9ae3f9
--- a/xlators/storage/posix/src/posix-entry-ops.c
9ae3f9
+++ b/xlators/storage/posix/src/posix-entry-ops.c
9ae3f9
@@ -2070,6 +2070,8 @@ posix_create(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags,
9ae3f9
     gf_boolean_t entry_created = _gf_false, gfid_set = _gf_false;
9ae3f9
     mode_t mode_bit = 0;
9ae3f9
 
9ae3f9
+    dict_t *xdata_rsp = dict_ref(xdata);
9ae3f9
+
9ae3f9
     DECLARE_OLD_FS_ID_VAR;
9ae3f9
 
9ae3f9
     VALIDATE_OR_GOTO(frame, out);
9ae3f9
@@ -2118,6 +2120,28 @@ posix_create(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags,
9ae3f9
         was_present = 0;
9ae3f9
     }
9ae3f9
 
9ae3f9
+    if (!was_present) {
9ae3f9
+        if (posix_is_layout_stale(xdata, par_path, this)) {
9ae3f9
+            op_ret = -1;
9ae3f9
+            op_errno = EIO;
9ae3f9
+            if (!xdata_rsp) {
9ae3f9
+                xdata_rsp = dict_new();
9ae3f9
+                if (!xdata_rsp) {
9ae3f9
+                    op_errno = ENOMEM;
9ae3f9
+                    goto out;
9ae3f9
+                }
9ae3f9
+            }
9ae3f9
+
9ae3f9
+            if (dict_set_int32_sizen(xdata_rsp, GF_PREOP_CHECK_FAILED, 1) ==
9ae3f9
+                -1) {
9ae3f9
+                gf_msg(this->name, GF_LOG_ERROR, errno, P_MSG_DICT_SET_FAILED,
9ae3f9
+                       "setting key %s in dict failed", GF_PREOP_CHECK_FAILED);
9ae3f9
+            }
9ae3f9
+
9ae3f9
+            goto out;
9ae3f9
+        }
9ae3f9
+    }
9ae3f9
+
9ae3f9
     if (priv->o_direct)
9ae3f9
         _flags |= O_DIRECT;
9ae3f9
 
9ae3f9
@@ -2239,7 +2263,10 @@ out:
9ae3f9
 
9ae3f9
     STACK_UNWIND_STRICT(create, frame, op_ret, op_errno, fd,
9ae3f9
                         (loc) ? loc->inode : NULL, &stbuf, &preparent,
9ae3f9
-                        &postparent, xdata);
9ae3f9
+                        &postparent, xdata_rsp);
9ae3f9
+
9ae3f9
+    if (xdata_rsp)
9ae3f9
+        dict_unref(xdata_rsp);
9ae3f9
 
9ae3f9
     return 0;
9ae3f9
 }
9ae3f9
diff --git a/xlators/storage/posix/src/posix-helpers.c b/xlators/storage/posix/src/posix-helpers.c
9ae3f9
index 35dd3b6..2c27d22 100644
9ae3f9
--- a/xlators/storage/posix/src/posix-helpers.c
9ae3f9
+++ b/xlators/storage/posix/src/posix-helpers.c
9ae3f9
@@ -3559,3 +3559,79 @@ posix_update_iatt_buf(struct iatt *buf, int fd, char *loc, dict_t *xattr_req)
9ae3f9
         }
9ae3f9
     }
9ae3f9
 }
9ae3f9
+
9ae3f9
+gf_boolean_t
9ae3f9
+posix_is_layout_stale(dict_t *xdata, char *par_path, xlator_t *this)
9ae3f9
+{
9ae3f9
+    int op_ret = 0;
9ae3f9
+    ssize_t size = 0;
9ae3f9
+    char value_buf[4096] = {
9ae3f9
+        0,
9ae3f9
+    };
9ae3f9
+    gf_boolean_t have_val = _gf_false;
9ae3f9
+    data_t *arg_data = NULL;
9ae3f9
+    char *xattr_name = NULL;
9ae3f9
+    gf_boolean_t is_stale = _gf_false;
9ae3f9
+
9ae3f9
+    op_ret = dict_get_str_sizen(xdata, GF_PREOP_PARENT_KEY, &xattr_name);
9ae3f9
+    if (xattr_name == NULL) {
9ae3f9
+        op_ret = 0;
9ae3f9
+        goto out;
9ae3f9
+    }
9ae3f9
+
9ae3f9
+    arg_data = dict_get(xdata, xattr_name);
9ae3f9
+    if (!arg_data) {
9ae3f9
+        op_ret = 0;
9ae3f9
+        goto out;
9ae3f9
+    }
9ae3f9
+
9ae3f9
+    size = sys_lgetxattr(par_path, xattr_name, value_buf,
9ae3f9
+                         sizeof(value_buf) - 1);
9ae3f9
+
9ae3f9
+    if (size >= 0) {
9ae3f9
+        have_val = _gf_true;
9ae3f9
+    } else {
9ae3f9
+        if (errno == ERANGE) {
9ae3f9
+            gf_msg(this->name, GF_LOG_INFO, errno, P_MSG_PREOP_CHECK_FAILED,
9ae3f9
+                   "getxattr on key (%s) path (%s) failed due to"
9ae3f9
+                   " buffer overflow",
9ae3f9
+                   xattr_name, par_path);
9ae3f9
+            size = sys_lgetxattr(par_path, xattr_name, NULL, 0);
9ae3f9
+        }
9ae3f9
+        if (size < 0) {
9ae3f9
+            op_ret = -1;
9ae3f9
+            gf_msg(this->name, GF_LOG_ERROR, errno, P_MSG_PREOP_CHECK_FAILED,
9ae3f9
+                   "getxattr on key (%s)  failed, path : %s", xattr_name,
9ae3f9
+                   par_path);
9ae3f9
+            goto out;
9ae3f9
+        }
9ae3f9
+    }
9ae3f9
+
9ae3f9
+    if (!have_val) {
9ae3f9
+        size = sys_lgetxattr(par_path, xattr_name, value_buf, size);
9ae3f9
+        if (size < 0) {
9ae3f9
+            gf_msg(this->name, GF_LOG_ERROR, errno, P_MSG_PREOP_CHECK_FAILED,
9ae3f9
+                   "getxattr on key (%s) failed (%s)", xattr_name,
9ae3f9
+                   strerror(errno));
9ae3f9
+            goto out;
9ae3f9
+        }
9ae3f9
+    }
9ae3f9
+
9ae3f9
+    if ((arg_data->len != size) || (memcmp(arg_data->data, value_buf, size))) {
9ae3f9
+        gf_msg(this->name, GF_LOG_INFO, EIO, P_MSG_PREOP_CHECK_FAILED,
9ae3f9
+               "failing preop as on-disk xattr value differs from argument "
9ae3f9
+               "value for key %s",
9ae3f9
+               xattr_name);
9ae3f9
+        op_ret = -1;
9ae3f9
+    }
9ae3f9
+
9ae3f9
+out:
9ae3f9
+    dict_del_sizen(xdata, xattr_name);
9ae3f9
+    dict_del_sizen(xdata, GF_PREOP_PARENT_KEY);
9ae3f9
+
9ae3f9
+    if (op_ret == -1) {
9ae3f9
+        is_stale = _gf_true;
9ae3f9
+    }
9ae3f9
+
9ae3f9
+    return is_stale;
9ae3f9
+}
9ae3f9
diff --git a/xlators/storage/posix/src/posix.h b/xlators/storage/posix/src/posix.h
9ae3f9
index dd51062..ac9d83c 100644
9ae3f9
--- a/xlators/storage/posix/src/posix.h
9ae3f9
+++ b/xlators/storage/posix/src/posix.h
9ae3f9
@@ -671,4 +671,8 @@ posix_spawn_ctx_janitor_thread(xlator_t *this);
9ae3f9
 
9ae3f9
 void
9ae3f9
 posix_update_iatt_buf(struct iatt *buf, int fd, char *loc, dict_t *xdata);
9ae3f9
+
9ae3f9
+gf_boolean_t
9ae3f9
+posix_is_layout_stale(dict_t *xdata, char *par_path, xlator_t *this);
9ae3f9
+
9ae3f9
 #endif /* _POSIX_H */
9ae3f9
-- 
9ae3f9
1.8.3.1
9ae3f9