[PATCH] files: fix preemption issues
authorDipankar Sarma <dipankar@in.ibm.com>
Sat, 17 Sep 2005 02:28:13 +0000 (19:28 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Sat, 17 Sep 2005 18:50:02 +0000 (11:50 -0700)
With the new fdtable locking rules, you have to protect fdtable with either
->file_lock or rcu_read_lock/unlock().  There are some places where we
aren't doing either.  This patch fixes those places.

Signed-off-by: Dipankar Sarma <dipankar@in.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
arch/alpha/kernel/osf_sys.c
arch/ia64/kernel/perfmon.c
fs/locks.c
fs/proc/array.c
kernel/exit.c

index 0636116210d236e2ed0353c4296036e2edf793ec..01fe990d3e54b2c59d8c5fdfafbbea79a11ce1d7 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/namei.h>
 #include <linux/uio.h>
 #include <linux/vfs.h>
+#include <linux/rcupdate.h>
 
 #include <asm/fpu.h>
 #include <asm/io.h>
@@ -975,6 +976,7 @@ osf_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp,
        long timeout;
        int ret = -EINVAL;
        struct fdtable *fdt;
+       int max_fdset;
 
        timeout = MAX_SCHEDULE_TIMEOUT;
        if (tvp) {
@@ -996,8 +998,11 @@ osf_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp,
                }
        }
 
+       rcu_read_lock();
        fdt = files_fdtable(current->files);
-       if (n < 0 || n > fdt->max_fdset)
+       max_fdset = fdt->max_fdset;
+       rcu_read_unlock();
+       if (n < 0 || n > max_fdset)
                goto out_nofds;
 
        /*
index af42cda6be80dfdc1935685de95e77f7a250e9a7..d71731ee5b61fc8ce322458d3ca4dc9012b48335 100644 (file)
@@ -2218,12 +2218,13 @@ static void
 pfm_free_fd(int fd, struct file *file)
 {
        struct files_struct *files = current->files;
-       struct fdtable *fdt = files_fdtable(files);
+       struct fdtable *fdt;
 
        /* 
         * there ie no fd_uninstall(), so we do it here
         */
        spin_lock(&files->file_lock);
+       fdt = files_fdtable(files);
        rcu_assign_pointer(fdt->fd[fd], NULL);
        spin_unlock(&files->file_lock);
 
index c2c09b4798d606b4bc9e5d56a518beef021543f3..f7daa5f48949c41ea02b687e1521a440387b0592 100644 (file)
 #include <linux/smp_lock.h>
 #include <linux/syscalls.h>
 #include <linux/time.h>
+#include <linux/rcupdate.h>
 
 #include <asm/semaphore.h>
 #include <asm/uaccess.h>
@@ -2205,6 +2206,7 @@ void steal_locks(fl_owner_t from)
 
        lock_kernel();
        j = 0;
+       rcu_read_lock();
        fdt = files_fdtable(files);
        for (;;) {
                unsigned long set;
@@ -2222,6 +2224,7 @@ void steal_locks(fl_owner_t from)
                        set >>= 1;
                }
        }
+       rcu_read_unlock();
        unlock_kernel();
 }
 EXPORT_SYMBOL(steal_locks);
index d88d518d30f605d216ba292e20be281cacf0eab4..d84eecacbeaff81b91cb4ed43d65c2b6e418c163 100644 (file)
@@ -74,6 +74,7 @@
 #include <linux/file.h>
 #include <linux/times.h>
 #include <linux/cpuset.h>
+#include <linux/rcupdate.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -180,12 +181,14 @@ static inline char * task_state(struct task_struct *p, char *buffer)
                p->gid, p->egid, p->sgid, p->fsgid);
        read_unlock(&tasklist_lock);
        task_lock(p);
+       rcu_read_lock();
        if (p->files)
                fdt = files_fdtable(p->files);
        buffer += sprintf(buffer,
                "FDSize:\t%d\n"
                "Groups:\t",
                fdt ? fdt->max_fds : 0);
+       rcu_read_unlock();
 
        group_info = p->group_info;
        get_group_info(group_info);
index 6d2089a1bce74614009acfb18f1e3b95458e90cf..ee6d8b8abef5454fc2e224fdfbdf12a332591c6e 100644 (file)
@@ -371,6 +371,12 @@ static inline void close_files(struct files_struct * files)
        struct fdtable *fdt;
 
        j = 0;
+
+       /*
+        * It is safe to dereference the fd table without RCU or
+        * ->file_lock because this is the last reference to the
+        * files structure.
+        */
        fdt = files_fdtable(files);
        for (;;) {
                unsigned long set;