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:
Linus Torvalds committed 2026-10-24 13:43:13 -10:00
commit fa899d500a
35 files changed
+1159 -307

No files matched your search

+9 -10
View File
@@ -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);
}
+32
View File
@@ -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);
+28 -6
View File
@@ -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 */
+7
View File
@@ -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 */
+8 -7
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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) ||
+8
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+2
View File
@@ -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, &notif)))
return NULL;
ctx->nr_notifs++;
notif->ctx = ctx;
notif->opcode = IORING_OP_NOP;
notif->flags = 0;
+7 -4
View File
@@ -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
View File
@@ -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);
+27
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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++;
+7
View File
@@ -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
View File
@@ -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)
+2
View File
@@ -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
View File
@@ -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
View File
@@ -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 */
+1 -1
View File
@@ -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
View File
@@ -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;
+15
View File
@@ -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
View File
@@ -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
View File
@@ -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;