cb8e9e
From 8509249e4a211013ff923bd5f2c6891da7275143 Mon Sep 17 00:00:00 2001
cb8e9e
From: Raghavendra Bhat <raghavendra@redhat.com>
cb8e9e
Date: Wed, 1 Jul 2015 15:56:58 +0530
cb8e9e
Subject: [PATCH 287/304] protocol/server: forget the inodes which got ENOENT in lookup
cb8e9e
cb8e9e
                 Upstream Review: http://review.gluster.org/11489
cb8e9e
cb8e9e
If a looked up object is removed from the backend, then upon getting a
cb8e9e
revalidated lookup on that object ENOENT error is received. protocol/server
cb8e9e
xlator handles it by removing dentry upon which ENOENT is received. But the
cb8e9e
inode associated with it still remains in the inode table, and whoever does
cb8e9e
nameless lookup on the gfid of that object will be able to do it successfully
cb8e9e
despite the object being not present.
cb8e9e
cb8e9e
For handling this issue, upon getting ENOENT on a looked up entry in revalidate
cb8e9e
lookups, protocol/server should forget the inode as well.
cb8e9e
cb8e9e
Though removing files directly from the backend is not allowed, in case of
cb8e9e
objects corrupted due to bitrot and marked as bad by scrubber, objects are
cb8e9e
removed directly from the backend in case of replicate volumes, so that the
cb8e9e
object is healed from the good copy. For handling this, the inode of the bad
cb8e9e
object removed from the backend should be forgotten. Otherwise, the inode which
cb8e9e
knows the object it represents is bad, does not allow read/write operations
cb8e9e
happening as part of self-heal.
cb8e9e
cb8e9e
> Change-Id: I23b7a5bef919c98eea684aa1e977e317066cfc71
cb8e9e
> BUG: 1238188
cb8e9e
> Signed-off-by: Raghavendra Bhat <raghavendra@redhat.com>
cb8e9e
> Reviewed-on: http://review.gluster.org/11489
cb8e9e
> Tested-by: NetBSD Build System <jenkins@build.gluster.org>
cb8e9e
> Reviewed-by: Raghavendra G <rgowdapp@redhat.com>
cb8e9e
> Signed-off-by: Raghavendra Bhat <raghavendra@redhat.com>
cb8e9e
cb8e9e
Change-Id: I9823e8562f05b2a5af0b70c17a5471014e0a179e
cb8e9e
BUG: 1238171
cb8e9e
Signed-off-by: Raghavendra Bhat <raghavendra@redhat.com>
cb8e9e
Reviewed-on: https://code.engineering.redhat.com/gerrit/55868
cb8e9e
---
cb8e9e
 libglusterfs/src/inode.c                      |   26 +++++++++++
cb8e9e
 libglusterfs/src/inode.h                      |    3 +
cb8e9e
 xlators/protocol/server/src/server-rpc-fops.c |   56 +++++++++++++++----------
cb8e9e
 xlators/protocol/server/src/server.h          |    3 +
cb8e9e
 4 files changed, 66 insertions(+), 22 deletions(-)
cb8e9e
cb8e9e
diff --git a/libglusterfs/src/inode.c b/libglusterfs/src/inode.c
cb8e9e
index 7b49fbe..af50865 100644
cb8e9e
--- a/libglusterfs/src/inode.c
cb8e9e
+++ b/libglusterfs/src/inode.c
cb8e9e
@@ -1319,6 +1319,32 @@ inode_parent (inode_t *inode, uuid_t pargfid, const char *name)
cb8e9e
         return parent;
cb8e9e
 }
cb8e9e
 
cb8e9e
+static int
cb8e9e
+__inode_has_dentry (inode_t *inode)
cb8e9e
+{
cb8e9e
+        if (!inode) {
cb8e9e
+                gf_msg_callingfn (THIS->name, GF_LOG_WARNING, 0,
cb8e9e
+                                  LG_MSG_INODE_NOT_FOUND, "inode not found");
cb8e9e
+                return 0;
cb8e9e
+        }
cb8e9e
+
cb8e9e
+        return !list_empty (&inode->dentry_list);
cb8e9e
+}
cb8e9e
+
cb8e9e
+int
cb8e9e
+inode_has_dentry (inode_t *inode)
cb8e9e
+{
cb8e9e
+
cb8e9e
+        int dentry_present = 0;
cb8e9e
+
cb8e9e
+        LOCK (&inode->lock);
cb8e9e
+        {
cb8e9e
+                dentry_present = __inode_has_dentry (inode);
cb8e9e
+        }
cb8e9e
+        UNLOCK (&inode->lock);
cb8e9e
+
cb8e9e
+        return dentry_present;
cb8e9e
+}
cb8e9e
 
cb8e9e
 int
cb8e9e
 __inode_path (inode_t *inode, const char *name, char **bufp)
cb8e9e
diff --git a/libglusterfs/src/inode.h b/libglusterfs/src/inode.h
cb8e9e
index 474dc39..fcc150b 100644
cb8e9e
--- a/libglusterfs/src/inode.h
cb8e9e
+++ b/libglusterfs/src/inode.h
cb8e9e
@@ -272,4 +272,7 @@ inode_ctx_merge (fd_t *fd, inode_t *inode, inode_t *linked_inode);
cb8e9e
 int
cb8e9e
 inode_is_linked (inode_t *inode);
cb8e9e
 
cb8e9e
+int
cb8e9e
+inode_has_dentry (inode_t *inode);
cb8e9e
+
cb8e9e
 #endif /* _INODE_H */
cb8e9e
diff --git a/xlators/protocol/server/src/server-rpc-fops.c b/xlators/protocol/server/src/server-rpc-fops.c
cb8e9e
index 99b8011..bd1ced4 100644
cb8e9e
--- a/xlators/protocol/server/src/server-rpc-fops.c
cb8e9e
+++ b/xlators/protocol/server/src/server-rpc-fops.c
cb8e9e
@@ -32,6 +32,16 @@
cb8e9e
                 ret = RPCSVC_ACTOR_ERROR;                       \
cb8e9e
         } while (0)
cb8e9e
 
cb8e9e
+void
cb8e9e
+forget_inode_if_no_dentry (inode_t *inode)
cb8e9e
+{
cb8e9e
+        if (!inode_has_dentry (inode))
cb8e9e
+                inode_forget (inode, 0);
cb8e9e
+
cb8e9e
+        return;
cb8e9e
+}
cb8e9e
+
cb8e9e
+
cb8e9e
 /* Callback function section */
cb8e9e
 int
cb8e9e
 server_statfs_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
cb8e9e
@@ -108,6 +118,23 @@ server_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
cb8e9e
                                 inode_unlink (state->loc.inode,
cb8e9e
                                               state->loc.parent,
cb8e9e
                                               state->loc.name);
cb8e9e
+                                /**
cb8e9e
+                                 * If the entry is not present, then just
cb8e9e
+                                 * unlinking the associated dentry is not
cb8e9e
+                                 * suffecient. This condition should be
cb8e9e
+                                 * treated as unlink of the entry. So along
cb8e9e
+                                 * with deleting the entry, its also important
cb8e9e
+                                 * to forget the inode for it (if the dentry
cb8e9e
+                                 * being considered was the last dentry).
cb8e9e
+                                 * Otherwise it might lead to inode leak.
cb8e9e
+                                 * It also might lead to wrong decisions being
cb8e9e
+                                 * taken if the future lookups on this inode are
cb8e9e
+                                 * successful since they are able to find the
cb8e9e
+                                 * inode in the inode table (atleast gfid based
cb8e9e
+                                 * lookups will be successful, if the lookup
cb8e9e
+                                 * is a soft lookup)
cb8e9e
+                                 */
cb8e9e
+                                forget_inode_if_no_dentry (state->loc.inode);
cb8e9e
                         }
cb8e9e
                 }
cb8e9e
                 goto out;
cb8e9e
@@ -416,7 +443,6 @@ server_rmdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
cb8e9e
 {
cb8e9e
         gfs3_rmdir_rsp       rsp    = {0,};
cb8e9e
         server_state_t      *state  = NULL;
cb8e9e
-        inode_t             *parent = NULL;
cb8e9e
         rpcsvc_request_t    *req    = NULL;
cb8e9e
 
cb8e9e
         GF_PROTOCOL_DICT_SERIALIZE (this, xdata, &rsp.xdata.xdata_val,
cb8e9e
@@ -436,15 +462,11 @@ server_rmdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
cb8e9e
 
cb8e9e
         inode_unlink (state->loc.inode, state->loc.parent,
cb8e9e
                       state->loc.name);
cb8e9e
-        parent = inode_parent (state->loc.inode, 0, NULL);
cb8e9e
-        if (parent)
cb8e9e
-                /* parent should not be found for directories after
cb8e9e
-                 * inode_unlink, since directories cannot have
cb8e9e
-                 * hardlinks.
cb8e9e
-                 */
cb8e9e
-                inode_unref (parent);
cb8e9e
-        else
cb8e9e
-                inode_forget (state->loc.inode, 0);
cb8e9e
+        /* parent should not be found for directories after
cb8e9e
+         * inode_unlink, since directories cannot have
cb8e9e
+         * hardlinks.
cb8e9e
+         */
cb8e9e
+        forget_inode_if_no_dentry (state->loc.inode);
cb8e9e
 
cb8e9e
         gf_stat_from_iatt (&rsp.preparent, preparent);
cb8e9e
         gf_stat_from_iatt (&rsp.postparent, postparent);
cb8e9e
@@ -1023,12 +1045,7 @@ server_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
cb8e9e
         if (tmp_inode) {
cb8e9e
                 inode_unlink (tmp_inode, state->loc2.parent,
cb8e9e
                               state->loc2.name);
cb8e9e
-                tmp_parent = inode_parent (tmp_inode, 0, NULL);
cb8e9e
-                if (tmp_parent)
cb8e9e
-                        inode_unref (tmp_parent);
cb8e9e
-                else
cb8e9e
-                        inode_forget (tmp_inode, 0);
cb8e9e
-
cb8e9e
+                forget_inode_if_no_dentry (tmp_inode);
cb8e9e
                 inode_unref (tmp_inode);
cb8e9e
         }
cb8e9e
 
cb8e9e
@@ -1064,7 +1081,6 @@ server_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
cb8e9e
 {
cb8e9e
         gfs3_unlink_rsp      rsp    = {0,};
cb8e9e
         server_state_t      *state  = NULL;
cb8e9e
-        inode_t             *parent = NULL;
cb8e9e
         rpcsvc_request_t    *req    = NULL;
cb8e9e
 
cb8e9e
         GF_PROTOCOL_DICT_SERIALIZE (this, xdata, &rsp.xdata.xdata_val,
cb8e9e
@@ -1089,11 +1105,7 @@ server_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
cb8e9e
         inode_unlink (state->loc.inode, state->loc.parent,
cb8e9e
                       state->loc.name);
cb8e9e
 
cb8e9e
-        parent = inode_parent (state->loc.inode, 0, NULL);
cb8e9e
-        if (parent)
cb8e9e
-                inode_unref (parent);
cb8e9e
-        else
cb8e9e
-                inode_forget (state->loc.inode, 0);
cb8e9e
+        forget_inode_if_no_dentry (state->loc.inode);
cb8e9e
 
cb8e9e
         gf_stat_from_iatt (&rsp.preparent, preparent);
cb8e9e
         gf_stat_from_iatt (&rsp.postparent, postparent);
cb8e9e
diff --git a/xlators/protocol/server/src/server.h b/xlators/protocol/server/src/server.h
cb8e9e
index 6caf449..1055b72 100644
cb8e9e
--- a/xlators/protocol/server/src/server.h
cb8e9e
+++ b/xlators/protocol/server/src/server.h
cb8e9e
@@ -172,4 +172,7 @@ server_submit_reply (call_frame_t *frame, rpcsvc_request_t *req, void *arg,
cb8e9e
 int gf_server_check_setxattr_cmd (call_frame_t *frame, dict_t *dict);
cb8e9e
 int gf_server_check_getxattr_cmd (call_frame_t *frame, const char *name);
cb8e9e
 
cb8e9e
+void
cb8e9e
+forget_inode_if_no_dentry (inode_t *inode);
cb8e9e
+
cb8e9e
 #endif /* !_SERVER_H */
cb8e9e
-- 
cb8e9e
1.7.1
cb8e9e