]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
get rid of perf_fget_light(), convert kernel/events/core.c to CLASS(fd)
authorAl Viro <viro@zeniv.linux.org.uk>
Sun, 2 Jun 2024 18:25:46 +0000 (14:25 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Sun, 3 Nov 2024 06:28:06 +0000 (01:28 -0500)
Lift fdget() and fdput() out of perf_fget_light(), turning it into
is_perf_file(struct fd f).  The life gets easier in both callers
if we do fdget() unconditionally, including the case when we are
given -1 instead of a descriptor - that avoids a reassignment in
perf_event_open(2) and it avoids a nasty temptation in _perf_ioctl()
where we must *not* lift output_event out of scope for output.

Reviewed-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
kernel/events/core.c

index e3589c4287cb458c09352dc7895d9812a9cc7158..85b209626dd76982c48ed0b5300e1b344ffca2b0 100644 (file)
@@ -5998,18 +5998,9 @@ 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 bool is_perf_file(struct fd f)
 {
-       struct fd f = fdget(fd);
-       if (!fd_file(f))
-               return -EBADF;
-
-       if (fd_file(f)->f_op != &perf_fops) {
-               fdput(f);
-               return -EBADF;
-       }
-       *p = f;
-       return 0;
+       return !fd_empty(f) && fd_file(f)->f_op == &perf_fops;
 }
 
 static int perf_event_set_output(struct perf_event *event,
@@ -6057,20 +6048,14 @@ static long _perf_ioctl(struct perf_event *event, unsigned int cmd, unsigned lon
 
        case PERF_EVENT_IOC_SET_OUTPUT:
        {
-               int ret;
+               CLASS(fd, output)(arg);      // arg == -1 => empty
+               struct perf_event *output_event = NULL;
                if (arg != -1) {
-                       struct perf_event *output_event;
-                       struct fd output;
-                       ret = perf_fget_light(arg, &output);
-                       if (ret)
-                               return ret;
+                       if (!is_perf_file(output))
+                               return -EBADF;
                        output_event = fd_file(output)->private_data;
-                       ret = perf_event_set_output(event, output_event);
-                       fdput(output);
-               } else {
-                       ret = perf_event_set_output(event, NULL);
                }
-               return ret;
+               return perf_event_set_output(event, output_event);
        }
 
        case PERF_EVENT_IOC_SET_FILTER:
@@ -12664,7 +12649,6 @@ SYSCALL_DEFINE5(perf_event_open,
        struct perf_event_attr attr;
        struct perf_event_context *ctx;
        struct file *event_file = NULL;
-       struct fd group = EMPTY_FD;
        struct task_struct *task = NULL;
        struct pmu *pmu;
        int event_fd;
@@ -12735,10 +12719,12 @@ SYSCALL_DEFINE5(perf_event_open,
        if (event_fd < 0)
                return event_fd;
 
+       CLASS(fd, group)(group_fd);     // group_fd == -1 => empty
        if (group_fd != -1) {
-               err = perf_fget_light(group_fd, &group);
-               if (err)
+               if (!is_perf_file(group)) {
+                       err = -EBADF;
                        goto err_fd;
+               }
                group_leader = fd_file(group)->private_data;
                if (flags & PERF_FLAG_FD_OUTPUT)
                        output_event = group_leader;
@@ -12750,7 +12736,7 @@ SYSCALL_DEFINE5(perf_event_open,
                task = find_lively_task_by_vpid(pid);
                if (IS_ERR(task)) {
                        err = PTR_ERR(task);
-                       goto err_group_fd;
+                       goto err_fd;
                }
        }
 
@@ -13017,12 +13003,11 @@ SYSCALL_DEFINE5(perf_event_open,
        mutex_unlock(&current->perf_event_mutex);
 
        /*
-        * Drop the reference on the group_event after placing the
-        * new event on the sibling_list. This ensures destruction
-        * of the group leader will find the pointer to itself in
-        * perf_group_detach().
+        * File reference in group guarantees that group_leader has been
+        * kept alive until we place the new event on the sibling_list.
+        * This ensures destruction of the group leader will find
+        * the pointer to itself in perf_group_detach().
         */
-       fdput(group);
        fd_install(event_fd, event_file);
        return event_fd;
 
@@ -13041,8 +13026,6 @@ err_alloc:
 err_task:
        if (task)
                put_task_struct(task);
-err_group_fd:
-       fdput(group);
 err_fd:
        put_unused_fd(event_fd);
        return err;