Skip to content

Commit 1ffc542

Browse files
isilenceaxboe
authored andcommitted
io_uring: fix io_sqe_files_unregister() hangs
io_sqe_files_unregister() uninterruptibly waits for enqueued ref nodes, however requests keeping them may never complete, e.g. because of some userspace dependency. Make sure it's interruptible otherwise it would hang forever. Cc: [email protected] # 5.6+ Signed-off-by: Pavel Begunkov <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
1 parent 1642b44 commit 1ffc542

File tree

1 file changed

+22
-2
lines changed

1 file changed

+22
-2
lines changed

fs/io_uring.c

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,10 @@ enum io_mem_account {
992992
ACCT_PINNED,
993993
};
994994

995+
static void destroy_fixed_file_ref_node(struct fixed_file_ref_node *ref_node);
996+
static struct fixed_file_ref_node *alloc_fixed_file_ref_node(
997+
struct io_ring_ctx *ctx);
998+
995999
static void __io_complete_rw(struct io_kiocb *req, long res, long res2,
9961000
struct io_comp_state *cs);
9971001
static void io_cqring_fill_event(struct io_kiocb *req, long res);
@@ -7244,11 +7248,15 @@ static void io_sqe_files_set_node(struct fixed_file_data *file_data,
72447248
static int io_sqe_files_unregister(struct io_ring_ctx *ctx)
72457249
{
72467250
struct fixed_file_data *data = ctx->file_data;
7247-
struct fixed_file_ref_node *ref_node = NULL;
7251+
struct fixed_file_ref_node *backup_node, *ref_node = NULL;
72487252
unsigned nr_tables, i;
7253+
int ret;
72497254

72507255
if (!data)
72517256
return -ENXIO;
7257+
backup_node = alloc_fixed_file_ref_node(ctx);
7258+
if (!backup_node)
7259+
return -ENOMEM;
72527260

72537261
spin_lock_bh(&data->lock);
72547262
ref_node = data->node;
@@ -7260,7 +7268,18 @@ static int io_sqe_files_unregister(struct io_ring_ctx *ctx)
72607268

72617269
/* wait for all refs nodes to complete */
72627270
flush_delayed_work(&ctx->file_put_work);
7263-
wait_for_completion(&data->done);
7271+
do {
7272+
ret = wait_for_completion_interruptible(&data->done);
7273+
if (!ret)
7274+
break;
7275+
ret = io_run_task_work_sig();
7276+
if (ret < 0) {
7277+
percpu_ref_resurrect(&data->refs);
7278+
reinit_completion(&data->done);
7279+
io_sqe_files_set_node(data, backup_node);
7280+
return ret;
7281+
}
7282+
} while (1);
72647283

72657284
__io_sqe_files_unregister(ctx);
72667285
nr_tables = DIV_ROUND_UP(ctx->nr_user_files, IORING_MAX_FILES_TABLE);
@@ -7271,6 +7290,7 @@ static int io_sqe_files_unregister(struct io_ring_ctx *ctx)
72717290
kfree(data);
72727291
ctx->file_data = NULL;
72737292
ctx->nr_user_files = 0;
7293+
destroy_fixed_file_ref_node(backup_node);
72747294
return 0;
72757295
}
72767296

0 commit comments

Comments
 (0)