@@ -81,6 +81,27 @@ int __io_napi_add_id(struct io_ring_ctx *ctx, unsigned int napi_id)
8181 return 0 ;
8282}
8383
84+ static int __io_napi_del_id (struct io_ring_ctx * ctx , unsigned int napi_id )
85+ {
86+ struct hlist_head * hash_list ;
87+ struct io_napi_entry * e ;
88+
89+ /* Non-NAPI IDs can be rejected. */
90+ if (napi_id < MIN_NAPI_ID )
91+ return - EINVAL ;
92+
93+ hash_list = & ctx -> napi_ht [hash_min (napi_id , HASH_BITS (ctx -> napi_ht ))];
94+ guard (spinlock )(& ctx -> napi_lock );
95+ e = io_napi_hash_find (hash_list , napi_id );
96+ if (!e )
97+ return - ENOENT ;
98+
99+ list_del_rcu (& e -> list );
100+ hash_del_rcu (& e -> node );
101+ kfree_rcu (e , rcu );
102+ return 0 ;
103+ }
104+
84105static void __io_napi_remove_stale (struct io_ring_ctx * ctx )
85106{
86107 struct io_napi_entry * e ;
@@ -136,9 +157,25 @@ static bool io_napi_busy_loop_should_end(void *data,
136157 return false;
137158}
138159
139- static bool __io_napi_do_busy_loop (struct io_ring_ctx * ctx ,
140- bool (* loop_end )(void * , unsigned long ),
141- void * loop_end_arg )
160+ /*
161+ * never report stale entries
162+ */
163+ static bool static_tracking_do_busy_loop (struct io_ring_ctx * ctx ,
164+ bool (* loop_end )(void * , unsigned long ),
165+ void * loop_end_arg )
166+ {
167+ struct io_napi_entry * e ;
168+
169+ list_for_each_entry_rcu (e , & ctx -> napi_list , list )
170+ napi_busy_loop_rcu (e -> napi_id , loop_end , loop_end_arg ,
171+ ctx -> napi_prefer_busy_poll , BUSY_POLL_BUDGET );
172+ return false;
173+ }
174+
175+ static bool
176+ dynamic_tracking_do_busy_loop (struct io_ring_ctx * ctx ,
177+ bool (* loop_end )(void * , unsigned long ),
178+ void * loop_end_arg )
142179{
143180 struct io_napi_entry * e ;
144181 bool is_stale = false;
@@ -154,6 +191,16 @@ static bool __io_napi_do_busy_loop(struct io_ring_ctx *ctx,
154191 return is_stale ;
155192}
156193
194+ static inline bool
195+ __io_napi_do_busy_loop (struct io_ring_ctx * ctx ,
196+ bool (* loop_end )(void * , unsigned long ),
197+ void * loop_end_arg )
198+ {
199+ if (READ_ONCE (ctx -> napi_track_mode ) == IO_URING_NAPI_TRACKING_STATIC )
200+ return static_tracking_do_busy_loop (ctx , loop_end , loop_end_arg );
201+ return dynamic_tracking_do_busy_loop (ctx , loop_end , loop_end_arg );
202+ }
203+
157204static void io_napi_blocking_busy_loop (struct io_ring_ctx * ctx ,
158205 struct io_wait_queue * iowq )
159206{
@@ -195,6 +242,7 @@ void io_napi_init(struct io_ring_ctx *ctx)
195242 spin_lock_init (& ctx -> napi_lock );
196243 ctx -> napi_prefer_busy_poll = false;
197244 ctx -> napi_busy_poll_dt = ns_to_ktime (sys_dt );
245+ ctx -> napi_track_mode = IO_URING_NAPI_TRACKING_INACTIVE ;
198246}
199247
200248/*
@@ -215,6 +263,24 @@ void io_napi_free(struct io_ring_ctx *ctx)
215263 INIT_LIST_HEAD_RCU (& ctx -> napi_list );
216264}
217265
266+ static int io_napi_register_napi (struct io_ring_ctx * ctx ,
267+ struct io_uring_napi * napi )
268+ {
269+ switch (napi -> op_param ) {
270+ case IO_URING_NAPI_TRACKING_DYNAMIC :
271+ case IO_URING_NAPI_TRACKING_STATIC :
272+ break ;
273+ default :
274+ return - EINVAL ;
275+ }
276+ /* clean the napi list for new settings */
277+ io_napi_free (ctx );
278+ WRITE_ONCE (ctx -> napi_track_mode , napi -> op_param );
279+ WRITE_ONCE (ctx -> napi_busy_poll_dt , napi -> busy_poll_to * NSEC_PER_USEC );
280+ WRITE_ONCE (ctx -> napi_prefer_busy_poll , !!napi -> prefer_busy_poll );
281+ return 0 ;
282+ }
283+
218284/*
219285 * io_napi_register() - Register napi with io-uring
220286 * @ctx: pointer to io-uring context structure
@@ -226,24 +292,35 @@ int io_register_napi(struct io_ring_ctx *ctx, void __user *arg)
226292{
227293 const struct io_uring_napi curr = {
228294 .busy_poll_to = ktime_to_us (ctx -> napi_busy_poll_dt ),
229- .prefer_busy_poll = ctx -> napi_prefer_busy_poll
295+ .prefer_busy_poll = ctx -> napi_prefer_busy_poll ,
296+ .op_param = ctx -> napi_track_mode
230297 };
231298 struct io_uring_napi napi ;
232299
233300 if (ctx -> flags & IORING_SETUP_IOPOLL )
234301 return - EINVAL ;
235302 if (copy_from_user (& napi , arg , sizeof (napi )))
236303 return - EFAULT ;
237- if (napi .pad [0 ] || napi .pad [1 ] || napi .pad [ 2 ] || napi . resv )
304+ if (napi .pad [0 ] || napi .pad [1 ] || napi .resv )
238305 return - EINVAL ;
239306
240307 if (copy_to_user (arg , & curr , sizeof (curr )))
241308 return - EFAULT ;
242309
243- WRITE_ONCE (ctx -> napi_busy_poll_dt , napi .busy_poll_to * NSEC_PER_USEC );
244- WRITE_ONCE (ctx -> napi_prefer_busy_poll , !!napi .prefer_busy_poll );
245- WRITE_ONCE (ctx -> napi_enabled , true);
246- return 0 ;
310+ switch (napi .opcode ) {
311+ case IO_URING_NAPI_REGISTER_OP :
312+ return io_napi_register_napi (ctx , & napi );
313+ case IO_URING_NAPI_STATIC_ADD_ID :
314+ if (curr .op_param != IO_URING_NAPI_TRACKING_STATIC )
315+ return - EINVAL ;
316+ return __io_napi_add_id (ctx , napi .op_param );
317+ case IO_URING_NAPI_STATIC_DEL_ID :
318+ if (curr .op_param != IO_URING_NAPI_TRACKING_STATIC )
319+ return - EINVAL ;
320+ return __io_napi_del_id (ctx , napi .op_param );
321+ default :
322+ return - EINVAL ;
323+ }
247324}
248325
249326/*
@@ -266,7 +343,7 @@ int io_unregister_napi(struct io_ring_ctx *ctx, void __user *arg)
266343
267344 WRITE_ONCE (ctx -> napi_busy_poll_dt , 0 );
268345 WRITE_ONCE (ctx -> napi_prefer_busy_poll , false);
269- WRITE_ONCE (ctx -> napi_enabled , false );
346+ WRITE_ONCE (ctx -> napi_track_mode , IO_URING_NAPI_TRACKING_INACTIVE );
270347 return 0 ;
271348}
272349
0 commit comments