]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
eventpoll: add file based control interface
authorJens Axboe <axboe@kernel.dk>
Thu, 14 May 2026 14:07:19 +0000 (08:07 -0600)
committerChristian Brauner <brauner@kernel.org>
Fri, 15 May 2026 15:34:26 +0000 (17:34 +0200)
Add do_epoll_ctl_file(), which takes a pre-resolved epoll file and a
struct epoll_filefd for the target rather than two integer file
descriptors. do_epoll_ctl() remains as a thin wrapper.

In preparation for using the file based interface from io_uring.

Signed-off-by: Jens Axboe <axboe@kernel.dk>
Link: https://patch.msgid.link/20260514140817.623026-4-axboe@kernel.dk
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/eventpoll.c
include/linux/eventpoll.h

index 9ea6a2bd3d872850ac07c8ceadee710f4c18281b..1c70018663408c0d0e332b36456de063a92c30bd 100644 (file)
 
 #define EP_ITEM_COST (sizeof(struct epitem) + sizeof(struct eppoll_entry))
 
-struct epoll_filefd {
-       struct file *file;
-       int fd;
-} __packed;
-
 /* Wait structure used by the poll hooks */
 struct eppoll_entry {
        /* List header used to link this structure to the "struct epitem" */
@@ -2225,30 +2220,17 @@ static inline int epoll_mutex_lock(struct mutex *mutex, int depth,
        return -EAGAIN;
 }
 
-int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds,
-                bool nonblock)
+int do_epoll_ctl_file(struct file *f, int op, struct epoll_filefd *tf,
+                     struct epoll_event *epds, bool nonblock)
 {
        int error;
        int full_check = 0;
        struct eventpoll *ep;
        struct epitem *epi;
        struct eventpoll *tep = NULL;
-       struct epoll_filefd efd;
-
-       CLASS(fd, f)(epfd);
-       if (fd_empty(f))
-               return -EBADF;
-
-       /* Get the "struct file *" for the target file */
-       CLASS(fd, tf)(fd);
-       if (fd_empty(tf))
-               return -EBADF;
-
-       efd.file = fd_file(tf);
-       efd.fd = fd;
 
        /* The target file descriptor must support poll */
-       if (!file_can_poll(fd_file(tf)))
+       if (!file_can_poll(tf->file))
                return -EPERM;
 
        /* Check if EPOLLWAKEUP is allowed */
@@ -2261,7 +2243,7 @@ int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds,
         * adding an epoll file descriptor inside itself.
         */
        error = -EINVAL;
-       if (fd_file(f) == fd_file(tf) || !is_file_epoll(fd_file(f)))
+       if (f == tf->file || !is_file_epoll(f))
                goto error_tgt_fput;
 
        /*
@@ -2272,7 +2254,7 @@ int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds,
        if (ep_op_has_event(op) && (epds->events & EPOLLEXCLUSIVE)) {
                if (op == EPOLL_CTL_MOD)
                        goto error_tgt_fput;
-               if (op == EPOLL_CTL_ADD && (is_file_epoll(fd_file(tf)) ||
+               if (op == EPOLL_CTL_ADD && (is_file_epoll(tf->file) ||
                                (epds->events & ~EPOLLEXCLUSIVE_OK_BITS)))
                        goto error_tgt_fput;
        }
@@ -2281,7 +2263,7 @@ int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds,
         * At this point it is safe to assume that the "private_data" contains
         * our own data structure.
         */
-       ep = fd_file(f)->private_data;
+       ep = f->private_data;
 
        /*
         * When we insert an epoll file descriptor inside another epoll file
@@ -2302,16 +2284,16 @@ int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds,
        if (error)
                goto error_tgt_fput;
        if (op == EPOLL_CTL_ADD) {
-               if (READ_ONCE(fd_file(f)->f_ep) || ep->gen == loop_check_gen ||
-                   is_file_epoll(fd_file(tf))) {
+               if (READ_ONCE(f->f_ep) || ep->gen == loop_check_gen ||
+                   is_file_epoll(tf->file)) {
                        mutex_unlock(&ep->mtx);
                        error = epoll_mutex_lock(&epnested_mutex, 0, nonblock);
                        if (error)
                                goto error_tgt_fput;
                        loop_check_gen++;
                        full_check = 1;
-                       if (is_file_epoll(fd_file(tf))) {
-                               tep = fd_file(tf)->private_data;
+                       if (is_file_epoll(tf->file)) {
+                               tep = tf->file->private_data;
                                error = -ELOOP;
                                if (ep_loop_check(ep, tep) != 0)
                                        goto error_tgt_fput;
@@ -2327,14 +2309,14 @@ int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds,
         * above, we can be sure to be able to use the item looked up by
         * ep_find() till we release the mutex.
         */
-       epi = ep_find(ep, &efd);
+       epi = ep_find(ep, tf);
 
        error = -EINVAL;
        switch (op) {
        case EPOLL_CTL_ADD:
                if (!epi) {
                        epds->events |= EPOLLERR | EPOLLHUP;
-                       error = ep_insert(ep, epds, &efd, full_check);
+                       error = ep_insert(ep, epds, tf, full_check);
                } else
                        error = -EEXIST;
                break;
@@ -2369,6 +2351,26 @@ error_tgt_fput:
                mutex_unlock(&epnested_mutex);
        }
        return error;
+
+}
+
+int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds,
+                bool nonblock)
+{
+       struct epoll_filefd efd;
+
+       CLASS(fd, f)(epfd);
+       if (fd_empty(f))
+               return -EBADF;
+
+       /* Get the "struct file *" for the target file */
+       CLASS(fd, tf)(fd);
+       if (fd_empty(tf))
+               return -EBADF;
+
+       efd.file = fd_file(tf);
+       efd.fd = fd;
+       return do_epoll_ctl_file(fd_file(f), op, &efd, epds, nonblock);
 }
 
 /*
index 7bf30e9f90d7b9c7aff4416c040eb919a8d7d40b..4a6fe989810b960fefed10fb95092bfd3190545a 100644 (file)
@@ -61,6 +61,13 @@ static inline void eventpoll_release(struct file *file)
        eventpoll_release_file(file);
 }
 
+struct epoll_filefd {
+       struct file *file;
+       int fd;
+} __packed;
+
+int do_epoll_ctl_file(struct file *f, int op, struct epoll_filefd *tf,
+                     struct epoll_event *epds, bool nonblock);
 int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds,
                 bool nonblock);
 int is_file_epoll(struct file *f);