Skip to content

Commit e5361d2

Browse files
isilenceaxboe
authored andcommitted
io_uring/zcrx: return back two step unregistration
There are reports where io_uring instance removal takes too long and an ifq reallocation by another zcrx instance fails. Split zcrx destruction into two steps similarly how it was before, first close the queue early but maintain zcrx alive, and then when all inflight requests are completed, drop the main zcrx reference. For extra protection, mark terminated zcrx instances in xarray and warn if we double put them. Cc: stable@vger.kernel.org # 6.19+ Link: axboe/liburing#1550 Reported-by: Youngmin Choi <youngminchoi94@gmail.com> Signed-off-by: Pavel Begunkov <asml.silence@gmail.com> Link: https://patch.msgid.link/0ce21f0565ab4358668922a28a8a36922dfebf76.1774261953.git.asml.silence@gmail.com [axboe: NULL ifq before break inside scoped guard] Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent f41b075 commit e5361d2

3 files changed

Lines changed: 51 additions & 3 deletions

File tree

io_uring/io_uring.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2308,6 +2308,10 @@ static __cold void io_ring_exit_work(struct work_struct *work)
23082308
struct io_tctx_node *node;
23092309
int ret;
23102310

2311+
mutex_lock(&ctx->uring_lock);
2312+
io_terminate_zcrx(ctx);
2313+
mutex_unlock(&ctx->uring_lock);
2314+
23112315
/*
23122316
* If we're doing polled IO and end up having requests being
23132317
* submitted async (out-of-line), then completions can come in while

io_uring/zcrx.c

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -624,12 +624,17 @@ static void io_zcrx_scrub(struct io_zcrx_ifq *ifq)
624624
}
625625
}
626626

627-
static void zcrx_unregister(struct io_zcrx_ifq *ifq)
627+
static void zcrx_unregister_user(struct io_zcrx_ifq *ifq)
628628
{
629629
if (refcount_dec_and_test(&ifq->user_refs)) {
630630
io_close_queue(ifq);
631631
io_zcrx_scrub(ifq);
632632
}
633+
}
634+
635+
static void zcrx_unregister(struct io_zcrx_ifq *ifq)
636+
{
637+
zcrx_unregister_user(ifq);
633638
io_put_zcrx_ifq(ifq);
634639
}
635640

@@ -887,6 +892,36 @@ static struct net_iov *__io_zcrx_get_free_niov(struct io_zcrx_area *area)
887892
return &area->nia.niovs[niov_idx];
888893
}
889894

895+
static inline bool is_zcrx_entry_marked(struct io_ring_ctx *ctx, unsigned long id)
896+
{
897+
return xa_get_mark(&ctx->zcrx_ctxs, id, XA_MARK_0);
898+
}
899+
900+
static inline void set_zcrx_entry_mark(struct io_ring_ctx *ctx, unsigned long id)
901+
{
902+
xa_set_mark(&ctx->zcrx_ctxs, id, XA_MARK_0);
903+
}
904+
905+
void io_terminate_zcrx(struct io_ring_ctx *ctx)
906+
{
907+
struct io_zcrx_ifq *ifq;
908+
unsigned long id = 0;
909+
910+
lockdep_assert_held(&ctx->uring_lock);
911+
912+
while (1) {
913+
scoped_guard(mutex, &ctx->mmap_lock)
914+
ifq = xa_find(&ctx->zcrx_ctxs, &id, ULONG_MAX, XA_PRESENT);
915+
if (!ifq)
916+
break;
917+
if (WARN_ON_ONCE(is_zcrx_entry_marked(ctx, id)))
918+
break;
919+
set_zcrx_entry_mark(ctx, id);
920+
id++;
921+
zcrx_unregister_user(ifq);
922+
}
923+
}
924+
890925
void io_unregister_zcrx_ifqs(struct io_ring_ctx *ctx)
891926
{
892927
struct io_zcrx_ifq *ifq;
@@ -898,12 +933,17 @@ void io_unregister_zcrx_ifqs(struct io_ring_ctx *ctx)
898933
unsigned long id = 0;
899934

900935
ifq = xa_find(&ctx->zcrx_ctxs, &id, ULONG_MAX, XA_PRESENT);
901-
if (ifq)
936+
if (ifq) {
937+
if (WARN_ON_ONCE(!is_zcrx_entry_marked(ctx, id))) {
938+
ifq = NULL;
939+
break;
940+
}
902941
xa_erase(&ctx->zcrx_ctxs, id);
942+
}
903943
}
904944
if (!ifq)
905945
break;
906-
zcrx_unregister(ifq);
946+
io_put_zcrx_ifq(ifq);
907947
}
908948

909949
xa_destroy(&ctx->zcrx_ctxs);

io_uring/zcrx.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ int io_zcrx_ctrl(struct io_ring_ctx *ctx, void __user *arg, unsigned nr_arg);
7474
int io_register_zcrx_ifq(struct io_ring_ctx *ctx,
7575
struct io_uring_zcrx_ifq_reg __user *arg);
7676
void io_unregister_zcrx_ifqs(struct io_ring_ctx *ctx);
77+
void io_terminate_zcrx(struct io_ring_ctx *ctx);
7778
int io_zcrx_recv(struct io_kiocb *req, struct io_zcrx_ifq *ifq,
7879
struct socket *sock, unsigned int flags,
7980
unsigned issue_flags, unsigned int *len);
@@ -88,6 +89,9 @@ static inline int io_register_zcrx_ifq(struct io_ring_ctx *ctx,
8889
static inline void io_unregister_zcrx_ifqs(struct io_ring_ctx *ctx)
8990
{
9091
}
92+
static inline void io_terminate_zcrx(struct io_ring_ctx *ctx)
93+
{
94+
}
9195
static inline int io_zcrx_recv(struct io_kiocb *req, struct io_zcrx_ifq *ifq,
9296
struct socket *sock, unsigned int flags,
9397
unsigned issue_flags, unsigned int *len)

0 commit comments

Comments
 (0)