18d0c12a8SStefan Roesch // SPDX-License-Identifier: GPL-2.0 28d0c12a8SStefan Roesch 38d0c12a8SStefan Roesch #include "io_uring.h" 48d0c12a8SStefan Roesch #include "napi.h" 58d0c12a8SStefan Roesch 68d0c12a8SStefan Roesch #ifdef CONFIG_NET_RX_BUSY_POLL 78d0c12a8SStefan Roesch 88d0c12a8SStefan Roesch /* Timeout for cleanout of stale entries. */ 98d0c12a8SStefan Roesch #define NAPI_TIMEOUT (60 * SEC_CONVERSION) 108d0c12a8SStefan Roesch 118d0c12a8SStefan Roesch struct io_napi_entry { 128d0c12a8SStefan Roesch unsigned int napi_id; 138d0c12a8SStefan Roesch struct list_head list; 148d0c12a8SStefan Roesch 158d0c12a8SStefan Roesch unsigned long timeout; 168d0c12a8SStefan Roesch struct hlist_node node; 178d0c12a8SStefan Roesch 188d0c12a8SStefan Roesch struct rcu_head rcu; 198d0c12a8SStefan Roesch }; 208d0c12a8SStefan Roesch 218d0c12a8SStefan Roesch static struct io_napi_entry *io_napi_hash_find(struct hlist_head *hash_list, 228d0c12a8SStefan Roesch unsigned int napi_id) 238d0c12a8SStefan Roesch { 248d0c12a8SStefan Roesch struct io_napi_entry *e; 258d0c12a8SStefan Roesch 268d0c12a8SStefan Roesch hlist_for_each_entry_rcu(e, hash_list, node) { 278d0c12a8SStefan Roesch if (e->napi_id != napi_id) 288d0c12a8SStefan Roesch continue; 298d0c12a8SStefan Roesch return e; 308d0c12a8SStefan Roesch } 318d0c12a8SStefan Roesch 328d0c12a8SStefan Roesch return NULL; 338d0c12a8SStefan Roesch } 348d0c12a8SStefan Roesch 35342b2e39SPavel Begunkov static inline ktime_t net_to_ktime(unsigned long t) 36342b2e39SPavel Begunkov { 37342b2e39SPavel Begunkov /* napi approximating usecs, reverse busy_loop_current_time */ 38342b2e39SPavel Begunkov return ns_to_ktime(t << 10); 39342b2e39SPavel Begunkov } 40342b2e39SPavel Begunkov 41*a5e26f49SOlivier Langlois int __io_napi_add_id(struct io_ring_ctx *ctx, unsigned int napi_id) 428d0c12a8SStefan Roesch { 438d0c12a8SStefan Roesch struct hlist_head *hash_list; 448d0c12a8SStefan Roesch struct io_napi_entry *e; 458d0c12a8SStefan Roesch 468d0c12a8SStefan Roesch /* Non-NAPI IDs can be rejected. */ 478d0c12a8SStefan Roesch if (napi_id < MIN_NAPI_ID) 48*a5e26f49SOlivier Langlois return -EINVAL; 498d0c12a8SStefan Roesch 508d0c12a8SStefan Roesch hash_list = &ctx->napi_ht[hash_min(napi_id, HASH_BITS(ctx->napi_ht))]; 518d0c12a8SStefan Roesch 528d0c12a8SStefan Roesch rcu_read_lock(); 538d0c12a8SStefan Roesch e = io_napi_hash_find(hash_list, napi_id); 548d0c12a8SStefan Roesch if (e) { 552f3cc8e4SOlivier Langlois WRITE_ONCE(e->timeout, jiffies + NAPI_TIMEOUT); 568d0c12a8SStefan Roesch rcu_read_unlock(); 57*a5e26f49SOlivier Langlois return -EEXIST; 588d0c12a8SStefan Roesch } 598d0c12a8SStefan Roesch rcu_read_unlock(); 608d0c12a8SStefan Roesch 618d0c12a8SStefan Roesch e = kmalloc(sizeof(*e), GFP_NOWAIT); 628d0c12a8SStefan Roesch if (!e) 63*a5e26f49SOlivier Langlois return -ENOMEM; 648d0c12a8SStefan Roesch 658d0c12a8SStefan Roesch e->napi_id = napi_id; 668d0c12a8SStefan Roesch e->timeout = jiffies + NAPI_TIMEOUT; 678d0c12a8SStefan Roesch 688d0c12a8SStefan Roesch spin_lock(&ctx->napi_lock); 698d0c12a8SStefan Roesch if (unlikely(io_napi_hash_find(hash_list, napi_id))) { 708d0c12a8SStefan Roesch spin_unlock(&ctx->napi_lock); 718d0c12a8SStefan Roesch kfree(e); 72*a5e26f49SOlivier Langlois return -EEXIST; 738d0c12a8SStefan Roesch } 748d0c12a8SStefan Roesch 758d0c12a8SStefan Roesch hlist_add_tail_rcu(&e->node, hash_list); 7645b3941dSOlivier Langlois list_add_tail_rcu(&e->list, &ctx->napi_list); 778d0c12a8SStefan Roesch spin_unlock(&ctx->napi_lock); 78*a5e26f49SOlivier Langlois return 0; 798d0c12a8SStefan Roesch } 808d0c12a8SStefan Roesch 818d0c12a8SStefan Roesch static void __io_napi_remove_stale(struct io_ring_ctx *ctx) 828d0c12a8SStefan Roesch { 838d0c12a8SStefan Roesch struct io_napi_entry *e; 848d0c12a8SStefan Roesch 858d0c12a8SStefan Roesch spin_lock(&ctx->napi_lock); 8645b3941dSOlivier Langlois /* 8745b3941dSOlivier Langlois * list_for_each_entry_safe() is not required as long as: 8845b3941dSOlivier Langlois * 1. list_del_rcu() does not reset the deleted node next pointer 8945b3941dSOlivier Langlois * 2. kfree_rcu() delays the memory freeing until the next quiescent 9045b3941dSOlivier Langlois * state 9145b3941dSOlivier Langlois */ 9245b3941dSOlivier Langlois list_for_each_entry(e, &ctx->napi_list, list) { 932f3cc8e4SOlivier Langlois if (time_after(jiffies, READ_ONCE(e->timeout))) { 9445b3941dSOlivier Langlois list_del_rcu(&e->list); 958d0c12a8SStefan Roesch hash_del_rcu(&e->node); 968d0c12a8SStefan Roesch kfree_rcu(e, rcu); 978d0c12a8SStefan Roesch } 988d0c12a8SStefan Roesch } 998d0c12a8SStefan Roesch spin_unlock(&ctx->napi_lock); 1008d0c12a8SStefan Roesch } 1018d0c12a8SStefan Roesch 1028d0c12a8SStefan Roesch static inline void io_napi_remove_stale(struct io_ring_ctx *ctx, bool is_stale) 1038d0c12a8SStefan Roesch { 1048d0c12a8SStefan Roesch if (is_stale) 1058d0c12a8SStefan Roesch __io_napi_remove_stale(ctx); 1068d0c12a8SStefan Roesch } 1078d0c12a8SStefan Roesch 108342b2e39SPavel Begunkov static inline bool io_napi_busy_loop_timeout(ktime_t start_time, 109342b2e39SPavel Begunkov ktime_t bp) 1108d0c12a8SStefan Roesch { 111342b2e39SPavel Begunkov if (bp) { 112342b2e39SPavel Begunkov ktime_t end_time = ktime_add(start_time, bp); 113342b2e39SPavel Begunkov ktime_t now = net_to_ktime(busy_loop_current_time()); 1148d0c12a8SStefan Roesch 115342b2e39SPavel Begunkov return ktime_after(now, end_time); 1168d0c12a8SStefan Roesch } 1178d0c12a8SStefan Roesch 1188d0c12a8SStefan Roesch return true; 1198d0c12a8SStefan Roesch } 1208d0c12a8SStefan Roesch 1218d0c12a8SStefan Roesch static bool io_napi_busy_loop_should_end(void *data, 1228d0c12a8SStefan Roesch unsigned long start_time) 1238d0c12a8SStefan Roesch { 1248d0c12a8SStefan Roesch struct io_wait_queue *iowq = data; 1258d0c12a8SStefan Roesch 1268d0c12a8SStefan Roesch if (signal_pending(current)) 1278d0c12a8SStefan Roesch return true; 128428f1382SJens Axboe if (io_should_wake(iowq) || io_has_work(iowq->ctx)) 1298d0c12a8SStefan Roesch return true; 130342b2e39SPavel Begunkov if (io_napi_busy_loop_timeout(net_to_ktime(start_time), 131342b2e39SPavel Begunkov iowq->napi_busy_poll_dt)) 1328d0c12a8SStefan Roesch return true; 1338d0c12a8SStefan Roesch 1348d0c12a8SStefan Roesch return false; 1358d0c12a8SStefan Roesch } 1368d0c12a8SStefan Roesch 1378d0c12a8SStefan Roesch static bool __io_napi_do_busy_loop(struct io_ring_ctx *ctx, 1388d0c12a8SStefan Roesch void *loop_end_arg) 1398d0c12a8SStefan Roesch { 1408d0c12a8SStefan Roesch struct io_napi_entry *e; 1418d0c12a8SStefan Roesch bool (*loop_end)(void *, unsigned long) = NULL; 1428d0c12a8SStefan Roesch bool is_stale = false; 1438d0c12a8SStefan Roesch 1448d0c12a8SStefan Roesch if (loop_end_arg) 1458d0c12a8SStefan Roesch loop_end = io_napi_busy_loop_should_end; 1468d0c12a8SStefan Roesch 1478d0c12a8SStefan Roesch list_for_each_entry_rcu(e, &ctx->napi_list, list) { 1488d0c12a8SStefan Roesch napi_busy_loop_rcu(e->napi_id, loop_end, loop_end_arg, 1498d0c12a8SStefan Roesch ctx->napi_prefer_busy_poll, BUSY_POLL_BUDGET); 1508d0c12a8SStefan Roesch 1512f3cc8e4SOlivier Langlois if (time_after(jiffies, READ_ONCE(e->timeout))) 1528d0c12a8SStefan Roesch is_stale = true; 1538d0c12a8SStefan Roesch } 1548d0c12a8SStefan Roesch 1558d0c12a8SStefan Roesch return is_stale; 1568d0c12a8SStefan Roesch } 1578d0c12a8SStefan Roesch 1588d0c12a8SStefan Roesch static void io_napi_blocking_busy_loop(struct io_ring_ctx *ctx, 1598d0c12a8SStefan Roesch struct io_wait_queue *iowq) 1608d0c12a8SStefan Roesch { 1618d0c12a8SStefan Roesch unsigned long start_time = busy_loop_current_time(); 1628d0c12a8SStefan Roesch void *loop_end_arg = NULL; 1638d0c12a8SStefan Roesch bool is_stale = false; 1648d0c12a8SStefan Roesch 1658d0c12a8SStefan Roesch /* Singular lists use a different napi loop end check function and are 1668d0c12a8SStefan Roesch * only executed once. 1678d0c12a8SStefan Roesch */ 1688d0c12a8SStefan Roesch if (list_is_singular(&ctx->napi_list)) 1698d0c12a8SStefan Roesch loop_end_arg = iowq; 1708d0c12a8SStefan Roesch 1718d0c12a8SStefan Roesch rcu_read_lock(); 1728d0c12a8SStefan Roesch do { 1738d0c12a8SStefan Roesch is_stale = __io_napi_do_busy_loop(ctx, loop_end_arg); 1748d0c12a8SStefan Roesch } while (!io_napi_busy_loop_should_end(iowq, start_time) && !loop_end_arg); 1758d0c12a8SStefan Roesch rcu_read_unlock(); 1768d0c12a8SStefan Roesch 1778d0c12a8SStefan Roesch io_napi_remove_stale(ctx, is_stale); 1788d0c12a8SStefan Roesch } 1798d0c12a8SStefan Roesch 1808d0c12a8SStefan Roesch /* 1818d0c12a8SStefan Roesch * io_napi_init() - Init napi settings 1828d0c12a8SStefan Roesch * @ctx: pointer to io-uring context structure 1838d0c12a8SStefan Roesch * 1848d0c12a8SStefan Roesch * Init napi settings in the io-uring context. 1858d0c12a8SStefan Roesch */ 1868d0c12a8SStefan Roesch void io_napi_init(struct io_ring_ctx *ctx) 1878d0c12a8SStefan Roesch { 188342b2e39SPavel Begunkov u64 sys_dt = READ_ONCE(sysctl_net_busy_poll) * NSEC_PER_USEC; 189342b2e39SPavel Begunkov 1908d0c12a8SStefan Roesch INIT_LIST_HEAD(&ctx->napi_list); 1918d0c12a8SStefan Roesch spin_lock_init(&ctx->napi_lock); 1928d0c12a8SStefan Roesch ctx->napi_prefer_busy_poll = false; 193342b2e39SPavel Begunkov ctx->napi_busy_poll_dt = ns_to_ktime(sys_dt); 1948d0c12a8SStefan Roesch } 1958d0c12a8SStefan Roesch 1968d0c12a8SStefan Roesch /* 1978d0c12a8SStefan Roesch * io_napi_free() - Deallocate napi 1988d0c12a8SStefan Roesch * @ctx: pointer to io-uring context structure 1998d0c12a8SStefan Roesch * 2008d0c12a8SStefan Roesch * Free the napi list and the hash table in the io-uring context. 2018d0c12a8SStefan Roesch */ 2028d0c12a8SStefan Roesch void io_napi_free(struct io_ring_ctx *ctx) 2038d0c12a8SStefan Roesch { 2048d0c12a8SStefan Roesch struct io_napi_entry *e; 2058d0c12a8SStefan Roesch 2068d0c12a8SStefan Roesch spin_lock(&ctx->napi_lock); 20745b3941dSOlivier Langlois list_for_each_entry(e, &ctx->napi_list, list) { 2088d0c12a8SStefan Roesch hash_del_rcu(&e->node); 2098d0c12a8SStefan Roesch kfree_rcu(e, rcu); 2108d0c12a8SStefan Roesch } 21145b3941dSOlivier Langlois INIT_LIST_HEAD_RCU(&ctx->napi_list); 2128d0c12a8SStefan Roesch spin_unlock(&ctx->napi_lock); 2138d0c12a8SStefan Roesch } 2148d0c12a8SStefan Roesch 2158d0c12a8SStefan Roesch /* 216ef1186c1SStefan Roesch * io_napi_register() - Register napi with io-uring 217ef1186c1SStefan Roesch * @ctx: pointer to io-uring context structure 218ef1186c1SStefan Roesch * @arg: pointer to io_uring_napi structure 219ef1186c1SStefan Roesch * 220ef1186c1SStefan Roesch * Register napi in the io-uring context. 221ef1186c1SStefan Roesch */ 222ef1186c1SStefan Roesch int io_register_napi(struct io_ring_ctx *ctx, void __user *arg) 223ef1186c1SStefan Roesch { 224ef1186c1SStefan Roesch const struct io_uring_napi curr = { 225342b2e39SPavel Begunkov .busy_poll_to = ktime_to_us(ctx->napi_busy_poll_dt), 226ef1186c1SStefan Roesch .prefer_busy_poll = ctx->napi_prefer_busy_poll 227ef1186c1SStefan Roesch }; 228ef1186c1SStefan Roesch struct io_uring_napi napi; 229ef1186c1SStefan Roesch 230bd44d7e9SPavel Begunkov if (ctx->flags & IORING_SETUP_IOPOLL) 231bd44d7e9SPavel Begunkov return -EINVAL; 232ef1186c1SStefan Roesch if (copy_from_user(&napi, arg, sizeof(napi))) 233ef1186c1SStefan Roesch return -EFAULT; 234ef1186c1SStefan Roesch if (napi.pad[0] || napi.pad[1] || napi.pad[2] || napi.resv) 235ef1186c1SStefan Roesch return -EINVAL; 236ef1186c1SStefan Roesch 237ef1186c1SStefan Roesch if (copy_to_user(arg, &curr, sizeof(curr))) 238ef1186c1SStefan Roesch return -EFAULT; 239ef1186c1SStefan Roesch 240342b2e39SPavel Begunkov WRITE_ONCE(ctx->napi_busy_poll_dt, napi.busy_poll_to * NSEC_PER_USEC); 241b4ccc4ddSJens Axboe WRITE_ONCE(ctx->napi_prefer_busy_poll, !!napi.prefer_busy_poll); 242b4ccc4ddSJens Axboe WRITE_ONCE(ctx->napi_enabled, true); 243ef1186c1SStefan Roesch return 0; 244ef1186c1SStefan Roesch } 245ef1186c1SStefan Roesch 246ef1186c1SStefan Roesch /* 247ef1186c1SStefan Roesch * io_napi_unregister() - Unregister napi with io-uring 248ef1186c1SStefan Roesch * @ctx: pointer to io-uring context structure 249ef1186c1SStefan Roesch * @arg: pointer to io_uring_napi structure 250ef1186c1SStefan Roesch * 251ef1186c1SStefan Roesch * Unregister napi. If arg has been specified copy the busy poll timeout and 252ef1186c1SStefan Roesch * prefer busy poll setting to the passed in structure. 253ef1186c1SStefan Roesch */ 254ef1186c1SStefan Roesch int io_unregister_napi(struct io_ring_ctx *ctx, void __user *arg) 255ef1186c1SStefan Roesch { 256ef1186c1SStefan Roesch const struct io_uring_napi curr = { 257342b2e39SPavel Begunkov .busy_poll_to = ktime_to_us(ctx->napi_busy_poll_dt), 258ef1186c1SStefan Roesch .prefer_busy_poll = ctx->napi_prefer_busy_poll 259ef1186c1SStefan Roesch }; 260ef1186c1SStefan Roesch 261ef1186c1SStefan Roesch if (arg && copy_to_user(arg, &curr, sizeof(curr))) 262ef1186c1SStefan Roesch return -EFAULT; 263ef1186c1SStefan Roesch 264342b2e39SPavel Begunkov WRITE_ONCE(ctx->napi_busy_poll_dt, 0); 265ef1186c1SStefan Roesch WRITE_ONCE(ctx->napi_prefer_busy_poll, false); 266b4ccc4ddSJens Axboe WRITE_ONCE(ctx->napi_enabled, false); 267ef1186c1SStefan Roesch return 0; 268ef1186c1SStefan Roesch } 269ef1186c1SStefan Roesch 270ef1186c1SStefan Roesch /* 2718d0c12a8SStefan Roesch * __io_napi_busy_loop() - execute busy poll loop 2728d0c12a8SStefan Roesch * @ctx: pointer to io-uring context structure 2738d0c12a8SStefan Roesch * @iowq: pointer to io wait queue 2748d0c12a8SStefan Roesch * 2758d0c12a8SStefan Roesch * Execute the busy poll loop and merge the spliced off list. 2768d0c12a8SStefan Roesch */ 2778d0c12a8SStefan Roesch void __io_napi_busy_loop(struct io_ring_ctx *ctx, struct io_wait_queue *iowq) 2788d0c12a8SStefan Roesch { 279489b8006SPavel Begunkov if (ctx->flags & IORING_SETUP_SQPOLL) 280489b8006SPavel Begunkov return; 2818d0c12a8SStefan Roesch 282d5cce407SPavel Begunkov iowq->napi_busy_poll_dt = READ_ONCE(ctx->napi_busy_poll_dt); 283d5cce407SPavel Begunkov if (iowq->timeout != KTIME_MAX) { 2842b8e976bSPavel Begunkov ktime_t dt = ktime_sub(iowq->timeout, io_get_time(ctx)); 285d5cce407SPavel Begunkov 286d5cce407SPavel Begunkov iowq->napi_busy_poll_dt = min_t(u64, iowq->napi_busy_poll_dt, dt); 287d5cce407SPavel Begunkov } 288d5cce407SPavel Begunkov 289489b8006SPavel Begunkov iowq->napi_prefer_busy_poll = READ_ONCE(ctx->napi_prefer_busy_poll); 2908d0c12a8SStefan Roesch io_napi_blocking_busy_loop(ctx, iowq); 2918d0c12a8SStefan Roesch } 2928d0c12a8SStefan Roesch 293ff183d42SStefan Roesch /* 294ff183d42SStefan Roesch * io_napi_sqpoll_busy_poll() - busy poll loop for sqpoll 295ff183d42SStefan Roesch * @ctx: pointer to io-uring context structure 296ff183d42SStefan Roesch * 297ff183d42SStefan Roesch * Splice of the napi list and execute the napi busy poll loop. 298ff183d42SStefan Roesch */ 299ff183d42SStefan Roesch int io_napi_sqpoll_busy_poll(struct io_ring_ctx *ctx) 300ff183d42SStefan Roesch { 301ff183d42SStefan Roesch bool is_stale = false; 302ff183d42SStefan Roesch 303342b2e39SPavel Begunkov if (!READ_ONCE(ctx->napi_busy_poll_dt)) 304ff183d42SStefan Roesch return 0; 305ff183d42SStefan Roesch if (list_empty_careful(&ctx->napi_list)) 306ff183d42SStefan Roesch return 0; 307ff183d42SStefan Roesch 308ff183d42SStefan Roesch rcu_read_lock(); 309ff183d42SStefan Roesch is_stale = __io_napi_do_busy_loop(ctx, NULL); 310ff183d42SStefan Roesch rcu_read_unlock(); 311ff183d42SStefan Roesch 312ff183d42SStefan Roesch io_napi_remove_stale(ctx, is_stale); 313ff183d42SStefan Roesch return 1; 314ff183d42SStefan Roesch } 315ff183d42SStefan Roesch 3168d0c12a8SStefan Roesch #endif 317