On Tue, Jan 22, 2013 at 09:03:26PM +0400, Maxim Patlasov wrote: > If proc_get_inode() succeeded, but d_make_root() failed, pde_put() for > proc_root will be called twice: the first time due to iput() called from > d_make_root() and the second time directly in the end of proc_fill_super().
I don't like that solution, TBH. How about making proc_get_inode() call pde_put() on failure instead? Note that it already does so if inode had been found in icache, so this will just make the refcounting consistent. Completely untested patch follows: Signed-off-by: Al Viro <v...@zeniv.linux.org.uk> --- diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 76ddae8..8b487e5 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -413,31 +413,24 @@ struct dentry *proc_lookup_de(struct proc_dir_entry *de, struct inode *dir, struct dentry *dentry) { struct inode *inode = NULL; - int error = -ENOENT; spin_lock(&proc_subdir_lock); for (de = de->subdir; de ; de = de->next) { if (de->namelen != dentry->d_name.len) continue; - if (!memcmp(dentry->d_name.name, de->name, de->namelen)) { - pde_get(de); - spin_unlock(&proc_subdir_lock); - error = -ENOMEM; - inode = proc_get_inode(dir->i_sb, de); - goto out_unlock; - } - } - spin_unlock(&proc_subdir_lock); -out_unlock: - - if (inode) { + if (memcmp(dentry->d_name.name, de->name, de->namelen)) + continue; + pde_get(de); + spin_unlock(&proc_subdir_lock); + inode = proc_get_inode(dir->i_sb, de); + if (!inode) + return ERR_PTR(-ENOMEM); d_set_d_op(dentry, &proc_dentry_operations); d_add(dentry, inode); return NULL; } - if (de) - pde_put(de); - return ERR_PTR(error); + spin_unlock(&proc_subdir_lock); + return ERR_PTR(-ENOENT); } struct dentry *proc_lookup(struct inode *dir, struct dentry *dentry, diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 439ae688..e2bbe20 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -448,9 +448,7 @@ struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de) struct inode * inode; inode = iget_locked(sb, de->low_ino); - if (!inode) - return NULL; - if (inode->i_state & I_NEW) { + if (inode && inode->i_state & I_NEW) { inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; PROC_I(inode)->pde = de; @@ -499,6 +497,5 @@ int proc_fill_super(struct super_block *s) return 0; printk("proc_read_super: get root inode failed\n"); - pde_put(&proc_root); return -ENOMEM; } -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/