Skip to content

Commit

Permalink
[patch] vfs: fix lookup on deleted directory
Browse files Browse the repository at this point in the history
Lookup can install a child dentry for a deleted directory.  This keeps
the directory dentry alive, and the inode pinned in the cache and on
disk, even after all external references have gone away.

This isn't a big problem normally, since memory pressure or umount
will clear out the directory dentry and its children, releasing the
inode.  But for UBIFS this causes problems because its orphan area can
overflow.

Fix this by returning ENOENT for all lookups on a S_DEAD directory
before creating a child dentry.

Thanks to Zoltan Sogor for noticing this while testing UBIFS, and
Artem for the excellent analysis of the problem and testing.

Reported-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Tested-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
  • Loading branch information
Miklos Szeredi authored and Al Viro committed Jul 27, 2008
1 parent a048d3a commit d70b67c
Showing 1 changed file with 17 additions and 2 deletions.
19 changes: 17 additions & 2 deletions fs/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,14 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, s
*/
result = d_lookup(parent, name);
if (!result) {
struct dentry * dentry = d_alloc(parent, name);
struct dentry *dentry;

/* Don't create child dentry for a dead directory. */
result = ERR_PTR(-ENOENT);
if (IS_DEADDIR(dir))
goto out_unlock;

dentry = d_alloc(parent, name);
result = ERR_PTR(-ENOMEM);
if (dentry) {
result = dir->i_op->lookup(dir, dentry, nd);
Expand All @@ -528,6 +535,7 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, s
else
result = dentry;
}
out_unlock:
mutex_unlock(&dir->i_mutex);
return result;
}
Expand Down Expand Up @@ -1317,7 +1325,14 @@ static struct dentry *__lookup_hash(struct qstr *name,

dentry = cached_lookup(base, name, nd);
if (!dentry) {
struct dentry *new = d_alloc(base, name);
struct dentry *new;

/* Don't create child dentry for a dead directory. */
dentry = ERR_PTR(-ENOENT);
if (IS_DEADDIR(inode))
goto out;

new = d_alloc(base, name);
dentry = ERR_PTR(-ENOMEM);
if (!new)
goto out;
Expand Down

0 comments on commit d70b67c

Please sign in to comment.