pretty much every member of the files struct is protected by the file_lock
rwlock now.  so it makes no sense to use xchg any more (extra unnecessary
atomic ops).  plus, there's two cases where the lock is missing.  i bet
you can't hit the race in practice, but it's easy to fix.

diff -urNX dontdiff linux-orig/fs/file.c linux-willy/fs/file.c
--- linux-orig/fs/file.c        Tue Nov 28 23:43:39 2000
+++ linux-willy/fs/file.c       Sat Feb 10 00:26:59 2001
@@ -98,8 +98,10 @@
                struct file **old_fds;
                int i;
                
-               old_fds = xchg(&files->fd, new_fds);
-               i = xchg(&files->max_fds, nfds);
+               old_fds = files->fd;
+               files->fd = new_fds;
+               i = files->max_fds;
+               files->max_fds = nfds;
 
                /* Don't copy/clear the array if we are creating a new
                   fd array for fork() */
@@ -195,6 +197,8 @@
        
        /* Copy the existing tables and install the new pointers */
        if (nfds > files->max_fdset) {
+               int ofds;
+               fd_set *old_openset, *old_execset;
                int i = files->max_fdset / (sizeof(unsigned long) * 8);
                int count = (nfds - files->max_fdset) / 8;
                
@@ -209,12 +213,15 @@
                        memset (&new_execset->fds_bits[i], 0, count);
                }
                
-               nfds = xchg(&files->max_fdset, nfds);
-               new_openset = xchg(&files->open_fds, new_openset);
-               new_execset = xchg(&files->close_on_exec, new_execset);
+               ofds = files->max_fdset;
+               files->max_fdset = nfds;
+               old_openset = files->open_fds;
+               files->open_fds = new_openset;
+               old_execset = files->close_on_exec;
+               files->close_on_exec = new_execset;
                write_unlock(&files->file_lock);
-               free_fdset (new_openset, nfds);
-               free_fdset (new_execset, nfds);
+               free_fdset (old_openset, ofds);
+               free_fdset (old_execset, ofds);
                write_lock(&files->file_lock);
                return 0;
        } 
diff -urNX dontdiff linux-orig/fs/select.c linux-willy/fs/select.c
--- linux-orig/fs/select.c      Thu Nov 16 13:54:18 2000
+++ linux-willy/fs/select.c     Sat Feb 10 00:32:42 2001
@@ -285,8 +285,10 @@
        if (n < 0)
                goto out_nofds;
 
+       read_lock(&current->files->file_lock);
        if (n > current->files->max_fdset)
                n = current->files->max_fdset;
+       read_unlock(&current->files->file_lock);
 
        /*
         * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
@@ -414,7 +416,11 @@
        int nchunks, nleft;
 
        /* Do a sanity check on nfds ... */
-       if (nfds > current->files->max_fds)
+       read_lock(&current->files->file_lock);
+       i = current->files->max_fds;
+       read_unlock(&current->files->file_lock);
+
+       if (nfds > i)
                return -EINVAL;
 
        if (timeout) {
diff -urNX dontdiff linux-orig/kernel/exit.c linux-willy/kernel/exit.c
--- linux-orig/kernel/exit.c    Thu Jan  4 02:00:35 2001
+++ linux-willy/kernel/exit.c   Sat Feb 10 00:44:37 2001
@@ -186,9 +186,11 @@
                set = files->open_fds->fds_bits[j++];
                while (set) {
                        if (set & 1) {
-                               struct file * file = xchg(&files->fd[i], NULL);
-                               if (file)
+                               struct file * file = files->fd[i];
+                               if (file) {
+                                       files->fd[i] = NULL;
                                        filp_close(file, files);
+                               }
                        }
                        i++;
                        set >>= 1;
-
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to [EMAIL PROTECTED]
  • No Subject Matthew Wilcox

Reply via email to