summaryrefslogtreecommitdiffstats
path: root/xlators/protocol
diff options
context:
space:
mode:
authorRaghavendra Bhat <raghavendra@redhat.com>2015-07-01 15:56:58 +0530
committerRaghavendra G <rgowdapp@redhat.com>2015-08-21 04:48:48 -0700
commitcb879d6adbb9194b488f2ad7a97cf7fc7f5a5ef5 (patch)
tree52f20d6d0fbd5f250baddc395a3e6da12e452298 /xlators/protocol
parent7322e6c5b405a754fea1e0eeddf8e66da1bdd326 (diff)
protocol/server: forget the inodes which got ENOENT in lookup
Backport of 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: I268eeaf37969458687425187be6622347a6cc1f1 BUG: 1255604 Signed-off-by: Raghavendra Bhat <raghavendra@redhat.com> Reviewed-on: http://review.gluster.org/11973 Tested-by: NetBSD Build System <jenkins@build.gluster.org> Tested-by: Gluster Build System <jenkins@build.gluster.com> Reviewed-by: Raghavendra G <rgowdapp@redhat.com>
Diffstat (limited to 'xlators/protocol')
-rw-r--r--xlators/protocol/server/src/server-rpc-fops.c56
-rw-r--r--xlators/protocol/server/src/server.h3
2 files changed, 37 insertions, 22 deletions
diff --git a/xlators/protocol/server/src/server-rpc-fops.c b/xlators/protocol/server/src/server-rpc-fops.c
index c8725739be4..d750a640655 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 6caf44926c9..1055b72dad5 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 */