Skip to content

Commit

Permalink
Merge tag 'io_uring-6.14-20250221' of git://git.kernel.dk/linux
Browse files Browse the repository at this point in the history
Pull io_uring fixes from Jens Axboe:

 - Series fixing an issue with multishot read on pollable files that may
   return -EIOCBQUEUED from ->read_iter(). Four small patches for that,
   the first one deliberately done in such a way that it'd be easy to
   backport

 - Remove some dead constant definitions

 - Use array_index_nospec() for opcode indexing

 - Work-around for worker creation retries in the presence of signals

* tag 'io_uring-6.14-20250221' of git://git.kernel.dk/linux:
  io_uring/rw: clean up mshot forced sync mode
  io_uring/rw: move ki_complete init into prep
  io_uring/rw: don't directly use ki_complete
  io_uring/rw: forbid multishot async reads
  io_uring/rsrc: remove unused constants
  io_uring: fix spelling error in uapi io_uring.h
  io_uring: prevent opcode speculation
  io-wq: backoff when retrying worker creation
  • Loading branch information
torvalds committed Feb 21, 2025
2 parents 7108b48 + 4614de7 commit f679ebf
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 21 deletions.
2 changes: 1 addition & 1 deletion include/uapi/linux/io_uring.h
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ enum io_uring_op {
* result will be the number of buffers send, with
* the starting buffer ID in cqe->flags as per
* usual for provided buffer usage. The buffers
* will be contigious from the starting buffer ID.
* will be contiguous from the starting buffer ID.
*/
#define IORING_RECVSEND_POLL_FIRST (1U << 0)
#define IORING_RECV_MULTISHOT (1U << 1)
Expand Down
23 changes: 18 additions & 5 deletions io_uring/io-wq.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ struct io_worker {

union {
struct rcu_head rcu;
struct work_struct work;
struct delayed_work work;
};
};

Expand Down Expand Up @@ -770,6 +770,18 @@ static inline bool io_should_retry_thread(struct io_worker *worker, long err)
}
}

static void queue_create_worker_retry(struct io_worker *worker)
{
/*
* We only bother retrying because there's a chance that the
* failure to create a worker is due to some temporary condition
* in the forking task (e.g. outstanding signal); give the task
* some time to clear that condition.
*/
schedule_delayed_work(&worker->work,
msecs_to_jiffies(worker->init_retries * 5));
}

static void create_worker_cont(struct callback_head *cb)
{
struct io_worker *worker;
Expand Down Expand Up @@ -809,12 +821,13 @@ static void create_worker_cont(struct callback_head *cb)

/* re-create attempts grab a new worker ref, drop the existing one */
io_worker_release(worker);
schedule_work(&worker->work);
queue_create_worker_retry(worker);
}

static void io_workqueue_create(struct work_struct *work)
{
struct io_worker *worker = container_of(work, struct io_worker, work);
struct io_worker *worker = container_of(work, struct io_worker,
work.work);
struct io_wq_acct *acct = io_wq_get_acct(worker);

if (!io_queue_worker_create(worker, acct, create_worker_cont))
Expand Down Expand Up @@ -855,8 +868,8 @@ static bool create_io_worker(struct io_wq *wq, int index)
kfree(worker);
goto fail;
} else {
INIT_WORK(&worker->work, io_workqueue_create);
schedule_work(&worker->work);
INIT_DELAYED_WORK(&worker->work, io_workqueue_create);
queue_create_worker_retry(worker);
}

return true;
Expand Down
2 changes: 2 additions & 0 deletions io_uring/io_uring.c
Original file line number Diff line number Diff line change
Expand Up @@ -2045,6 +2045,8 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
req->opcode = 0;
return io_init_fail_req(req, -EINVAL);
}
opcode = array_index_nospec(opcode, IORING_OP_LAST);

def = &io_issue_defs[opcode];
if (unlikely(sqe_flags & ~SQE_COMMON_FLAGS)) {
/* enforce forwards compatibility on users */
Expand Down
6 changes: 0 additions & 6 deletions io_uring/rsrc.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,6 @@

#include <linux/lockdep.h>

#define IO_NODE_ALLOC_CACHE_MAX 32

#define IO_RSRC_TAG_TABLE_SHIFT (PAGE_SHIFT - 3)
#define IO_RSRC_TAG_TABLE_MAX (1U << IO_RSRC_TAG_TABLE_SHIFT)
#define IO_RSRC_TAG_TABLE_MASK (IO_RSRC_TAG_TABLE_MAX - 1)

enum {
IORING_RSRC_FILE = 0,
IORING_RSRC_BUFFER = 1,
Expand Down
30 changes: 21 additions & 9 deletions io_uring/rw.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
#include "poll.h"
#include "rw.h"

static void io_complete_rw(struct kiocb *kiocb, long res);
static void io_complete_rw_iopoll(struct kiocb *kiocb, long res);

struct io_rw {
/* NOTE: kiocb has the file as the first member, so don't do it here */
struct kiocb kiocb;
Expand Down Expand Up @@ -289,6 +292,11 @@ static int io_prep_rw(struct io_kiocb *req, const struct io_uring_sqe *sqe,
rw->kiocb.dio_complete = NULL;
rw->kiocb.ki_flags = 0;

if (req->ctx->flags & IORING_SETUP_IOPOLL)
rw->kiocb.ki_complete = io_complete_rw_iopoll;
else
rw->kiocb.ki_complete = io_complete_rw;

rw->addr = READ_ONCE(sqe->addr);
rw->len = READ_ONCE(sqe->len);
rw->flags = READ_ONCE(sqe->rw_flags);
Expand Down Expand Up @@ -563,8 +571,10 @@ static void io_complete_rw_iopoll(struct kiocb *kiocb, long res)
smp_store_release(&req->iopoll_completed, 1);
}

static inline void io_rw_done(struct kiocb *kiocb, ssize_t 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);

/* IO was queued async, completion will happen later */
if (ret == -EIOCBQUEUED)
return;
Expand All @@ -586,8 +596,10 @@ static inline void io_rw_done(struct kiocb *kiocb, ssize_t ret)
}
}

INDIRECT_CALL_2(kiocb->ki_complete, io_complete_rw_iopoll,
io_complete_rw, kiocb, ret);
if (req->ctx->flags & IORING_SETUP_IOPOLL)
io_complete_rw_iopoll(&rw->kiocb, ret);
else
io_complete_rw(&rw->kiocb, ret);
}

static int kiocb_done(struct io_kiocb *req, ssize_t ret,
Expand All @@ -598,7 +610,7 @@ static int kiocb_done(struct io_kiocb *req, ssize_t ret,

if (ret >= 0 && req->flags & REQ_F_CUR_POS)
req->file->f_pos = rw->kiocb.ki_pos;
if (ret >= 0 && (rw->kiocb.ki_complete == io_complete_rw)) {
if (ret >= 0 && !(req->ctx->flags & IORING_SETUP_IOPOLL)) {
__io_complete_rw_common(req, ret);
/*
* Safe to call io_end from here as we're inline
Expand All @@ -609,7 +621,7 @@ static int kiocb_done(struct io_kiocb *req, ssize_t ret,
io_req_rw_cleanup(req, issue_flags);
return IOU_OK;
} else {
io_rw_done(&rw->kiocb, ret);
io_rw_done(req, ret);
}

return IOU_ISSUE_SKIP_COMPLETE;
Expand Down Expand Up @@ -813,10 +825,8 @@ static int io_rw_init_file(struct io_kiocb *req, fmode_t mode, int rw_type)
if (ctx->flags & IORING_SETUP_IOPOLL) {
if (!(kiocb->ki_flags & IOCB_DIRECT) || !file->f_op->iopoll)
return -EOPNOTSUPP;

kiocb->private = NULL;
kiocb->ki_flags |= IOCB_HIPRI;
kiocb->ki_complete = io_complete_rw_iopoll;
req->iopoll_completed = 0;
if (ctx->flags & IORING_SETUP_HYBRID_IOPOLL) {
/* make sure every req only blocks once*/
Expand All @@ -826,7 +836,6 @@ static int io_rw_init_file(struct io_kiocb *req, fmode_t mode, int rw_type)
} else {
if (kiocb->ki_flags & IOCB_HIPRI)
return -EINVAL;
kiocb->ki_complete = io_complete_rw;
}

if (req->flags & REQ_F_HAS_METADATA) {
Expand Down Expand Up @@ -904,7 +913,8 @@ static int __io_read(struct io_kiocb *req, unsigned int issue_flags)
} else if (ret == -EIOCBQUEUED) {
return IOU_ISSUE_SKIP_COMPLETE;
} else if (ret == req->cqe.res || ret <= 0 || !force_nonblock ||
(req->flags & REQ_F_NOWAIT) || !need_complete_io(req)) {
(req->flags & REQ_F_NOWAIT) || !need_complete_io(req) ||
(issue_flags & IO_URING_F_MULTISHOT)) {
/* read all, failed, already did sync or don't want to retry */
goto done;
}
Expand Down Expand Up @@ -977,6 +987,8 @@ int io_read_mshot(struct io_kiocb *req, unsigned int issue_flags)
if (!io_file_can_poll(req))
return -EBADFD;

/* make it sync, multishot doesn't support async execution */
rw->kiocb.ki_complete = NULL;
ret = __io_read(req, issue_flags);

/*
Expand Down

0 comments on commit f679ebf

Please sign in to comment.