On 4/26/23 8:56?PM, Ammar Faizi wrote: > On Tue, Apr 25, 2023 at 11:18:42AM -0700, Stefan Roesch wrote: >> +void __io_napi_add(struct io_ring_ctx *ctx, struct file *file) >> +{ >> + unsigned int napi_id; >> + struct socket *sock; >> + struct sock *sk; >> + struct io_napi_ht_entry *he; >> + >> + sock = sock_from_file(file); >> + if (!sock) >> + return; >> + >> + sk = sock->sk; >> + if (!sk) >> + return; >> + >> + napi_id = READ_ONCE(sk->sk_napi_id); >> + >> + /* Non-NAPI IDs can be rejected. */ >> + if (napi_id < MIN_NAPI_ID) >> + return; >> + >> + spin_lock(&ctx->napi_lock); >> + hash_for_each_possible(ctx->napi_ht, he, node, napi_id) { >> + if (he->napi_id == napi_id) { >> + he->timeout = jiffies + NAPI_TIMEOUT; >> + goto out; >> + } >> + } >> + >> + he = kmalloc(sizeof(*he), GFP_NOWAIT); >> + if (!he) >> + goto out; >> + >> + he->napi_id = napi_id; >> + he->timeout = jiffies + NAPI_TIMEOUT; >> + hash_add(ctx->napi_ht, &he->node, napi_id); >> + >> + list_add_tail(&he->list, &ctx->napi_list); >> + >> +out: >> + spin_unlock(&ctx->napi_lock); >> +} > > What about using GFP_KERNEL to allocate 'he' outside the spin lock, then > kfree() it in the (he->napi_id == napi_id) path after unlock? We actually discussed this in previous versions of this, it kind of optimizes for the wrong thing. Only the first trip through here should allocate a 'he' unit, the rest will find it on the hash. That means that now the common case will alloc+free an extra one, pointlessly. > That would make the critical section shorter. Also, GFP_NOWAIT is likely > to fail under memory pressure. If a ~48 byte allocation fails, then I suspect we have more serious issues at hand rather than ignoring NAPI for this socket! -- Jens Axboe