mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 20:22:09 +00:00
io_uring: fix put_kbuf without proper locking
io_put_kbuf_comp() should only be called while holding
->completion_lock, however there is no such assumption in io_clean_op()
and thus it can corrupt ->io_buffer_comp. Take the lock there, and
workaround the only user of io_clean_op() calling it with locks. Not
the prettiest solution, but it's easier to refactor it for-next.
Fixes: cc3cec8367
("io_uring: speedup provided buffer handling")
Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
Link: https://lore.kernel.org/r/743e2130b73ec6d48c4c5dd15db896c433431e6d.1648212967.git.asml.silence@gmail.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
parent
ab0ac0959b
commit
8197b053a8
@ -1338,6 +1338,8 @@ static unsigned int __io_put_kbuf(struct io_kiocb *req, struct list_head *list)
|
|||||||
|
|
||||||
static inline unsigned int io_put_kbuf_comp(struct io_kiocb *req)
|
static inline unsigned int io_put_kbuf_comp(struct io_kiocb *req)
|
||||||
{
|
{
|
||||||
|
lockdep_assert_held(&req->ctx->completion_lock);
|
||||||
|
|
||||||
if (likely(!(req->flags & REQ_F_BUFFER_SELECTED)))
|
if (likely(!(req->flags & REQ_F_BUFFER_SELECTED)))
|
||||||
return 0;
|
return 0;
|
||||||
return __io_put_kbuf(req, &req->ctx->io_buffers_comp);
|
return __io_put_kbuf(req, &req->ctx->io_buffers_comp);
|
||||||
@ -2123,6 +2125,12 @@ static void __io_req_complete_post(struct io_kiocb *req, s32 res,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
io_req_put_rsrc(req, ctx);
|
io_req_put_rsrc(req, ctx);
|
||||||
|
/*
|
||||||
|
* Selected buffer deallocation in io_clean_op() assumes that
|
||||||
|
* we don't hold ->completion_lock. Clean them here to avoid
|
||||||
|
* deadlocks.
|
||||||
|
*/
|
||||||
|
io_put_kbuf_comp(req);
|
||||||
io_dismantle_req(req);
|
io_dismantle_req(req);
|
||||||
io_put_task(req->task, 1);
|
io_put_task(req->task, 1);
|
||||||
wq_list_add_head(&req->comp_list, &ctx->locked_free_list);
|
wq_list_add_head(&req->comp_list, &ctx->locked_free_list);
|
||||||
@ -7126,8 +7134,11 @@ fail:
|
|||||||
|
|
||||||
static void io_clean_op(struct io_kiocb *req)
|
static void io_clean_op(struct io_kiocb *req)
|
||||||
{
|
{
|
||||||
if (req->flags & REQ_F_BUFFER_SELECTED)
|
if (req->flags & REQ_F_BUFFER_SELECTED) {
|
||||||
|
spin_lock(&req->ctx->completion_lock);
|
||||||
io_put_kbuf_comp(req);
|
io_put_kbuf_comp(req);
|
||||||
|
spin_unlock(&req->ctx->completion_lock);
|
||||||
|
}
|
||||||
|
|
||||||
if (req->flags & REQ_F_NEED_CLEANUP) {
|
if (req->flags & REQ_F_NEED_CLEANUP) {
|
||||||
switch (req->opcode) {
|
switch (req->opcode) {
|
||||||
|
Loading…
Reference in New Issue
Block a user