a3470f
From 90092b0c276f599bbe415ecc3051ca12d99461b6 Mon Sep 17 00:00:00 2001
a3470f
From: Raghavendra G <rgowdapp@redhat.com>
a3470f
Date: Sat, 17 Mar 2018 13:16:59 +0530
a3470f
Subject: [PATCH 263/271] server/resolver: don't trust inode-table for
a3470f
 RESOLVE_NOT
a3470f
a3470f
There have been known races between fops which add a dentry (like
a3470f
lookup, create, mknod etc) and fops that remove a dentry (like rename,
a3470f
unlink, rmdir etc) due to which stale dentries are left out in inode
a3470f
table even though the dentry doesn't exist on backend. For eg.,
a3470f
consider a lookup (parent/bname) and unlink (parent/bname) racing in
a3470f
the following order:
a3470f
a3470f
* lookup hits storage/posix and finds that dentry exists
a3470f
* unlink removes the dentry on storage/posix
a3470f
* unlink reaches protocol/server where the dentry (parent/bname) is
a3470f
  unlinked from the inode
a3470f
* lookup reaches protocol/server and creates a dentry (parent/bname)
a3470f
  on the inode
a3470f
a3470f
Now we've a stale dentry (parent/bname) associated with the inode in
a3470f
itable. This situation is bad for fops like link, create etc which
a3470f
invoke resolver with type RESOLVE_NOT. These fops fail with EEXIST
a3470f
even though there is no such dentry on backend fs. This issue can be
a3470f
solved in two ways:
a3470f
a3470f
* Enable "dentry fop serializer" xlator [1].
a3470f
  # gluster volume set features.sdfs on
a3470f
a3470f
* Make sure resolver does a lookup on backend when it finds a dentry
a3470f
  in itable and validates the state of itable.
a3470f
   - If a dentry is not found, unlink those stale dentries from itable
a3470f
     and continue with fop
a3470f
   - If dentry is found, fail the fop with EEXIST
a3470f
a3470f
This patch implements second solution as sdfs is not enabled by
a3470f
default in brick xlator stack. Once sdfs is enabled by default, this
a3470f
patch can be reverted.
a3470f
a3470f
[1] https://github.com/gluster/glusterfs/issues/397
a3470f
a3470f
>Change-Id: Ia8bb0cf97f97cb0e72639bce8aadb0f6d3f4a34a
a3470f
>updates: bz#1543279
a3470f
>BUG: 1543279
a3470f
>Signed-off-by: Raghavendra G <rgowdapp@redhat.com>
a3470f
a3470f
upstream patch: https://review.gluster.org/19732
a3470f
BUG: 1488120
a3470f
Change-Id: I78df4f6751e5db1fc659ee15d92b76d1486455f0
a3470f
Signed-off-by: Raghavendra G <rgowdapp@redhat.com>
a3470f
Reviewed-on: https://code.engineering.redhat.com/gerrit/138152
a3470f
Tested-by: RHGS Build Bot <nigelb@redhat.com>
a3470f
Reviewed-by: Nithya Balachandran <nbalacha@redhat.com>
a3470f
---
a3470f
 xlators/protocol/server/src/server-resolve.c | 27 +++++++++++++++++++++++----
a3470f
 1 file changed, 23 insertions(+), 4 deletions(-)
a3470f
a3470f
diff --git a/xlators/protocol/server/src/server-resolve.c b/xlators/protocol/server/src/server-resolve.c
a3470f
index d0126aa..6ffb909 100644
a3470f
--- a/xlators/protocol/server/src/server-resolve.c
a3470f
+++ b/xlators/protocol/server/src/server-resolve.c
a3470f
@@ -58,10 +58,27 @@ resolve_gfid_entry_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
a3470f
 
a3470f
         if (op_ret == -1) {
a3470f
                 if (op_errno == ENOENT) {
a3470f
-                        gf_msg_debug (this->name, 0, "%s/%s: failed to resolve"
a3470f
-                                      " (%s)",
a3470f
+                        gf_msg_debug (this->name, 0,
a3470f
+                                      "%s/%s: failed to resolve (%s)",
a3470f
                                       uuid_utoa (resolve_loc->pargfid),
a3470f
                                       resolve_loc->name, strerror (op_errno));
a3470f
+                        if (resolve->type == RESOLVE_NOT) {
a3470f
+                                do {
a3470f
+                                        inode = inode_grep (state->itable,
a3470f
+                                                            resolve_loc->parent,
a3470f
+                                                            resolve->bname);
a3470f
+
a3470f
+                                        if (inode) {
a3470f
+                                                gf_msg_debug (this->name, 0, "%s/%s: "
a3470f
+                                                              "removing stale dentry",
a3470f
+                                                              uuid_utoa (resolve_loc->pargfid),
a3470f
+                                                              resolve->bname);
a3470f
+                                                inode_unlink (inode,
a3470f
+                                                              resolve_loc->parent,
a3470f
+                                                              resolve->bname);
a3470f
+                                        }
a3470f
+                                } while (inode);
a3470f
+                        }
a3470f
                 } else {
a3470f
                         gf_msg (this->name, GF_LOG_WARNING, op_errno,
a3470f
                                 PS_MSG_GFID_RESOLVE_FAILED, "%s/%s: failed to "
a3470f
@@ -318,11 +335,13 @@ resolve_entry_simple (call_frame_t *frame)
a3470f
 
a3470f
         if (resolve->type == RESOLVE_NOT) {
a3470f
                 gf_msg_debug (this->name, 0, "inode (pointer: %p gfid:%s found"
a3470f
-                              " for path (%s) while type is RESOLVE_NOT",
a3470f
+                              " for path (%s) while type is RESOLVE_NOT. "
a3470f
+                              "Performing lookup on backend to rule out any "
a3470f
+                              "possible stale dentries in inode table",
a3470f
                               inode, uuid_utoa (inode->gfid), resolve->path);
a3470f
                 resolve->op_ret   = -1;
a3470f
                 resolve->op_errno = EEXIST;
a3470f
-                ret = -1;
a3470f
+                ret = 1;
a3470f
                 goto out;
a3470f
         }
a3470f
 
a3470f
-- 
a3470f
1.8.3.1
a3470f