io_uring/napi.c

Source file repositories/reference/linux-study-clean/io_uring/napi.c

File Facts

System
Linux kernel
Corpus path
io_uring/napi.c
Extension
.c
Size
10265 bytes
Lines
412
Domain
Kernel Services
Bucket
io_uring
Inferred role
Kernel Services: implementation source
Status
source implementation candidate

Why This File Exists

Shared kernel service surface used by multiple subsystems, including helpers, cryptography, virtualization support, and async I/O infrastructure.

Dependency Surface

Detected Declarations

Annotated Snippet

struct io_napi_entry {
	unsigned int		napi_id;
	struct list_head	list;

	unsigned long		timeout;
	struct hlist_node	node;

	struct rcu_head		rcu;
};

static struct io_napi_entry *io_napi_hash_find(struct hlist_head *hash_list,
					       unsigned int napi_id)
{
	struct io_napi_entry *e;

	hlist_for_each_entry_rcu(e, hash_list, node) {
		if (e->napi_id != napi_id)
			continue;
		return e;
	}

	return NULL;
}

static inline ktime_t net_to_ktime(unsigned long t)
{
	/* napi approximating usecs, reverse busy_loop_current_time */
	return ns_to_ktime(t << 10);
}

int __io_napi_add_id(struct io_ring_ctx *ctx, unsigned int napi_id,
		     unsigned int mode)
{
	struct hlist_head *hash_list;
	struct io_napi_entry *e;

	/* Non-NAPI IDs can be rejected. */
	if (!napi_id_valid(napi_id))
		return -EINVAL;

	hash_list = &ctx->napi_ht[hash_min(napi_id, HASH_BITS(ctx->napi_ht))];

	scoped_guard(rcu) {
		e = io_napi_hash_find(hash_list, napi_id);
		if (e) {
			WRITE_ONCE(e->timeout, jiffies + NAPI_TIMEOUT);
			return -EEXIST;
		}
	}

	e = kmalloc(sizeof(*e), GFP_NOWAIT);
	if (!e)
		return -ENOMEM;

	e->napi_id = napi_id;
	e->timeout = jiffies + NAPI_TIMEOUT;

	/*
	 * guard(spinlock) is not used to manually unlock it before calling
	 * kfree()
	 */
	spin_lock(&ctx->napi_lock);
	if (unlikely(READ_ONCE(ctx->napi_track_mode) != mode)) {
		spin_unlock(&ctx->napi_lock);
		kfree(e);
		return -EINVAL;
	}
	if (unlikely(io_napi_hash_find(hash_list, napi_id))) {
		spin_unlock(&ctx->napi_lock);
		kfree(e);
		return -EEXIST;
	}

	hlist_add_tail_rcu(&e->node, hash_list);
	list_add_tail_rcu(&e->list, &ctx->napi_list);
	spin_unlock(&ctx->napi_lock);
	return 0;
}

static int __io_napi_del_id(struct io_ring_ctx *ctx, unsigned int napi_id)
{
	struct hlist_head *hash_list;
	struct io_napi_entry *e;

	/* Non-NAPI IDs can be rejected. */
	if (!napi_id_valid(napi_id))
		return -EINVAL;

	hash_list = &ctx->napi_ht[hash_min(napi_id, HASH_BITS(ctx->napi_ht))];
	guard(spinlock)(&ctx->napi_lock);

Annotation

Implementation Notes