Skip to content

Commit

Permalink
io_uring/rsrc: use non-pcpu refcounts for nodes
Browse files Browse the repository at this point in the history
One problem with the current rsrc infra is that often updates will
generates lots of rsrc nodes, each carry pcpu refs. That takes quite a
lot of memory, especially if there is a stall, and takes lots of CPU
cycles. Only pcpu allocations takes >50 of CPU with a naive benchmark
updating files in a loop.

Replace pcpu refs with normal refcounting. There is already a hot path
avoiding atomics / refs, but following patches will further improve it.

Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
Link: https://lore.kernel.org/r/e9ed8a9457b331a26555ff9443afc64cdaab7247.1680576071.git.asml.silence@gmail.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
  • Loading branch information
isilence authored and axboe committed Apr 4, 2023
1 parent e3ef728 commit b8fb5b4
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 12 deletions.
15 changes: 5 additions & 10 deletions io_uring/rsrc.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ void io_rsrc_refs_refill(struct io_ring_ctx *ctx)
__must_hold(&ctx->uring_lock)
{
ctx->rsrc_cached_refs += IO_RSRC_REF_BATCH;
percpu_ref_get_many(&ctx->rsrc_node->refs, IO_RSRC_REF_BATCH);
refcount_add(IO_RSRC_REF_BATCH, &ctx->rsrc_node->refs);
}

static void __io_rsrc_put_work(struct io_rsrc_node *ref_node)
Expand Down Expand Up @@ -220,13 +220,11 @@ void io_wait_rsrc_data(struct io_rsrc_data *data)

void io_rsrc_node_destroy(struct io_rsrc_node *ref_node)
{
percpu_ref_exit(&ref_node->refs);
kfree(ref_node);
}

static __cold void io_rsrc_node_ref_zero(struct percpu_ref *ref)
__cold void io_rsrc_node_ref_zero(struct io_rsrc_node *node)
{
struct io_rsrc_node *node = container_of(ref, struct io_rsrc_node, refs);
struct io_ring_ctx *ctx = node->rsrc_data->ctx;
unsigned long flags;
bool first_add = false;
Expand Down Expand Up @@ -269,11 +267,7 @@ static struct io_rsrc_node *io_rsrc_node_alloc(void)
if (!ref_node)
return NULL;

if (percpu_ref_init(&ref_node->refs, io_rsrc_node_ref_zero,
0, GFP_KERNEL)) {
kfree(ref_node);
return NULL;
}
refcount_set(&ref_node->refs, 1);
INIT_LIST_HEAD(&ref_node->node);
INIT_LIST_HEAD(&ref_node->rsrc_list);
ref_node->done = false;
Expand All @@ -298,7 +292,8 @@ void io_rsrc_node_switch(struct io_ring_ctx *ctx,
spin_unlock_irq(&ctx->rsrc_ref_lock);

atomic_inc(&data_to_kill->refs);
percpu_ref_kill(&rsrc_node->refs);
/* put master ref */
io_rsrc_put_node(rsrc_node, 1);
ctx->rsrc_node = NULL;
}

Expand Down
6 changes: 4 additions & 2 deletions io_uring/rsrc.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ struct io_rsrc_data {
};

struct io_rsrc_node {
struct percpu_ref refs;
refcount_t refs;
struct list_head node;
struct list_head rsrc_list;
struct io_rsrc_data *rsrc_data;
Expand All @@ -54,6 +54,7 @@ struct io_mapped_ubuf {
};

void io_rsrc_put_tw(struct callback_head *cb);
void io_rsrc_node_ref_zero(struct io_rsrc_node *node);
void io_rsrc_put_work(struct work_struct *work);
void io_rsrc_refs_refill(struct io_ring_ctx *ctx);
void io_wait_rsrc_data(struct io_rsrc_data *data);
Expand Down Expand Up @@ -109,7 +110,8 @@ int io_register_rsrc(struct io_ring_ctx *ctx, void __user *arg,

static inline void io_rsrc_put_node(struct io_rsrc_node *node, int nr)
{
percpu_ref_put_many(&node->refs, nr);
if (refcount_sub_and_test(nr, &node->refs))
io_rsrc_node_ref_zero(node);
}

static inline void io_req_put_rsrc(struct io_kiocb *req)
Expand Down

0 comments on commit b8fb5b4

Please sign in to comment.