diff options
author | Raghavendra Bhat <raghavendrabhat@gluster.com> | 2012-03-06 14:35:45 +0530 |
---|---|---|
committer | Anand Avati <avati@redhat.com> | 2012-03-18 01:00:01 -0700 |
commit | 6bf0a809c99ec33fee73e6ebebb58baa2614f977 (patch) | |
tree | b98ac8abdb614d3baa47eb3730a2a0c9ff2c6cda | |
parent | 93022c0cc6c22b3a30ded3e109a3fe0a0dce8ca0 (diff) |
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 <raghavendrabhat@gluster.com>
Reviewed-on: http://review.gluster.com/2874
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Amar Tumballi <amarts@redhat.com>
Reviewed-by: Anand Avati <avati@redhat.com>
-rw-r--r-- | xlators/protocol/server/src/server3_1-fops.c | 28 |
1 files changed, 28 insertions, 0 deletions
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, |