mirror of
https://github.com/torvalds/linux.git
synced 2025-11-30 23:16:01 +07:00
io_uring: fix buffer auto-commit for multishot uring_cmd
Commit620a50c927("io_uring: uring_cmd: add multishot support") added multishot uring_cmd support with explicit buffer upfront commit via io_uring_mshot_cmd_post_cqe(). However, the buffer selection path in io_ring_buffer_select() was auto-committing buffers for non-pollable files, which conflicts with uring_cmd's explicit upfront commit model. This way consumes the whole selected buffer immediately, and causes failure on the following buffer selection. Fix this by checking uring_cmd to identify operations that handle buffer commit explicitly, and skip auto-commit for these operations. Cc: Caleb Sander Mateos <csander@purestorage.com> Fixes:620a50c927("io_uring: uring_cmd: add multishot support") Signed-off-by: Ming Lei <ming.lei@redhat.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
@@ -155,6 +155,27 @@ static int io_provided_buffers_select(struct io_kiocb *req, size_t *len,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool io_should_commit(struct io_kiocb *req, unsigned int issue_flags)
|
||||
{
|
||||
/*
|
||||
* If we came in unlocked, we have no choice but to consume the
|
||||
* buffer here, otherwise nothing ensures that the buffer won't
|
||||
* get used by others. This does mean it'll be pinned until the
|
||||
* IO completes, coming in unlocked means we're being called from
|
||||
* io-wq context and there may be further retries in async hybrid
|
||||
* mode. For the locked case, the caller must call commit when
|
||||
* the transfer completes (or if we get -EAGAIN and must poll of
|
||||
* retry).
|
||||
*/
|
||||
if (issue_flags & IO_URING_F_UNLOCKED)
|
||||
return true;
|
||||
|
||||
/* uring_cmd commits kbuf upfront, no need to auto-commit */
|
||||
if (!io_file_can_poll(req) && req->opcode != IORING_OP_URING_CMD)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct io_br_sel io_ring_buffer_select(struct io_kiocb *req, size_t *len,
|
||||
struct io_buffer_list *bl,
|
||||
unsigned int issue_flags)
|
||||
@@ -181,17 +202,7 @@ static struct io_br_sel io_ring_buffer_select(struct io_kiocb *req, size_t *len,
|
||||
sel.buf_list = bl;
|
||||
sel.addr = u64_to_user_ptr(buf->addr);
|
||||
|
||||
if (issue_flags & IO_URING_F_UNLOCKED || !io_file_can_poll(req)) {
|
||||
/*
|
||||
* If we came in unlocked, we have no choice but to consume the
|
||||
* buffer here, otherwise nothing ensures that the buffer won't
|
||||
* get used by others. This does mean it'll be pinned until the
|
||||
* IO completes, coming in unlocked means we're being called from
|
||||
* io-wq context and there may be further retries in async hybrid
|
||||
* mode. For the locked case, the caller must call commit when
|
||||
* the transfer completes (or if we get -EAGAIN and must poll of
|
||||
* retry).
|
||||
*/
|
||||
if (io_should_commit(req, issue_flags)) {
|
||||
io_kbuf_commit(req, sel.buf_list, *len, 1);
|
||||
sel.buf_list = NULL;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user