linux/io_uring/napi.h
Yufan Chen b8c2e9e276 io_uring/napi: clear tracked NAPI entries on unregister
IORING_UNREGISTER_NAPI disables NAPI busy polling, but it currently
leaves any previously tracked NAPI IDs on the ring context. The normal
wait path only checks whether the list is empty before entering the busy
poll helper, so an unregistered ring can still observe stale entries and
run an unexpected busy poll pass.

Make unregister switch the context to inactive and free the tracked
entries. Do the same inactive transition while changing the tracking
strategy, and recheck the expected tracking mode under napi_lock before
inserting a newly learned NAPI ID. This prevents a racing poll path from
repopulating the list after unregister or reconfiguration.

Also make the busy poll dispatcher ignore inactive mode explicitly.

Signed-off-by: Yufan Chen <ericterminal@gmail.com>
Fixes: 6bf90bd8c5 ("io_uring/napi: add static napi tracking strategy")
Link: https://patch.msgid.link/20260503175610.35521-1-yufan.chen@linux.dev
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2026-05-03 23:21:23 -06:00

91 lines
2.1 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
#ifndef IOU_NAPI_H
#define IOU_NAPI_H
#include <linux/kernel.h>
#include <linux/io_uring.h>
#include <net/busy_poll.h>
#ifdef CONFIG_NET_RX_BUSY_POLL
void io_napi_init(struct io_ring_ctx *ctx);
void io_napi_free(struct io_ring_ctx *ctx);
int io_register_napi(struct io_ring_ctx *ctx, void __user *arg);
int io_unregister_napi(struct io_ring_ctx *ctx, void __user *arg);
int __io_napi_add_id(struct io_ring_ctx *ctx, unsigned int napi_id,
unsigned int mode);
void __io_napi_busy_loop(struct io_ring_ctx *ctx, struct io_wait_queue *iowq);
int io_napi_sqpoll_busy_poll(struct io_ring_ctx *ctx);
static inline bool io_napi(struct io_ring_ctx *ctx)
{
return !list_empty(&ctx->napi_list);
}
static inline void io_napi_busy_loop(struct io_ring_ctx *ctx,
struct io_wait_queue *iowq)
{
if (!io_napi(ctx))
return;
__io_napi_busy_loop(ctx, iowq);
}
/*
* io_napi_add() - Add napi id to the busy poll list
* @req: pointer to io_kiocb request
*
* Add the napi id of the socket to the napi busy poll list and hash table.
*/
static inline void io_napi_add(struct io_kiocb *req)
{
struct io_ring_ctx *ctx = req->ctx;
struct socket *sock;
unsigned int mode = IO_URING_NAPI_TRACKING_DYNAMIC;
if (READ_ONCE(ctx->napi_track_mode) != mode)
return;
sock = sock_from_file(req->file);
if (sock && sock->sk)
__io_napi_add_id(ctx, READ_ONCE(sock->sk->sk_napi_id), mode);
}
#else
static inline void io_napi_init(struct io_ring_ctx *ctx)
{
}
static inline void io_napi_free(struct io_ring_ctx *ctx)
{
}
static inline int io_register_napi(struct io_ring_ctx *ctx, void __user *arg)
{
return -EOPNOTSUPP;
}
static inline int io_unregister_napi(struct io_ring_ctx *ctx, void __user *arg)
{
return -EOPNOTSUPP;
}
static inline bool io_napi(struct io_ring_ctx *ctx)
{
return false;
}
static inline void io_napi_add(struct io_kiocb *req)
{
}
static inline void io_napi_busy_loop(struct io_ring_ctx *ctx,
struct io_wait_queue *iowq)
{
}
static inline int io_napi_sqpoll_busy_poll(struct io_ring_ctx *ctx)
{
return 0;
}
#endif /* CONFIG_NET_RX_BUSY_POLL */
#endif