@@ -81,6 +81,27 @@ int __io_napi_add_id(struct io_ring_ctx *ctx, unsigned int napi_id)
81
81
return 0 ;
82
82
}
83
83
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
+
84
105
static void __io_napi_remove_stale (struct io_ring_ctx * ctx )
85
106
{
86
107
struct io_napi_entry * e ;
@@ -136,9 +157,25 @@ static bool io_napi_busy_loop_should_end(void *data,
136
157
return false;
137
158
}
138
159
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 )
142
179
{
143
180
struct io_napi_entry * e ;
144
181
bool is_stale = false;
@@ -154,6 +191,16 @@ static bool __io_napi_do_busy_loop(struct io_ring_ctx *ctx,
154
191
return is_stale ;
155
192
}
156
193
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
+
157
204
static void io_napi_blocking_busy_loop (struct io_ring_ctx * ctx ,
158
205
struct io_wait_queue * iowq )
159
206
{
@@ -195,6 +242,7 @@ void io_napi_init(struct io_ring_ctx *ctx)
195
242
spin_lock_init (& ctx -> napi_lock );
196
243
ctx -> napi_prefer_busy_poll = false;
197
244
ctx -> napi_busy_poll_dt = ns_to_ktime (sys_dt );
245
+ ctx -> napi_track_mode = IO_URING_NAPI_TRACKING_INACTIVE ;
198
246
}
199
247
200
248
/*
@@ -215,6 +263,24 @@ void io_napi_free(struct io_ring_ctx *ctx)
215
263
INIT_LIST_HEAD_RCU (& ctx -> napi_list );
216
264
}
217
265
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
+
218
284
/*
219
285
* io_napi_register() - Register napi with io-uring
220
286
* @ctx: pointer to io-uring context structure
@@ -226,24 +292,35 @@ int io_register_napi(struct io_ring_ctx *ctx, void __user *arg)
226
292
{
227
293
const struct io_uring_napi curr = {
228
294
.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
230
297
};
231
298
struct io_uring_napi napi ;
232
299
233
300
if (ctx -> flags & IORING_SETUP_IOPOLL )
234
301
return - EINVAL ;
235
302
if (copy_from_user (& napi , arg , sizeof (napi )))
236
303
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 )
238
305
return - EINVAL ;
239
306
240
307
if (copy_to_user (arg , & curr , sizeof (curr )))
241
308
return - EFAULT ;
242
309
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
+ }
247
324
}
248
325
249
326
/*
@@ -266,7 +343,7 @@ int io_unregister_napi(struct io_ring_ctx *ctx, void __user *arg)
266
343
267
344
WRITE_ONCE (ctx -> napi_busy_poll_dt , 0 );
268
345
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 );
270
347
return 0 ;
271
348
}
272
349
0 commit comments