]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
[PATCH] Fix file lookup without ref
authorDipankar Sarma <dipankar@in.ibm.com>
Wed, 19 Apr 2006 17:00:12 +0000 (17:00 +0000)
committerGreg Kroah-Hartman <gregkh@suse.de>
Mon, 24 Apr 2006 16:56:05 +0000 (09:56 -0700)
There are places in the kernel where we look up files in fd tables and
access the file structure without holding refereces to the file.  So, we
need special care to avoid the race between looking up files in the fd
table and tearing down of the file in another CPU.  Otherwise, one might
see a NULL f_dentry or such torn down version of the file.  This patch
fixes those special places where such a race may happen.

Signed-off-by: Dipankar Sarma <dipankar@in.ibm.com>
Acked-by: "Paul E. McKenney" <paulmck@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/char/tty_io.c
fs/locks.c
fs/proc/base.c

index 53d3d066554e556b4110398990294a12af9d1c97..edaee70b2e662d692f26149642d84473cfc791fd 100644 (file)
@@ -2706,7 +2706,11 @@ static void __do_SAK(void *arg)
                }
                task_lock(p);
                if (p->files) {
-                       rcu_read_lock();
+                       /*
+                        * We don't take a ref to the file, so we must
+                        * hold ->file_lock instead.
+                        */
+                       spin_lock(&p->files->file_lock);
                        fdt = files_fdtable(p->files);
                        for (i=0; i < fdt->max_fds; i++) {
                                filp = fcheck_files(p->files, i);
@@ -2721,7 +2725,7 @@ static void __do_SAK(void *arg)
                                        break;
                                }
                        }
-                       rcu_read_unlock();
+                       spin_unlock(&p->files->file_lock);
                }
                task_unlock(p);
        } while_each_task_pid(session, PIDTYPE_SID, p);
index 909eab8fb1d09ba157f578a4817fefb7d0937c36..e75ac392a313f3fad823bf2e46a03f29701e3e34 100644 (file)
@@ -2212,7 +2212,12 @@ void steal_locks(fl_owner_t from)
 
        lock_kernel();
        j = 0;
-       rcu_read_lock();
+
+       /*
+        * We are not taking a ref to the file structures, so
+        * we need to acquire ->file_lock.
+        */
+       spin_lock(&files->file_lock);
        fdt = files_fdtable(files);
        for (;;) {
                unsigned long set;
@@ -2230,7 +2235,7 @@ void steal_locks(fl_owner_t from)
                        set >>= 1;
                }
        }
-       rcu_read_unlock();
+       spin_unlock(&files->file_lock);
        unlock_kernel();
 }
 EXPORT_SYMBOL(steal_locks);
index 20feb7568deb4e3456f596ed98318c49e6de2c09..c192cb2af2c864d5882e34627523bfbcb7f4f40f 100644 (file)
@@ -294,16 +294,20 @@ static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsm
 
        files = get_files_struct(task);
        if (files) {
-               rcu_read_lock();
+               /*
+                * We are not taking a ref to the file structure, so we must
+                * hold ->file_lock.
+                */
+               spin_lock(&files->file_lock);
                file = fcheck_files(files, fd);
                if (file) {
                        *mnt = mntget(file->f_vfsmnt);
                        *dentry = dget(file->f_dentry);
-                       rcu_read_unlock();
+                       spin_unlock(&files->file_lock);
                        put_files_struct(files);
                        return 0;
                }
-               rcu_read_unlock();
+               spin_unlock(&files->file_lock);
                put_files_struct(files);
        }
        return -ENOENT;
@@ -1485,7 +1489,12 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
        if (!files)
                goto out_unlock;
        inode->i_mode = S_IFLNK;
-       rcu_read_lock();
+
+       /*
+        * We are not taking a ref to the file structure, so we must
+        * hold ->file_lock.
+        */
+       spin_lock(&files->file_lock);
        file = fcheck_files(files, fd);
        if (!file)
                goto out_unlock2;
@@ -1493,7 +1502,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
                inode->i_mode |= S_IRUSR | S_IXUSR;
        if (file->f_mode & 2)
                inode->i_mode |= S_IWUSR | S_IXUSR;
-       rcu_read_unlock();
+       spin_unlock(&files->file_lock);
        put_files_struct(files);
        inode->i_op = &proc_pid_link_inode_operations;
        inode->i_size = 64;
@@ -1503,7 +1512,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
        return NULL;
 
 out_unlock2:
-       rcu_read_unlock();
+       spin_unlock(&files->file_lock);
        put_files_struct(files);
 out_unlock:
        iput(inode);