This adds IORING_OP_EPOLL_CTL, which can perform the same work as the epoll_ctl(2) system call.
Unified · Split
| @@ -74,6 +74,7 @@ · 73 unmodified lines | |||
| 74 | #include <linux/namei.h> | 74 | #include <linux/namei.h> |
| 75 | #include <linux/fsnotify.h> | 75 | #include <linux/fsnotify.h> |
| 76 | #include <linux/fadvise.h> | 76 | #include <linux/fadvise.h> |
| 77 | #include <linux/eventpoll.h> | ||
| 77 | 78 | ||
| 78 | #define CREATE_TRACE_POINTS | 79 | #define CREATE_TRACE_POINTS |
| 79 | #include <trace/events/io_uring.h> | 80 | #include <trace/events/io_uring.h> |
| @@ -423,6 +424,14 @@ struct io_madvise { · 343 unmodified lines | |||
| 423 | u32 advice; | 424 | u32 advice; |
| 424 | }; | 425 | }; |
| 425 | 426 | ||
| 427 | struct io_epoll { | ||
| 428 | struct file *file; | ||
| 429 | int epfd; | ||
| 430 | int op; | ||
| 431 | int fd; | ||
| 432 | struct epoll_event event; | ||
| 433 | }; | ||
| 434 | |||
| 426 | struct io_async_connect { | 435 | struct io_async_connect { |
| 427 | struct sockaddr_storage address; | 436 | struct sockaddr_storage address; |
| 428 | }; | 437 | }; |
| @@ -536,6 +545,7 @@ struct io_kiocb { · 107 unmodified lines | |||
| 536 | struct io_files_update files_update; | 545 | struct io_files_update files_update; |
| 537 | struct io_fadvise fadvise; | 546 | struct io_fadvise fadvise; |
| 538 | struct io_madvise madvise; | 547 | struct io_madvise madvise; |
| 548 | struct io_epoll epoll; | ||
| 539 | }; | 549 | }; |
| 540 | 550 | ||
| 541 | struct io_async_ctx *io; | 551 | struct io_async_ctx *io; |
| @@ -728,6 +738,10 @@ static const struct io_op_def io_op_defs[] = { · 186 unmodified lines | |||
| 728 | .fd_non_neg = 1, | 738 | .fd_non_neg = 1, |
| 729 | .file_table = 1, | 739 | .file_table = 1, |
| 730 | }, | 740 | }, |
| 741 | [IORING_OP_EPOLL_CTL] = { | ||
| 742 | .unbound_nonreg_file = 1, | ||
| 743 | .file_table = 1, | ||
| 744 | }, | ||
| 731 | }; | 745 | }; |
| 732 | 746 | ||
| 733 | static void io_wq_submit_work(struct io_wq_work **workptr); | 747 | static void io_wq_submit_work(struct io_wq_work **workptr); |
| @@ -2611,6 +2625,52 @@ static int io_openat(struct io_kiocb *req, struct io_kiocb **nxt, · 1877 unmodified lines | |||
| 2611 | return io_openat2(req, nxt, force_nonblock); | 2625 | return io_openat2(req, nxt, force_nonblock); |
| 2612 | } | 2626 | } |
| 2613 | 2627 | ||
| 2628 | static int io_epoll_ctl_prep(struct io_kiocb *req, | ||
| 2629 | const struct io_uring_sqe *sqe) | ||
| 2630 | { | ||
| 2631 | #if defined(CONFIG_EPOLL) | ||
| 2632 | if (sqe->ioprio || sqe->buf_index) | ||
| 2633 | return -EINVAL; | ||
| 2634 | |||
| 2635 | req->epoll.epfd = READ_ONCE(sqe->fd); | ||
| 2636 | req->epoll.op = READ_ONCE(sqe->len); | ||
| 2637 | req->epoll.fd = READ_ONCE(sqe->off); | ||
| 2638 | |||
| 2639 | if (ep_op_has_event(req->epoll.op)) { | ||
| 2640 | struct epoll_event __user *ev; | ||
| 2641 | |||
| 2642 | ev = u64_to_user_ptr(READ_ONCE(sqe->addr)); | ||
| 2643 | if (copy_from_user(&req->epoll.event, ev, sizeof(*ev))) | ||
| 2644 | return -EFAULT; | ||
| 2645 | } | ||
| 2646 | |||
| 2647 | return 0; | ||
| 2648 | #else | ||
| 2649 | return -EOPNOTSUPP; | ||
| 2650 | #endif | ||
| 2651 | } | ||
| 2652 | |||
| 2653 | static int io_epoll_ctl(struct io_kiocb *req, struct io_kiocb **nxt, | ||
| 2654 | bool force_nonblock) | ||
| 2655 | { | ||
| 2656 | #if defined(CONFIG_EPOLL) | ||
| 2657 | struct io_epoll *ie = &req->epoll; | ||
| 2658 | int ret; | ||
| 2659 | |||
| 2660 | ret = do_epoll_ctl(ie->epfd, ie->op, ie->fd, &ie->event, force_nonblock); | ||
| 2661 | if (force_nonblock && ret == -EAGAIN) | ||
| 2662 | return -EAGAIN; | ||
| 2663 | |||
| 2664 | if (ret < 0) | ||
| 2665 | req_set_fail_links(req); | ||
| 2666 | io_cqring_add_event(req, ret); | ||
| 2667 | io_put_req_find_next(req, nxt); | ||
| 2668 | return 0; | ||
| 2669 | #else | ||
| 2670 | return -EOPNOTSUPP; | ||
| 2671 | #endif | ||
| 2672 | } | ||
| 2673 | |||
| 2614 | static int io_madvise_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) | 2674 | static int io_madvise_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) |
| 2615 | { | 2675 | { |
| 2616 | #if defined(CONFIG_ADVISE_SYSCALLS) && defined(CONFIG_MMU) | 2676 | #if defined(CONFIG_ADVISE_SYSCALLS) && defined(CONFIG_MMU) |
| @@ -4075,6 +4135,9 @@ static int io_req_defer_prep(struct io_kiocb *req, · 1458 unmodified lines | |||
| 4075 | case IORING_OP_OPENAT2: | 4135 | case IORING_OP_OPENAT2: |
| 4076 | ret = io_openat2_prep(req, sqe); | 4136 | ret = io_openat2_prep(req, sqe); |
| 4077 | break; | 4137 | break; |
| 4138 | case IORING_OP_EPOLL_CTL: | ||
| 4139 | ret = io_epoll_ctl_prep(req, sqe); | ||
| 4140 | break; | ||
| 4078 | default: | 4141 | default: |
| 4079 | printk_once(KERN_WARNING "io_uring: unhandled opcode %d\n", | 4142 | printk_once(KERN_WARNING "io_uring: unhandled opcode %d\n", |
| 4080 | req->opcode); | 4143 | req->opcode); |
| @@ -4303,6 +4366,14 @@ static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe, · 222 unmodified lines | |||
| 4303 | } | 4366 | } |
| 4304 | ret = io_openat2(req, nxt, force_nonblock); | 4367 | ret = io_openat2(req, nxt, force_nonblock); |
| 4305 | break; | 4368 | break; |
| 4369 | case IORING_OP_EPOLL_CTL: | ||
| 4370 | if (sqe) { | ||
| 4371 | ret = io_epoll_ctl_prep(req, sqe); | ||
| 4372 | if (ret) | ||
| 4373 | break; | ||
| 4374 | } | ||
| 4375 | ret = io_epoll_ctl(req, nxt, force_nonblock); | ||
| 4376 | break; | ||
| 4306 | default: | 4377 | default: |
| 4307 | ret = -EINVAL; | 4378 | ret = -EINVAL; |
| 4308 | break; | 4379 | break; |
| @@ -112,6 +112,7 @@ enum { · 111 unmodified lines | |||
| 112 | IORING_OP_SEND, | 112 | IORING_OP_SEND, |
| 113 | IORING_OP_RECV, | 113 | IORING_OP_RECV, |
| 114 | IORING_OP_OPENAT2, | 114 | IORING_OP_OPENAT2, |
| 115 | IORING_OP_EPOLL_CTL, | ||
| 115 | 116 | ||
| 116 | /* this goes last, obviously */ | 117 | /* this goes last, obviously */ |
| 117 | IORING_OP_LAST, | 118 | IORING_OP_LAST, |