21ab4e
From b3b78fa20f8e186d9bba8082814247ebee902f96 Mon Sep 17 00:00:00 2001
21ab4e
From: Susant Palai <spalai@redhat.com>
21ab4e
Date: Wed, 11 Jan 2017 16:04:47 +0530
21ab4e
Subject: [PATCH 419/426] dht: send lookup on old name inside rename with bname
21ab4e
 and pargfid
21ab4e
21ab4e
Inside rename, a lookup is done on the source name to make sure that
21ab4e
the file is there. But we used to do a gfid based lookup and hence,
21ab4e
even if the source name was renamed to a new name from some other client,
21ab4e
lookup will be successful as server3_3_lookup will fetch the new path
21ab4e
based on the gfid.
21ab4e
21ab4e
So even if the source file does not exist any more rename will carry on,
21ab4e
and as server3_3_link(destination is hashed to a different brick other
21ab4e
than source cached scenario) also does gfid based resolve, it wont
21ab4e
detect that the source name does not exist and hardlink creation will be
21ab4e
successful (since gfid based resolve will get the new dentry).
21ab4e
21ab4e
To solve this problem, do a name based lookup inside rename. So that
21ab4e
rename will fail right away if the source does not exist.
21ab4e
21ab4e
>Reviewed-on: https://review.gluster.org/16375
21ab4e
>Smoke: Gluster Build System <jenkins@build.gluster.org>
21ab4e
>NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org>
21ab4e
>Reviewed-by: N Balachandran <nbalacha@redhat.com>
21ab4e
>CentOS-regression: Gluster Build System <jenkins@build.gluster.org>
21ab4e
21ab4e
Change-Id: Ieba8bdd6675088dbf18de90ed4622df043d163bd
21ab4e
BUG: 1411352
21ab4e
Signed-off-by: Susant Palai <spalai@redhat.com>
21ab4e
Reviewed-on: https://code.engineering.redhat.com/gerrit/104688
21ab4e
Tested-by: Atin Mukherjee <amukherj@redhat.com>
21ab4e
Reviewed-by: Nithya Balachandran <nbalacha@redhat.com>
21ab4e
---
21ab4e
 libglusterfs/src/xlator.c            |  6 +++-
21ab4e
 xlators/cluster/dht/src/dht-rename.c | 64 +++++++++++++++++++++++++++++++-----
21ab4e
 2 files changed, 61 insertions(+), 9 deletions(-)
21ab4e
21ab4e
diff --git a/libglusterfs/src/xlator.c b/libglusterfs/src/xlator.c
21ab4e
index 6775efc..6e3ff51 100644
21ab4e
--- a/libglusterfs/src/xlator.c
21ab4e
+++ b/libglusterfs/src/xlator.c
21ab4e
@@ -922,7 +922,11 @@ loc_copy (loc_t *dst, loc_t *src)
21ab4e
         GF_VALIDATE_OR_GOTO ("xlator", dst, err);
21ab4e
         GF_VALIDATE_OR_GOTO ("xlator", src, err);
21ab4e
 
21ab4e
-        gf_uuid_copy (dst->gfid, src->gfid);
21ab4e
+        if (!gf_uuid_is_null (src->gfid))
21ab4e
+                gf_uuid_copy (dst->gfid, src->gfid);
21ab4e
+        else if (src->inode && !gf_uuid_is_null (src->inode->gfid))
21ab4e
+                gf_uuid_copy (dst->gfid, src->inode->gfid);
21ab4e
+
21ab4e
         gf_uuid_copy (dst->pargfid, src->pargfid);
21ab4e
 
21ab4e
         if (src->inode)
21ab4e
diff --git a/xlators/cluster/dht/src/dht-rename.c b/xlators/cluster/dht/src/dht-rename.c
21ab4e
index 7e7e715..3cd400f 100644
21ab4e
--- a/xlators/cluster/dht/src/dht-rename.c
21ab4e
+++ b/xlators/cluster/dht/src/dht-rename.c
21ab4e
@@ -1307,9 +1307,15 @@ dht_rename_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
21ab4e
                        inode_t *inode, struct iatt *stbuf, dict_t *xattr,
21ab4e
                        struct iatt *postparent)
21ab4e
 {
21ab4e
-        dht_local_t *local                      = NULL;
21ab4e
-        int          call_cnt                   = 0;
21ab4e
-        dht_conf_t  *conf                       = NULL;
21ab4e
+        dht_local_t *local                              = NULL;
21ab4e
+        int          call_cnt                           = 0;
21ab4e
+        dht_conf_t  *conf                               = NULL;
21ab4e
+        char         gfid_local[GF_UUID_BUF_SIZE]       = {0};
21ab4e
+        char         gfid_server[GF_UUID_BUF_SIZE]      = {0};
21ab4e
+        int          child_index                        = -1;
21ab4e
+
21ab4e
+
21ab4e
+        child_index = (long)cookie;
21ab4e
 
21ab4e
         local = frame->local;
21ab4e
         conf = this->private;
21ab4e
@@ -1328,16 +1334,39 @@ dht_rename_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
21ab4e
                  * that this is a linkfile and fail the rename operation.
21ab4e
                  */
21ab4e
                 local->is_linkfile = _gf_true;
21ab4e
+                local->op_errno = op_errno;
21ab4e
         } else if (xattr && check_is_linkfile (inode, stbuf, xattr,
21ab4e
                                                conf->link_xattr_name)) {
21ab4e
                 local->is_linkfile = _gf_true;
21ab4e
+                /* Found linkto file instead of data file, passdown ENOENT
21ab4e
+                 * based on the above comment */
21ab4e
+                local->op_errno = ENOENT;
21ab4e
+        }
21ab4e
+
21ab4e
+        if (!local->is_linkfile &&
21ab4e
+             gf_uuid_compare (local->lock.locks[child_index]->loc.gfid,
21ab4e
+             stbuf->ia_gfid)) {
21ab4e
+                gf_uuid_unparse (local->lock.locks[child_index]->loc.gfid, gfid_local);
21ab4e
+                gf_uuid_unparse (stbuf->ia_gfid, gfid_server);
21ab4e
+
21ab4e
+                gf_msg (this->name, GF_LOG_WARNING, 0,
21ab4e
+                        DHT_MSG_GFID_MISMATCH,
21ab4e
+                        "path:%s, received a different gfid, local_gfid= %s"
21ab4e
+                        " server_gfid: %s",
21ab4e
+                        local->loc.path, gfid_local, gfid_server);
21ab4e
+
21ab4e
+                /* Will passdown ENOENT anyway since the file we sent on
21ab4e
+                 * rename is replaced with a different file */
21ab4e
+                local->op_errno = ENOENT;
21ab4e
+                /* Since local->is_linkfile is used here to detect failure,
21ab4e
+                 * marking this to true */
21ab4e
+                local->is_linkfile = _gf_true;
21ab4e
         }
21ab4e
 
21ab4e
         call_cnt = dht_frame_return (frame);
21ab4e
         if (is_last_call (call_cnt)) {
21ab4e
                 if (local->is_linkfile) {
21ab4e
                         local->op_ret = -1;
21ab4e
-                        local->op_errno = op_errno;
21ab4e
                         goto fail;
21ab4e
                 }
21ab4e
 
21ab4e
@@ -1401,11 +1430,30 @@ dht_rename_lock_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
21ab4e
 
21ab4e
         local->call_cnt = local->lock.lk_count;
21ab4e
 
21ab4e
+        /* Why not use local->lock.locks[?].loc for lookup post lock phase
21ab4e
+         * ---------------------------------------------------------------
21ab4e
+         * "locks[?].loc" does not have the name and pargfid populated.
21ab4e
+         * Reason: If we had populated the name and pargfid, server might
21ab4e
+         * resolve to a successful lookup even if there is a file with same name
21ab4e
+         * with a different gfid(unlink & create) as server does name based
21ab4e
+         * resolution on first priority. And this can result in operating on a
21ab4e
+         * different inode entirely.
21ab4e
+         *
21ab4e
+         * Now consider a scenario where source file was renamed by some other
21ab4e
+         * client to a new name just before this lock was granted. So if a
21ab4e
+         * lookup would be done on local->lock.locks[?].loc, server will send
21ab4e
+         * success even if the entry was renamed (since server willl do a gfid
21ab4e
+         * based resolution). So once a lock is granted, make sure the file
21ab4e
+         * exists with the name that the client requested with.
21ab4e
+         * */
21ab4e
+
21ab4e
         for (i = 0; i < local->lock.lk_count; i++) {
21ab4e
-                STACK_WIND (frame, dht_rename_lookup_cbk,
21ab4e
-                            local->lock.locks[i]->xl,
21ab4e
-                            local->lock.locks[i]->xl->fops->lookup,
21ab4e
-                            &local->lock.locks[i]->loc, xattr_req);
21ab4e
+                STACK_WIND_COOKIE (frame, dht_rename_lookup_cbk, (void *)(long)i
21ab4e
+                                   , local->lock.locks[i]->xl,
21ab4e
+                                   local->lock.locks[i]->xl->fops->lookup,
21ab4e
+                                   ((gf_uuid_compare (local->loc.gfid, \
21ab4e
+                                     local->lock.locks[i]->loc.gfid) == 0) ?
21ab4e
+                                    &local->loc : &local->loc2), xattr_req);
21ab4e
         }
21ab4e
 
21ab4e
         dict_unref (xattr_req);
21ab4e
-- 
21ab4e
1.8.3.1
21ab4e