| From d70b67c8bc72ee23b55381bd6a884f4796692f77 Mon Sep 17 00:00:00 2001 |
| From: Miklos Szeredi <mszeredi@suse.cz> |
| Date: Wed, 2 Jul 2008 21:30:15 +0200 |
| Subject: vfs: fix lookup on deleted directory |
| |
| From: Miklos Szeredi <mszeredi@suse.cz> |
| |
| commit d70b67c8bc72ee23b55381bd6a884f4796692f77 upstream |
| |
| 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> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| fs/namei.c | 19 +++++++++++++++++-- |
| 1 file changed, 17 insertions(+), 2 deletions(-) |
| |
| --- a/fs/namei.c |
| +++ b/fs/namei.c |
| @@ -519,7 +519,14 @@ static struct dentry * real_lookup(struc |
| */ |
| 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); |
| @@ -528,6 +535,7 @@ static struct dentry * real_lookup(struc |
| else |
| result = dentry; |
| } |
| +out_unlock: |
| mutex_unlock(&dir->i_mutex); |
| return result; |
| } |
| @@ -1317,7 +1325,14 @@ static struct dentry *__lookup_hash(stru |
| |
| 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; |