Revert "fget: clarify and improve __fget_files() implementation"
Temporarily revert commit 0849f83e47
("fget: clarify and improve
__fget_files() implementation") to enable subsequent upstream
commits to apply and build cleanly.
Stable-dep-of: bebf684bf330 ("file: Rename __fcheck_files to files_lookup_fd_raw")
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
4d037e1173
commit
e6f42bc11a
72
fs/file.c
72
fs/file.c
@@ -849,68 +849,28 @@ void do_close_on_exec(struct files_struct *files)
|
|||||||
spin_unlock(&files->file_lock);
|
spin_unlock(&files->file_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct file *__fget_files_rcu(struct files_struct *files,
|
|
||||||
unsigned int fd, fmode_t mask, unsigned int refs)
|
|
||||||
{
|
|
||||||
for (;;) {
|
|
||||||
struct file *file;
|
|
||||||
struct fdtable *fdt = rcu_dereference_raw(files->fdt);
|
|
||||||
struct file __rcu **fdentry;
|
|
||||||
|
|
||||||
if (unlikely(fd >= fdt->max_fds))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
fdentry = fdt->fd + array_index_nospec(fd, fdt->max_fds);
|
|
||||||
file = rcu_dereference_raw(*fdentry);
|
|
||||||
if (unlikely(!file))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (unlikely(file->f_mode & mask))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Ok, we have a file pointer. However, because we do
|
|
||||||
* this all locklessly under RCU, we may be racing with
|
|
||||||
* that file being closed.
|
|
||||||
*
|
|
||||||
* Such a race can take two forms:
|
|
||||||
*
|
|
||||||
* (a) the file ref already went down to zero,
|
|
||||||
* and get_file_rcu_many() fails. Just try
|
|
||||||
* again:
|
|
||||||
*/
|
|
||||||
if (unlikely(!get_file_rcu_many(file, refs)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (b) the file table entry has changed under us.
|
|
||||||
* Note that we don't need to re-check the 'fdt->fd'
|
|
||||||
* pointer having changed, because it always goes
|
|
||||||
* hand-in-hand with 'fdt'.
|
|
||||||
*
|
|
||||||
* If so, we need to put our refs and try again.
|
|
||||||
*/
|
|
||||||
if (unlikely(rcu_dereference_raw(files->fdt) != fdt) ||
|
|
||||||
unlikely(rcu_dereference_raw(*fdentry) != file)) {
|
|
||||||
fput_many(file, refs);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Ok, we have a ref to the file, and checked that it
|
|
||||||
* still exists.
|
|
||||||
*/
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct file *__fget_files(struct files_struct *files, unsigned int fd,
|
static struct file *__fget_files(struct files_struct *files, unsigned int fd,
|
||||||
fmode_t mask, unsigned int refs)
|
fmode_t mask, unsigned int refs)
|
||||||
{
|
{
|
||||||
struct file *file;
|
struct file *file;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
file = __fget_files_rcu(files, fd, mask, refs);
|
loop:
|
||||||
|
file = fcheck_files(files, fd);
|
||||||
|
if (file) {
|
||||||
|
/* File object ref couldn't be taken.
|
||||||
|
* dup2() atomicity guarantee is the reason
|
||||||
|
* we loop to catch the new file (or NULL pointer)
|
||||||
|
*/
|
||||||
|
if (file->f_mode & mask)
|
||||||
|
file = NULL;
|
||||||
|
else if (!get_file_rcu_many(file, refs))
|
||||||
|
goto loop;
|
||||||
|
else if (__fcheck_files(files, fd) != file) {
|
||||||
|
fput_many(file, refs);
|
||||||
|
goto loop;
|
||||||
|
}
|
||||||
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
return file;
|
return file;
|
||||||
|
Reference in New Issue
Block a user