change close_files() to use rcu_dereference_raw(files->fdt)
authorOleg Nesterov <oleg@redhat.com>
Sat, 11 Jan 2014 18:19:53 +0000 (19:19 +0100)
committerAl Viro <viro@zeniv.linux.org.uk>
Sat, 25 Jan 2014 08:14:37 +0000 (03:14 -0500)
put_files_struct() and close_files() do rcu_read_lock() to make
rcu_dereference_check_fdtable() happy.

This looks a bit ugly, files_fdtable() just reads the pointer,
we can simply use rcu_dereference_raw() to avoid the warning.

The patch also changes close_files() to return fdt, this avoids
another rcu_read_lock()/files_fdtable() in put_files_struct().

I think close_files() needs more cleanups:

- we do not need xchg() exactly because we are the last
  user of this files_struct

- "if (file)" should be turned into WARN_ON(!file)

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/file.c

index 957cbc0..d34e59e 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -348,21 +348,16 @@ out:
        return NULL;
 }
 
-static void close_files(struct files_struct * files)
+static struct fdtable *close_files(struct files_struct * files)
 {
-       int i, j;
-       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.  But use RCU to shut RCU-lockdep up.
+        * files structure.
         */
-       rcu_read_lock();
-       fdt = files_fdtable(files);
-       rcu_read_unlock();
+       struct fdtable *fdt = rcu_dereference_raw(files->fdt);
+       int i, j = 0;
+
        for (;;) {
                unsigned long set;
                i = j * BITS_PER_LONG;
@@ -381,6 +376,8 @@ static void close_files(struct files_struct * files)
                        set >>= 1;
                }
        }
+
+       return fdt;
 }
 
 struct files_struct *get_files_struct(struct task_struct *task)
@@ -398,14 +395,9 @@ struct files_struct *get_files_struct(struct task_struct *task)
 
 void put_files_struct(struct files_struct *files)
 {
-       struct fdtable *fdt;
-
        if (atomic_dec_and_test(&files->count)) {
-               close_files(files);
-               /* not really needed, since nobody can see us */
-               rcu_read_lock();
-               fdt = files_fdtable(files);
-               rcu_read_unlock();
+               struct fdtable *fdt = close_files(files);
+
                /* free the arrays if they are not embedded */
                if (fdt != &files->fdtab)
                        __free_fdtable(fdt);