[PATCH] files: lock-free fd look-up
[linux-2.6.git] / fs / select.c
index b80e7eb0ac0dac26325c8ac0d2b7d992c1d7da20..f10a10317d5494e0eb4995d9c016113a093f34ee 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/personality.h> /* for STICKY_TIMEOUTS */
 #include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/personality.h> /* for STICKY_TIMEOUTS */
 #include <linux/file.h>
 #include <linux/fs.h>
+#include <linux/rcupdate.h>
 
 #include <asm/uaccess.h>
 
 
 #include <asm/uaccess.h>
 
@@ -132,11 +133,13 @@ static int max_select_fd(unsigned long n, fd_set_bits *fds)
        unsigned long *open_fds;
        unsigned long set;
        int max;
        unsigned long *open_fds;
        unsigned long set;
        int max;
+       struct fdtable *fdt;
 
        /* handle last in-complete long-word first */
        set = ~(~0UL << (n & (__NFDBITS-1)));
        n /= __NFDBITS;
 
        /* handle last in-complete long-word first */
        set = ~(~0UL << (n & (__NFDBITS-1)));
        n /= __NFDBITS;
-       open_fds = current->files->open_fds->fds_bits+n;
+       fdt = files_fdtable(current->files);
+       open_fds = fdt->open_fds->fds_bits+n;
        max = 0;
        if (set) {
                set &= BITS(fds, n);
        max = 0;
        if (set) {
                set &= BITS(fds, n);
@@ -183,9 +186,9 @@ int do_select(int n, fd_set_bits *fds, long *timeout)
        int retval, i;
        long __timeout = *timeout;
 
        int retval, i;
        long __timeout = *timeout;
 
-       spin_lock(&current->files->file_lock);
+       rcu_read_lock();
        retval = max_select_fd(n, fds);
        retval = max_select_fd(n, fds);
-       spin_unlock(&current->files->file_lock);
+       rcu_read_unlock();
 
        if (retval < 0)
                return retval;
 
        if (retval < 0)
                return retval;
@@ -299,6 +302,7 @@ sys_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, s
        char *bits;
        long timeout;
        int ret, size, max_fdset;
        char *bits;
        long timeout;
        int ret, size, max_fdset;
+       struct fdtable *fdt;
 
        timeout = MAX_SCHEDULE_TIMEOUT;
        if (tvp) {
 
        timeout = MAX_SCHEDULE_TIMEOUT;
        if (tvp) {
@@ -326,7 +330,10 @@ sys_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, s
                goto out_nofds;
 
        /* max_fdset can increase, so grab it once to avoid race */
                goto out_nofds;
 
        /* max_fdset can increase, so grab it once to avoid race */
-       max_fdset = current->files->max_fdset;
+       rcu_read_lock();
+       fdt = files_fdtable(current->files);
+       max_fdset = fdt->max_fdset;
+       rcu_read_unlock();
        if (n > max_fdset)
                n = max_fdset;
 
        if (n > max_fdset)
                n = max_fdset;
 
@@ -464,9 +471,15 @@ asmlinkage long sys_poll(struct pollfd __user * ufds, unsigned int nfds, long ti
        unsigned int i;
        struct poll_list *head;
        struct poll_list *walk;
        unsigned int i;
        struct poll_list *head;
        struct poll_list *walk;
+       struct fdtable *fdt;
+       int max_fdset;
 
        /* Do a sanity check on nfds ... */
 
        /* Do a sanity check on nfds ... */
-       if (nfds > current->files->max_fdset && nfds > OPEN_MAX)
+       rcu_read_lock();
+       fdt = files_fdtable(current->files);
+       max_fdset = fdt->max_fdset;
+       rcu_read_unlock();
+       if (nfds > max_fdset && nfds > OPEN_MAX)
                return -EINVAL;
 
        if (timeout) {
                return -EINVAL;
 
        if (timeout) {