Blob Blame History Raw
From 8509249e4a211013ff923bd5f2c6891da7275143 Mon Sep 17 00:00:00 2001
From: Raghavendra Bhat <raghavendra@redhat.com>
Date: Wed, 1 Jul 2015 15:56:58 +0530
Subject: [PATCH 287/304] protocol/server: forget the inodes which got ENOENT in lookup

                 Upstream Review: http://review.gluster.org/11489

If a looked up object is removed from the backend, then upon getting a
revalidated lookup on that object ENOENT error is received. protocol/server
xlator handles it by removing dentry upon which ENOENT is received. But the
inode associated with it still remains in the inode table, and whoever does
nameless lookup on the gfid of that object will be able to do it successfully
despite the object being not present.

For handling this issue, upon getting ENOENT on a looked up entry in revalidate
lookups, protocol/server should forget the inode as well.

Though removing files directly from the backend is not allowed, in case of
objects corrupted due to bitrot and marked as bad by scrubber, objects are
removed directly from the backend in case of replicate volumes, so that the
object is healed from the good copy. For handling this, the inode of the bad
object removed from the backend should be forgotten. Otherwise, the inode which
knows the object it represents is bad, does not allow read/write operations
happening as part of self-heal.

> Change-Id: I23b7a5bef919c98eea684aa1e977e317066cfc71
> BUG: 1238188
> Signed-off-by: Raghavendra Bhat <raghavendra@redhat.com>
> Reviewed-on: http://review.gluster.org/11489
> Tested-by: NetBSD Build System <jenkins@build.gluster.org>
> Reviewed-by: Raghavendra G <rgowdapp@redhat.com>
> Signed-off-by: Raghavendra Bhat <raghavendra@redhat.com>

Change-Id: I9823e8562f05b2a5af0b70c17a5471014e0a179e
BUG: 1238171
Signed-off-by: Raghavendra Bhat <raghavendra@redhat.com>
Reviewed-on: https://code.engineering.redhat.com/gerrit/55868
---
 libglusterfs/src/inode.c                      |   26 +++++++++++
 libglusterfs/src/inode.h                      |    3 +
 xlators/protocol/server/src/server-rpc-fops.c |   56 +++++++++++++++----------
 xlators/protocol/server/src/server.h          |    3 +
 4 files changed, 66 insertions(+), 22 deletions(-)

diff --git a/libglusterfs/src/inode.c b/libglusterfs/src/inode.c
index 7b49fbe..af50865 100644
--- a/libglusterfs/src/inode.c
+++ b/libglusterfs/src/inode.c
@@ -1319,6 +1319,32 @@ inode_parent (inode_t *inode, uuid_t pargfid, const char *name)
         return parent;
 }
 
+static int
+__inode_has_dentry (inode_t *inode)
+{
+        if (!inode) {
+                gf_msg_callingfn (THIS->name, GF_LOG_WARNING, 0,
+                                  LG_MSG_INODE_NOT_FOUND, "inode not found");
+                return 0;
+        }
+
+        return !list_empty (&inode->dentry_list);
+}
+
+int
+inode_has_dentry (inode_t *inode)
+{
+
+        int dentry_present = 0;
+
+        LOCK (&inode->lock);
+        {
+                dentry_present = __inode_has_dentry (inode);
+        }
+        UNLOCK (&inode->lock);
+
+        return dentry_present;
+}
 
 int
 __inode_path (inode_t *inode, const char *name, char **bufp)
diff --git a/libglusterfs/src/inode.h b/libglusterfs/src/inode.h
index 474dc39..fcc150b 100644
--- a/libglusterfs/src/inode.h
+++ b/libglusterfs/src/inode.h
@@ -272,4 +272,7 @@ inode_ctx_merge (fd_t *fd, inode_t *inode, inode_t *linked_inode);
 int
 inode_is_linked (inode_t *inode);
 
+int
+inode_has_dentry (inode_t *inode);
+
 #endif /* _INODE_H */
diff --git a/xlators/protocol/server/src/server-rpc-fops.c b/xlators/protocol/server/src/server-rpc-fops.c
index 99b8011..bd1ced4 100644
--- a/xlators/protocol/server/src/server-rpc-fops.c
+++ b/xlators/protocol/server/src/server-rpc-fops.c
@@ -32,6 +32,16 @@
                 ret = RPCSVC_ACTOR_ERROR;                       \
         } while (0)
 
+void
+forget_inode_if_no_dentry (inode_t *inode)
+{
+        if (!inode_has_dentry (inode))
+                inode_forget (inode, 0);
+
+        return;
+}
+
+
 /* Callback function section */
 int
 server_statfs_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
@@ -108,6 +118,23 @@ server_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
                                 inode_unlink (state->loc.inode,
                                               state->loc.parent,
                                               state->loc.name);
+                                /**
+                                 * If the entry is not present, then just
+                                 * unlinking the associated dentry is not
+                                 * suffecient. This condition should be
+                                 * treated as unlink of the entry. So along
+                                 * with deleting the entry, its also important
+                                 * to forget the inode for it (if the dentry
+                                 * being considered was the last dentry).
+                                 * Otherwise it might lead to inode leak.
+                                 * It also might lead to wrong decisions being
+                                 * taken if the future lookups on this inode are
+                                 * successful since they are able to find the
+                                 * inode in the inode table (atleast gfid based
+                                 * lookups will be successful, if the lookup
+                                 * is a soft lookup)
+                                 */
+                                forget_inode_if_no_dentry (state->loc.inode);
                         }
                 }
                 goto out;
@@ -416,7 +443,6 @@ server_rmdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
 {
         gfs3_rmdir_rsp       rsp    = {0,};
         server_state_t      *state  = NULL;
-        inode_t             *parent = NULL;
         rpcsvc_request_t    *req    = NULL;
 
         GF_PROTOCOL_DICT_SERIALIZE (this, xdata, &rsp.xdata.xdata_val,
@@ -436,15 +462,11 @@ server_rmdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
 
         inode_unlink (state->loc.inode, state->loc.parent,
                       state->loc.name);
-        parent = inode_parent (state->loc.inode, 0, NULL);
-        if (parent)
-                /* parent should not be found for directories after
-                 * inode_unlink, since directories cannot have
-                 * hardlinks.
-                 */
-                inode_unref (parent);
-        else
-                inode_forget (state->loc.inode, 0);
+        /* parent should not be found for directories after
+         * inode_unlink, since directories cannot have
+         * hardlinks.
+         */
+        forget_inode_if_no_dentry (state->loc.inode);
 
         gf_stat_from_iatt (&rsp.preparent, preparent);
         gf_stat_from_iatt (&rsp.postparent, postparent);
@@ -1023,12 +1045,7 @@ server_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
         if (tmp_inode) {
                 inode_unlink (tmp_inode, state->loc2.parent,
                               state->loc2.name);
-                tmp_parent = inode_parent (tmp_inode, 0, NULL);
-                if (tmp_parent)
-                        inode_unref (tmp_parent);
-                else
-                        inode_forget (tmp_inode, 0);
-
+                forget_inode_if_no_dentry (tmp_inode);
                 inode_unref (tmp_inode);
         }
 
@@ -1064,7 +1081,6 @@ server_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
 {
         gfs3_unlink_rsp      rsp    = {0,};
         server_state_t      *state  = NULL;
-        inode_t             *parent = NULL;
         rpcsvc_request_t    *req    = NULL;
 
         GF_PROTOCOL_DICT_SERIALIZE (this, xdata, &rsp.xdata.xdata_val,
@@ -1089,11 +1105,7 @@ server_unlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
         inode_unlink (state->loc.inode, state->loc.parent,
                       state->loc.name);
 
-        parent = inode_parent (state->loc.inode, 0, NULL);
-        if (parent)
-                inode_unref (parent);
-        else
-                inode_forget (state->loc.inode, 0);
+        forget_inode_if_no_dentry (state->loc.inode);
 
         gf_stat_from_iatt (&rsp.preparent, preparent);
         gf_stat_from_iatt (&rsp.postparent, postparent);
diff --git a/xlators/protocol/server/src/server.h b/xlators/protocol/server/src/server.h
index 6caf449..1055b72 100644
--- a/xlators/protocol/server/src/server.h
+++ b/xlators/protocol/server/src/server.h
@@ -172,4 +172,7 @@ server_submit_reply (call_frame_t *frame, rpcsvc_request_t *req, void *arg,
 int gf_server_check_setxattr_cmd (call_frame_t *frame, dict_t *dict);
 int gf_server_check_getxattr_cmd (call_frame_t *frame, const char *name);
 
+void
+forget_inode_if_no_dentry (inode_t *inode);
+
 #endif /* !_SERVER_H */
-- 
1.7.1