From 6bf0a809c99ec33fee73e6ebebb58baa2614f977 Mon Sep 17 00:00:00 2001 From: Raghavendra Bhat Date: Tue, 6 Mar 2012 14:35:45 +0530 Subject: protocol/server: send forget on the renamed inode If rename is given on a file "a" to "b" ("b" is already existing file), then after rename, the inode for "b" would still be in the inode table and would not get forget (for fuse client, the fuse kernel module would send, but on server forget will not come on that inode), thus leading to inode leak even when the mount point is empty. To avoid that before doing inode rename, unlink the previous inode that "b" is pointing to and send forget on that, if "b" is the last dentry for that inode. Change-Id: Ie4dcc39ea190ee8f28029b4d7661df576d9cf319 BUG: 799833 Signed-off-by: Raghavendra Bhat Reviewed-on: http://review.gluster.com/2874 Tested-by: Gluster Build System Reviewed-by: Amar Tumballi Reviewed-by: Anand Avati --- xlators/protocol/server/src/server3_1-fops.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'xlators/protocol/server/src') diff --git a/xlators/protocol/server/src/server3_1-fops.c b/xlators/protocol/server/src/server3_1-fops.c index d44ee1cf7..ef9a98f38 100644 --- a/xlators/protocol/server/src/server3_1-fops.c +++ b/xlators/protocol/server/src/server3_1-fops.c @@ -414,6 +414,10 @@ server_rmdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this, 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); @@ -830,6 +834,8 @@ server_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this, gfs3_rename_rsp rsp = {0,}; server_state_t *state = NULL; rpcsvc_request_t *req = NULL; + inode_t *tmp_inode = NULL; + inode_t *tmp_parent = NULL; req = frame->local; @@ -846,6 +852,28 @@ server_rename_cbk (call_frame_t *frame, void *cookie, xlator_t *this, "%"PRId64": RENAME_CBK %s ==> %s", frame->root->unique, state->loc.name, state->loc2.name); + /* Before renaming the inode, we have to get the inode for the + * destination entry (i.e. inode with state->loc2.parent as + * parent and state->loc2.name as name). If it exists, then + * unlink that inode, and send forget on that inode if the + * unlinked entry is the last entry. In case of fuse client + * the fuse kernel module itself sends the forget on the + * unlinked inode. + */ + tmp_inode = inode_grep (state->loc.inode->table, + state->loc2.parent, state->loc2.name); + 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); + + inode_unref (tmp_inode); + } + inode_rename (state->itable, state->loc.parent, state->loc.name, state->loc2.parent, state->loc2.name, -- cgit