mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 10:09:10 +02:00
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 <axboe@kernel.dk> Link: https://patch.msgid.link/20260514140817.623026-4-axboe@kernel.dk Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
parent
5de2759f2b
commit
0995baf261
|
|
@ -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 @@ int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds,
|
|||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user