[PATCH] files: lock-free fd look-up
authorDipankar Sarma <dipankar@in.ibm.com>
Fri, 9 Sep 2005 20:04:14 +0000 (13:04 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Fri, 9 Sep 2005 20:57:55 +0000 (13:57 -0700)
With the use of RCU in files structure, the look-up of files using fds can now
be lock-free.  The lookup is protected by rcu_read_lock()/rcu_read_unlock().
This patch changes the readers to use lock-free lookup.

Signed-off-by: Maneesh Soni <maneesh@in.ibm.com>
Signed-off-by: Ravikiran Thirumalai <kiran_th@gmail.com>
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/mips/kernel/irixioctl.c
arch/sparc64/solaris/ioctl.c
drivers/char/tty_io.c
fs/fcntl.c
fs/proc/base.c
fs/select.c
net/ipv4/netfilter/ipt_owner.c
net/ipv6/netfilter/ip6t_owner.c
security/selinux/hooks.c

index 4cd3d38a22c254ce7fec677d85ca766d2986f07e..3cdc22346f4c75a69729810a668c0cb4aaafaf14 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/syscalls.h>
 #include <linux/tty.h>
 #include <linux/file.h>
+#include <linux/rcupdate.h>
 
 #include <asm/uaccess.h>
 #include <asm/ioctl.h>
@@ -33,7 +34,7 @@ static struct tty_struct *get_tty(int fd)
        struct file *filp;
        struct tty_struct *ttyp = NULL;
 
-       spin_lock(&current->files->file_lock);
+       rcu_read_lock();
        filp = fcheck(fd);
        if(filp && filp->private_data) {
                ttyp = (struct tty_struct *) filp->private_data;
@@ -41,7 +42,7 @@ static struct tty_struct *get_tty(int fd)
                if(ttyp->magic != TTY_MAGIC)
                        ttyp =NULL;
        }
-       spin_unlock(&current->files->file_lock);
+       rcu_read_unlock();
        return ttyp;
 }
 
index 374766455f5e2d1d9b1aa4834984229a4c3ccfdb..be0a054e3ed6b1d3c22b652978a56d916aa25c0f 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/netdevice.h>
 #include <linux/mtio.h>
 #include <linux/time.h>
+#include <linux/rcupdate.h>
 #include <linux/compat.h>
 
 #include <net/sock.h>
@@ -295,16 +296,16 @@ static inline int solaris_sockmod(unsigned int fd, unsigned int cmd, u32 arg)
        struct inode *ino;
        struct fdtable *fdt;
        /* I wonder which of these tests are superfluous... --patrik */
-       spin_lock(&current->files->file_lock);
+       rcu_read_lock();
        fdt = files_fdtable(current->files);
        if (! fdt->fd[fd] ||
            ! fdt->fd[fd]->f_dentry ||
            ! (ino = fdt->fd[fd]->f_dentry->d_inode) ||
            ! S_ISSOCK(ino->i_mode)) {
-               spin_unlock(&current->files->file_lock);
+               rcu_read_unlock();
                return TBADF;
        }
-       spin_unlock(&current->files->file_lock);
+       rcu_read_unlock();
        
        switch (cmd & 0xff) {
        case 109: /* SI_SOCKPARAMS */
index 0bfc7af689172655c948ee2c025a69331692e98a..e5953f3433f3ea425ecd966c752a35ec68b63901 100644 (file)
@@ -2480,7 +2480,7 @@ static void __do_SAK(void *arg)
                }
                task_lock(p);
                if (p->files) {
-                       spin_lock(&p->files->file_lock);
+                       rcu_read_lock();
                        fdt = files_fdtable(p->files);
                        for (i=0; i < fdt->max_fds; i++) {
                                filp = fcheck_files(p->files, i);
@@ -2495,7 +2495,7 @@ static void __do_SAK(void *arg)
                                        break;
                                }
                        }
-                       spin_unlock(&p->files->file_lock);
+                       rcu_read_unlock();
                }
                task_unlock(p);
        } while_each_task_pid(session, PIDTYPE_SID, p);
index d2f3ed8acd932e92a21844fd6df19d7ad3a10b36..863b46e0d78a6594371a744358104faae657c307 100644 (file)
@@ -40,10 +40,10 @@ static inline int get_close_on_exec(unsigned int fd)
        struct files_struct *files = current->files;
        struct fdtable *fdt;
        int res;
-       spin_lock(&files->file_lock);
+       rcu_read_lock();
        fdt = files_fdtable(files);
        res = FD_ISSET(fd, fdt->close_on_exec);
-       spin_unlock(&files->file_lock);
+       rcu_read_unlock();
        return res;
 }
 
index d0087a0b024be49d86a1ec0ee47df2259d711c7c..23db452ab428c9896a96aad29217100e67aeb78a 100644 (file)
@@ -62,6 +62,7 @@
 #include <linux/namespace.h>
 #include <linux/mm.h>
 #include <linux/smp_lock.h>
+#include <linux/rcupdate.h>
 #include <linux/kallsyms.h>
 #include <linux/mount.h>
 #include <linux/security.h>
@@ -283,16 +284,16 @@ static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsm
 
        files = get_files_struct(task);
        if (files) {
-               spin_lock(&files->file_lock);
+               rcu_read_lock();
                file = fcheck_files(files, fd);
                if (file) {
                        *mnt = mntget(file->f_vfsmnt);
                        *dentry = dget(file->f_dentry);
-                       spin_unlock(&files->file_lock);
+                       rcu_read_unlock();
                        put_files_struct(files);
                        return 0;
                }
-               spin_unlock(&files->file_lock);
+               rcu_read_unlock();
                put_files_struct(files);
        }
        return -ENOENT;
@@ -1062,7 +1063,7 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
                        files = get_files_struct(p);
                        if (!files)
                                goto out;
-                       spin_lock(&files->file_lock);
+                       rcu_read_lock();
                        fdt = files_fdtable(files);
                        for (fd = filp->f_pos-2;
                             fd < fdt->max_fds;
@@ -1071,7 +1072,7 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
 
                                if (!fcheck_files(files, fd))
                                        continue;
-                               spin_unlock(&files->file_lock);
+                               rcu_read_unlock();
 
                                j = NUMBUF;
                                i = fd;
@@ -1083,12 +1084,12 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
 
                                ino = fake_ino(tid, PROC_TID_FD_DIR + fd);
                                if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino, DT_LNK) < 0) {
-                                       spin_lock(&files->file_lock);
+                                       rcu_read_lock();
                                        break;
                                }
-                               spin_lock(&files->file_lock);
+                               rcu_read_lock();
                        }
-                       spin_unlock(&files->file_lock);
+                       rcu_read_unlock();
                        put_files_struct(files);
        }
 out:
@@ -1263,9 +1264,9 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
 
        files = get_files_struct(task);
        if (files) {
-               spin_lock(&files->file_lock);
+               rcu_read_lock();
                if (fcheck_files(files, fd)) {
-                       spin_unlock(&files->file_lock);
+                       rcu_read_unlock();
                        put_files_struct(files);
                        if (task_dumpable(task)) {
                                inode->i_uid = task->euid;
@@ -1277,7 +1278,7 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
                        security_task_to_inode(task, inode);
                        return 1;
                }
-               spin_unlock(&files->file_lock);
+               rcu_read_unlock();
                put_files_struct(files);
        }
        d_drop(dentry);
@@ -1369,7 +1370,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
        if (!files)
                goto out_unlock;
        inode->i_mode = S_IFLNK;
-       spin_lock(&files->file_lock);
+       rcu_read_lock();
        file = fcheck_files(files, fd);
        if (!file)
                goto out_unlock2;
@@ -1377,7 +1378,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;
-       spin_unlock(&files->file_lock);
+       rcu_read_unlock();
        put_files_struct(files);
        inode->i_op = &proc_pid_link_inode_operations;
        inode->i_size = 64;
@@ -1387,7 +1388,7 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
        return NULL;
 
 out_unlock2:
-       spin_unlock(&files->file_lock);
+       rcu_read_unlock();
        put_files_struct(files);
 out_unlock:
        iput(inode);
index 2e56325c73c47933e10be4d695831639c84744a1..f10a10317d5494e0eb4995d9c016113a093f34ee 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/personality.h> /* for STICKY_TIMEOUTS */
 #include <linux/file.h>
 #include <linux/fs.h>
+#include <linux/rcupdate.h>
 
 #include <asm/uaccess.h>
 
@@ -185,9 +186,9 @@ int do_select(int n, fd_set_bits *fds, long *timeout)
        int retval, i;
        long __timeout = *timeout;
 
-       spin_lock(&current->files->file_lock);
+       rcu_read_lock();
        retval = max_select_fd(n, fds);
-       spin_unlock(&current->files->file_lock);
+       rcu_read_unlock();
 
        if (retval < 0)
                return retval;
@@ -329,8 +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 */
+       rcu_read_lock();
        fdt = files_fdtable(current->files);
        max_fdset = fdt->max_fdset;
+       rcu_read_unlock();
        if (n > max_fdset)
                n = max_fdset;
 
@@ -469,10 +472,14 @@ asmlinkage long sys_poll(struct pollfd __user * ufds, unsigned int nfds, long ti
        struct poll_list *head;
        struct poll_list *walk;
        struct fdtable *fdt;
+       int max_fdset;
 
        /* Do a sanity check on nfds ... */
+       rcu_read_lock();
        fdt = files_fdtable(current->files);
-       if (nfds > fdt->max_fdset && nfds > OPEN_MAX)
+       max_fdset = fdt->max_fdset;
+       rcu_read_unlock();
+       if (nfds > max_fdset && nfds > OPEN_MAX)
                return -EINVAL;
 
        if (timeout) {
index c1889f88262b4867bc844322351e4909f14ed434..0cee2862ed85f46d3fbbbe96c908c16aeb92489d 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/file.h>
+#include <linux/rcupdate.h>
 #include <net/sock.h>
 
 #include <linux/netfilter_ipv4/ipt_owner.h>
index 9b91decbfddba43f44f05ab1fe104e9c4c016000..4de4cdad4b7d281522aeb34ca813f9db5c4fa7c0 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/file.h>
+#include <linux/rcupdate.h>
 #include <net/sock.h>
 
 #include <linux/netfilter_ipv6/ip6t_owner.h>
index acb5a495a902fa792c05677d6b638021d94d966a..f40c8221ec1ba215b9526d74993ad5e8a4ed4256 100644 (file)
@@ -1652,7 +1652,7 @@ static inline void flush_unauthorized_files(struct files_struct * files)
                                                continue;
                                        }
                                        if (devnull) {
-                                               atomic_inc(&devnull->f_count);
+                                               rcuref_inc(&devnull->f_count);
                                        } else {
                                                devnull = dentry_open(dget(selinux_null), mntget(selinuxfs_mount), O_RDWR);
                                                if (!devnull) {