change close_files() to use rcu_dereference_raw(files->fdt)

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>
This commit is contained in:
Oleg Nesterov 2014-01-11 19:19:53 +01:00 committed by Al Viro
parent a8d4b8345e
commit ce08b62d18
1 changed files with 9 additions and 17 deletions

View File

@ -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);