Skip to content

Commit bb17534

Browse files
isilenceaxboe
authored andcommitted
io_uring: fix racy req->flags modification
Setting and clearing REQ_F_OVERFLOW in io_uring_cancel_files() and io_cqring_overflow_flush() are racy, because they might be called asynchronously. REQ_F_OVERFLOW flag in only needed for files cancellation, so if it can be guaranteed that requests _currently_ marked inflight can't be overflown, the problem will be solved with removing the flag altogether. That's how the patch works, it removes inflight status of a request in io_cqring_fill_event() whenever it should be thrown into CQ-overflow list. That's Ok to do, because no opcode specific handling can be done after io_cqring_fill_event(), the same assumption as with "struct io_completion" patches. And it already have a good place for such cleanups, which is io_clean_op(). A nice side effect of this is removing this inflight check from the hot path. note on synchronisation: now __io_cqring_fill_event() may be taking two spinlocks simultaneously, completion_lock and inflight_lock. It's fine, because we never do that in reverse order, and CQ-overflow of inflight requests shouldn't happen often. Signed-off-by: Pavel Begunkov <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
1 parent fc66677 commit bb17534

File tree

1 file changed

+17
-44
lines changed

1 file changed

+17
-44
lines changed

fs/io_uring.c

Lines changed: 17 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -540,7 +540,6 @@ enum {
540540
REQ_F_ISREG_BIT,
541541
REQ_F_COMP_LOCKED_BIT,
542542
REQ_F_NEED_CLEANUP_BIT,
543-
REQ_F_OVERFLOW_BIT,
544543
REQ_F_POLLED_BIT,
545544
REQ_F_BUFFER_SELECTED_BIT,
546545
REQ_F_NO_FILE_TABLE_BIT,
@@ -583,8 +582,6 @@ enum {
583582
REQ_F_COMP_LOCKED = BIT(REQ_F_COMP_LOCKED_BIT),
584583
/* needs cleanup */
585584
REQ_F_NEED_CLEANUP = BIT(REQ_F_NEED_CLEANUP_BIT),
586-
/* in overflow list */
587-
REQ_F_OVERFLOW = BIT(REQ_F_OVERFLOW_BIT),
588585
/* already went through poll handler */
589586
REQ_F_POLLED = BIT(REQ_F_POLLED_BIT),
590587
/* buffer already selected */
@@ -946,7 +943,8 @@ static void io_get_req_task(struct io_kiocb *req)
946943

947944
static inline void io_clean_op(struct io_kiocb *req)
948945
{
949-
if (req->flags & (REQ_F_NEED_CLEANUP | REQ_F_BUFFER_SELECTED))
946+
if (req->flags & (REQ_F_NEED_CLEANUP | REQ_F_BUFFER_SELECTED |
947+
REQ_F_INFLIGHT))
950948
__io_clean_op(req);
951949
}
952950

@@ -1366,7 +1364,6 @@ static bool io_cqring_overflow_flush(struct io_ring_ctx *ctx, bool force)
13661364
req = list_first_entry(&ctx->cq_overflow_list, struct io_kiocb,
13671365
compl.list);
13681366
list_move(&req->compl.list, &list);
1369-
req->flags &= ~REQ_F_OVERFLOW;
13701367
if (cqe) {
13711368
WRITE_ONCE(cqe->user_data, req->user_data);
13721369
WRITE_ONCE(cqe->res, req->result);
@@ -1419,7 +1416,6 @@ static void __io_cqring_fill_event(struct io_kiocb *req, long res, long cflags)
14191416
ctx->rings->sq_flags |= IORING_SQ_CQ_OVERFLOW;
14201417
}
14211418
io_clean_op(req);
1422-
req->flags |= REQ_F_OVERFLOW;
14231419
req->result = res;
14241420
req->compl.cflags = cflags;
14251421
refcount_inc(&req->refs);
@@ -1563,17 +1559,6 @@ static bool io_dismantle_req(struct io_kiocb *req)
15631559
if (req->file)
15641560
io_put_file(req, req->file, (req->flags & REQ_F_FIXED_FILE));
15651561

1566-
if (req->flags & REQ_F_INFLIGHT) {
1567-
struct io_ring_ctx *ctx = req->ctx;
1568-
unsigned long flags;
1569-
1570-
spin_lock_irqsave(&ctx->inflight_lock, flags);
1571-
list_del(&req->inflight_entry);
1572-
if (waitqueue_active(&ctx->inflight_wait))
1573-
wake_up(&ctx->inflight_wait);
1574-
spin_unlock_irqrestore(&ctx->inflight_lock, flags);
1575-
}
1576-
15771562
return io_req_clean_work(req);
15781563
}
15791564

@@ -5634,6 +5619,18 @@ static void __io_clean_op(struct io_kiocb *req)
56345619
}
56355620
req->flags &= ~REQ_F_NEED_CLEANUP;
56365621
}
5622+
5623+
if (req->flags & REQ_F_INFLIGHT) {
5624+
struct io_ring_ctx *ctx = req->ctx;
5625+
unsigned long flags;
5626+
5627+
spin_lock_irqsave(&ctx->inflight_lock, flags);
5628+
list_del(&req->inflight_entry);
5629+
if (waitqueue_active(&ctx->inflight_wait))
5630+
wake_up(&ctx->inflight_wait);
5631+
spin_unlock_irqrestore(&ctx->inflight_lock, flags);
5632+
req->flags &= ~REQ_F_INFLIGHT;
5633+
}
56375634
}
56385635

56395636
static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
@@ -8108,33 +8105,9 @@ static void io_uring_cancel_files(struct io_ring_ctx *ctx,
81088105
/* We need to keep going until we don't find a matching req */
81098106
if (!cancel_req)
81108107
break;
8111-
8112-
if (cancel_req->flags & REQ_F_OVERFLOW) {
8113-
spin_lock_irq(&ctx->completion_lock);
8114-
list_del(&cancel_req->compl.list);
8115-
cancel_req->flags &= ~REQ_F_OVERFLOW;
8116-
8117-
io_cqring_mark_overflow(ctx);
8118-
WRITE_ONCE(ctx->rings->cq_overflow,
8119-
atomic_inc_return(&ctx->cached_cq_overflow));
8120-
io_commit_cqring(ctx);
8121-
spin_unlock_irq(&ctx->completion_lock);
8122-
8123-
/*
8124-
* Put inflight ref and overflow ref. If that's
8125-
* all we had, then we're done with this request.
8126-
*/
8127-
if (refcount_sub_and_test(2, &cancel_req->refs)) {
8128-
io_free_req(cancel_req);
8129-
finish_wait(&ctx->inflight_wait, &wait);
8130-
continue;
8131-
}
8132-
} else {
8133-
/* cancel this request, or head link requests */
8134-
io_attempt_cancel(ctx, cancel_req);
8135-
io_put_req(cancel_req);
8136-
}
8137-
8108+
/* cancel this request, or head link requests */
8109+
io_attempt_cancel(ctx, cancel_req);
8110+
io_put_req(cancel_req);
81388111
schedule();
81398112
finish_wait(&ctx->inflight_wait, &wait);
81408113
}

0 commit comments

Comments
 (0)