From 5de2759f2b7c925f187e552cae47775acd5f4b40 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 14 May 2026 08:07:18 -0600 Subject: eventpoll: export is_file_epoll() Make is_file_epoll() available outside of epoll. This is in preparation from using it from io_uring. Signed-off-by: Jens Axboe Link: https://patch.msgid.link/20260514140817.623026-3-axboe@kernel.dk Reviewed-by: Christian Brauner Signed-off-by: Christian Brauner --- include/linux/eventpoll.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/linux/eventpoll.h b/include/linux/eventpoll.h index 728fb5dee5ed..7bf30e9f90d7 100644 --- a/include/linux/eventpoll.h +++ b/include/linux/eventpoll.h @@ -63,6 +63,7 @@ static inline void eventpoll_release(struct file *file) int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds, bool nonblock); +int is_file_epoll(struct file *f); /* Tells if the epoll_ctl(2) operation needs an event copy from userspace */ static inline int ep_op_has_event(int op) -- cgit v1.2.3 From 0995baf261ce8fc141768911d97ba76e854e26cf Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 14 May 2026 08:07:19 -0600 Subject: eventpoll: add file based control interface 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 Link: https://patch.msgid.link/20260514140817.623026-4-axboe@kernel.dk Signed-off-by: Christian Brauner --- fs/eventpoll.c | 62 ++++++++++++++++++++++++----------------------- include/linux/eventpoll.h | 7 ++++++ 2 files changed, 39 insertions(+), 30 deletions(-) (limited to 'include') diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 9ea6a2bd3d87..1c7001866340 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -99,11 +99,6 @@ #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); } /* diff --git a/include/linux/eventpoll.h b/include/linux/eventpoll.h index 7bf30e9f90d7..4a6fe989810b 100644 --- a/include/linux/eventpoll.h +++ b/include/linux/eventpoll.h @@ -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); -- cgit v1.2.3 From 463aba8090738bcd956297f7341b6874e76ae664 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 14 May 2026 08:07:20 -0600 Subject: eventpoll: rename struct epoll_filefd to epoll_key This more accurately describes what purpose this structure serves, as a lookup key. Suggested-by: Christian Brauner Signed-off-by: Jens Axboe Link: https://patch.msgid.link/20260514140817.623026-5-axboe@kernel.dk Signed-off-by: Christian Brauner --- fs/eventpoll.c | 13 ++++++------- include/linux/eventpoll.h | 4 ++-- 2 files changed, 8 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 1c7001866340..7535b10f8c6a 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -141,7 +141,7 @@ struct epitem { struct epitem *next; /* The file descriptor information this item refers to */ - struct epoll_filefd ffd; + struct epoll_key ffd; /* List containing poll wait queues */ struct eppoll_entry *pwqlist; @@ -335,8 +335,7 @@ int is_file_epoll(struct file *f) } /* Compare RB tree keys */ -static inline int ep_cmp_ffd(struct epoll_filefd *p1, - struct epoll_filefd *p2) +static inline int ep_cmp_ffd(struct epoll_key *p1, struct epoll_key *p2) { return (p1->file > p2->file ? +1: (p1->file < p2->file ? -1 : p1->fd - p2->fd)); @@ -1160,7 +1159,7 @@ static int ep_alloc(struct eventpoll **pep) * are protected by the "mtx" mutex, and ep_find() must be called with * "mtx" held. */ -static struct epitem *ep_find(struct eventpoll *ep, struct epoll_filefd *tf) +static struct epitem *ep_find(struct eventpoll *ep, struct epoll_key *tf) { int kcmp; struct rb_node *rbp; @@ -1549,7 +1548,7 @@ allocate: * Must be called with "mtx" held. */ static int ep_insert(struct eventpoll *ep, const struct epoll_event *event, - struct epoll_filefd *tf, int full_check) + struct epoll_key *tf, int full_check) { int error, pwake = 0; __poll_t revents; @@ -2220,7 +2219,7 @@ static inline int epoll_mutex_lock(struct mutex *mutex, int depth, return -EAGAIN; } -int do_epoll_ctl_file(struct file *f, int op, struct epoll_filefd *tf, +int do_epoll_ctl_file(struct file *f, int op, struct epoll_key *tf, struct epoll_event *epds, bool nonblock) { int error; @@ -2357,7 +2356,7 @@ error_tgt_fput: int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds, bool nonblock) { - struct epoll_filefd efd; + struct epoll_key efd; CLASS(fd, f)(epfd); if (fd_empty(f)) diff --git a/include/linux/eventpoll.h b/include/linux/eventpoll.h index 4a6fe989810b..c214c374fefc 100644 --- a/include/linux/eventpoll.h +++ b/include/linux/eventpoll.h @@ -61,12 +61,12 @@ static inline void eventpoll_release(struct file *file) eventpoll_release_file(file); } -struct epoll_filefd { +struct epoll_key { struct file *file; int fd; } __packed; -int do_epoll_ctl_file(struct file *f, int op, struct epoll_filefd *tf, +int do_epoll_ctl_file(struct file *f, int op, struct epoll_key *tf, struct epoll_event *epds, bool nonblock); int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds, bool nonblock); -- cgit v1.2.3