get rid of ...lookup...fdget_rcu() family

Once upon a time, predecessors of those used to do file lookup
without bumping a refcount, provided that caller held rcu_read_lock()
across the lookup and whatever it wanted to read from the struct
file found.  When struct file allocation switched to SLAB_TYPESAFE_BY_RCU,
that stopped being feasible and these primitives started to bump the
file refcount for lookup result, requiring the caller to call fput()
afterwards.

But that turned them pointless - e.g.
	rcu_read_lock();
	file = lookup_fdget_rcu(fd);
	rcu_read_unlock();
is equivalent to
	file = fget_raw(fd);
and all callers of lookup_fdget_rcu() are of that form.  Similarly,
task_lookup_fdget_rcu() calls can be replaced with calling fget_task().
task_lookup_next_fdget_rcu() doesn't have direct counterparts, but
its callers would be happier if we replaced it with an analogue that
deals with RCU internally.

Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Al Viro 2024-07-31 11:49:04 -04:00
parent 8cf0b93919
commit 8fd3395ec9
9 changed files with 14 additions and 62 deletions

View File

@ -73,9 +73,7 @@ static struct spu_context *coredump_next_context(int *fd)
return NULL; return NULL;
*fd = n - 1; *fd = n - 1;
rcu_read_lock(); file = fget_raw(*fd);
file = lookup_fdget_rcu(*fd);
rcu_read_unlock();
if (file) { if (file) {
ctx = SPUFS_I(file_inode(file))->i_ctx; ctx = SPUFS_I(file_inode(file))->i_ctx;
get_spu_context(ctx); get_spu_context(ctx);

View File

@ -1037,29 +1037,7 @@ struct file *fget_task(struct task_struct *task, unsigned int fd)
return file; return file;
} }
struct file *lookup_fdget_rcu(unsigned int fd) struct file *fget_task_next(struct task_struct *task, unsigned int *ret_fd)
{
return __fget_files_rcu(current->files, fd, 0);
}
EXPORT_SYMBOL_GPL(lookup_fdget_rcu);
struct file *task_lookup_fdget_rcu(struct task_struct *task, unsigned int fd)
{
/* Must be called with rcu_read_lock held */
struct files_struct *files;
struct file *file = NULL;
task_lock(task);
files = task->files;
if (files)
file = __fget_files_rcu(files, fd, 0);
task_unlock(task);
return file;
}
struct file *task_lookup_next_fdget_rcu(struct task_struct *task, unsigned int *ret_fd)
{ {
/* Must be called with rcu_read_lock held */ /* Must be called with rcu_read_lock held */
struct files_struct *files; struct files_struct *files;
@ -1069,17 +1047,19 @@ struct file *task_lookup_next_fdget_rcu(struct task_struct *task, unsigned int *
task_lock(task); task_lock(task);
files = task->files; files = task->files;
if (files) { if (files) {
rcu_read_lock();
for (; fd < files_fdtable(files)->max_fds; fd++) { for (; fd < files_fdtable(files)->max_fds; fd++) {
file = __fget_files_rcu(files, fd, 0); file = __fget_files_rcu(files, fd, 0);
if (file) if (file)
break; break;
} }
rcu_read_unlock();
} }
task_unlock(task); task_unlock(task);
*ret_fd = fd; *ret_fd = fd;
return file; return file;
} }
EXPORT_SYMBOL(task_lookup_next_fdget_rcu); EXPORT_SYMBOL(fget_task_next);
/* /*
* Lightweight file lookup - no refcnt increment if fd table isn't shared. * Lightweight file lookup - no refcnt increment if fd table isn't shared.

View File

@ -34,7 +34,6 @@
#include <linux/lockref.h> #include <linux/lockref.h>
#include <linux/rhashtable.h> #include <linux/rhashtable.h>
#include <linux/pid_namespace.h> #include <linux/pid_namespace.h>
#include <linux/fdtable.h>
#include <linux/file.h> #include <linux/file.h>
#include "gfs2.h" #include "gfs2.h"
@ -2768,25 +2767,18 @@ static struct file *gfs2_glockfd_next_file(struct gfs2_glockfd_iter *i)
i->file = NULL; i->file = NULL;
} }
rcu_read_lock();
for(;; i->fd++) { for(;; i->fd++) {
struct inode *inode; i->file = fget_task_next(i->task, &i->fd);
i->file = task_lookup_next_fdget_rcu(i->task, &i->fd);
if (!i->file) { if (!i->file) {
i->fd = 0; i->fd = 0;
break; break;
} }
inode = file_inode(i->file); if (file_inode(i->file)->i_sb == i->sb)
if (inode->i_sb == i->sb)
break; break;
rcu_read_unlock();
fput(i->file); fput(i->file);
rcu_read_lock();
} }
rcu_read_unlock();
return i->file; return i->file;
} }

View File

@ -16,7 +16,6 @@
#include <linux/security.h> #include <linux/security.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/fdtable.h>
#include <linux/fsnotify_backend.h> #include <linux/fsnotify_backend.h>
static int dir_notify_enable __read_mostly = 1; static int dir_notify_enable __read_mostly = 1;
@ -347,9 +346,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned int arg)
new_fsn_mark = NULL; new_fsn_mark = NULL;
} }
rcu_read_lock(); f = fget_raw(fd);
f = lookup_fdget_rcu(fd);
rcu_read_unlock();
/* if (f != filp) means that we lost a race and another task/thread /* if (f != filp) means that we lost a race and another task/thread
* actually closed the fd we are still playing with before we grabbed * actually closed the fd we are still playing with before we grabbed

View File

@ -116,9 +116,7 @@ static bool tid_fd_mode(struct task_struct *task, unsigned fd, fmode_t *mode)
{ {
struct file *file; struct file *file;
rcu_read_lock(); file = fget_task(task, fd);
file = task_lookup_fdget_rcu(task, fd);
rcu_read_unlock();
if (file) { if (file) {
*mode = file->f_mode; *mode = file->f_mode;
fput(file); fput(file);
@ -258,19 +256,17 @@ static int proc_readfd_common(struct file *file, struct dir_context *ctx,
if (!dir_emit_dots(file, ctx)) if (!dir_emit_dots(file, ctx))
goto out; goto out;
rcu_read_lock();
for (fd = ctx->pos - 2;; fd++) { for (fd = ctx->pos - 2;; fd++) {
struct file *f; struct file *f;
struct fd_data data; struct fd_data data;
char name[10 + 1]; char name[10 + 1];
unsigned int len; unsigned int len;
f = task_lookup_next_fdget_rcu(p, &fd); f = fget_task_next(p, &fd);
ctx->pos = fd + 2LL; ctx->pos = fd + 2LL;
if (!f) if (!f)
break; break;
data.mode = f->f_mode; data.mode = f->f_mode;
rcu_read_unlock();
fput(f); fput(f);
data.fd = fd; data.fd = fd;
@ -278,11 +274,9 @@ static int proc_readfd_common(struct file *file, struct dir_context *ctx,
if (!proc_fill_cache(file, ctx, if (!proc_fill_cache(file, ctx,
name, len, instantiate, p, name, len, instantiate, p,
&data)) &data))
goto out; break;
cond_resched(); cond_resched();
rcu_read_lock();
} }
rcu_read_unlock();
out: out:
put_task_struct(p); put_task_struct(p);
return 0; return 0;

View File

@ -92,10 +92,6 @@ static inline struct file *files_lookup_fd_locked(struct files_struct *files, un
return files_lookup_fd_raw(files, fd); return files_lookup_fd_raw(files, fd);
} }
struct file *lookup_fdget_rcu(unsigned int fd);
struct file *task_lookup_fdget_rcu(struct task_struct *task, unsigned int fd);
struct file *task_lookup_next_fdget_rcu(struct task_struct *task, unsigned int *fd);
static inline bool close_on_exec(unsigned int fd, const struct files_struct *files) static inline bool close_on_exec(unsigned int fd, const struct files_struct *files)
{ {
return test_bit(fd, files_fdtable(files)->close_on_exec); return test_bit(fd, files_fdtable(files)->close_on_exec);

View File

@ -72,6 +72,7 @@ static inline void fdput(struct fd fd)
extern struct file *fget(unsigned int fd); extern struct file *fget(unsigned int fd);
extern struct file *fget_raw(unsigned int fd); extern struct file *fget_raw(unsigned int fd);
extern struct file *fget_task(struct task_struct *task, unsigned int fd); extern struct file *fget_task(struct task_struct *task, unsigned int fd);
extern struct file *fget_task_next(struct task_struct *task, unsigned int *fd);
extern void __f_unlock_pos(struct file *); extern void __f_unlock_pos(struct file *);
struct fd fdget(unsigned int fd); struct fd fdget(unsigned int fd);

View File

@ -5,7 +5,6 @@
#include <linux/namei.h> #include <linux/namei.h>
#include <linux/pid_namespace.h> #include <linux/pid_namespace.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/fdtable.h>
#include <linux/filter.h> #include <linux/filter.h>
#include <linux/bpf_mem_alloc.h> #include <linux/bpf_mem_alloc.h>
#include <linux/btf_ids.h> #include <linux/btf_ids.h>
@ -286,17 +285,14 @@ again:
curr_fd = 0; curr_fd = 0;
} }
rcu_read_lock(); f = fget_task_next(curr_task, &curr_fd);
f = task_lookup_next_fdget_rcu(curr_task, &curr_fd);
if (f) { if (f) {
/* set info->fd */ /* set info->fd */
info->fd = curr_fd; info->fd = curr_fd;
rcu_read_unlock();
return f; return f;
} }
/* the current task is done, go to the next task */ /* the current task is done, go to the next task */
rcu_read_unlock();
put_task_struct(curr_task); put_task_struct(curr_task);
if (info->common.type == BPF_TASK_ITER_TID) { if (info->common.type == BPF_TASK_ITER_TID) {

View File

@ -63,9 +63,7 @@ get_file_raw_ptr(struct task_struct *task, unsigned int idx)
{ {
struct file *file; struct file *file;
rcu_read_lock(); file = fget_task(task, idx);
file = task_lookup_fdget_rcu(task, idx);
rcu_read_unlock();
if (file) if (file)
fput(file); fput(file);