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:
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);
|
||||
}
|
||||
|
||||
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,
|
||||
fmode_t mask, unsigned int refs)
|
||||
{
|
||||
struct file *file;
|
||||
|
||||
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();
|
||||
|
||||
return file;
|
||||
|
Loading…
Reference in New Issue
Block a user