[PATCH] proc: fix of error path in proc_get_inode()
authorKirill Korotaev <dev@sw.ru>
Sun, 30 Oct 2005 23:02:26 +0000 (15:02 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Mon, 31 Oct 2005 01:37:21 +0000 (17:37 -0800)
This patch fixes incorrect error path in proc_get_inode(), when module
can't be get due to being unloaded.  When try_module_get() fails, this
function puts de(!) and still returns inode with non-getted de.

There are still unresolved known bugs in proc yet to be fixed:
- proc_dir_entry tree is managed without any serialization
- create_proc_entry() doesn't setup de->owner anyhow,
   so setting it later manually is inatomic.
- looks like almost all modules do not care whether
   it's de->owner is set...

Signed-Off-By: Denis Lunev <den@sw.ru>
Signed-Off-By: Kirill Korotaev <dev@sw.ru>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
fs/proc/inode.c

index effa6c0..e6a818a 100644 (file)
@@ -156,10 +156,13 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino,
 
        WARN_ON(de && de->deleted);
 
+       if (de != NULL && !try_module_get(de->owner))
+               goto out_mod;
+
        inode = iget(sb, ino);
        if (!inode)
-               goto out_fail;
-       
+               goto out_ino;
+
        PROC_I(inode)->pde = de;
        if (de) {
                if (de->mode) {
@@ -171,20 +174,20 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino,
                        inode->i_size = de->size;
                if (de->nlink)
                        inode->i_nlink = de->nlink;
-               if (!try_module_get(de->owner))
-                       goto out_fail;
                if (de->proc_iops)
                        inode->i_op = de->proc_iops;
                if (de->proc_fops)
                        inode->i_fop = de->proc_fops;
        }
 
-out:
        return inode;
 
-out_fail:
+out_ino:
+       if (de != NULL)
+               module_put(de->owner);
+out_mod:
        de_put(de);
-       goto out;
+       return NULL;
 }                      
 
 int proc_fill_super(struct super_block *s, void *data, int silent)