mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-10-26 10:57:38 +08:00
Merge tag 'for-7.4/io_uring-20261021' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux
Pull io_uring updates from Jens Axboe:
"The bulk of this is a big robustness pass over cancelation, io-wq,
timeouts, and poll. Outside of that:
- Large series from Josef hardening the cancelation, io-wq, timeout,
poll, and wait paths. Fixes for lost wakeups and lost cancels as
io-wq arms poll/timeouts, work stranding on worker exit, CQE32
resize handling, napi entry timeouts, and a pile of smaller
correctness issues across the board
- Rework of how io-wq posts completions, posting from the last
request reference and dropping the request file before the
completion, and running ring release cancelations synchronously -
canceling and waiting for all in-flight requests and dropping
registered files and buffers at release time
- Don't charge the SQ/CQ rings or provided buffer rings to
RLIMIT_MEMLOCK, which the region API conversion had started doing
- Split io_uring_cmd_set_res() out from io_uring_cmd_done() so a
command can set the result from its ->end_io() handler, used by
nvme
- CQE32 ring fixes for the free entry check, aux CQE big_cqe zeroing,
and the dummy skip CQE
- Timeout fixes for sequence handling and multishot updates
- net fixes for MSG_TRUNC buffer overconsumption and keeping recv
buffer select length within MAX_RW_COUNT
- Wake real-time waiters from hard interrupt context
- Don't spin on local work an exiting task can't run, reachable by an
unprivileged user
- Various other fixes and cleanups"
* tag 'for-7.4/io_uring-20261021' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux: (75 commits)
io_uring: end the drain when the drain request completes
io_uring/futex: return a wait's data to the cache when it fails to arm
io_uring/wait: wake real-time waiters from hard interrupt context
io_uring/waitid: return -EAGAIN for a non-blocking pidfd
io_uring/net: keep recv buffer select length within MAX_RW_COUNT
io_uring/waitid: prevent cancel reference wrap
io_uring/poll: don't loop on HUP with multiple references
io_uring/timeout: don't lose a cancel as io-wq arms a timeout
io_uring/timeout: don't flush with the sequence behind the last flush
io_uring/timeout: don't put a sequence target behind the last flush
io_uring/poll: avoid retry wakeup loss when dropping ownership
io_uring: look up the file before queueing to io-wq
io_uring/timeout: don't end a linked timeout with 1
io_uring/timeout: no ABS update of multishot timeouts
io_uring/net: don't retry recv on uncommitted buffers
io_uring: don't pass restart error codes to userspace
io_uring/openclose: keep the lock in io_pipe_fixed()
io_uring/sqpoll: let the thread sleep on disabled rings
io_uring/kbuf: handle index wrap in last buffer check
io_uring/zcrx: fix buffer offsets in areas above 4GB
...
This commit is contained in:
commit
fa899d500a
35 files changed
+1159
-307
No files matched your search
@@ -423,8 +423,6 @@ struct nvme_uring_data {
|
||||
struct nvme_uring_cmd_pdu {
|
||||
struct request *req;
|
||||
struct bio *bio;
|
||||
u64 result;
|
||||
int status;
|
||||
};
|
||||
|
||||
static inline struct nvme_uring_cmd_pdu *nvme_uring_cmd_pdu(
|
||||
@@ -440,8 +438,7 @@ static void nvme_uring_task_cb(struct io_tw_req tw_req, io_tw_token_t tw)
|
||||
|
||||
if (pdu->bio)
|
||||
blk_rq_unmap_user(pdu->bio);
|
||||
io_uring_cmd_done32(ioucmd, pdu->status, pdu->result,
|
||||
IO_URING_CMD_TASK_WORK_ISSUE_FLAGS);
|
||||
__io_uring_cmd_done(ioucmd, IO_URING_CMD_TASK_WORK_ISSUE_FLAGS);
|
||||
}
|
||||
|
||||
static enum rq_end_io_ret nvme_uring_cmd_end_io(struct request *req,
|
||||
@@ -450,15 +447,17 @@ static enum rq_end_io_ret nvme_uring_cmd_end_io(struct request *req,
|
||||
{
|
||||
struct io_uring_cmd *ioucmd = req->end_io_data;
|
||||
struct nvme_uring_cmd_pdu *pdu = nvme_uring_cmd_pdu(ioucmd);
|
||||
u64 result = le64_to_cpu(nvme_req(req)->result.u64);
|
||||
int status;
|
||||
|
||||
if (nvme_req(req)->flags & NVME_REQ_CANCELLED) {
|
||||
pdu->status = -EINTR;
|
||||
status = -EINTR;
|
||||
} else {
|
||||
pdu->status = nvme_req(req)->status;
|
||||
if (!pdu->status)
|
||||
pdu->status = blk_status_to_errno(err);
|
||||
status = nvme_req(req)->status;
|
||||
if (!status)
|
||||
status = blk_status_to_errno(err);
|
||||
}
|
||||
pdu->result = le64_to_cpu(nvme_req(req)->result.u64);
|
||||
io_uring_cmd_set_res32(ioucmd, status, result);
|
||||
|
||||
/*
|
||||
* For IOPOLL, check if this completion is happening in the context
|
||||
@@ -471,7 +470,7 @@ static enum rq_end_io_ret nvme_uring_cmd_end_io(struct request *req,
|
||||
iob->poll_ctx == io_uring_cmd_ctx_handle(ioucmd)) {
|
||||
if (pdu->bio)
|
||||
blk_rq_unmap_user(pdu->bio);
|
||||
io_uring_cmd_done32(ioucmd, pdu->status, pdu->result, 0);
|
||||
__io_uring_cmd_done(ioucmd, 0);
|
||||
} else {
|
||||
io_uring_cmd_do_in_task_lazy(ioucmd, nvme_uring_task_cb);
|
||||
}
|
||||
|
||||
@@ -2,10 +2,42 @@
|
||||
#ifndef _LINUX_IO_URING_H
|
||||
#define _LINUX_IO_URING_H
|
||||
|
||||
#include <linux/io_uring_types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/xarray.h>
|
||||
#include <uapi/linux/io_uring.h>
|
||||
|
||||
static inline void req_set_fail(struct io_kiocb *req)
|
||||
{
|
||||
req->flags |= REQ_F_FAIL;
|
||||
if (req->flags & REQ_F_CQE_SKIP) {
|
||||
req->flags &= ~REQ_F_CQE_SKIP;
|
||||
req->flags |= REQ_F_SKIP_LINK_CQES;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void io_req_set_res(struct io_kiocb *req, s32 res, u32 cflags)
|
||||
{
|
||||
req->cqe.res = res;
|
||||
req->cqe.flags = cflags;
|
||||
}
|
||||
|
||||
static inline u32 ctx_cqe32_flags(struct io_ring_ctx *ctx)
|
||||
{
|
||||
if (ctx->flags & IORING_SETUP_CQE_MIXED)
|
||||
return IORING_CQE_F_32;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void io_req_set_res32(struct io_kiocb *req, s32 res, u32 cflags,
|
||||
__u64 extra1, __u64 extra2)
|
||||
{
|
||||
req->cqe.res = res;
|
||||
req->cqe.flags = cflags | ctx_cqe32_flags(req->ctx);
|
||||
req->big_cqe.extra1 = extra1;
|
||||
req->big_cqe.extra2 = extra2;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_IO_URING)
|
||||
void __io_uring_cancel(bool cancel_all);
|
||||
void __io_uring_free(struct task_struct *tsk);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#define _LINUX_IO_URING_CMD_H
|
||||
|
||||
#include <uapi/linux/io_uring.h>
|
||||
#include <linux/io_uring.h>
|
||||
#include <linux/io_uring_types.h>
|
||||
#include <linux/blk-mq.h>
|
||||
|
||||
@@ -41,6 +42,24 @@ static inline void io_uring_cmd_private_sz_check(size_t cmd_sz)
|
||||
((pdu_type *)&(cmd)->pdu) \
|
||||
)
|
||||
|
||||
static inline void io_uring_cmd_set_res(struct io_uring_cmd *cmd, s32 ret)
|
||||
{
|
||||
struct io_kiocb *req = cmd_to_io_kiocb(cmd);
|
||||
|
||||
if (ret < 0)
|
||||
req_set_fail(req);
|
||||
io_req_set_res(req, ret, 0);
|
||||
}
|
||||
|
||||
static inline void io_uring_cmd_set_res32(struct io_uring_cmd *cmd, s32 ret, u64 res2)
|
||||
{
|
||||
struct io_kiocb *req = cmd_to_io_kiocb(cmd);
|
||||
|
||||
if (ret < 0)
|
||||
req_set_fail(req);
|
||||
io_req_set_res32(req, ret, 0, res2, 0);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_IO_URING)
|
||||
int io_uring_cmd_import_fixed(u64 ubuf, unsigned long len, int rw,
|
||||
struct iov_iter *iter,
|
||||
@@ -56,11 +75,12 @@ int io_uring_cmd_import_fixed_vec(struct io_uring_cmd *ioucmd,
|
||||
* Completes the request, i.e. posts an io_uring CQE and deallocates @ioucmd
|
||||
* and the corresponding io_uring request.
|
||||
*
|
||||
* io_uring_cmd_set_res()/io_uring_cmd_set_res32() must be called first.
|
||||
*
|
||||
* Note: the caller should never hard code @issue_flags and is only allowed
|
||||
* to pass the mask provided by the core io_uring code.
|
||||
*/
|
||||
void __io_uring_cmd_done(struct io_uring_cmd *cmd, s32 ret, u64 res2,
|
||||
unsigned issue_flags, bool is_cqe32);
|
||||
void __io_uring_cmd_done(struct io_uring_cmd *, unsigned issue_flags);
|
||||
|
||||
void __io_uring_cmd_do_in_task(struct io_uring_cmd *ioucmd,
|
||||
io_req_tw_func_t task_work_cb,
|
||||
@@ -116,8 +136,8 @@ static inline int io_uring_cmd_import_fixed_vec(struct io_uring_cmd *ioucmd,
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static inline void __io_uring_cmd_done(struct io_uring_cmd *cmd, s32 ret,
|
||||
u64 ret2, unsigned issue_flags, bool is_cqe32)
|
||||
static inline void __io_uring_cmd_done(struct io_uring_cmd *cmd,
|
||||
unsigned issue_flags)
|
||||
{
|
||||
}
|
||||
static inline void __io_uring_cmd_do_in_task(struct io_uring_cmd *ioucmd,
|
||||
@@ -205,13 +225,15 @@ static inline void *io_uring_cmd_ctx_handle(struct io_uring_cmd *cmd)
|
||||
static inline void io_uring_cmd_done(struct io_uring_cmd *ioucmd, s32 ret,
|
||||
unsigned issue_flags)
|
||||
{
|
||||
return __io_uring_cmd_done(ioucmd, ret, 0, issue_flags, false);
|
||||
io_uring_cmd_set_res(ioucmd, ret);
|
||||
__io_uring_cmd_done(ioucmd, issue_flags);
|
||||
}
|
||||
|
||||
static inline void io_uring_cmd_done32(struct io_uring_cmd *ioucmd, s32 ret,
|
||||
u64 res2, unsigned issue_flags)
|
||||
{
|
||||
return __io_uring_cmd_done(ioucmd, ret, res2, issue_flags, true);
|
||||
io_uring_cmd_set_res32(ioucmd, ret, res2);
|
||||
__io_uring_cmd_done(ioucmd, issue_flags);
|
||||
}
|
||||
|
||||
#endif /* _LINUX_IO_URING_CMD_H */
|
||||
@@ -519,11 +519,18 @@ struct io_ring_ctx {
|
||||
u32 iowq_limits[2];
|
||||
|
||||
struct callback_head poll_wq_task_work;
|
||||
/* deferred ->poll_wq wake up for local task_work */
|
||||
struct rcu_head poll_wq_rcu;
|
||||
atomic_t poll_wq_rcu_pending;
|
||||
struct list_head defer_list;
|
||||
unsigned nr_drained;
|
||||
/* drain request dispatched from ->defer_list, until it completes */
|
||||
struct io_kiocb *drain_req;
|
||||
|
||||
/* protected by ->completion_lock */
|
||||
unsigned nr_req_allocated;
|
||||
/* pending SEND_ZC notifications, protected by ->uring_lock */
|
||||
unsigned nr_notifs;
|
||||
|
||||
#ifdef CONFIG_NET_RX_BUSY_POLL
|
||||
struct list_head napi_list; /* track busy poll napi_id */
|
||||
|
||||
@@ -121,14 +121,15 @@ struct io_uring_sqe {
|
||||
|
||||
/* sqe->attr_type_mask flags */
|
||||
#define IORING_RW_ATTR_FLAG_PI (1U << 0)
|
||||
/* PI attribute information */
|
||||
|
||||
/* PI attribute information in sqe->attr_ptr for IORING_RW_ATTR_FLAG_PI: */
|
||||
struct io_uring_attr_pi {
|
||||
__u16 flags;
|
||||
__u16 app_tag;
|
||||
__u32 len;
|
||||
__u64 addr;
|
||||
__u64 seed;
|
||||
__u64 rsvd;
|
||||
__u16 flags;
|
||||
__u16 app_tag;
|
||||
__u32 len;
|
||||
__u64 addr;
|
||||
__u64 seed;
|
||||
__u64 rsvd;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
+114
-18
@@ -72,7 +72,16 @@ static bool io_cancel_cb(struct io_wq_work *work, void *data)
|
||||
struct io_kiocb *req = container_of(work, struct io_kiocb, work);
|
||||
struct io_cancel_data *cd = data;
|
||||
|
||||
return io_cancel_req_match(req, cd);
|
||||
if (!io_cancel_req_match(req, cd))
|
||||
return false;
|
||||
/*
|
||||
* Pending work is gone once it has matched. Work that is running may
|
||||
* park the request where the same cancellation looks next. Don't make
|
||||
* it skip the request as one that it has dealt with.
|
||||
*/
|
||||
if (cd->flags & (IORING_ASYNC_CANCEL_ALL | IORING_ASYNC_CANCEL_ANY))
|
||||
req->cancel_seq_set = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int io_async_cancel_one(struct io_uring_task *tctx,
|
||||
@@ -117,6 +126,8 @@ int io_try_cancel(struct io_uring_task *tctx, struct io_cancel_data *cd,
|
||||
*/
|
||||
if (!ret)
|
||||
return 0;
|
||||
if (ret == -EALREADY)
|
||||
cd->running = true;
|
||||
|
||||
ret = io_poll_cancel(ctx, cd, issue_flags);
|
||||
if (ret != -ENOENT)
|
||||
@@ -180,6 +191,7 @@ static int __io_async_cancel(struct io_cancel_data *cd,
|
||||
struct io_tctx_node *node;
|
||||
int ret, nr = 0;
|
||||
|
||||
cd->running = false;
|
||||
do {
|
||||
ret = io_try_cancel(tctx, cd, issue_flags);
|
||||
if (ret == -ENOENT)
|
||||
@@ -195,6 +207,9 @@ static int __io_async_cancel(struct io_cancel_data *cd,
|
||||
mutex_lock(&ctx->tctx_lock);
|
||||
ret = -ENOENT;
|
||||
list_for_each_entry(node, &ctx->tctx_list, ctx_node) {
|
||||
/* has been done above, don't count what is running there */
|
||||
if (all && node->task->io_uring == tctx)
|
||||
continue;
|
||||
ret = io_async_cancel_one(node->task->io_uring, cd);
|
||||
if (ret != -ENOENT) {
|
||||
if (!all)
|
||||
@@ -204,7 +219,15 @@ static int __io_async_cancel(struct io_cancel_data *cd,
|
||||
}
|
||||
mutex_unlock(&ctx->tctx_lock);
|
||||
io_ring_submit_unlock(ctx, issue_flags);
|
||||
return all ? nr : ret;
|
||||
if (all)
|
||||
return nr;
|
||||
/*
|
||||
* The worker may be done with the work that was found running, and
|
||||
* flagged, above. That isn't the same as not having found it.
|
||||
*/
|
||||
if (ret == -ENOENT && cd->running)
|
||||
ret = -EALREADY;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int io_async_cancel(struct io_kiocb *req, unsigned int issue_flags)
|
||||
@@ -308,7 +331,7 @@ int io_sync_cancel(struct io_ring_ctx *ctx, void __user *arg)
|
||||
if (ret != -EALREADY)
|
||||
goto out;
|
||||
|
||||
if (sc.timeout.tv_sec != -1UL || sc.timeout.tv_nsec != -1UL) {
|
||||
if (sc.timeout.tv_sec != -1 || sc.timeout.tv_nsec != -1) {
|
||||
struct timespec64 ts = {
|
||||
.tv_sec = sc.timeout.tv_sec,
|
||||
.tv_nsec = sc.timeout.tv_nsec
|
||||
@@ -514,8 +537,9 @@ static __cold bool io_uring_try_cancel_iowq(struct io_ring_ctx *ctx)
|
||||
|
||||
__cold bool io_uring_try_cancel_requests(struct io_ring_ctx *ctx,
|
||||
struct io_uring_task *tctx,
|
||||
bool cancel_all, bool is_sqpoll_thread)
|
||||
unsigned int flags)
|
||||
{
|
||||
bool cancel_all = flags & IO_CANCEL_ALL;
|
||||
struct io_task_cancel cancel = { .tctx = tctx, .all = cancel_all, };
|
||||
enum io_wq_cancel cret;
|
||||
bool ret = false;
|
||||
@@ -544,7 +568,7 @@ __cold bool io_uring_try_cancel_requests(struct io_ring_ctx *ctx,
|
||||
|
||||
/* SQPOLL thread does its own polling */
|
||||
if ((!(ctx->flags & IORING_SETUP_SQPOLL) && cancel_all) ||
|
||||
is_sqpoll_thread) {
|
||||
(flags & IO_CANCEL_SQPOLL)) {
|
||||
while (!list_empty(&ctx->iopoll_list)) {
|
||||
io_iopoll_try_reap_events(ctx);
|
||||
ret = true;
|
||||
@@ -560,7 +584,9 @@ __cold bool io_uring_try_cancel_requests(struct io_ring_ctx *ctx,
|
||||
ret |= io_poll_remove_all(ctx, tctx, cancel_all);
|
||||
ret |= io_waitid_remove_all(ctx, tctx, cancel_all);
|
||||
ret |= io_futex_remove_all(ctx, tctx, cancel_all);
|
||||
ret |= io_uring_try_cancel_uring_cmd(ctx, tctx, cancel_all);
|
||||
ret |= io_uring_try_cancel_uring_cmd(ctx, tctx);
|
||||
if (flags & IO_CANCEL_KEEP_TIMEOUTS)
|
||||
cancel_all = false;
|
||||
ret |= io_kill_timeouts(ctx, tctx, cancel_all);
|
||||
mutex_unlock(&ctx->uring_lock);
|
||||
if (tctx)
|
||||
@@ -575,6 +601,44 @@ static s64 tctx_inflight(struct io_uring_task *tctx, bool tracked)
|
||||
return percpu_counter_sum(&tctx->inflight);
|
||||
}
|
||||
|
||||
/*
|
||||
* If true, whole thread group is exiting, at which point no task is left that
|
||||
* can reap completions and care about requests in-flight.
|
||||
*/
|
||||
static bool io_task_group_exiting(void)
|
||||
{
|
||||
return current->signal->flags & SIGNAL_GROUP_EXIT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a count of requests an exiting task should wait for.
|
||||
*/
|
||||
static s64 tctx_inflight_exit(struct io_uring_task *tctx)
|
||||
{
|
||||
struct io_tctx_node *node;
|
||||
unsigned long index;
|
||||
s64 inflight;
|
||||
|
||||
inflight = tctx_inflight(tctx, false);
|
||||
xa_for_each(&tctx->xa, index, node) {
|
||||
/* unlocked read is fine, the caller re-evaluates until done */
|
||||
inflight -= data_race(node->ctx->nr_notifs);
|
||||
/* takes ->uring_lock, we hold nothing on the group exit path */
|
||||
inflight -= io_timeouts_armed(node->ctx, tctx);
|
||||
}
|
||||
return inflight;
|
||||
}
|
||||
|
||||
static bool io_tctx_cancel_done(struct io_uring_task *tctx, bool cancel_all,
|
||||
bool group_exit)
|
||||
{
|
||||
if (cancel_all)
|
||||
return !tctx_inflight(tctx, false);
|
||||
if (tctx_inflight(tctx, true))
|
||||
return false;
|
||||
return !group_exit || tctx_inflight_exit(tctx) <= 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find any io_uring ctx that this task has registered or done IO on, and cancel
|
||||
* requests. @sqd should be not-null IFF it's an SQPOLL thread cancellation.
|
||||
@@ -584,7 +648,9 @@ __cold void io_uring_cancel_generic(bool cancel_all, struct io_sq_data *sqd)
|
||||
struct io_uring_task *tctx = current->io_uring;
|
||||
struct io_ring_ctx *ctx;
|
||||
struct io_tctx_node *node;
|
||||
unsigned int flags = 0;
|
||||
unsigned long index;
|
||||
bool group_exit;
|
||||
s64 inflight;
|
||||
DEFINE_WAIT(wait);
|
||||
|
||||
@@ -595,18 +661,30 @@ __cold void io_uring_cancel_generic(bool cancel_all, struct io_sq_data *sqd)
|
||||
if (tctx->io_wq)
|
||||
io_wq_exit_start(tctx->io_wq);
|
||||
|
||||
/*
|
||||
* If a whole thread group is exiting, nobody will look at completions.
|
||||
* If a single thread is exiting, cancel only those that belong to that
|
||||
* thread.
|
||||
*/
|
||||
group_exit = !cancel_all && io_task_group_exiting();
|
||||
if (cancel_all)
|
||||
flags = IO_CANCEL_ALL;
|
||||
else if (group_exit)
|
||||
flags = IO_CANCEL_ALL | IO_CANCEL_KEEP_TIMEOUTS;
|
||||
if (sqd)
|
||||
flags |= IO_CANCEL_SQPOLL;
|
||||
|
||||
atomic_inc(&tctx->in_cancel);
|
||||
do {
|
||||
bool loop = false;
|
||||
unsigned int state;
|
||||
|
||||
io_uring_drop_tctx_refs(current);
|
||||
if (!tctx_inflight(tctx, !cancel_all))
|
||||
if (io_tctx_cancel_done(tctx, cancel_all, group_exit))
|
||||
break;
|
||||
|
||||
/* read completions before cancelations */
|
||||
inflight = tctx_inflight(tctx, false);
|
||||
if (!inflight)
|
||||
break;
|
||||
|
||||
if (!sqd) {
|
||||
xa_for_each(&tctx->xa, index, node) {
|
||||
@@ -615,15 +693,13 @@ __cold void io_uring_cancel_generic(bool cancel_all, struct io_sq_data *sqd)
|
||||
continue;
|
||||
loop |= io_uring_try_cancel_requests(node->ctx,
|
||||
current->io_uring,
|
||||
cancel_all,
|
||||
false);
|
||||
flags);
|
||||
}
|
||||
} else {
|
||||
list_for_each_entry(ctx, &sqd->ctx_list, sqd_list)
|
||||
loop |= io_uring_try_cancel_requests(ctx,
|
||||
current->io_uring,
|
||||
cancel_all,
|
||||
true);
|
||||
flags);
|
||||
}
|
||||
|
||||
if (loop) {
|
||||
@@ -631,13 +707,28 @@ __cold void io_uring_cancel_generic(bool cancel_all, struct io_sq_data *sqd)
|
||||
continue;
|
||||
}
|
||||
|
||||
prepare_to_wait(&tctx->wait, &wait, TASK_INTERRUPTIBLE);
|
||||
state = TASK_INTERRUPTIBLE;
|
||||
if (task_sigpending(current))
|
||||
state = TASK_UNINTERRUPTIBLE;
|
||||
if (!cancel_all)
|
||||
state |= TASK_FREEZABLE;
|
||||
prepare_to_wait(&tctx->wait, &wait, state);
|
||||
io_run_task_work();
|
||||
io_uring_drop_tctx_refs(current);
|
||||
/* only skip the sleep for local work this task may run */
|
||||
xa_for_each(&tctx->xa, index, node) {
|
||||
if (io_local_work_pending(node->ctx) &&
|
||||
io_allowed_defer_tw_run(node->ctx))
|
||||
if (!(node->ctx->flags & IORING_SETUP_DEFER_TASKRUN) ||
|
||||
!io_allowed_defer_tw_run(node->ctx))
|
||||
continue;
|
||||
/*
|
||||
* The wake up io_uring_try_cancel_requests() asked for
|
||||
* may have been issued while we were still running. Ask
|
||||
* again now that it can't be missed.
|
||||
*/
|
||||
atomic_set(&node->ctx->cq_wait_nr, 1);
|
||||
/* pairs with the xchg() in mpscq_push() */
|
||||
smp_mb();
|
||||
if (io_local_work_pending(node->ctx))
|
||||
goto end_wait;
|
||||
}
|
||||
/*
|
||||
@@ -645,8 +736,13 @@ __cold void io_uring_cancel_generic(bool cancel_all, struct io_sq_data *sqd)
|
||||
* avoids a race where a completion comes in before we did
|
||||
* prepare_to_wait().
|
||||
*/
|
||||
if (inflight == tctx_inflight(tctx, !cancel_all))
|
||||
schedule();
|
||||
if (inflight == tctx_inflight(tctx, false)) {
|
||||
unsigned long timeout = 1;
|
||||
|
||||
if (state & TASK_INTERRUPTIBLE)
|
||||
timeout = MAX_SCHEDULE_TIMEOUT;
|
||||
schedule_timeout(timeout);
|
||||
}
|
||||
end_wait:
|
||||
finish_wait(&tctx->wait, &wait);
|
||||
} while (1);
|
||||
|
||||
+14
-1
@@ -11,6 +11,8 @@ struct io_cancel_data {
|
||||
u8 opcode;
|
||||
u32 flags;
|
||||
int seq;
|
||||
/* io_try_cancel() has found it being run by io-wq, and flagged it */
|
||||
bool running;
|
||||
};
|
||||
|
||||
int io_async_cancel_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
|
||||
@@ -30,9 +32,20 @@ bool io_cancel_remove_all(struct io_ring_ctx *ctx, struct io_uring_task *tctx,
|
||||
int io_cancel_remove(struct io_ring_ctx *ctx, struct io_cancel_data *cd,
|
||||
unsigned int issue_flags, struct hlist_head *list,
|
||||
bool (*cancel)(struct io_kiocb *));
|
||||
|
||||
/* io_uring_try_cancel_requests() flags */
|
||||
enum {
|
||||
/* match all requests, not just REQ_F_INFLIGHT */
|
||||
IO_CANCEL_ALL = 1,
|
||||
/* ignore timeouts */
|
||||
IO_CANCEL_KEEP_TIMEOUTS = 2,
|
||||
/* called by the SQPOLL thread */
|
||||
IO_CANCEL_SQPOLL = 4,
|
||||
};
|
||||
|
||||
__cold bool io_uring_try_cancel_requests(struct io_ring_ctx *ctx,
|
||||
struct io_uring_task *tctx,
|
||||
bool cancel_all, bool is_sqpoll_thread);
|
||||
unsigned int flags);
|
||||
__cold void io_uring_cancel_generic(bool cancel_all, struct io_sq_data *sqd);
|
||||
__cold bool io_cancel_ctx_cb(struct io_wq_work *work, void *data);
|
||||
|
||||
|
||||
+19
-4
@@ -154,11 +154,26 @@ static void __io_uring_show_fdinfo(struct io_ring_ctx *ctx, struct seq_file *m)
|
||||
cq_entries = min(cq_tail - cq_head, ctx->cq_entries);
|
||||
for (i = 0; i < cq_entries; i++) {
|
||||
struct io_uring_cqe *cqe;
|
||||
bool cqe32 = false;
|
||||
bool cqe32 = false, two_entries = false;
|
||||
bool is_last_cqarray_slot = (cq_head & cq_mask) == cq_mask;
|
||||
|
||||
cqe = &r->cqes[(cq_head & cq_mask)];
|
||||
if (cqe->flags & IORING_CQE_F_32 || ctx->flags & IORING_SETUP_CQE32)
|
||||
if (ctx->flags & IORING_SETUP_CQE32) {
|
||||
/* all entries have twice the size */
|
||||
cqe = &r->cqes[(cq_head & cq_mask) << 1];
|
||||
cqe32 = true;
|
||||
} else {
|
||||
cqe = &r->cqes[(cq_head & cq_mask)];
|
||||
/*
|
||||
* Userspace can manipulate the last cqarray slot to
|
||||
* have IORING_CQE_F_32 set, which would cause the second
|
||||
* half of that CQE to be read out of bounds.
|
||||
* Ignore the flag for the last cqarray slot, which can't
|
||||
* legitimately have the flag set.
|
||||
*/
|
||||
two_entries = (cqe->flags & IORING_CQE_F_32) &&
|
||||
!is_last_cqarray_slot;
|
||||
cqe32 = two_entries;
|
||||
}
|
||||
seq_printf(m, "%5u: user_data:%llu, res:%d, flags:%x",
|
||||
cq_head & cq_mask, cqe->user_data, cqe->res,
|
||||
cqe->flags);
|
||||
@@ -167,7 +182,7 @@ static void __io_uring_show_fdinfo(struct io_ring_ctx *ctx, struct seq_file *m)
|
||||
cqe->big_cqe[0], cqe->big_cqe[1]);
|
||||
seq_printf(m, "\n");
|
||||
cq_head++;
|
||||
if (cqe32) {
|
||||
if (two_entries) {
|
||||
cq_head++;
|
||||
i++;
|
||||
}
|
||||
|
||||
+33
-5
@@ -152,6 +152,24 @@ int io_futex_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* A wait on a private futex does not block the submitter. Even a single
|
||||
* threaded task can go on and have the mm private hash installed by clone()
|
||||
* or prctl(), which does not pick up waiters from the global hash. Make
|
||||
* sure the private hash exists before the first waiter is queued.
|
||||
*/
|
||||
static int io_futex_prep_private(struct io_kiocb *req)
|
||||
{
|
||||
int ret = futex_hash_allocate_default();
|
||||
|
||||
if (unlikely(ret))
|
||||
return ret;
|
||||
|
||||
/* inflight tracking only needed for mm private hash */
|
||||
io_req_track_inflight(req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int io_futex_wait_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
||||
{
|
||||
struct io_futex *iof = io_kiocb_to_cmd(req, struct io_futex);
|
||||
@@ -161,9 +179,8 @@ int io_futex_wait_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
||||
if (unlikely(ret))
|
||||
return ret;
|
||||
|
||||
/* inflight tracking only needed for mm private hash */
|
||||
if (!(iof->futex_flags & FLAGS_SHARED))
|
||||
io_req_track_inflight(req);
|
||||
return io_futex_prep_private(req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -213,10 +230,13 @@ int io_futexv_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* inflight tracking only needed for mm private hash */
|
||||
for (i = 0; i < iof->futex_nr; i++) {
|
||||
if (!(ifd->futexv[i].w.flags & FLAGS_SHARED)) {
|
||||
io_req_track_inflight(req);
|
||||
ret = io_futex_prep_private(req);
|
||||
if (ret) {
|
||||
kfree(ifd);
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -283,6 +303,8 @@ int io_futexv_wait(struct io_kiocb *req, unsigned int issue_flags)
|
||||
*/
|
||||
__set_current_state(TASK_RUNNING);
|
||||
hlist_add_head(&req->hash_node, &ctx->futex_list);
|
||||
if (io_wq_cancel_seen(req, issue_flags))
|
||||
__io_futex_cancel(req);
|
||||
} else {
|
||||
iof->futexv_unqueued = 1;
|
||||
if (woken != -1)
|
||||
@@ -323,18 +345,24 @@ int io_futex_wait(struct io_kiocb *req, unsigned int issue_flags)
|
||||
&ifd->q, NULL, NULL);
|
||||
if (!ret) {
|
||||
hlist_add_head(&req->hash_node, &ctx->futex_list);
|
||||
if (io_wq_cancel_seen(req, issue_flags))
|
||||
__io_futex_cancel(req);
|
||||
io_ring_submit_unlock(ctx, issue_flags);
|
||||
|
||||
return IOU_ISSUE_SKIP_COMPLETE;
|
||||
}
|
||||
|
||||
done_unlock:
|
||||
if (ifd) {
|
||||
/* As in io_futex_complete(), or failed arms would drain it. */
|
||||
io_cache_free(&ctx->futex_cache, ifd);
|
||||
io_req_async_data_clear(req, 0);
|
||||
}
|
||||
io_ring_submit_unlock(ctx, issue_flags);
|
||||
done:
|
||||
if (ret < 0)
|
||||
req_set_fail(req);
|
||||
io_req_set_res(req, ret, 0);
|
||||
io_req_async_data_free(req);
|
||||
return IOU_COMPLETE;
|
||||
}
|
||||
|
||||
|
||||
+116
-22
@@ -56,6 +56,8 @@ struct io_worker {
|
||||
struct io_wq_acct *acct;
|
||||
|
||||
struct io_wq_work *cur_work;
|
||||
/* rest of the hashed chain ->cur_work was taken off the list with */
|
||||
struct io_wq_work *next_work;
|
||||
raw_spinlock_t lock;
|
||||
|
||||
struct completion ref_done;
|
||||
@@ -467,11 +469,9 @@ static void io_wq_dec_running(struct io_worker *worker)
|
||||
|
||||
if (!atomic_dec_and_test(&acct->nr_running))
|
||||
return;
|
||||
if (!worker->cur_work)
|
||||
return;
|
||||
if (!io_acct_run_queue(acct))
|
||||
return;
|
||||
if (io_wq_hash_defer(worker->cur_work, acct)) {
|
||||
if (worker->cur_work && io_wq_hash_defer(worker->cur_work, acct)) {
|
||||
raw_spin_unlock(&acct->lock);
|
||||
return;
|
||||
}
|
||||
@@ -526,7 +526,8 @@ static bool io_wait_on_hash(struct io_wq *wq, unsigned int hash)
|
||||
}
|
||||
|
||||
static struct io_wq_work *io_get_next_work(struct io_wq_acct *acct,
|
||||
struct io_wq *wq)
|
||||
struct io_wq *wq,
|
||||
bool *need_wake)
|
||||
__must_hold(acct->lock)
|
||||
{
|
||||
struct io_wq_work_node *node, *prev;
|
||||
@@ -575,14 +576,24 @@ static struct io_wq_work *io_get_next_work(struct io_wq_acct *acct,
|
||||
raw_spin_lock(&acct->lock);
|
||||
if (unstalled) {
|
||||
clear_bit(IO_ACCT_STALLED_BIT, &acct->flags);
|
||||
if (wq_has_sleeper(&wq->hash->wait))
|
||||
wake_up(&wq->hash->wait);
|
||||
*need_wake = wq_has_sleeper(&wq->hash->wait);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void __io_assign_current_work(struct io_worker *worker,
|
||||
struct io_wq_work *work)
|
||||
{
|
||||
raw_spin_lock(&worker->lock);
|
||||
worker->cur_work = work;
|
||||
/* stays valid while in between two items of a chain */
|
||||
if (work)
|
||||
worker->next_work = wq_next_work(work);
|
||||
raw_spin_unlock(&worker->lock);
|
||||
}
|
||||
|
||||
static void io_assign_current_work(struct io_worker *worker,
|
||||
struct io_wq_work *work)
|
||||
{
|
||||
@@ -591,9 +602,7 @@ static void io_assign_current_work(struct io_worker *worker,
|
||||
cond_resched();
|
||||
}
|
||||
|
||||
raw_spin_lock(&worker->lock);
|
||||
worker->cur_work = work;
|
||||
raw_spin_unlock(&worker->lock);
|
||||
__io_assign_current_work(worker, work);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -607,6 +616,7 @@ static void io_worker_handle_work(struct io_wq_acct *acct,
|
||||
|
||||
do {
|
||||
struct io_wq_work *work;
|
||||
bool need_wake = false;
|
||||
|
||||
/*
|
||||
* If we got some work, mark us as busy. If we didn't, but
|
||||
@@ -615,7 +625,7 @@ static void io_worker_handle_work(struct io_wq_acct *acct,
|
||||
* can't make progress, any work completion or insertion will
|
||||
* clear the stalled flag.
|
||||
*/
|
||||
work = io_get_next_work(acct, wq);
|
||||
work = io_get_next_work(acct, wq, &need_wake);
|
||||
if (work) {
|
||||
/*
|
||||
* Make sure cancelation can find this, even before
|
||||
@@ -624,13 +634,14 @@ static void io_worker_handle_work(struct io_wq_acct *acct,
|
||||
* work list, but isn't yet discoverable as the
|
||||
* current work item for this worker.
|
||||
*/
|
||||
raw_spin_lock(&worker->lock);
|
||||
worker->cur_work = work;
|
||||
raw_spin_unlock(&worker->lock);
|
||||
__io_assign_current_work(worker, work);
|
||||
}
|
||||
|
||||
raw_spin_unlock(&acct->lock);
|
||||
|
||||
if (need_wake)
|
||||
wake_up(&wq->hash->wait);
|
||||
|
||||
if (!work)
|
||||
break;
|
||||
|
||||
@@ -642,25 +653,32 @@ static void io_worker_handle_work(struct io_wq_acct *acct,
|
||||
/* handle a whole dependent link */
|
||||
do {
|
||||
bool do_kill = test_bit(IO_WQ_BIT_EXIT, &wq->state);
|
||||
struct io_wq_work *next_hashed, *linked;
|
||||
struct io_wq_work *next_hashed, *linked, *done = work;
|
||||
unsigned int work_flags = atomic_read(&work->flags);
|
||||
unsigned int hash = __io_wq_is_hashed(work_flags)
|
||||
? __io_get_work_hash(work_flags)
|
||||
: -1U;
|
||||
struct io_kiocb *req;
|
||||
bool last;
|
||||
|
||||
next_hashed = wq_next_work(work);
|
||||
|
||||
if (do_kill &&
|
||||
(work_flags & IO_WQ_WORK_UNBOUND))
|
||||
/*
|
||||
* io_wq_exit_workers() signals us once, so that we
|
||||
* don't sleep for ever. If that was before this work
|
||||
* became the current one, the signal is gone.
|
||||
*/
|
||||
if (do_kill && (work_flags & IO_WQ_WORK_UNBOUND))
|
||||
atomic_or(IO_WQ_WORK_CANCEL, &work->flags);
|
||||
else if (do_kill)
|
||||
set_notify_signal(current);
|
||||
req = container_of(work, struct io_kiocb, work);
|
||||
kcov_remote_start_common(req->ctx->kcov_handle);
|
||||
io_wq_submit_work(work);
|
||||
kcov_remote_stop();
|
||||
io_assign_current_work(worker, NULL);
|
||||
|
||||
linked = io_wq_free_work(work);
|
||||
last = io_wq_put_work(work, &linked);
|
||||
work = next_hashed;
|
||||
if (!work && linked && !io_wq_is_hashed(linked)) {
|
||||
work = linked;
|
||||
@@ -669,6 +687,13 @@ static void io_worker_handle_work(struct io_wq_acct *acct,
|
||||
io_assign_current_work(worker, work);
|
||||
if (linked)
|
||||
io_wq_enqueue(wq, linked);
|
||||
/*
|
||||
* Not before the link is current or pending work again.
|
||||
* This may be the last time that a task is woken up
|
||||
* which exits and looks for requests to cancel.
|
||||
*/
|
||||
if (last)
|
||||
io_wq_free_work(done);
|
||||
|
||||
if (hash != -1U && !next_hashed) {
|
||||
/* serialize hash clear with wake_up() */
|
||||
@@ -687,6 +712,35 @@ static void io_worker_handle_work(struct io_wq_acct *acct,
|
||||
} while (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* The worker has decided to exit, and has given up its ->nr_workers slot and
|
||||
* its place on the free list. io_wq_enqueue() may have picked it from that
|
||||
* list, or seen it running, after it last looked at the work list. Leave
|
||||
* ->nr_running as well and check again. Returns false if the worker has to
|
||||
* stay.
|
||||
*/
|
||||
static bool io_worker_retire(struct io_wq_acct *acct, struct io_worker *worker)
|
||||
{
|
||||
/* turns io_wq_dec_running() and the scheduler hooks into no-ops */
|
||||
clear_bit(IO_WORKER_F_UP, &worker->flags);
|
||||
atomic_dec(&acct->nr_running);
|
||||
if (!io_acct_run_queue(acct))
|
||||
return true;
|
||||
raw_spin_unlock(&acct->lock);
|
||||
|
||||
raw_spin_lock(&acct->workers_lock);
|
||||
if (acct->nr_workers >= acct->max_workers) {
|
||||
/* a worker was created in our place, the work is its business */
|
||||
raw_spin_unlock(&acct->workers_lock);
|
||||
return true;
|
||||
}
|
||||
acct->nr_workers++;
|
||||
raw_spin_unlock(&acct->workers_lock);
|
||||
atomic_inc(&acct->nr_running);
|
||||
set_bit(IO_WORKER_F_UP, &worker->flags);
|
||||
return false;
|
||||
}
|
||||
|
||||
static int io_wq_worker(void *data)
|
||||
{
|
||||
struct io_worker *worker = data;
|
||||
@@ -720,19 +774,41 @@ static int io_wq_worker(void *data)
|
||||
* idle-exit, drop the worker as well. This is used to avoid
|
||||
* keeping io-wq workers around for tasks that no longer have
|
||||
* any active io_uring instances.
|
||||
* Not as long as a request of ours for another worker is
|
||||
* pending, though. It is accounted as a running worker, which
|
||||
* others rely on, and io_worker_exit() would cancel it.
|
||||
*/
|
||||
if ((last_timeout && (exit_mask || acct->nr_workers > 1)) ||
|
||||
test_bit(IO_WQ_BIT_EXIT_ON_IDLE, &wq->state)) {
|
||||
if (((last_timeout && (exit_mask || acct->nr_workers > 1)) ||
|
||||
test_bit(IO_WQ_BIT_EXIT_ON_IDLE, &wq->state)) &&
|
||||
!test_bit(0, &worker->create_state)) {
|
||||
acct->nr_workers--;
|
||||
if (test_and_clear_bit(IO_WORKER_F_FREE, &worker->flags))
|
||||
hlist_nulls_del_init_rcu(&worker->nulls_node);
|
||||
raw_spin_unlock(&acct->workers_lock);
|
||||
__set_current_state(TASK_RUNNING);
|
||||
break;
|
||||
if (io_worker_retire(acct, worker))
|
||||
break;
|
||||
last_timeout = false;
|
||||
continue;
|
||||
}
|
||||
last_timeout = false;
|
||||
__io_worker_idle(acct, worker);
|
||||
raw_spin_unlock(&acct->workers_lock);
|
||||
if (io_run_task_work())
|
||||
continue;
|
||||
/*
|
||||
* io_wq_enqueue() leaves new work to us for as long as we are
|
||||
* accounted as running. Get out of ->nr_running before taking
|
||||
* the last look at the work list, rather than when scheduling
|
||||
* out. No need to ask for another worker then, we can do it.
|
||||
*/
|
||||
clear_bit(IO_WORKER_F_RUNNING, &worker->flags);
|
||||
atomic_dec(&acct->nr_running);
|
||||
if (io_acct_run_queue(acct)) {
|
||||
io_wq_worker_running(current);
|
||||
io_worker_handle_work(acct, worker);
|
||||
continue;
|
||||
}
|
||||
ret = schedule_timeout(WORKER_IDLE_TIMEOUT);
|
||||
if (signal_pending(current)) {
|
||||
struct ksignal ksig;
|
||||
@@ -972,7 +1048,7 @@ static void io_wq_for_each_worker(struct io_wq *wq,
|
||||
|
||||
static bool io_wq_worker_wake(struct io_worker *worker, void *data)
|
||||
{
|
||||
__set_notify_signal(worker->task);
|
||||
set_tsk_thread_flag(worker->task, TIF_NOTIFY_SIGNAL);
|
||||
wake_up_process(worker->task);
|
||||
return false;
|
||||
}
|
||||
@@ -998,9 +1074,13 @@ void io_wq_set_exit_on_idle(struct io_wq *wq, bool enable)
|
||||
static void io_run_cancel(struct io_wq_work *work, struct io_wq *wq)
|
||||
{
|
||||
do {
|
||||
struct io_wq_work *linked;
|
||||
|
||||
atomic_or(IO_WQ_WORK_CANCEL, &work->flags);
|
||||
io_wq_submit_work(work);
|
||||
work = io_wq_free_work(work);
|
||||
if (io_wq_put_work(work, &linked))
|
||||
io_wq_free_work(work);
|
||||
work = linked;
|
||||
} while (work);
|
||||
}
|
||||
|
||||
@@ -1108,6 +1188,7 @@ static bool __io_wq_worker_cancel(struct io_worker *worker,
|
||||
static bool io_wq_worker_cancel(struct io_worker *worker, void *data)
|
||||
{
|
||||
struct io_cb_cancel_data *match = data;
|
||||
struct io_wq_work *work;
|
||||
|
||||
/*
|
||||
* Hold the lock to avoid ->cur_work going out of scope, caller
|
||||
@@ -1116,6 +1197,19 @@ static bool io_wq_worker_cancel(struct io_worker *worker, void *data)
|
||||
raw_spin_lock(&worker->lock);
|
||||
if (__io_wq_worker_cancel(worker, match, worker->cur_work))
|
||||
match->nr_running++;
|
||||
/*
|
||||
* Hashed work is taken off the work list a chain at a time, what the
|
||||
* worker hasn't started yet can only be found here. It doesn't move on
|
||||
* without the lock. Just mark the work, it fails once it is its turn.
|
||||
*/
|
||||
for (work = worker->next_work; work; work = wq_next_work(work)) {
|
||||
if (match->nr_running && !match->cancel_all)
|
||||
break;
|
||||
if (match->fn(work, match->data)) {
|
||||
atomic_or(IO_WQ_WORK_CANCEL, &work->flags);
|
||||
match->nr_running++;
|
||||
}
|
||||
}
|
||||
raw_spin_unlock(&worker->lock);
|
||||
|
||||
return match->nr_running && !match->cancel_all;
|
||||
|
||||
+309
-79
@@ -407,17 +407,46 @@ static void io_prep_async_link(struct io_kiocb *req)
|
||||
}
|
||||
}
|
||||
|
||||
/* Called for every request that is issued: keep it inline */
|
||||
static __always_inline bool io_assign_file(struct io_kiocb *req,
|
||||
const struct io_issue_def *def,
|
||||
unsigned int issue_flags)
|
||||
{
|
||||
if (req->file || !def->needs_file)
|
||||
return true;
|
||||
|
||||
if (req->flags & REQ_F_FIXED_FILE)
|
||||
req->file = io_file_get_fixed(req, req->cqe.fd, issue_flags);
|
||||
else
|
||||
req->file = io_file_get_normal(req, req->cqe.fd);
|
||||
|
||||
return !!req->file;
|
||||
}
|
||||
|
||||
void io_queue_iowq(struct io_kiocb *req)
|
||||
{
|
||||
struct io_uring_task *tctx = req->tctx;
|
||||
|
||||
BUG_ON(!tctx);
|
||||
lockdep_assert_held(&req->ctx->uring_lock);
|
||||
|
||||
if ((current->flags & PF_KTHREAD) || !tctx->io_wq) {
|
||||
io_req_task_queue_fail(req, -ECANCELED);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The file is looked up as late as possible, as it may be the result
|
||||
* of an earlier request of the link. This one is up now, and what kind
|
||||
* of work it is depends on the file. If that fails, leave the error
|
||||
* handling to the worker.
|
||||
*
|
||||
* Not for a splice: whatever it writes to, it may wait for its input
|
||||
* for ever. It has to remain unbound work that isn't hashed.
|
||||
*/
|
||||
if (req->opcode != IORING_OP_SPLICE)
|
||||
io_assign_file(req, &io_issue_defs[req->opcode], 0);
|
||||
|
||||
/* init ->work of the whole link before punting */
|
||||
io_prep_async_link(req);
|
||||
|
||||
@@ -451,6 +480,9 @@ static __cold noinline void io_queue_deferred(struct io_ring_ctx *ctx)
|
||||
|
||||
lockdep_assert_held(&ctx->uring_lock);
|
||||
__io_req_caches_free(ctx);
|
||||
/* nothing outside of ->defer_list is alive */
|
||||
if (ctx->nr_req_allocated == ctx->nr_drained)
|
||||
ctx->drain_req = NULL;
|
||||
|
||||
while (!list_empty(&ctx->defer_list)) {
|
||||
struct io_defer_entry *de = list_first_entry(&ctx->defer_list,
|
||||
@@ -462,6 +494,9 @@ static __cold noinline void io_queue_deferred(struct io_ring_ctx *ctx)
|
||||
|
||||
list_del_init(&de->list);
|
||||
ctx->nr_drained -= io_linked_nr(de->req);
|
||||
/* it runs alone, track its completion unless it's a link */
|
||||
if ((de->req->flags & REQ_F_IO_DRAIN) && !de->req->link)
|
||||
ctx->drain_req = de->req;
|
||||
io_req_task_queue(de->req);
|
||||
kfree(de);
|
||||
first = false;
|
||||
@@ -729,12 +764,22 @@ bool io_cqe_cache_refill(struct io_ring_ctx *ctx, bool overflow, bool cqe32)
|
||||
if (!overflow && (ctx->check_cq & BIT(IO_CHECK_CQ_OVERFLOW_BIT)))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* A single entry may be left if a 32b CQE is asked for. It must not be
|
||||
* handed out later on if this fails, as the CQE is going to overflow.
|
||||
*/
|
||||
ctx->cqe_cached = NULL;
|
||||
ctx->cqe_sentinel = NULL;
|
||||
|
||||
/*
|
||||
* Post dummy CQE if a 32b CQE is needed and there's only room for a
|
||||
* 16b CQE before the ring wraps.
|
||||
*/
|
||||
if (cqe32 && (ctx->flags & IORING_SETUP_CQE_MIXED) &&
|
||||
off + 1 == ctx->cq_entries) {
|
||||
/* one for the dummy CQE, two for the 32b CQE itself */
|
||||
if (ctx->cq_entries - io_cqring_queued(ctx) < 3)
|
||||
return false;
|
||||
if (!io_fill_nop_cqe(ctx, off))
|
||||
return false;
|
||||
off = 0;
|
||||
@@ -909,6 +954,22 @@ bool io_req_post_cqe32(struct io_kiocb *req, struct io_uring_cqe cqe[2])
|
||||
return posted;
|
||||
}
|
||||
|
||||
/* drop the request file before the CQE is posted, not deferred after it */
|
||||
static void io_req_put_file(struct io_kiocb *req, bool sync)
|
||||
{
|
||||
struct file *file = req->file;
|
||||
|
||||
if (!file || (req->flags & (REQ_F_FIXED_FILE | REQ_F_REISSUE)))
|
||||
return;
|
||||
|
||||
WRITE_ONCE(req->file, NULL);
|
||||
/* releasing a ring may wait on other rings, keep that deferred */
|
||||
if (sync && !io_is_uring_fops(file))
|
||||
__fput_sync(file);
|
||||
else
|
||||
fput(file);
|
||||
}
|
||||
|
||||
static void io_req_complete_post(struct io_kiocb *req, unsigned issue_flags)
|
||||
{
|
||||
struct io_ring_ctx *ctx = req->ctx;
|
||||
@@ -921,11 +982,15 @@ static void io_req_complete_post(struct io_kiocb *req, unsigned issue_flags)
|
||||
if (WARN_ON_ONCE(!(issue_flags & IO_URING_F_IOWQ)))
|
||||
return;
|
||||
|
||||
io_req_put_file(req, true);
|
||||
|
||||
/*
|
||||
* Handle special CQ sync cases via task_work. DEFER_TASKRUN requires
|
||||
* the submitter task context, IOPOLL protects with uring_lock.
|
||||
* the submitter task context, IOPOLL protects with uring_lock. A drain
|
||||
* request ends the drain under uring_lock as its CQE is posted.
|
||||
*/
|
||||
if ((ctx->int_flags & IO_RING_F_LOCKLESS_CQ) || (req->flags & REQ_F_REISSUE)) {
|
||||
if ((ctx->int_flags & IO_RING_F_LOCKLESS_CQ) ||
|
||||
(req->flags & (REQ_F_REISSUE | REQ_F_IO_DRAIN))) {
|
||||
defer_complete:
|
||||
req->io_task_work.func = io_req_task_complete;
|
||||
io_req_task_work_add(req);
|
||||
@@ -941,9 +1006,11 @@ defer_complete:
|
||||
goto defer_complete;
|
||||
|
||||
/*
|
||||
* We don't free the request here because we know it's called from
|
||||
* io-wq only, which holds a reference, so it cannot be the last put.
|
||||
* Request not freed here because we know it's called from io-wq only,
|
||||
* which holds a reference. Hence it can't be the last put. The CQE
|
||||
* has been posted, last put frees it.
|
||||
*/
|
||||
req->flags |= REQ_F_CQE_SKIP;
|
||||
req_ref_put(req);
|
||||
}
|
||||
|
||||
@@ -997,8 +1064,6 @@ __cold void io_free_req(struct io_kiocb *req)
|
||||
{
|
||||
/* refs were already put, restore them for io_req_task_complete() */
|
||||
req->flags &= ~REQ_F_REFCOUNT;
|
||||
/* we only want to free it, don't post CQEs */
|
||||
req->flags |= REQ_F_CQE_SKIP;
|
||||
req->io_task_work.func = io_req_task_complete;
|
||||
io_req_task_work_add(req);
|
||||
}
|
||||
@@ -1101,6 +1166,8 @@ static void io_free_batch_list(struct io_ring_ctx *ctx,
|
||||
}
|
||||
if (req->flags & REQ_F_REFCOUNT) {
|
||||
node = req->comp_list.next;
|
||||
/* CQE posted, the last put only frees */
|
||||
req->flags |= REQ_F_CQE_SKIP;
|
||||
if (!req_ref_put_and_test(req))
|
||||
continue;
|
||||
}
|
||||
@@ -1126,11 +1193,46 @@ static void io_free_batch_list(struct io_ring_ctx *ctx,
|
||||
} while (node);
|
||||
}
|
||||
|
||||
/*
|
||||
* The dispatched drain request ran alone, and anything submitted after it was
|
||||
* deferred. Once it completed, new requests may run if nothing is waiting.
|
||||
*/
|
||||
static __cold bool io_drain_req_completed(struct io_ring_ctx *ctx)
|
||||
{
|
||||
struct io_wq_work_node *node;
|
||||
|
||||
__wq_list_for_each(node, &ctx->submit_state.compl_reqs) {
|
||||
struct io_kiocb *req = container_of(node, struct io_kiocb,
|
||||
comp_list);
|
||||
|
||||
/* a requeued request hasn't completed */
|
||||
if (req == ctx->drain_req && !(req->flags & REQ_F_REISSUE)) {
|
||||
ctx->drain_req = NULL;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void __io_submit_flush_completions(struct io_ring_ctx *ctx)
|
||||
__must_hold(&ctx->uring_lock)
|
||||
{
|
||||
struct io_submit_state *state = &ctx->submit_state;
|
||||
struct io_wq_work_node *node;
|
||||
bool drain_done = false;
|
||||
|
||||
/*
|
||||
* Drop the files before the CQEs are posted, so they're released by
|
||||
* the time the completions are visible. Not for requests that are
|
||||
* requeued or still referenced, those aren't freed below.
|
||||
*/
|
||||
__wq_list_for_each(node, &state->compl_reqs) {
|
||||
struct io_kiocb *req = container_of(node, struct io_kiocb,
|
||||
comp_list);
|
||||
|
||||
if (!io_req_shared(req))
|
||||
io_req_put_file(req, true);
|
||||
}
|
||||
|
||||
__io_cq_lock(ctx);
|
||||
__wq_list_for_each(node, &state->compl_reqs) {
|
||||
@@ -1152,13 +1254,19 @@ void __io_submit_flush_completions(struct io_ring_ctx *ctx)
|
||||
}
|
||||
__io_cq_unlock_post(ctx);
|
||||
|
||||
if (unlikely(ctx->int_flags & IO_RING_F_DRAIN_ACTIVE) && ctx->drain_req)
|
||||
drain_done = io_drain_req_completed(ctx);
|
||||
|
||||
if (!wq_list_empty(&state->compl_reqs)) {
|
||||
io_free_batch_list(ctx, state->compl_reqs.first);
|
||||
INIT_WQ_LIST(&state->compl_reqs);
|
||||
}
|
||||
|
||||
if (unlikely(ctx->int_flags & IO_RING_F_DRAIN_ACTIVE))
|
||||
if (unlikely(ctx->int_flags & IO_RING_F_DRAIN_ACTIVE)) {
|
||||
io_queue_deferred(ctx);
|
||||
if (drain_done && list_empty(&ctx->defer_list))
|
||||
ctx->int_flags &= ~IO_RING_F_DRAIN_ACTIVE;
|
||||
}
|
||||
|
||||
ctx->submit_state.cq_flush = false;
|
||||
}
|
||||
@@ -1264,7 +1372,10 @@ static int io_iopoll_check(struct io_ring_ctx *ctx, unsigned int min_events)
|
||||
|
||||
void io_req_task_complete(struct io_tw_req tw_req, io_tw_token_t tw)
|
||||
{
|
||||
io_req_complete_defer(tw_req.req);
|
||||
struct io_kiocb *req = tw_req.req;
|
||||
|
||||
if (io_req_complete_ready(req))
|
||||
io_req_complete_defer(req);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1351,20 +1462,6 @@ static __cold void io_drain_req(struct io_kiocb *req)
|
||||
ctx->int_flags &= ~IO_RING_F_DRAIN_ACTIVE;
|
||||
}
|
||||
|
||||
static bool io_assign_file(struct io_kiocb *req, const struct io_issue_def *def,
|
||||
unsigned int issue_flags)
|
||||
{
|
||||
if (req->file || !def->needs_file)
|
||||
return true;
|
||||
|
||||
if (req->flags & REQ_F_FIXED_FILE)
|
||||
req->file = io_file_get_fixed(req, req->cqe.fd, issue_flags);
|
||||
else
|
||||
req->file = io_file_get_normal(req, req->cqe.fd);
|
||||
|
||||
return !!req->file;
|
||||
}
|
||||
|
||||
#define REQ_ISSUE_SLOW_FLAGS (REQ_F_CREDS | REQ_F_ARM_LTIMEOUT)
|
||||
|
||||
static inline int __io_issue_sqe(struct io_kiocb *req,
|
||||
@@ -1411,6 +1508,9 @@ static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags)
|
||||
ret = __io_issue_sqe(req, issue_flags, def);
|
||||
|
||||
if (ret == IOU_COMPLETE) {
|
||||
/* not all handlers take care of the internal restart codes */
|
||||
if (unlikely(req->cqe.res <= -ERESTARTSYS))
|
||||
req->cqe.res = io_fixup_restart_res(req->cqe.res);
|
||||
if (issue_flags & IO_URING_F_COMPLETE_DEFER)
|
||||
io_req_complete_defer(req);
|
||||
else
|
||||
@@ -1425,6 +1525,8 @@ static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags)
|
||||
if (req->flags & REQ_F_IOPOLL)
|
||||
io_iopoll_req_issued(req, issue_flags);
|
||||
}
|
||||
if (unlikely(ret <= -ERESTARTSYS))
|
||||
ret = io_fixup_restart_res(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1447,22 +1549,40 @@ int io_poll_issue(struct io_kiocb *req, io_tw_token_t tw)
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct io_wq_work *io_wq_free_work(struct io_wq_work *work)
|
||||
/*
|
||||
* io-wq is done with @work. Returns true if it held the last reference, and
|
||||
* hands out the next request of the link then. The caller has to make sure
|
||||
* that cancellations can find the latter before it calls io_wq_free_work().
|
||||
*/
|
||||
bool io_wq_put_work(struct io_wq_work *work, struct io_wq_work **linked)
|
||||
{
|
||||
struct io_kiocb *req = container_of(work, struct io_kiocb, work);
|
||||
struct io_kiocb *nxt = NULL;
|
||||
|
||||
if (req_ref_put_and_test_atomic(req)) {
|
||||
if (req->flags & IO_REQ_LINK_FLAGS) {
|
||||
struct io_ring_ctx *ctx = req->ctx;
|
||||
*linked = NULL;
|
||||
if (!req_ref_put_and_test_atomic(req))
|
||||
return false;
|
||||
|
||||
mutex_lock(&ctx->uring_lock);
|
||||
nxt = io_req_find_next(req);
|
||||
mutex_unlock(&ctx->uring_lock);
|
||||
}
|
||||
io_free_req(req);
|
||||
/*
|
||||
* Only continue the link from here if the completion has been posted.
|
||||
* If it's still pending, io_free_req() completes the request and the
|
||||
* next link follows from there, after the CQE.
|
||||
*/
|
||||
if ((req->flags & IO_REQ_LINK_FLAGS) && (req->flags & REQ_F_CQE_SKIP)) {
|
||||
struct io_ring_ctx *ctx = req->ctx;
|
||||
|
||||
mutex_lock(&ctx->uring_lock);
|
||||
nxt = io_req_find_next(req);
|
||||
mutex_unlock(&ctx->uring_lock);
|
||||
}
|
||||
return nxt ? &nxt->work : NULL;
|
||||
if (nxt)
|
||||
*linked = &nxt->work;
|
||||
return true;
|
||||
}
|
||||
|
||||
void io_wq_free_work(struct io_wq_work *work)
|
||||
{
|
||||
io_free_req(container_of(work, struct io_kiocb, work));
|
||||
}
|
||||
|
||||
void io_wq_submit_work(struct io_wq_work *work)
|
||||
@@ -1473,7 +1593,7 @@ void io_wq_submit_work(struct io_wq_work *work)
|
||||
bool needs_poll = false;
|
||||
int ret = 0, err = -ECANCELED;
|
||||
|
||||
/* one will be dropped by io_wq_free_work() after returning to io-wq */
|
||||
/* one will be dropped by io_wq_put_work() after returning to io-wq */
|
||||
if (!(req->flags & REQ_F_REFCOUNT))
|
||||
__io_req_set_refcount(req, 2);
|
||||
else
|
||||
@@ -1482,6 +1602,7 @@ void io_wq_submit_work(struct io_wq_work *work)
|
||||
/* either cancelled or io-wq is dying, so don't touch tctx->iowq */
|
||||
if (atomic_read(&work->flags) & IO_WQ_WORK_CANCEL) {
|
||||
fail:
|
||||
io_req_put_file(req, false);
|
||||
io_req_task_queue_fail(req, err);
|
||||
return;
|
||||
}
|
||||
@@ -1557,8 +1678,10 @@ fail:
|
||||
} while (1);
|
||||
|
||||
/* avoid locking problems by failing it from a clean context */
|
||||
if (ret)
|
||||
if (ret) {
|
||||
io_req_put_file(req, true);
|
||||
io_req_task_queue_fail(req, ret);
|
||||
}
|
||||
}
|
||||
|
||||
inline struct file *io_file_get_fixed(struct io_kiocb *req, int fd,
|
||||
@@ -1751,17 +1874,27 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
|
||||
* A 128b op on a non-128b SQ requires mixed SQE support as
|
||||
* well as 2 contiguous entries.
|
||||
*/
|
||||
if (!(ctx->flags & IORING_SETUP_SQE_MIXED) || *left < 2 ||
|
||||
if (!(ctx->flags & IORING_SETUP_SQE_MIXED) ||
|
||||
(unsigned)(sqe - ctx->sq_sqes) >= ctx->sq_entries - 1)
|
||||
return io_init_fail_req(req, -EINVAL);
|
||||
if (*left >= 2) {
|
||||
/*
|
||||
* A 128b operation on a mixed SQ uses two entries, so
|
||||
* we have to increment the head and cached refs, and
|
||||
* decrement what's left.
|
||||
*/
|
||||
current->io_uring->cached_refs++;
|
||||
(*left)--;
|
||||
} else if (!(ctx->flags & IORING_SETUP_SQPOLL) ||
|
||||
!__io_sqring_entries(ctx)) {
|
||||
return io_init_fail_req(req, -EINVAL);
|
||||
}
|
||||
/*
|
||||
* A 128b operation on a mixed SQ uses two entries, so we have
|
||||
* to increment the head and cached refs, and decrement what's
|
||||
* left.
|
||||
* else: the SQPOLL thread caps the number of entries it submits
|
||||
* in one go, which is none of the application's business. Take
|
||||
* the 2nd entry on top.
|
||||
*/
|
||||
current->io_uring->cached_refs++;
|
||||
ctx->cached_sq_head++;
|
||||
(*left)--;
|
||||
}
|
||||
|
||||
if (unlikely(sqe_flags & ~SQE_COMMON_FLAGS)) {
|
||||
@@ -2160,8 +2293,6 @@ static __cold void io_ring_ctx_free(struct io_ring_ctx *ctx)
|
||||
io_sq_thread_finish(ctx);
|
||||
|
||||
mutex_lock(&ctx->uring_lock);
|
||||
io_sqe_buffers_unregister(ctx);
|
||||
io_sqe_files_unregister(ctx);
|
||||
io_unregister_zcrx(ctx);
|
||||
io_cqring_overflow_kill(ctx);
|
||||
io_eventfd_unregister(ctx);
|
||||
@@ -2290,6 +2421,7 @@ struct io_tctx_exit {
|
||||
struct callback_head task_work;
|
||||
struct completion completion;
|
||||
struct io_ring_ctx *ctx;
|
||||
bool in_cancel;
|
||||
};
|
||||
|
||||
static __cold void io_tctx_exit_cb(struct callback_head *cb)
|
||||
@@ -2304,11 +2436,121 @@ static __cold void io_tctx_exit_cb(struct callback_head *cb)
|
||||
* tctx can be NULL if the queueing of this task_work raced with
|
||||
* work cancelation off the exec path.
|
||||
*/
|
||||
if (tctx && !atomic_read(&tctx->in_cancel))
|
||||
work->in_cancel = tctx && atomic_read(&tctx->in_cancel);
|
||||
if (tctx && !work->in_cancel)
|
||||
io_uring_del_tctx_node((unsigned long)work->ctx);
|
||||
complete(&work->completion);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cancel what can be canceled on a dying ring and reap what has completed.
|
||||
* Only waits on polled I/O, never anything else.
|
||||
*/
|
||||
static __cold void io_ring_ctx_cancel(struct io_ring_ctx *ctx)
|
||||
{
|
||||
struct io_sq_data *sqd = ctx->sq_data;
|
||||
|
||||
if (test_bit(IO_CHECK_CQ_OVERFLOW_BIT, &ctx->check_cq)) {
|
||||
scoped_guard(mutex, &ctx->uring_lock)
|
||||
io_cqring_overflow_kill(ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're doing polled IO and end up having requests being
|
||||
* submitted async (out-of-line), then completions can come in while
|
||||
* we're waiting for refs to drop. We need to reap these manually,
|
||||
* as nobody else will be looking for them.
|
||||
*/
|
||||
do {
|
||||
if (ctx->flags & IORING_SETUP_DEFER_TASKRUN)
|
||||
io_cancel_local_task_work(ctx);
|
||||
cond_resched();
|
||||
} while (io_uring_try_cancel_requests(ctx, NULL, IO_CANCEL_ALL));
|
||||
|
||||
if (sqd) {
|
||||
struct task_struct *tsk;
|
||||
|
||||
io_sq_thread_park(sqd);
|
||||
tsk = sqpoll_task_locked(sqd);
|
||||
if (tsk && tsk->io_uring && tsk->io_uring->io_wq)
|
||||
io_wq_cancel_cb(tsk->io_uring->io_wq,
|
||||
io_cancel_ctx_cb, ctx, true);
|
||||
io_sq_thread_unpark(sqd);
|
||||
}
|
||||
|
||||
io_req_caches_free(ctx);
|
||||
}
|
||||
|
||||
/* Number of requests that should be waited for */
|
||||
static __cold unsigned int io_ring_ctx_inflight(struct io_ring_ctx *ctx)
|
||||
{
|
||||
guard(mutex)(&ctx->uring_lock);
|
||||
__io_req_caches_free(ctx);
|
||||
return ctx->nr_req_allocated - ctx->nr_notifs;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run task_work completions for current. Only do so if the io_uring callback
|
||||
* itself can get pruned first, otherwise we risk recursing.
|
||||
*/
|
||||
static __cold bool io_ring_run_own_completions(struct io_uring_task *tctx)
|
||||
{
|
||||
unsigned int count = 0;
|
||||
|
||||
if (!tctx || mpscq_empty(&tctx->task_list))
|
||||
return true;
|
||||
if (!task_work_cancel(current, &tctx->task_work))
|
||||
return false;
|
||||
tctx_task_work_run(tctx, UINT_MAX, &count);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Requests may remain after cancelations have been run, as not all requests
|
||||
* are cancelable. Storage I/O is an example. Wait for those so that once
|
||||
* close(2) returns, files pinned by these requests have been released.
|
||||
*/
|
||||
static __cold void io_ring_ctx_wait_inflight(struct io_ring_ctx *ctx)
|
||||
{
|
||||
struct io_uring_task *tctx = current->io_uring;
|
||||
bool ran_own = true;
|
||||
|
||||
if (current->flags & (PF_KTHREAD | PF_EXITING))
|
||||
return;
|
||||
if (tctx && atomic_read(&tctx->in_cancel))
|
||||
return;
|
||||
|
||||
while (io_ring_ctx_inflight(ctx) && !fatal_signal_pending(current)) {
|
||||
unsigned int state;
|
||||
|
||||
if (test_thread_flag(TIF_NOTIFY_SIGNAL)) {
|
||||
clear_notify_signal();
|
||||
if (task_work_pending(current))
|
||||
set_notify_resume(current);
|
||||
}
|
||||
state = TASK_INTERRUPTIBLE;
|
||||
if (signal_pending(current))
|
||||
state = TASK_KILLABLE;
|
||||
set_current_state(state | TASK_FREEZABLE);
|
||||
/* don't sleep on work that's already there and that we can run */
|
||||
if (ran_own && ((tctx && !mpscq_empty(&tctx->task_list)) ||
|
||||
io_local_work_pending(ctx)))
|
||||
__set_current_state(TASK_RUNNING);
|
||||
else
|
||||
schedule_timeout(1);
|
||||
|
||||
/* completions may be queued behind us */
|
||||
if (!io_ring_run_own_completions(tctx)) {
|
||||
if (!ran_own)
|
||||
break;
|
||||
ran_own = false;
|
||||
} else {
|
||||
ran_own = true;
|
||||
}
|
||||
io_ring_ctx_cancel(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static __cold void io_ring_exit_work(struct work_struct *work)
|
||||
{
|
||||
struct io_ring_ctx *ctx = container_of(work, struct io_ring_ctx, exit_work);
|
||||
@@ -2318,43 +2560,8 @@ static __cold void io_ring_exit_work(struct work_struct *work)
|
||||
struct io_tctx_node *node;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&ctx->uring_lock);
|
||||
io_terminate_zcrx(ctx);
|
||||
mutex_unlock(&ctx->uring_lock);
|
||||
|
||||
/*
|
||||
* If we're doing polled IO and end up having requests being
|
||||
* submitted async (out-of-line), then completions can come in while
|
||||
* we're waiting for refs to drop. We need to reap these manually,
|
||||
* as nobody else will be looking for them.
|
||||
*/
|
||||
do {
|
||||
if (test_bit(IO_CHECK_CQ_OVERFLOW_BIT, &ctx->check_cq)) {
|
||||
mutex_lock(&ctx->uring_lock);
|
||||
io_cqring_overflow_kill(ctx);
|
||||
mutex_unlock(&ctx->uring_lock);
|
||||
}
|
||||
|
||||
/* The SQPOLL thread never reaches this path */
|
||||
do {
|
||||
if (ctx->flags & IORING_SETUP_DEFER_TASKRUN)
|
||||
io_cancel_local_task_work(ctx);
|
||||
cond_resched();
|
||||
} while (io_uring_try_cancel_requests(ctx, NULL, true, false));
|
||||
|
||||
if (ctx->sq_data) {
|
||||
struct io_sq_data *sqd = ctx->sq_data;
|
||||
struct task_struct *tsk;
|
||||
|
||||
io_sq_thread_park(sqd);
|
||||
tsk = sqpoll_task_locked(sqd);
|
||||
if (tsk && tsk->io_uring && tsk->io_uring->io_wq)
|
||||
io_wq_cancel_cb(tsk->io_uring->io_wq,
|
||||
io_cancel_ctx_cb, ctx, true);
|
||||
io_sq_thread_unpark(sqd);
|
||||
}
|
||||
|
||||
io_req_caches_free(ctx);
|
||||
io_ring_ctx_cancel(ctx);
|
||||
|
||||
if (WARN_ON_ONCE(time_after(jiffies, timeout))) {
|
||||
/* there is little hope left, don't run it too often */
|
||||
@@ -2398,6 +2605,14 @@ static __cold void io_ring_exit_work(struct work_struct *work)
|
||||
* wait is marked as interruptible.
|
||||
*/
|
||||
wait_for_completion_interruptible(&exit.completion);
|
||||
/*
|
||||
* The task removes the node when it is done with its
|
||||
* cancellation. Give it the time for that: it doesn't get back
|
||||
* to it as long as it finds new task_work each time it has run
|
||||
* the old one, and we may be one of many who send it.
|
||||
*/
|
||||
if (exit.in_cancel)
|
||||
schedule_timeout_idle(HZ / 20);
|
||||
mutex_lock(&ctx->uring_lock);
|
||||
mutex_lock(&ctx->tctx_lock);
|
||||
}
|
||||
@@ -2422,8 +2637,23 @@ static __cold void io_ring_ctx_wait_and_kill(struct io_ring_ctx *ctx)
|
||||
percpu_ref_kill(&ctx->refs);
|
||||
xa_for_each(&ctx->personalities, index, creds)
|
||||
io_unregister_personality(ctx, index);
|
||||
io_terminate_zcrx(ctx);
|
||||
/* Drop these now, rather than async, to unpin the files */
|
||||
io_sqe_buffers_unregister(ctx);
|
||||
io_sqe_files_unregister(ctx);
|
||||
mutex_unlock(&ctx->uring_lock);
|
||||
|
||||
/*
|
||||
* Do the first round of cancelations upfront rather than leaving it
|
||||
* to to exit_work. Anything cancelable is then already on its way
|
||||
* out, and for requests owned by the task closing the ring, this
|
||||
* ensures any held files are put before close(2) returns.
|
||||
*/
|
||||
if (!(current->flags & PF_IO_WORKER)) {
|
||||
io_ring_ctx_cancel(ctx);
|
||||
io_ring_ctx_wait_inflight(ctx);
|
||||
}
|
||||
|
||||
INIT_WORK(&ctx->exit_work, io_ring_exit_work);
|
||||
/*
|
||||
* Use system_dfl_wq to avoid spawning tons of event kworkers
|
||||
|
||||
+39
-28
@@ -204,7 +204,8 @@ int io_do_iopoll(struct io_ring_ctx *ctx, bool force_nonspin);
|
||||
__cold void io_iopoll_try_reap_events(struct io_ring_ctx *ctx);
|
||||
void __io_submit_flush_completions(struct io_ring_ctx *ctx);
|
||||
|
||||
struct io_wq_work *io_wq_free_work(struct io_wq_work *work);
|
||||
bool io_wq_put_work(struct io_wq_work *work, struct io_wq_work **linked);
|
||||
void io_wq_free_work(struct io_wq_work *work);
|
||||
void io_wq_submit_work(struct io_wq_work *work);
|
||||
|
||||
void io_free_req(struct io_kiocb *req);
|
||||
@@ -318,37 +319,24 @@ static __always_inline bool io_fill_cqe_req(struct io_ring_ctx *ctx,
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void req_set_fail(struct io_kiocb *req)
|
||||
static inline ssize_t io_fixup_restart_res(ssize_t ret)
|
||||
{
|
||||
req->flags |= REQ_F_FAIL;
|
||||
if (req->flags & REQ_F_CQE_SKIP) {
|
||||
req->flags &= ~REQ_F_CQE_SKIP;
|
||||
req->flags |= REQ_F_SKIP_LINK_CQES;
|
||||
switch (ret) {
|
||||
case -ERESTARTSYS:
|
||||
case -ERESTARTNOINTR:
|
||||
case -ERESTARTNOHAND:
|
||||
case -ERESTART_RESTARTBLOCK:
|
||||
/*
|
||||
* We can't just restart the syscall, since previously
|
||||
* submitted sqes may already be in progress. Just fail
|
||||
* this IO with EINTR.
|
||||
*/
|
||||
return -EINTR;
|
||||
default:
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void io_req_set_res(struct io_kiocb *req, s32 res, u32 cflags)
|
||||
{
|
||||
req->cqe.res = res;
|
||||
req->cqe.flags = cflags;
|
||||
}
|
||||
|
||||
static inline u32 ctx_cqe32_flags(struct io_ring_ctx *ctx)
|
||||
{
|
||||
if (ctx->flags & IORING_SETUP_CQE_MIXED)
|
||||
return IORING_CQE_F_32;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void io_req_set_res32(struct io_kiocb *req, s32 res, u32 cflags,
|
||||
__u64 extra1, __u64 extra2)
|
||||
{
|
||||
req->cqe.res = res;
|
||||
req->cqe.flags = cflags | ctx_cqe32_flags(req->ctx);
|
||||
req->big_cqe.extra1 = extra1;
|
||||
req->big_cqe.extra2 = extra2;
|
||||
}
|
||||
|
||||
static inline void *io_uring_alloc_async_data(struct io_alloc_cache *cache,
|
||||
struct io_kiocb *req)
|
||||
{
|
||||
@@ -411,6 +399,29 @@ static inline void io_ring_submit_lock(struct io_ring_ctx *ctx,
|
||||
lockdep_assert_held(&ctx->uring_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* For a handler that is run by io-wq and parks the request on a list where
|
||||
* cancellations find it, rather than completing it. Whoever tried to cancel
|
||||
* the request before that found it running. It has flagged the work item,
|
||||
* has searched the list in vain, and won't come back. To be called with
|
||||
* the lock the search takes held: if the search came first, the flag is
|
||||
* visible. For most lists that is ->uring_lock, timeouts use ->timeout_lock.
|
||||
*/
|
||||
static inline bool __io_wq_cancel_seen(struct io_kiocb *req,
|
||||
unsigned int issue_flags)
|
||||
{
|
||||
return (issue_flags & IO_URING_F_IOWQ) &&
|
||||
(atomic_read(&req->work.flags) & IO_WQ_WORK_CANCEL);
|
||||
}
|
||||
|
||||
static inline bool io_wq_cancel_seen(struct io_kiocb *req,
|
||||
unsigned int issue_flags)
|
||||
{
|
||||
lockdep_assert_held(&req->ctx->uring_lock);
|
||||
|
||||
return __io_wq_cancel_seen(req, issue_flags);
|
||||
}
|
||||
|
||||
static inline void io_commit_cqring(struct io_ring_ctx *ctx)
|
||||
{
|
||||
/* order cqe stores with ring update */
|
||||
|
||||
+1
-1
@@ -204,7 +204,7 @@ static struct io_br_sel io_ring_buffer_select(struct io_kiocb *req, size_t *len,
|
||||
if (unlikely(tail == head))
|
||||
return sel;
|
||||
|
||||
if (head + 1 == tail)
|
||||
if ((__u16)(head + 1) == tail)
|
||||
req->flags |= REQ_F_BL_EMPTY;
|
||||
|
||||
buf = io_ring_head_to_buf(br, head, bl->mask);
|
||||
|
||||
+1
-7
@@ -10,12 +10,6 @@ static inline int io_loop_nr_cqes(const struct io_ring_ctx *ctx,
|
||||
return lp->cq_wait_idx - READ_ONCE(ctx->rings->cq.tail);
|
||||
}
|
||||
|
||||
static inline void io_loop_wait_start(struct io_ring_ctx *ctx, unsigned nr_wait)
|
||||
{
|
||||
atomic_set(&ctx->cq_wait_nr, nr_wait);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
}
|
||||
|
||||
static inline void io_loop_wait_finish(struct io_ring_ctx *ctx)
|
||||
{
|
||||
__set_current_state(TASK_RUNNING);
|
||||
@@ -25,7 +19,7 @@ static inline void io_loop_wait_finish(struct io_ring_ctx *ctx)
|
||||
static void io_loop_wait(struct io_ring_ctx *ctx, struct iou_loop_params *lp,
|
||||
unsigned nr_wait)
|
||||
{
|
||||
io_loop_wait_start(ctx, nr_wait);
|
||||
io_cq_wait_arm(ctx, nr_wait);
|
||||
|
||||
if (unlikely(io_local_work_pending(ctx) ||
|
||||
io_loop_nr_cqes(ctx, lp) <= 0) ||
|
||||
|
||||
@@ -180,6 +180,7 @@ static int io_region_allocate_pages(struct io_mapped_region *mr,
|
||||
size_t size = io_region_size(mr);
|
||||
unsigned long nr_allocated;
|
||||
struct page **pages;
|
||||
struct page *page;
|
||||
|
||||
pages = kvmalloc_objs(*pages, mr->nr_pages, gfp);
|
||||
if (!pages)
|
||||
@@ -192,6 +193,13 @@ static int io_region_allocate_pages(struct io_mapped_region *mr,
|
||||
|
||||
nr_allocated = alloc_pages_bulk_node(gfp, NUMA_NO_NODE,
|
||||
mr->nr_pages, pages);
|
||||
while (nr_allocated < mr->nr_pages) {
|
||||
page = alloc_page(gfp);
|
||||
if (!page)
|
||||
break;
|
||||
|
||||
pages[nr_allocated++] = page;
|
||||
}
|
||||
if (nr_allocated != mr->nr_pages) {
|
||||
if (nr_allocated)
|
||||
release_pages(pages, nr_allocated);
|
||||
|
||||
+11
-3
@@ -25,9 +25,10 @@
|
||||
* its predecessor. In between, the tail end of the queue is not yet reachable
|
||||
* from the head. mpscq_pop() detects this and returns NULL, while mpscq_empty()
|
||||
* reports false. The consumer must not treat such a NULL as "queue empty" - it
|
||||
* should retry later. The window is two instructions wide, but a producer can
|
||||
* be preempted inside it, so the consumer must not spin on it while holding
|
||||
* resources the producer might need to make progress.
|
||||
* should retry later. The window is two instructions wide and the producer
|
||||
* can't be preempted inside it, but it can be interrupted, so the consumer must
|
||||
* not spin on it while holding resources the producer might need to make
|
||||
* progress.
|
||||
*
|
||||
* The consumer side only supports a single consumer at a time, callers must
|
||||
* provide their own serialization for it. The stub node is what allows the
|
||||
@@ -69,6 +70,12 @@ static inline bool mpscq_push(struct mpscq *q, struct llist_node *node)
|
||||
struct llist_node *prev;
|
||||
|
||||
node->next = NULL;
|
||||
/*
|
||||
* All the consumer can do about a node that isn't linked yet is to try
|
||||
* again. If it is what preempted us, and we don't get to run as long
|
||||
* as it does, that never ends.
|
||||
*/
|
||||
preempt_disable();
|
||||
/*
|
||||
* xchg() implies a full barrier, so the initialization of the
|
||||
* entry (including ->next above) is visible before the node can
|
||||
@@ -77,6 +84,7 @@ static inline bool mpscq_push(struct mpscq *q, struct llist_node *node)
|
||||
*/
|
||||
prev = xchg(&q->tail, node);
|
||||
WRITE_ONCE(prev->next, node);
|
||||
preempt_enable();
|
||||
return prev == &q->stub;
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -6,7 +6,7 @@
|
||||
#ifdef CONFIG_NET_RX_BUSY_POLL
|
||||
|
||||
/* Timeout for cleanout of stale entries. */
|
||||
#define NAPI_TIMEOUT (60 * SEC_CONVERSION)
|
||||
#define NAPI_TIMEOUT (60 * HZ)
|
||||
|
||||
struct io_napi_entry {
|
||||
unsigned int napi_id;
|
||||
@@ -378,6 +378,8 @@ void __io_napi_busy_loop(struct io_ring_ctx *ctx, struct io_wait_queue *iowq)
|
||||
if (iowq->timeout != KTIME_MAX) {
|
||||
ktime_t dt = ktime_sub(iowq->timeout, io_get_time(ctx));
|
||||
|
||||
/* an absolute timeout may have passed already */
|
||||
dt = max_t(ktime_t, dt, 0);
|
||||
iowq->napi_busy_poll_dt = min_t(u64, iowq->napi_busy_poll_dt, dt);
|
||||
}
|
||||
|
||||
|
||||
+24
-2
@@ -480,6 +480,24 @@ static int io_bundle_nbufs(struct io_async_msghdr *kmsg, int ret)
|
||||
return nbufs;
|
||||
}
|
||||
|
||||
/*
|
||||
* A receive that is retried after a partial transfer keeps writing to what it
|
||||
* has mapped. io_net_kbuf_recyle() only commits what was filled so far, which
|
||||
* takes a buffer out of circulation if it's a single one that is consumed as a
|
||||
* whole. The tail of an incrementally consumed buffer, or the yet unused
|
||||
* buffers of a bundle, would be up for grabs. They can't be committed in
|
||||
* advance either, the CQE has no way to tell if they end up not being used.
|
||||
*/
|
||||
static bool io_net_kbuf_can_retry(struct io_kiocb *req,
|
||||
struct io_buffer_list *bl,
|
||||
struct io_async_msghdr *kmsg)
|
||||
{
|
||||
/* not ring provided, or committed at selection time */
|
||||
if (!(req->flags & REQ_F_BUFFERS_COMMIT))
|
||||
return true;
|
||||
return !(bl->flags & IOBL_INC) && iter_is_ubuf(&kmsg->msg.msg_iter);
|
||||
}
|
||||
|
||||
static int io_net_kbuf_recyle(struct io_kiocb *req, struct io_buffer_list *bl,
|
||||
struct io_async_msghdr *kmsg, int len)
|
||||
{
|
||||
@@ -1091,7 +1109,8 @@ retry_multishot:
|
||||
io_kbuf_recycle(req, sel.buf_list, issue_flags);
|
||||
return IOU_RETRY;
|
||||
}
|
||||
if (ret > 0 && io_net_retry(sock, flags)) {
|
||||
if (ret > 0 && io_net_retry(sock, flags) &&
|
||||
io_net_kbuf_can_retry(req, sel.buf_list, kmsg)) {
|
||||
sr->done_io += ret;
|
||||
return io_net_kbuf_recyle(req, sel.buf_list, kmsg, ret);
|
||||
}
|
||||
@@ -1178,6 +1197,8 @@ static int io_recv_buf_select(struct io_kiocb *req, struct io_async_msghdr *kmsg
|
||||
*sel = io_buffer_select(req, &len, sr->buf_group, issue_flags);
|
||||
if (!sel->addr)
|
||||
return -ENOBUFS;
|
||||
/* ring provided buffers can be up to 4G, keep len an int */
|
||||
len = min_t(size_t, len, MAX_RW_COUNT);
|
||||
sr->buf = sel->addr;
|
||||
sr->len = len;
|
||||
map_ubuf:
|
||||
@@ -1252,7 +1273,8 @@ retry_multishot:
|
||||
io_kbuf_recycle(req, sel.buf_list, issue_flags);
|
||||
return IOU_RETRY;
|
||||
}
|
||||
if (ret > 0 && io_net_retry(sock, flags)) {
|
||||
if (ret > 0 && io_net_retry(sock, flags) &&
|
||||
io_net_kbuf_can_retry(req, sel.buf_list, kmsg)) {
|
||||
sr->len -= ret;
|
||||
sr->buf += ret;
|
||||
sr->done_io += ret;
|
||||
|
||||
@@ -36,6 +36,7 @@ static void io_notif_tw_complete(struct io_tw_req tw_req, io_tw_token_t tw)
|
||||
}
|
||||
|
||||
nd = nd->next;
|
||||
ctx->nr_notifs--;
|
||||
io_req_task_complete((struct io_tw_req){notif}, tw);
|
||||
} while (nd);
|
||||
}
|
||||
@@ -119,6 +120,7 @@ struct io_kiocb *io_alloc_notif(struct io_ring_ctx *ctx)
|
||||
|
||||
if (unlikely(!io_alloc_req(ctx, ¬if)))
|
||||
return NULL;
|
||||
ctx->nr_notifs++;
|
||||
notif->ctx = ctx;
|
||||
notif->opcode = IORING_OP_NOP;
|
||||
notif->flags = 0;
|
||||
|
||||
@@ -375,13 +375,16 @@ static int io_pipe_fixed(struct io_kiocb *req, struct file **files,
|
||||
fds[1] = alloc_slot ? ret : slot - 1;
|
||||
files[1] = NULL;
|
||||
|
||||
io_ring_submit_unlock(ctx, issue_flags);
|
||||
|
||||
if (!copy_to_user(p->fds, fds, sizeof(fds)))
|
||||
/*
|
||||
* Hang on to the lock. If this fails, the slots have to be cleared, and
|
||||
* they must still hold what was put there.
|
||||
*/
|
||||
if (!copy_to_user(p->fds, fds, sizeof(fds))) {
|
||||
io_ring_submit_unlock(ctx, issue_flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = -EFAULT;
|
||||
io_ring_submit_lock(ctx, issue_flags);
|
||||
err:
|
||||
if (fds[0] != -1)
|
||||
io_fixed_fd_remove(ctx, fds[0]);
|
||||
|
||||
+34
-4
@@ -241,12 +241,14 @@ static inline void io_poll_execute(struct io_kiocb *req, int res,
|
||||
*/
|
||||
static int io_poll_check_events(struct io_kiocb *req, io_tw_token_t tw)
|
||||
{
|
||||
bool again;
|
||||
int v;
|
||||
|
||||
if (unlikely(tw.cancel))
|
||||
return -ECANCELED;
|
||||
|
||||
do {
|
||||
again = false;
|
||||
v = atomic_read(&req->poll_refs);
|
||||
|
||||
if (unlikely(v != 1)) {
|
||||
@@ -310,9 +312,15 @@ static int io_poll_check_events(struct io_kiocb *req, io_tw_token_t tw)
|
||||
} else {
|
||||
int ret;
|
||||
|
||||
/* multiple refs and HUP, ensure we loop once more */
|
||||
if ((req->cqe.res & (POLLHUP | POLLRDHUP)) && v != 1)
|
||||
v--;
|
||||
/*
|
||||
* Multiple refs and HUP, ensure we loop once more. Drop
|
||||
* down to one ref now, so the next pass ends unless a
|
||||
* wake up came in.
|
||||
*/
|
||||
if ((req->cqe.res & (POLLHUP | POLLRDHUP)) && v != 1) {
|
||||
atomic_sub(v - 1, &req->poll_refs);
|
||||
again = true;
|
||||
}
|
||||
|
||||
ret = io_poll_issue(req, tw);
|
||||
if (ret == IOU_COMPLETE)
|
||||
@@ -330,7 +338,8 @@ static int io_poll_check_events(struct io_kiocb *req, io_tw_token_t tw)
|
||||
* Release all references, retry if someone tried to restart
|
||||
* task_work while we were executing it.
|
||||
*/
|
||||
} while (atomic_sub_return(v, &req->poll_refs) & IO_POLL_REF_MASK);
|
||||
v &= IO_POLL_REF_MASK;
|
||||
} while (again || atomic_cmpxchg(&req->poll_refs, v, 0) != v);
|
||||
|
||||
io_napi_add(req);
|
||||
return IOU_POLL_NO_ACTION;
|
||||
@@ -617,6 +626,18 @@ static int __io_arm_poll_handler(struct io_kiocb *req,
|
||||
|
||||
io_poll_add_hash(req, issue_flags);
|
||||
|
||||
/*
|
||||
* Whoever tried to cancel the request while io-wq was running it has
|
||||
* flagged the work item. If it searched the hash table before the
|
||||
* request got there it found nothing, and it won't come back. Both
|
||||
* the search and the insertion are done with ->uring_lock held, and
|
||||
* the flag is set before the search. If the search came first,
|
||||
* the flag is visible by now.
|
||||
*/
|
||||
if (ipt->owning &&
|
||||
(atomic_read(&req->work.flags) & IO_WQ_WORK_CANCEL))
|
||||
io_poll_mark_cancelled(req);
|
||||
|
||||
if (mask && (poll->events & EPOLLET) &&
|
||||
io_poll_can_finish_inline(req, ipt)) {
|
||||
__io_poll_execute(req, mask, 0);
|
||||
@@ -906,6 +927,15 @@ int io_poll_add(struct io_kiocb *req, unsigned int issue_flags)
|
||||
|
||||
ipt.pt._qproc = io_poll_queue_proc;
|
||||
|
||||
/*
|
||||
* A poll update or a spurious wake up arms the request again. Forget
|
||||
* the entries of the previous round like io_arm_apoll() does, a stale
|
||||
* second entry would be taken for a third wait queue.
|
||||
*/
|
||||
if (req_has_async_data(req))
|
||||
io_req_async_data_free(req);
|
||||
req->flags &= ~(REQ_F_SINGLE_POLL | REQ_F_DOUBLE_POLL);
|
||||
|
||||
ret = __io_arm_poll_handler(req, poll, &ipt, poll->events, issue_flags);
|
||||
if (ret > 0) {
|
||||
io_req_set_res(req, ipt.result_mask, 0);
|
||||
|
||||
@@ -56,6 +56,33 @@ static inline void __io_req_set_refcount(struct io_kiocb *req, int nr)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* io-wq may still hold a reference if the issue completed async. If so, the
|
||||
* last put completes the request, so that file drop and CQE visibility are
|
||||
* ordered. The last reference stays for the free path to put, a linked
|
||||
* timeout may still look at the request until then.
|
||||
*/
|
||||
static inline bool io_req_complete_ready(struct io_kiocb *req)
|
||||
{
|
||||
if (!(req->flags & REQ_F_REFCOUNT) || (req->flags & REQ_F_REISSUE))
|
||||
return true;
|
||||
if (atomic_read(&req->refs) == 1)
|
||||
return true;
|
||||
if (!req_ref_put_and_test(req))
|
||||
return false;
|
||||
/* the other put raced us, ours was the last after all */
|
||||
atomic_set(&req->refs, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* io-wq still holds a reference, the request can't be completed yet */
|
||||
static inline bool io_req_shared(struct io_kiocb *req)
|
||||
{
|
||||
if (!(req->flags & REQ_F_REFCOUNT) || (req->flags & REQ_F_REISSUE))
|
||||
return false;
|
||||
return atomic_read(&req->refs) > 1;
|
||||
}
|
||||
|
||||
static inline void io_req_set_refcount(struct io_kiocb *req)
|
||||
{
|
||||
__io_req_set_refcount(req, 1);
|
||||
|
||||
+51
-3
@@ -496,6 +496,17 @@ static void io_register_free_rings(struct io_ring_ctx *ctx,
|
||||
IORING_SETUP_CQE32 | IORING_SETUP_NO_MMAP | \
|
||||
IORING_SETUP_CQE_MIXED | IORING_SETUP_SQE_MIXED)
|
||||
|
||||
static bool io_sqe_is_128(struct io_ring_ctx *ctx,
|
||||
const struct io_uring_sqe *sqe)
|
||||
{
|
||||
u8 opcode = READ_ONCE(sqe->opcode);
|
||||
|
||||
if (!(ctx->flags & IORING_SETUP_SQE_MIXED) || opcode >= IORING_OP_LAST)
|
||||
return false;
|
||||
opcode = array_index_nospec(opcode, IORING_OP_LAST);
|
||||
return io_issue_defs[opcode].is_128;
|
||||
}
|
||||
|
||||
static int io_register_resize_rings(struct io_ring_ctx *ctx, void __user *arg)
|
||||
{
|
||||
struct io_ctx_config config;
|
||||
@@ -505,6 +516,8 @@ static int io_register_resize_rings(struct io_ring_ctx *ctx, void __user *arg)
|
||||
struct io_uring_params *p = &config.p;
|
||||
struct io_rings_layout *rl = &config.layout;
|
||||
u32 *o_sq_array, *n_sq_array = NULL;
|
||||
bool cqe32_tail = false;
|
||||
unsigned int sqe128_src = 0;
|
||||
int ret;
|
||||
|
||||
memset(&config, 0, sizeof(config));
|
||||
@@ -603,13 +616,20 @@ static int io_register_resize_rings(struct io_ring_ctx *ctx, void __user *arg)
|
||||
old_head = READ_ONCE(o.rings->sq.head);
|
||||
if (tail - old_head > p->sq_entries)
|
||||
goto overflow;
|
||||
for (i = old_head; i < tail; i++) {
|
||||
for (i = old_head; i != tail; i++) {
|
||||
bool sqe128_tail = sqe128_src;
|
||||
unsigned int dst, src;
|
||||
size_t sq_size;
|
||||
|
||||
dst = i & (p->sq_entries - 1);
|
||||
src = i & (ctx->sq_entries - 1);
|
||||
if (n_sq_array) {
|
||||
if (sqe128_tail) {
|
||||
/* it follows the first half, whatever the array says */
|
||||
src = sqe128_src;
|
||||
sqe128_src = 0;
|
||||
if (n_sq_array)
|
||||
WRITE_ONCE(n_sq_array[dst], dst);
|
||||
} else if (n_sq_array) {
|
||||
src = READ_ONCE(o_sq_array[src]);
|
||||
if (unlikely(src >= ctx->sq_entries)) {
|
||||
WRITE_ONCE(n_sq_array[dst], UINT_MAX);
|
||||
@@ -618,6 +638,19 @@ static int io_register_resize_rings(struct io_ring_ctx *ctx, void __user *arg)
|
||||
WRITE_ONCE(n_sq_array[dst], dst);
|
||||
}
|
||||
|
||||
/*
|
||||
* A 128b SQE on a SQE_MIXED ring takes two contiguous entries
|
||||
* and must not wrap. A smaller ring may place it on the last
|
||||
* entry, fail the resize if that happens.
|
||||
*/
|
||||
if (!sqe128_tail && i + 1 != tail &&
|
||||
src < ctx->sq_entries - 1 &&
|
||||
io_sqe_is_128(ctx, &o.sq_sqes[src])) {
|
||||
if (dst == p->sq_entries - 1)
|
||||
goto overflow;
|
||||
sqe128_src = src + 1;
|
||||
}
|
||||
|
||||
sq_size = sizeof(struct io_uring_sqe);
|
||||
if (ctx->flags & IORING_SETUP_SQE128) {
|
||||
dst <<= 1;
|
||||
@@ -640,7 +673,7 @@ overflow:
|
||||
ret = -EOVERFLOW;
|
||||
goto out;
|
||||
}
|
||||
for (i = old_head; i < tail; i++) {
|
||||
for (i = old_head; i != tail; i++) {
|
||||
unsigned index, dst_mask, src_mask;
|
||||
size_t cq_size;
|
||||
|
||||
@@ -654,6 +687,21 @@ overflow:
|
||||
src_mask = (ctx->cq_entries << 1) - 1;
|
||||
dst_mask = (p->cq_entries << 1) - 1;
|
||||
}
|
||||
/*
|
||||
* A 32b CQE on a CQE_MIXED ring takes two contiguous entries
|
||||
* and must not wrap. A smaller ring may place it on the last
|
||||
* entry, fail the resize if that happens.
|
||||
*/
|
||||
if (ctx->flags & IORING_SETUP_CQE_MIXED) {
|
||||
if (cqe32_tail) {
|
||||
cqe32_tail = false;
|
||||
} else if (READ_ONCE(o.rings->cqes[index & src_mask].flags) &
|
||||
IORING_CQE_F_32) {
|
||||
if ((index & dst_mask) == dst_mask)
|
||||
goto overflow;
|
||||
cqe32_tail = true;
|
||||
}
|
||||
}
|
||||
memcpy(&n.rings->cqes[index & dst_mask], &o.rings->cqes[index & src_mask], cq_size);
|
||||
}
|
||||
WRITE_ONCE(n.rings->cq.head, old_head);
|
||||
|
||||
+32
-10
@@ -174,8 +174,8 @@ static void io_free_imu(struct io_ring_ctx *ctx, struct io_mapped_ubuf *imu)
|
||||
kvfree(imu);
|
||||
}
|
||||
|
||||
static unsigned long io_buffer_unaccount_pages(struct io_ring_ctx *ctx,
|
||||
struct io_mapped_ubuf *imu)
|
||||
static unsigned long io_imu_unaccount_hpages(struct io_ring_ctx *ctx,
|
||||
struct io_mapped_ubuf *imu)
|
||||
{
|
||||
struct page *seen = NULL;
|
||||
unsigned long acct = 0;
|
||||
@@ -188,17 +188,14 @@ static unsigned long io_buffer_unaccount_pages(struct io_ring_ctx *ctx,
|
||||
struct page *page = imu->bvec[i].bv_page;
|
||||
struct page *hpage;
|
||||
|
||||
if (!PageCompound(page)) {
|
||||
acct++;
|
||||
if (!PageCompound(page))
|
||||
continue;
|
||||
}
|
||||
|
||||
hpage = compound_head(page);
|
||||
if (hpage == seen)
|
||||
continue;
|
||||
seen = hpage;
|
||||
|
||||
/* Unaccount on last reference */
|
||||
if (hpage_acct_unref(ctx, hpage))
|
||||
acct += page_size(hpage) >> PAGE_SHIFT;
|
||||
cond_resched();
|
||||
@@ -207,18 +204,38 @@ static unsigned long io_buffer_unaccount_pages(struct io_ring_ctx *ctx,
|
||||
return acct;
|
||||
}
|
||||
|
||||
static unsigned long io_imu_unaccount_reg_pages(struct io_ring_ctx *ctx,
|
||||
struct io_mapped_ubuf *imu)
|
||||
{
|
||||
unsigned long acct = 0;
|
||||
int i;
|
||||
|
||||
if (imu->flags & IO_REGBUF_F_KBUF || !ctx->user)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < imu->nr_bvecs; i++) {
|
||||
if (!PageCompound(imu->bvec[i].bv_page))
|
||||
acct++;
|
||||
}
|
||||
return acct;
|
||||
}
|
||||
|
||||
static void io_buffer_unmap(struct io_ring_ctx *ctx, struct io_mapped_ubuf *imu)
|
||||
{
|
||||
unsigned long acct_pages = 0;
|
||||
unsigned long acct_pages;
|
||||
|
||||
/* Always decrement, so it works for cloned buffers too */
|
||||
acct_pages = io_buffer_unaccount_pages(ctx, imu);
|
||||
/* Compound hpages are accounted per-ring in ctx->hpage_acct */
|
||||
acct_pages = io_imu_unaccount_hpages(ctx, imu);
|
||||
|
||||
if (unlikely(refcount_read(&imu->refs) > 1)) {
|
||||
if (!refcount_dec_and_test(&imu->refs))
|
||||
if (!refcount_dec_and_test(&imu->refs)) {
|
||||
if (acct_pages)
|
||||
io_unaccount_mem(ctx->user, ctx->mm_account, acct_pages);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
acct_pages += io_imu_unaccount_reg_pages(ctx, imu);
|
||||
if (acct_pages)
|
||||
io_unaccount_mem(ctx->user, ctx->mm_account, acct_pages);
|
||||
imu->release(imu->priv);
|
||||
@@ -1280,6 +1297,7 @@ static int io_buffer_acct_cloned_hpages(struct io_ring_ctx *ctx,
|
||||
struct io_mapped_ubuf *imu)
|
||||
{
|
||||
struct page *seen = NULL;
|
||||
unsigned long acct = 0;
|
||||
int i, ret = 0;
|
||||
|
||||
if (imu->flags & IO_REGBUF_F_KBUF || !ctx->user)
|
||||
@@ -1302,10 +1320,14 @@ static int io_buffer_acct_cloned_hpages(struct io_ring_ctx *ctx,
|
||||
ret = hpage_acct_ref(ctx, hpage, &acct_new);
|
||||
if (ret)
|
||||
break;
|
||||
if (acct_new)
|
||||
acct += page_size(hpage) >> PAGE_SHIFT;
|
||||
|
||||
cond_resched();
|
||||
}
|
||||
|
||||
if (!ret && acct)
|
||||
ret = io_account_mem(ctx->user, ctx->mm_account, acct);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
|
||||
+11
-31
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "filetable.h"
|
||||
#include "io_uring.h"
|
||||
#include "refs.h"
|
||||
#include "opdef.h"
|
||||
#include "kbuf.h"
|
||||
#include "alloc_cache.h"
|
||||
@@ -248,7 +249,6 @@ static int __io_prep_rw(struct io_kiocb *req, const struct io_uring_sqe *sqe,
|
||||
struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
|
||||
struct io_async_rw *io;
|
||||
unsigned ioprio;
|
||||
u64 attr_type_mask;
|
||||
int ret;
|
||||
|
||||
if (io_rw_alloc_async(req))
|
||||
@@ -281,19 +281,14 @@ static int __io_prep_rw(struct io_kiocb *req, const struct io_uring_sqe *sqe,
|
||||
rw->addr = READ_ONCE(sqe->addr);
|
||||
rw->len = READ_ONCE(sqe->len);
|
||||
rw->flags = (__force rwf_t) READ_ONCE(sqe->rw_flags);
|
||||
|
||||
attr_type_mask = READ_ONCE(sqe->attr_type_mask);
|
||||
if (attr_type_mask) {
|
||||
u64 attr_ptr;
|
||||
|
||||
/* only PI attribute is supported currently */
|
||||
if (attr_type_mask != IORING_RW_ATTR_FLAG_PI)
|
||||
return -EINVAL;
|
||||
|
||||
attr_ptr = READ_ONCE(sqe->attr_ptr);
|
||||
return io_prep_rw_pi(req, rw, ddir, attr_ptr);
|
||||
switch (READ_ONCE(sqe->attr_type_mask)) {
|
||||
case 0:
|
||||
return 0;
|
||||
case IORING_RW_ATTR_FLAG_PI:
|
||||
return io_prep_rw_pi(req, rw, ddir, READ_ONCE(sqe->attr_ptr));
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int io_rw_do_import(struct io_kiocb *req, int ddir)
|
||||
@@ -610,24 +605,6 @@ static void io_complete_rw_iopoll(struct kiocb *kiocb, long res)
|
||||
smp_store_release(&req->iopoll_completed, 1);
|
||||
}
|
||||
|
||||
static inline ssize_t io_fixup_restart_res(ssize_t ret)
|
||||
{
|
||||
switch (ret) {
|
||||
case -ERESTARTSYS:
|
||||
case -ERESTARTNOINTR:
|
||||
case -ERESTARTNOHAND:
|
||||
case -ERESTART_RESTARTBLOCK:
|
||||
/*
|
||||
* We can't just restart the syscall, since previously
|
||||
* submitted sqes may already be in progress. Just fail
|
||||
* this IO with EINTR.
|
||||
*/
|
||||
return -EINTR;
|
||||
default:
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void io_rw_done(struct io_kiocb *req, ssize_t ret)
|
||||
{
|
||||
struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
|
||||
@@ -1380,6 +1357,9 @@ int io_do_iopoll(struct io_ring_ctx *ctx, bool force_nonspin)
|
||||
/* order with io_complete_rw_iopoll(), e.g. ->result updates */
|
||||
if (!smp_load_acquire(&req->iopoll_completed))
|
||||
continue;
|
||||
/* io-wq still has a reference, reap it on the next pass */
|
||||
if (io_req_shared(req))
|
||||
continue;
|
||||
list_del(&req->iopoll_node);
|
||||
wq_list_add_tail(&req->comp_list, &ctx->submit_state.compl_reqs);
|
||||
nr_events++;
|
||||
|
||||
@@ -385,6 +385,13 @@ static int io_sq_thread(void *data)
|
||||
*/
|
||||
smp_mb__after_atomic();
|
||||
|
||||
/*
|
||||
* Nothing gets submitted before the ring is
|
||||
* enabled, which comes with a wake up.
|
||||
*/
|
||||
if (READ_ONCE(ctx->flags) & IORING_SETUP_R_DISABLED)
|
||||
continue;
|
||||
|
||||
if (io_sqring_entries(ctx)) {
|
||||
needs_sched = false;
|
||||
break;
|
||||
|
||||
+98
-22
@@ -171,6 +171,14 @@ __cold void io_flush_timeouts(struct io_ring_ctx *ctx)
|
||||
raw_spin_lock_irq(&ctx->timeout_lock);
|
||||
seq = READ_ONCE(ctx->cached_cq_tail) - atomic_read(&ctx->cq_timeouts);
|
||||
|
||||
/*
|
||||
* A fired timeout bumps ->cq_timeouts before its CQE is posted, which
|
||||
* leaves the sequence behind the last flush until it is. No event has
|
||||
* happened then, see io_timeout().
|
||||
*/
|
||||
if ((s32)(seq - ctx->cq_last_tm_flush) < 0)
|
||||
seq = ctx->cq_last_tm_flush;
|
||||
|
||||
list_for_each_entry_safe(timeout, tmp, &ctx->timeout_list, list) {
|
||||
struct io_kiocb *req = cmd_to_io_kiocb(timeout);
|
||||
u32 events_needed, events_got;
|
||||
@@ -321,22 +329,29 @@ static enum hrtimer_restart io_timeout_fn(struct hrtimer *timer)
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
|
||||
static struct io_kiocb *io_timeout_find(struct io_ring_ctx *ctx,
|
||||
struct io_cancel_data *cd)
|
||||
__must_hold(&ctx->timeout_lock)
|
||||
{
|
||||
struct io_timeout *timeout;
|
||||
|
||||
list_for_each_entry(timeout, &ctx->timeout_list, list) {
|
||||
struct io_kiocb *req = cmd_to_io_kiocb(timeout);
|
||||
|
||||
if (io_cancel_req_match(req, cd))
|
||||
return req;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct io_kiocb *io_timeout_extract(struct io_ring_ctx *ctx,
|
||||
struct io_cancel_data *cd)
|
||||
__must_hold(&ctx->timeout_lock)
|
||||
{
|
||||
struct io_kiocb *req = io_timeout_find(ctx, cd);
|
||||
struct io_timeout *timeout;
|
||||
struct io_timeout_data *io;
|
||||
struct io_kiocb *req = NULL;
|
||||
|
||||
list_for_each_entry(timeout, &ctx->timeout_list, list) {
|
||||
struct io_kiocb *tmp = cmd_to_io_kiocb(timeout);
|
||||
|
||||
if (io_cancel_req_match(tmp, cd)) {
|
||||
req = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!req)
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
@@ -386,6 +401,9 @@ static void io_req_task_link_timeout(struct io_tw_req tw_req, io_tw_token_t tw)
|
||||
};
|
||||
|
||||
ret = io_try_cancel(req->tctx, &cd, 0);
|
||||
/* a number of requests for futex and waitid */
|
||||
if (ret > 0)
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = -ECANCELED;
|
||||
}
|
||||
@@ -458,6 +476,8 @@ static int io_linked_timeout_update(struct io_ring_ctx *ctx, __u64 user_data,
|
||||
io = req->async_data;
|
||||
if (hrtimer_try_to_cancel(&io->timer) == -1)
|
||||
return -EALREADY;
|
||||
if (mode == HRTIMER_MODE_ABS)
|
||||
ts = timens_ktime_to_host(io_timeout_get_clock(io), ts);
|
||||
hrtimer_setup(&io->timer, io_link_timeout_fn, io_timeout_get_clock(io), mode);
|
||||
hrtimer_start(&io->timer, ts, mode);
|
||||
return 0;
|
||||
@@ -468,15 +488,26 @@ static int io_timeout_update(struct io_ring_ctx *ctx, __u64 user_data,
|
||||
__must_hold(&ctx->timeout_lock)
|
||||
{
|
||||
struct io_cancel_data cd = { .ctx = ctx, .data = user_data, };
|
||||
struct io_kiocb *req = io_timeout_extract(ctx, &cd);
|
||||
struct io_kiocb *req = io_timeout_find(ctx, &cd);
|
||||
struct io_timeout *timeout = io_kiocb_to_cmd(req, struct io_timeout);
|
||||
struct io_timeout_data *data;
|
||||
|
||||
if (!req)
|
||||
return -ENOENT;
|
||||
|
||||
data = req->async_data;
|
||||
/* multishot requests only make sense with rel values */
|
||||
if ((data->flags & IORING_TIMEOUT_MULTISHOT) && mode == HRTIMER_MODE_ABS)
|
||||
return -EINVAL;
|
||||
|
||||
req = io_timeout_extract(ctx, &cd);
|
||||
if (IS_ERR(req))
|
||||
return PTR_ERR(req);
|
||||
|
||||
timeout->off = 0; /* noseq */
|
||||
data = req->async_data;
|
||||
/* for a multishot request this isn't a sequence, keep the repeats */
|
||||
if (!(data->flags & IORING_TIMEOUT_MULTISHOT))
|
||||
timeout->off = 0; /* noseq */
|
||||
if (mode == HRTIMER_MODE_ABS)
|
||||
time = timens_ktime_to_host(io_timeout_get_clock(data), time);
|
||||
data->time = time;
|
||||
|
||||
list_add_tail(&timeout->list, &ctx->timeout_list);
|
||||
@@ -509,7 +540,12 @@ int io_timeout_remove_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
||||
IORING_TIMEOUT_ABS |
|
||||
IORING_TIMEOUT_IMMEDIATE_ARG))
|
||||
return -EINVAL;
|
||||
ret = io_parse_user_time(&tr->time, READ_ONCE(sqe->addr2), tr->flags);
|
||||
/*
|
||||
* The clock is that of the timeout to update, an absolute time
|
||||
* is converted to the host's view once that has been found.
|
||||
*/
|
||||
ret = io_parse_user_time(&tr->time, READ_ONCE(sqe->addr2),
|
||||
tr->flags & ~IORING_TIMEOUT_ABS);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else if (tr->flags) {
|
||||
@@ -645,11 +681,19 @@ int io_timeout(struct io_kiocb *req, unsigned int issue_flags)
|
||||
struct io_timeout *timeout = io_kiocb_to_cmd(req, struct io_timeout);
|
||||
struct io_ring_ctx *ctx = req->ctx;
|
||||
struct io_timeout_data *data = req->async_data;
|
||||
struct io_timeout *first;
|
||||
struct list_head *entry;
|
||||
u32 tail, off = timeout->off;
|
||||
u32 tail, base, off = timeout->off;
|
||||
|
||||
raw_spin_lock_irq(&ctx->timeout_lock);
|
||||
|
||||
/* the list is searched under ->timeout_lock, see io_wq_cancel_seen() */
|
||||
if (__io_wq_cancel_seen(req, issue_flags)) {
|
||||
raw_spin_unlock_irq(&ctx->timeout_lock);
|
||||
io_req_task_queue_fail(req, -ECANCELED);
|
||||
return IOU_ISSUE_SKIP_COMPLETE;
|
||||
}
|
||||
|
||||
/*
|
||||
* sqe->off holds how many events that need to occur for this
|
||||
* timeout event to be satisfied. If it isn't set, then this is
|
||||
@@ -661,13 +705,27 @@ int io_timeout(struct io_kiocb *req, unsigned int issue_flags)
|
||||
}
|
||||
|
||||
tail = data_race(ctx->cached_cq_tail) - atomic_read(&ctx->cq_timeouts);
|
||||
timeout->target_seq = tail + off;
|
||||
|
||||
/* Update the last seq here in case io_flush_timeouts() hasn't.
|
||||
* This is safe because ->completion_lock is held, and submissions
|
||||
* and completions are never mixed in the same ->completion_lock section.
|
||||
/*
|
||||
* Update the last seq here in case io_flush_timeouts() hasn't, it only
|
||||
* gets called once sequences are in use. Leave it alone if there are
|
||||
* timeouts waiting for one. CQEs may have been posted since the last
|
||||
* flush, and a target that has been reached must not fall behind it.
|
||||
*/
|
||||
ctx->cq_last_tm_flush = tail;
|
||||
first = list_first_entry_or_null(&ctx->timeout_list, struct io_timeout,
|
||||
list);
|
||||
if (!first || io_is_timeout_noseq(cmd_to_io_kiocb(first)))
|
||||
ctx->cq_last_tm_flush = tail;
|
||||
base = ctx->cq_last_tm_flush;
|
||||
|
||||
/*
|
||||
* A fired timeout bumps ->cq_timeouts before its CQE is posted, which
|
||||
* leaves the sequence behind the last flush until it is. Nothing else
|
||||
* separates the two then, so count from the flush.
|
||||
*/
|
||||
if ((s32)(tail - base) < 0)
|
||||
tail = base;
|
||||
timeout->target_seq = tail + off;
|
||||
|
||||
/*
|
||||
* Insertion sort, ensuring the first entry in the list is always
|
||||
@@ -679,8 +737,8 @@ int io_timeout(struct io_kiocb *req, unsigned int issue_flags)
|
||||
|
||||
if (io_is_timeout_noseq(nxt))
|
||||
continue;
|
||||
/* nxt.seq is behind @tail, otherwise would've been completed */
|
||||
if (off >= nextt->target_seq - tail)
|
||||
/* no target is behind the last flush, see io_flush_timeouts() */
|
||||
if (timeout->target_seq - base >= nextt->target_seq - base)
|
||||
break;
|
||||
}
|
||||
add:
|
||||
@@ -729,6 +787,24 @@ static bool io_match_task(struct io_kiocb *head, struct io_uring_task *tctx,
|
||||
return false;
|
||||
}
|
||||
|
||||
__cold unsigned int io_timeouts_armed(struct io_ring_ctx *ctx,
|
||||
struct io_uring_task *tctx)
|
||||
{
|
||||
struct io_timeout *timeout;
|
||||
unsigned int nr = 0;
|
||||
|
||||
guard(mutex)(&ctx->uring_lock);
|
||||
raw_spin_lock_irq(&ctx->timeout_lock);
|
||||
list_for_each_entry(timeout, &ctx->timeout_list, list) {
|
||||
struct io_kiocb *req = cmd_to_io_kiocb(timeout);
|
||||
|
||||
if (req->tctx == tctx)
|
||||
nr += io_linked_nr(req);
|
||||
}
|
||||
raw_spin_unlock_irq(&ctx->timeout_lock);
|
||||
return nr;
|
||||
}
|
||||
|
||||
/* Returns true if we found and killed one or more timeouts */
|
||||
__cold bool io_kill_timeouts(struct io_ring_ctx *ctx, struct io_uring_task *tctx,
|
||||
bool cancel_all)
|
||||
|
||||
@@ -11,6 +11,8 @@ struct io_timeout_data {
|
||||
__cold void io_flush_timeouts(struct io_ring_ctx *ctx);
|
||||
struct io_cancel_data;
|
||||
int io_timeout_cancel(struct io_ring_ctx *ctx, struct io_cancel_data *cd);
|
||||
__cold unsigned int io_timeouts_armed(struct io_ring_ctx *ctx,
|
||||
struct io_uring_task *tctx);
|
||||
__cold bool io_kill_timeouts(struct io_ring_ctx *ctx, struct io_uring_task *tctx,
|
||||
bool cancel_all);
|
||||
void io_queue_linked_timeout(struct io_kiocb *req);
|
||||
|
||||
+35
-1
@@ -148,6 +148,37 @@ static void io_ctx_mark_taskrun(struct io_ring_ctx *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
static void io_poll_wq_wake_rcu(struct rcu_head *rcu)
|
||||
{
|
||||
struct io_ring_ctx *ctx = container_of(rcu, struct io_ring_ctx,
|
||||
poll_wq_rcu);
|
||||
|
||||
atomic_set(&ctx->poll_wq_rcu_pending, 0);
|
||||
io_poll_wq_wake(ctx);
|
||||
percpu_ref_put(&ctx->refs);
|
||||
}
|
||||
|
||||
/*
|
||||
* io_uring_poll() reports pending local work as EPOLLIN, as it takes a trip to
|
||||
* the kernel to turn it into CQEs. Let those know who are asleep already.
|
||||
*/
|
||||
static void io_local_work_wake_poll(struct io_ring_ctx *ctx, unsigned int flags)
|
||||
{
|
||||
if (!(flags & IOU_F_TWQ_IN_WAKE)) {
|
||||
io_poll_wq_wake(ctx);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Called from a wake up handler with some wait queue lock held, this
|
||||
* one could lead back to it. Do it from a clean context.
|
||||
*/
|
||||
if (!wq_has_sleeper(&ctx->poll_wq) ||
|
||||
atomic_xchg(&ctx->poll_wq_rcu_pending, 1))
|
||||
return;
|
||||
percpu_ref_get(&ctx->refs);
|
||||
call_rcu_hurry(&ctx->poll_wq_rcu, io_poll_wq_wake_rcu);
|
||||
}
|
||||
|
||||
void io_req_local_work_add(struct io_kiocb *req, unsigned flags)
|
||||
{
|
||||
struct io_ring_ctx *ctx = req->ctx;
|
||||
@@ -165,7 +196,7 @@ void io_req_local_work_add(struct io_kiocb *req, unsigned flags)
|
||||
|
||||
/*
|
||||
* The xchg() in mpscq_push() implies a full barrier, which pairs with
|
||||
* the barrier in set_current_state() on the io_cqring_wait() side. This
|
||||
* the barrier in io_cq_wait_arm() on the io_cqring_wait() side. This
|
||||
* ensures that either we see the updated ->cq_wait_nr, or waiters going
|
||||
* to sleep will observe the work added to the list, which is similar to
|
||||
* the wait/wake task state sync.
|
||||
@@ -174,6 +205,9 @@ void io_req_local_work_add(struct io_kiocb *req, unsigned flags)
|
||||
io_ctx_mark_taskrun(ctx);
|
||||
if (data_race(ctx->int_flags) & IO_RING_F_HAS_EVFD)
|
||||
io_eventfd_signal(ctx, false, flags & IOU_F_TWQ_IN_WAKE);
|
||||
/* whoever sets the flag wakes ->poll_wq afterwards */
|
||||
if (data_race(ctx->int_flags) & IO_RING_F_POLL_ACTIVATED)
|
||||
io_local_work_wake_poll(ctx, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+4
-21
@@ -49,7 +49,7 @@ void io_uring_cmd_cleanup(struct io_kiocb *req)
|
||||
}
|
||||
|
||||
bool io_uring_try_cancel_uring_cmd(struct io_ring_ctx *ctx,
|
||||
struct io_uring_task *tctx, bool cancel_all)
|
||||
struct io_uring_task *tctx)
|
||||
{
|
||||
struct hlist_node *tmp;
|
||||
struct io_kiocb *req;
|
||||
@@ -63,7 +63,7 @@ bool io_uring_try_cancel_uring_cmd(struct io_ring_ctx *ctx,
|
||||
struct io_uring_cmd);
|
||||
struct file *file = req->file;
|
||||
|
||||
if (!cancel_all && req->tctx != tctx)
|
||||
if (tctx && req->tctx != tctx)
|
||||
continue;
|
||||
|
||||
if (cmd->flags & IORING_URING_CMD_CANCELABLE) {
|
||||
@@ -87,7 +87,7 @@ static void io_uring_cmd_del_cancelable(struct io_uring_cmd *cmd,
|
||||
|
||||
cmd->flags &= ~IORING_URING_CMD_CANCELABLE;
|
||||
io_ring_submit_lock(ctx, issue_flags);
|
||||
hlist_del(&req->hash_node);
|
||||
hlist_del_init(&req->hash_node);
|
||||
io_ring_submit_unlock(ctx, issue_flags);
|
||||
}
|
||||
|
||||
@@ -138,19 +138,11 @@ void __io_uring_cmd_do_in_task(struct io_uring_cmd *ioucmd,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__io_uring_cmd_do_in_task);
|
||||
|
||||
static inline void io_req_set_cqe32_extra(struct io_kiocb *req,
|
||||
u64 extra1, u64 extra2)
|
||||
{
|
||||
req->big_cqe.extra1 = extra1;
|
||||
req->big_cqe.extra2 = extra2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called by consumers of io_uring_cmd, if they originally returned
|
||||
* -EIOCBQUEUED upon receiving the command.
|
||||
*/
|
||||
void __io_uring_cmd_done(struct io_uring_cmd *ioucmd, s32 ret, u64 res2,
|
||||
unsigned issue_flags, bool is_cqe32)
|
||||
void __io_uring_cmd_done(struct io_uring_cmd *ioucmd, unsigned issue_flags)
|
||||
{
|
||||
struct io_kiocb *req = cmd_to_io_kiocb(ioucmd);
|
||||
|
||||
@@ -159,15 +151,6 @@ void __io_uring_cmd_done(struct io_uring_cmd *ioucmd, s32 ret, u64 res2,
|
||||
|
||||
io_uring_cmd_del_cancelable(ioucmd, issue_flags);
|
||||
|
||||
if (ret < 0)
|
||||
req_set_fail(req);
|
||||
|
||||
io_req_set_res(req, ret, 0);
|
||||
if (is_cqe32) {
|
||||
if (req->ctx->flags & IORING_SETUP_CQE_MIXED)
|
||||
req->cqe.flags |= IORING_CQE_F_32;
|
||||
io_req_set_cqe32_extra(req, res2, 0);
|
||||
}
|
||||
io_req_uring_cleanup(req, issue_flags);
|
||||
if (req->flags & REQ_F_IOPOLL) {
|
||||
/* order with io_do_iopoll() checking ->iopoll_completed */
|
||||
|
||||
@@ -14,7 +14,7 @@ void io_uring_cmd_sqe_copy(struct io_kiocb *req);
|
||||
void io_uring_cmd_cleanup(struct io_kiocb *req);
|
||||
|
||||
bool io_uring_try_cancel_uring_cmd(struct io_ring_ctx *ctx,
|
||||
struct io_uring_task *tctx, bool cancel_all);
|
||||
struct io_uring_task *tctx);
|
||||
|
||||
bool io_uring_cmd_post_mshot_cqe32(struct io_uring_cmd *cmd,
|
||||
unsigned int issue_flags,
|
||||
|
||||
+37
-11
@@ -3,6 +3,7 @@
|
||||
* Waiting for completion events
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched/rt.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/io_uring.h>
|
||||
#include <linux/time_namespace.h>
|
||||
@@ -26,7 +27,8 @@ static int io_wake_function(struct wait_queue_entry *curr, unsigned int mode,
|
||||
*/
|
||||
if (io_should_wake(iowq) || io_has_work(iowq->ctx))
|
||||
return autoremove_wake_function(curr, mode, wake_flags, key);
|
||||
return -1;
|
||||
/* keep going, a waiter further down may be content with less */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int io_run_task_work_sig(struct io_ring_ctx *ctx)
|
||||
@@ -76,9 +78,16 @@ static enum hrtimer_restart io_cqring_min_timer_wakeup(struct hrtimer *timer)
|
||||
if (iowq->timeout == KTIME_MAX ||
|
||||
ktime_compare(iowq->min_timeout, iowq->timeout) >= 0)
|
||||
goto out_wake;
|
||||
/* work we may need to run, wake function will see if we need to wake */
|
||||
if (io_has_work(ctx))
|
||||
goto out_wake;
|
||||
/*
|
||||
* Work we need to run. It isn't known if that is going to post a CQE,
|
||||
* so this isn't a timeout. Carry on with the normal one if it doesn't.
|
||||
*/
|
||||
if (io_has_work(ctx)) {
|
||||
iowq->min_timeout = 0;
|
||||
iowq->cq_tail = iowq->cq_min_tail + 1;
|
||||
wake_up_process(iowq->wq.private);
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
/* got events since we started waiting, min timeout is done */
|
||||
scoped_guard(rcu) {
|
||||
struct io_rings *rings = io_get_rings(ctx);
|
||||
@@ -112,23 +121,32 @@ out_wake:
|
||||
return io_cqring_timer_wakeup(timer);
|
||||
}
|
||||
|
||||
/* Same policy as for hrtimer sleepers, see __hrtimer_setup_sleeper(). */
|
||||
static enum hrtimer_mode io_cqring_timer_mode(void)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_PREEMPT_RT) && rt_or_dl_task_policy(current))
|
||||
return HRTIMER_MODE_ABS_HARD;
|
||||
return HRTIMER_MODE_ABS;
|
||||
}
|
||||
|
||||
static int io_cqring_schedule_timeout(struct io_wait_queue *iowq,
|
||||
clockid_t clock_id, ktime_t start_time)
|
||||
{
|
||||
enum hrtimer_mode mode = io_cqring_timer_mode();
|
||||
ktime_t timeout;
|
||||
|
||||
if (iowq->min_timeout) {
|
||||
timeout = ktime_add_ns(iowq->min_timeout, start_time);
|
||||
hrtimer_setup_on_stack(&iowq->t, io_cqring_min_timer_wakeup, clock_id,
|
||||
HRTIMER_MODE_ABS);
|
||||
mode);
|
||||
} else {
|
||||
timeout = iowq->timeout;
|
||||
hrtimer_setup_on_stack(&iowq->t, io_cqring_timer_wakeup, clock_id,
|
||||
HRTIMER_MODE_ABS);
|
||||
mode);
|
||||
}
|
||||
|
||||
hrtimer_set_expires_range_ns(&iowq->t, timeout, 0);
|
||||
hrtimer_start_expires(&iowq->t, HRTIMER_MODE_ABS);
|
||||
hrtimer_start_expires(&iowq->t, mode);
|
||||
|
||||
if (!READ_ONCE(iowq->hit_timeout))
|
||||
schedule();
|
||||
@@ -257,8 +275,7 @@ int io_cqring_wait(struct io_ring_ctx *ctx, int min_events, u32 flags,
|
||||
unsigned long check_cq;
|
||||
|
||||
if (ctx->flags & IORING_SETUP_DEFER_TASKRUN) {
|
||||
atomic_set(&ctx->cq_wait_nr, nr_wait);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
io_cq_wait_arm(ctx, nr_wait);
|
||||
} else {
|
||||
prepare_to_wait_exclusive(&ctx->cq_wait, &iowq.wq,
|
||||
TASK_INTERRUPTIBLE);
|
||||
@@ -291,9 +308,18 @@ int io_cqring_wait(struct io_ring_ctx *ctx, int min_events, u32 flags,
|
||||
|
||||
check_cq = READ_ONCE(ctx->check_cq);
|
||||
if (unlikely(check_cq)) {
|
||||
/* let the caller flush overflows, retry */
|
||||
if (check_cq & BIT(IO_CHECK_CQ_OVERFLOW_BIT))
|
||||
if (check_cq & BIT(IO_CHECK_CQ_OVERFLOW_BIT)) {
|
||||
io_cqring_do_overflow_flush(ctx);
|
||||
/*
|
||||
* No room for what has overflown. It takes the
|
||||
* application to change that, so return to it.
|
||||
*/
|
||||
if (test_bit(IO_CHECK_CQ_OVERFLOW_BIT,
|
||||
&ctx->check_cq)) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (check_cq & BIT(IO_CHECK_CQ_DROPPED_BIT)) {
|
||||
ret = -EBADR;
|
||||
break;
|
||||
|
||||
@@ -14,6 +14,21 @@
|
||||
*/
|
||||
#define IO_CQ_WAKE_INIT (-1)
|
||||
|
||||
/*
|
||||
* Start a wait cycle of the current task. The add that uses up ->cq_wait_nr
|
||||
* may be one that queued its entry long ago and only now gets to look at the
|
||||
* count. As nobody else wakes us after that, it has to find us sleeping, hence
|
||||
* the task state must be visible before the count is. The barrier pairs with
|
||||
* the xchg() in mpscq_push(), see io_req_local_work_add().
|
||||
*/
|
||||
static inline void io_cq_wait_arm(struct io_ring_ctx *ctx, int nr_wait)
|
||||
{
|
||||
__set_current_state(TASK_INTERRUPTIBLE);
|
||||
atomic_set_release(&ctx->cq_wait_nr, nr_wait);
|
||||
/* order the above against looking at the work list */
|
||||
smp_mb();
|
||||
}
|
||||
|
||||
struct ext_arg {
|
||||
size_t argsz;
|
||||
struct timespec64 ts;
|
||||
|
||||
+19
-4
@@ -10,6 +10,7 @@
|
||||
#include <linux/io_uring.h>
|
||||
|
||||
#include <uapi/linux/io_uring.h>
|
||||
#include <uapi/linux/wait.h>
|
||||
|
||||
#include "io_uring.h"
|
||||
#include "cancel.h"
|
||||
@@ -154,9 +155,12 @@ static bool __io_waitid_cancel(struct io_kiocb *req, bool copy_si)
|
||||
|
||||
/*
|
||||
* Mark us canceled regardless of ownership. This will prevent a
|
||||
* potential retry from a spurious wakeup.
|
||||
* potential retry from a spurious wakeup. Only the first cancel
|
||||
* attempt should take a reference for the ownership handoff.
|
||||
*/
|
||||
atomic_or(IO_WAITID_CANCEL_FLAG, &iw->refs);
|
||||
if (atomic_fetch_or(IO_WAITID_CANCEL_FLAG, &iw->refs) &
|
||||
IO_WAITID_CANCEL_FLAG)
|
||||
return false;
|
||||
|
||||
/* claim ownership */
|
||||
if (atomic_fetch_inc(&iw->refs) & IO_WAITID_REF_MASK)
|
||||
@@ -265,12 +269,18 @@ static int io_waitid_wait(struct wait_queue_entry *wait, unsigned mode,
|
||||
return 0;
|
||||
|
||||
list_del_init(&wait->entry);
|
||||
smp_store_release(&iw->head, NULL);
|
||||
|
||||
/* cancel is in progress */
|
||||
/*
|
||||
* Cancel or issue is in progress. Leave ->head alone, so that whoever
|
||||
* owns the request has to take the wait queue lock, which we hold,
|
||||
* before it can complete and free it.
|
||||
*/
|
||||
if (atomic_fetch_inc(&iw->refs) & IO_WAITID_REF_MASK)
|
||||
return 1;
|
||||
|
||||
/* pairs with the smp_load_acquire() in io_waitid_remove_wq() */
|
||||
smp_store_release(&iw->head, NULL);
|
||||
|
||||
req->io_task_work.func = io_waitid_cb;
|
||||
__io_req_task_work_add(req, IOU_F_TWQ_IN_WAKE);
|
||||
return 1;
|
||||
@@ -343,6 +353,8 @@ int io_waitid(struct io_kiocb *req, unsigned int issue_flags)
|
||||
* a waitqueue callback, or if someone cancels it.
|
||||
*/
|
||||
if (!io_waitid_drop_issue_ref(req)) {
|
||||
if (io_wq_cancel_seen(req, issue_flags))
|
||||
__io_waitid_cancel(req, true);
|
||||
io_ring_submit_unlock(ctx, issue_flags);
|
||||
return IOU_ISSUE_SKIP_COMPLETE;
|
||||
}
|
||||
@@ -357,6 +369,9 @@ int io_waitid(struct io_kiocb *req, unsigned int issue_flags)
|
||||
|
||||
hlist_del_init(&req->hash_node);
|
||||
io_waitid_remove_wq(req);
|
||||
/* a non-blocking pidfd implies WNOHANG, report it as waitid(2) does */
|
||||
if (!ret && !(iw->options & WNOHANG) && (iwa->wo.wo_flags & WNOHANG))
|
||||
ret = -EAGAIN;
|
||||
ret = io_waitid_finish(req, ret);
|
||||
|
||||
io_ring_submit_unlock(ctx, issue_flags);
|
||||
|
||||
+1
-1
@@ -1645,7 +1645,7 @@ static bool io_zcrx_queue_cqe(struct io_kiocb *req, struct net_iov *niov,
|
||||
cqe->flags |= IORING_CQE_F_32;
|
||||
|
||||
area = io_zcrx_iov_to_area(niov);
|
||||
offset = off + (net_iov_idx(niov) << ifq->niov_shift);
|
||||
offset = off + ((u64)net_iov_idx(niov) << ifq->niov_shift);
|
||||
rcqe = (struct io_uring_zcrx_cqe *)(cqe + 1);
|
||||
rcqe->off = offset + zcrx_area_id_to_token(area->area_id);
|
||||
rcqe->__pad = 0;
|
||||
|
||||
Reference in new issue
Block a user