Introduce fdnull and use it to simplify perf_fget_light() to either return a valid struct fd or not -- much like fdget() itself. Signed-off-by: Peter Zijlstra (Intel) <peterz@xxxxxxxxxxxxx> --- include/linux/file.h | 7 ++++++- kernel/events/core.c | 22 +++++++++++----------- 2 files changed, 17 insertions(+), 12 deletions(-) --- a/include/linux/file.h +++ b/include/linux/file.h @@ -59,6 +59,8 @@ static inline struct fd __to_fd(unsigned return (struct fd){(struct file *)(v & ~3),v & 3}; } +#define fdnull __to_fd(0) + static inline struct fd fdget(unsigned int fd) { return __to_fd(__fdget(fd)); --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -5802,18 +5802,17 @@ EXPORT_SYMBOL_GPL(perf_event_period); static const struct file_operations perf_fops; -static inline int perf_fget_light(int fd, struct fd *p) +static inline struct fd perf_fdget(int fd) { struct fd f = fdget(fd); if (!f.file) - return -EBADF; + return fdnull; if (f.file->f_op != &perf_fops) { fdput(f); - return -EBADF; + return fdnull; } - *p = f; - return 0; + return f; } static int perf_event_set_output(struct perf_event *event, @@ -5864,10 +5863,9 @@ static long _perf_ioctl(struct perf_even int ret; if (arg != -1) { struct perf_event *output_event; - struct fd output; - ret = perf_fget_light(arg, &output); - if (ret) - return ret; + struct fd output = perf_fdget(arg); + if (!output.file) + return -EBADF; output_event = output.file->private_data; ret = perf_event_set_output(event, output_event); fdput(output); @@ -12401,9 +12399,11 @@ SYSCALL_DEFINE5(perf_event_open, return event_fd; if (group_fd != -1) { - err = perf_fget_light(group_fd, &group); - if (err) + group = perf_fdget(group_fd); + if (!group.file) { + err = -EBADF; goto err_fd; + } group_leader = group.file->private_data; if (flags & PERF_FLAG_FD_OUTPUT) output_event = group_leader;