Skip to content

Commit 2ca1025

Browse files
committed
io_uring: prune request from overflow list on flush
Carter reported an issue where he could produce a stall on ring exit, when we're cleaning up requests that match the given file table. For this particular test case, a combination of a few things caused the issue: - The cq ring was overflown - The request being canceled was in the overflow list The combination of the above means that the cq overflow list holds a reference to the request. The request is canceled correctly, but since the overflow list holds a reference to it, the final put won't happen. Since the final put doesn't happen, the request remains in the inflight. Hence we never finish the cancelation flush. Fix this by removing requests from the overflow list if we're canceling them. Cc: [email protected] # 5.5 Reported-by: Carter Li 李通洲 <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
1 parent 7563439 commit 2ca1025

File tree

1 file changed

+28
-0
lines changed

1 file changed

+28
-0
lines changed

fs/io_uring.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,7 @@ enum {
481481
REQ_F_TIMEOUT_NOSEQ_BIT,
482482
REQ_F_COMP_LOCKED_BIT,
483483
REQ_F_NEED_CLEANUP_BIT,
484+
REQ_F_OVERFLOW_BIT,
484485
};
485486

486487
enum {
@@ -521,6 +522,8 @@ enum {
521522
REQ_F_COMP_LOCKED = BIT(REQ_F_COMP_LOCKED_BIT),
522523
/* needs cleanup */
523524
REQ_F_NEED_CLEANUP = BIT(REQ_F_NEED_CLEANUP_BIT),
525+
/* in overflow list */
526+
REQ_F_OVERFLOW = BIT(REQ_F_OVERFLOW_BIT),
524527
};
525528

526529
/*
@@ -1103,6 +1106,7 @@ static bool io_cqring_overflow_flush(struct io_ring_ctx *ctx, bool force)
11031106
req = list_first_entry(&ctx->cq_overflow_list, struct io_kiocb,
11041107
list);
11051108
list_move(&req->list, &list);
1109+
req->flags &= ~REQ_F_OVERFLOW;
11061110
if (cqe) {
11071111
WRITE_ONCE(cqe->user_data, req->user_data);
11081112
WRITE_ONCE(cqe->res, req->result);
@@ -1155,6 +1159,7 @@ static void io_cqring_fill_event(struct io_kiocb *req, long res)
11551159
set_bit(0, &ctx->sq_check_overflow);
11561160
set_bit(0, &ctx->cq_check_overflow);
11571161
}
1162+
req->flags |= REQ_F_OVERFLOW;
11581163
refcount_inc(&req->refs);
11591164
req->result = res;
11601165
list_add_tail(&req->list, &ctx->cq_overflow_list);
@@ -6463,6 +6468,29 @@ static void io_uring_cancel_files(struct io_ring_ctx *ctx,
64636468
if (!cancel_req)
64646469
break;
64656470

6471+
if (cancel_req->flags & REQ_F_OVERFLOW) {
6472+
spin_lock_irq(&ctx->completion_lock);
6473+
list_del(&cancel_req->list);
6474+
cancel_req->flags &= ~REQ_F_OVERFLOW;
6475+
if (list_empty(&ctx->cq_overflow_list)) {
6476+
clear_bit(0, &ctx->sq_check_overflow);
6477+
clear_bit(0, &ctx->cq_check_overflow);
6478+
}
6479+
spin_unlock_irq(&ctx->completion_lock);
6480+
6481+
WRITE_ONCE(ctx->rings->cq_overflow,
6482+
atomic_inc_return(&ctx->cached_cq_overflow));
6483+
6484+
/*
6485+
* Put inflight ref and overflow ref. If that's
6486+
* all we had, then we're done with this request.
6487+
*/
6488+
if (refcount_sub_and_test(2, &cancel_req->refs)) {
6489+
io_put_req(cancel_req);
6490+
continue;
6491+
}
6492+
}
6493+
64666494
io_wq_cancel_work(ctx->io_wq, &cancel_req->work);
64676495
io_put_req(cancel_req);
64686496
schedule();

0 commit comments

Comments
 (0)