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