Commit d70b67c8 authored by Miklos Szeredi's avatar Miklos Szeredi Committed by Al Viro

[patch] vfs: fix lookup on deleted directory

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: default avatarArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
Tested-by: default avatarArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
Signed-off-by: default avatarMiklos Szeredi <mszeredi@suse.cz>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent a048d3af
...@@ -519,7 +519,14 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, s ...@@ -519,7 +519,14 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, s
*/ */
result = d_lookup(parent, name); result = d_lookup(parent, name);
if (!result) { 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); result = ERR_PTR(-ENOMEM);
if (dentry) { if (dentry) {
result = dir->i_op->lookup(dir, dentry, nd); result = dir->i_op->lookup(dir, dentry, nd);
...@@ -528,6 +535,7 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, s ...@@ -528,6 +535,7 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, s
else else
result = dentry; result = dentry;
} }
out_unlock:
mutex_unlock(&dir->i_mutex); mutex_unlock(&dir->i_mutex);
return result; return result;
} }
...@@ -1317,7 +1325,14 @@ static struct dentry *__lookup_hash(struct qstr *name, ...@@ -1317,7 +1325,14 @@ static struct dentry *__lookup_hash(struct qstr *name,
dentry = cached_lookup(base, name, nd); dentry = cached_lookup(base, name, nd);
if (!dentry) { 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); dentry = ERR_PTR(-ENOMEM);
if (!new) if (!new)
goto out; goto out;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment