1*8d0c12a8SStefan Roesch // SPDX-License-Identifier: GPL-2.0 2*8d0c12a8SStefan Roesch 3*8d0c12a8SStefan Roesch #include "io_uring.h" 4*8d0c12a8SStefan Roesch #include "napi.h" 5*8d0c12a8SStefan Roesch 6*8d0c12a8SStefan Roesch #ifdef CONFIG_NET_RX_BUSY_POLL 7*8d0c12a8SStefan Roesch 8*8d0c12a8SStefan Roesch /* Timeout for cleanout of stale entries. */ 9*8d0c12a8SStefan Roesch #define NAPI_TIMEOUT (60 * SEC_CONVERSION) 10*8d0c12a8SStefan Roesch 11*8d0c12a8SStefan Roesch struct io_napi_entry { 12*8d0c12a8SStefan Roesch unsigned int napi_id; 13*8d0c12a8SStefan Roesch struct list_head list; 14*8d0c12a8SStefan Roesch 15*8d0c12a8SStefan Roesch unsigned long timeout; 16*8d0c12a8SStefan Roesch struct hlist_node node; 17*8d0c12a8SStefan Roesch 18*8d0c12a8SStefan Roesch struct rcu_head rcu; 19*8d0c12a8SStefan Roesch }; 20*8d0c12a8SStefan Roesch 21*8d0c12a8SStefan Roesch static struct io_napi_entry *io_napi_hash_find(struct hlist_head *hash_list, 22*8d0c12a8SStefan Roesch unsigned int napi_id) 23*8d0c12a8SStefan Roesch { 24*8d0c12a8SStefan Roesch struct io_napi_entry *e; 25*8d0c12a8SStefan Roesch 26*8d0c12a8SStefan Roesch hlist_for_each_entry_rcu(e, hash_list, node) { 27*8d0c12a8SStefan Roesch if (e->napi_id != napi_id) 28*8d0c12a8SStefan Roesch continue; 29*8d0c12a8SStefan Roesch e->timeout = jiffies + NAPI_TIMEOUT; 30*8d0c12a8SStefan Roesch return e; 31*8d0c12a8SStefan Roesch } 32*8d0c12a8SStefan Roesch 33*8d0c12a8SStefan Roesch return NULL; 34*8d0c12a8SStefan Roesch } 35*8d0c12a8SStefan Roesch 36*8d0c12a8SStefan Roesch void __io_napi_add(struct io_ring_ctx *ctx, struct socket *sock) 37*8d0c12a8SStefan Roesch { 38*8d0c12a8SStefan Roesch struct hlist_head *hash_list; 39*8d0c12a8SStefan Roesch unsigned int napi_id; 40*8d0c12a8SStefan Roesch struct sock *sk; 41*8d0c12a8SStefan Roesch struct io_napi_entry *e; 42*8d0c12a8SStefan Roesch 43*8d0c12a8SStefan Roesch sk = sock->sk; 44*8d0c12a8SStefan Roesch if (!sk) 45*8d0c12a8SStefan Roesch return; 46*8d0c12a8SStefan Roesch 47*8d0c12a8SStefan Roesch napi_id = READ_ONCE(sk->sk_napi_id); 48*8d0c12a8SStefan Roesch 49*8d0c12a8SStefan Roesch /* Non-NAPI IDs can be rejected. */ 50*8d0c12a8SStefan Roesch if (napi_id < MIN_NAPI_ID) 51*8d0c12a8SStefan Roesch return; 52*8d0c12a8SStefan Roesch 53*8d0c12a8SStefan Roesch hash_list = &ctx->napi_ht[hash_min(napi_id, HASH_BITS(ctx->napi_ht))]; 54*8d0c12a8SStefan Roesch 55*8d0c12a8SStefan Roesch rcu_read_lock(); 56*8d0c12a8SStefan Roesch e = io_napi_hash_find(hash_list, napi_id); 57*8d0c12a8SStefan Roesch if (e) { 58*8d0c12a8SStefan Roesch e->timeout = jiffies + NAPI_TIMEOUT; 59*8d0c12a8SStefan Roesch rcu_read_unlock(); 60*8d0c12a8SStefan Roesch return; 61*8d0c12a8SStefan Roesch } 62*8d0c12a8SStefan Roesch rcu_read_unlock(); 63*8d0c12a8SStefan Roesch 64*8d0c12a8SStefan Roesch e = kmalloc(sizeof(*e), GFP_NOWAIT); 65*8d0c12a8SStefan Roesch if (!e) 66*8d0c12a8SStefan Roesch return; 67*8d0c12a8SStefan Roesch 68*8d0c12a8SStefan Roesch e->napi_id = napi_id; 69*8d0c12a8SStefan Roesch e->timeout = jiffies + NAPI_TIMEOUT; 70*8d0c12a8SStefan Roesch 71*8d0c12a8SStefan Roesch spin_lock(&ctx->napi_lock); 72*8d0c12a8SStefan Roesch if (unlikely(io_napi_hash_find(hash_list, napi_id))) { 73*8d0c12a8SStefan Roesch spin_unlock(&ctx->napi_lock); 74*8d0c12a8SStefan Roesch kfree(e); 75*8d0c12a8SStefan Roesch return; 76*8d0c12a8SStefan Roesch } 77*8d0c12a8SStefan Roesch 78*8d0c12a8SStefan Roesch hlist_add_tail_rcu(&e->node, hash_list); 79*8d0c12a8SStefan Roesch list_add_tail(&e->list, &ctx->napi_list); 80*8d0c12a8SStefan Roesch spin_unlock(&ctx->napi_lock); 81*8d0c12a8SStefan Roesch } 82*8d0c12a8SStefan Roesch 83*8d0c12a8SStefan Roesch static void __io_napi_remove_stale(struct io_ring_ctx *ctx) 84*8d0c12a8SStefan Roesch { 85*8d0c12a8SStefan Roesch struct io_napi_entry *e; 86*8d0c12a8SStefan Roesch unsigned int i; 87*8d0c12a8SStefan Roesch 88*8d0c12a8SStefan Roesch spin_lock(&ctx->napi_lock); 89*8d0c12a8SStefan Roesch hash_for_each(ctx->napi_ht, i, e, node) { 90*8d0c12a8SStefan Roesch if (time_after(jiffies, e->timeout)) { 91*8d0c12a8SStefan Roesch list_del(&e->list); 92*8d0c12a8SStefan Roesch hash_del_rcu(&e->node); 93*8d0c12a8SStefan Roesch kfree_rcu(e, rcu); 94*8d0c12a8SStefan Roesch } 95*8d0c12a8SStefan Roesch } 96*8d0c12a8SStefan Roesch spin_unlock(&ctx->napi_lock); 97*8d0c12a8SStefan Roesch } 98*8d0c12a8SStefan Roesch 99*8d0c12a8SStefan Roesch static inline void io_napi_remove_stale(struct io_ring_ctx *ctx, bool is_stale) 100*8d0c12a8SStefan Roesch { 101*8d0c12a8SStefan Roesch if (is_stale) 102*8d0c12a8SStefan Roesch __io_napi_remove_stale(ctx); 103*8d0c12a8SStefan Roesch } 104*8d0c12a8SStefan Roesch 105*8d0c12a8SStefan Roesch static inline bool io_napi_busy_loop_timeout(unsigned long start_time, 106*8d0c12a8SStefan Roesch unsigned long bp_usec) 107*8d0c12a8SStefan Roesch { 108*8d0c12a8SStefan Roesch if (bp_usec) { 109*8d0c12a8SStefan Roesch unsigned long end_time = start_time + bp_usec; 110*8d0c12a8SStefan Roesch unsigned long now = busy_loop_current_time(); 111*8d0c12a8SStefan Roesch 112*8d0c12a8SStefan Roesch return time_after(now, end_time); 113*8d0c12a8SStefan Roesch } 114*8d0c12a8SStefan Roesch 115*8d0c12a8SStefan Roesch return true; 116*8d0c12a8SStefan Roesch } 117*8d0c12a8SStefan Roesch 118*8d0c12a8SStefan Roesch static bool io_napi_busy_loop_should_end(void *data, 119*8d0c12a8SStefan Roesch unsigned long start_time) 120*8d0c12a8SStefan Roesch { 121*8d0c12a8SStefan Roesch struct io_wait_queue *iowq = data; 122*8d0c12a8SStefan Roesch 123*8d0c12a8SStefan Roesch if (signal_pending(current)) 124*8d0c12a8SStefan Roesch return true; 125*8d0c12a8SStefan Roesch if (io_should_wake(iowq)) 126*8d0c12a8SStefan Roesch return true; 127*8d0c12a8SStefan Roesch if (io_napi_busy_loop_timeout(start_time, iowq->napi_busy_poll_to)) 128*8d0c12a8SStefan Roesch return true; 129*8d0c12a8SStefan Roesch 130*8d0c12a8SStefan Roesch return false; 131*8d0c12a8SStefan Roesch } 132*8d0c12a8SStefan Roesch 133*8d0c12a8SStefan Roesch static bool __io_napi_do_busy_loop(struct io_ring_ctx *ctx, 134*8d0c12a8SStefan Roesch void *loop_end_arg) 135*8d0c12a8SStefan Roesch { 136*8d0c12a8SStefan Roesch struct io_napi_entry *e; 137*8d0c12a8SStefan Roesch bool (*loop_end)(void *, unsigned long) = NULL; 138*8d0c12a8SStefan Roesch bool is_stale = false; 139*8d0c12a8SStefan Roesch 140*8d0c12a8SStefan Roesch if (loop_end_arg) 141*8d0c12a8SStefan Roesch loop_end = io_napi_busy_loop_should_end; 142*8d0c12a8SStefan Roesch 143*8d0c12a8SStefan Roesch list_for_each_entry_rcu(e, &ctx->napi_list, list) { 144*8d0c12a8SStefan Roesch napi_busy_loop_rcu(e->napi_id, loop_end, loop_end_arg, 145*8d0c12a8SStefan Roesch ctx->napi_prefer_busy_poll, BUSY_POLL_BUDGET); 146*8d0c12a8SStefan Roesch 147*8d0c12a8SStefan Roesch if (time_after(jiffies, e->timeout)) 148*8d0c12a8SStefan Roesch is_stale = true; 149*8d0c12a8SStefan Roesch } 150*8d0c12a8SStefan Roesch 151*8d0c12a8SStefan Roesch return is_stale; 152*8d0c12a8SStefan Roesch } 153*8d0c12a8SStefan Roesch 154*8d0c12a8SStefan Roesch static void io_napi_blocking_busy_loop(struct io_ring_ctx *ctx, 155*8d0c12a8SStefan Roesch struct io_wait_queue *iowq) 156*8d0c12a8SStefan Roesch { 157*8d0c12a8SStefan Roesch unsigned long start_time = busy_loop_current_time(); 158*8d0c12a8SStefan Roesch void *loop_end_arg = NULL; 159*8d0c12a8SStefan Roesch bool is_stale = false; 160*8d0c12a8SStefan Roesch 161*8d0c12a8SStefan Roesch /* Singular lists use a different napi loop end check function and are 162*8d0c12a8SStefan Roesch * only executed once. 163*8d0c12a8SStefan Roesch */ 164*8d0c12a8SStefan Roesch if (list_is_singular(&ctx->napi_list)) 165*8d0c12a8SStefan Roesch loop_end_arg = iowq; 166*8d0c12a8SStefan Roesch 167*8d0c12a8SStefan Roesch rcu_read_lock(); 168*8d0c12a8SStefan Roesch do { 169*8d0c12a8SStefan Roesch is_stale = __io_napi_do_busy_loop(ctx, loop_end_arg); 170*8d0c12a8SStefan Roesch } while (!io_napi_busy_loop_should_end(iowq, start_time) && !loop_end_arg); 171*8d0c12a8SStefan Roesch rcu_read_unlock(); 172*8d0c12a8SStefan Roesch 173*8d0c12a8SStefan Roesch io_napi_remove_stale(ctx, is_stale); 174*8d0c12a8SStefan Roesch } 175*8d0c12a8SStefan Roesch 176*8d0c12a8SStefan Roesch /* 177*8d0c12a8SStefan Roesch * io_napi_init() - Init napi settings 178*8d0c12a8SStefan Roesch * @ctx: pointer to io-uring context structure 179*8d0c12a8SStefan Roesch * 180*8d0c12a8SStefan Roesch * Init napi settings in the io-uring context. 181*8d0c12a8SStefan Roesch */ 182*8d0c12a8SStefan Roesch void io_napi_init(struct io_ring_ctx *ctx) 183*8d0c12a8SStefan Roesch { 184*8d0c12a8SStefan Roesch INIT_LIST_HEAD(&ctx->napi_list); 185*8d0c12a8SStefan Roesch spin_lock_init(&ctx->napi_lock); 186*8d0c12a8SStefan Roesch ctx->napi_prefer_busy_poll = false; 187*8d0c12a8SStefan Roesch ctx->napi_busy_poll_to = READ_ONCE(sysctl_net_busy_poll); 188*8d0c12a8SStefan Roesch } 189*8d0c12a8SStefan Roesch 190*8d0c12a8SStefan Roesch /* 191*8d0c12a8SStefan Roesch * io_napi_free() - Deallocate napi 192*8d0c12a8SStefan Roesch * @ctx: pointer to io-uring context structure 193*8d0c12a8SStefan Roesch * 194*8d0c12a8SStefan Roesch * Free the napi list and the hash table in the io-uring context. 195*8d0c12a8SStefan Roesch */ 196*8d0c12a8SStefan Roesch void io_napi_free(struct io_ring_ctx *ctx) 197*8d0c12a8SStefan Roesch { 198*8d0c12a8SStefan Roesch struct io_napi_entry *e; 199*8d0c12a8SStefan Roesch LIST_HEAD(napi_list); 200*8d0c12a8SStefan Roesch unsigned int i; 201*8d0c12a8SStefan Roesch 202*8d0c12a8SStefan Roesch spin_lock(&ctx->napi_lock); 203*8d0c12a8SStefan Roesch hash_for_each(ctx->napi_ht, i, e, node) { 204*8d0c12a8SStefan Roesch hash_del_rcu(&e->node); 205*8d0c12a8SStefan Roesch kfree_rcu(e, rcu); 206*8d0c12a8SStefan Roesch } 207*8d0c12a8SStefan Roesch spin_unlock(&ctx->napi_lock); 208*8d0c12a8SStefan Roesch } 209*8d0c12a8SStefan Roesch 210*8d0c12a8SStefan Roesch /* 211*8d0c12a8SStefan Roesch * __io_napi_adjust_timeout() - Add napi id to the busy poll list 212*8d0c12a8SStefan Roesch * @ctx: pointer to io-uring context structure 213*8d0c12a8SStefan Roesch * @iowq: pointer to io wait queue 214*8d0c12a8SStefan Roesch * @ts: pointer to timespec or NULL 215*8d0c12a8SStefan Roesch * 216*8d0c12a8SStefan Roesch * Adjust the busy loop timeout according to timespec and busy poll timeout. 217*8d0c12a8SStefan Roesch */ 218*8d0c12a8SStefan Roesch void __io_napi_adjust_timeout(struct io_ring_ctx *ctx, struct io_wait_queue *iowq, 219*8d0c12a8SStefan Roesch struct timespec64 *ts) 220*8d0c12a8SStefan Roesch { 221*8d0c12a8SStefan Roesch unsigned int poll_to = READ_ONCE(ctx->napi_busy_poll_to); 222*8d0c12a8SStefan Roesch 223*8d0c12a8SStefan Roesch if (ts) { 224*8d0c12a8SStefan Roesch struct timespec64 poll_to_ts = ns_to_timespec64(1000 * (s64)poll_to); 225*8d0c12a8SStefan Roesch 226*8d0c12a8SStefan Roesch if (timespec64_compare(ts, &poll_to_ts) > 0) { 227*8d0c12a8SStefan Roesch *ts = timespec64_sub(*ts, poll_to_ts); 228*8d0c12a8SStefan Roesch } else { 229*8d0c12a8SStefan Roesch u64 to = timespec64_to_ns(ts); 230*8d0c12a8SStefan Roesch 231*8d0c12a8SStefan Roesch do_div(to, 1000); 232*8d0c12a8SStefan Roesch ts->tv_sec = 0; 233*8d0c12a8SStefan Roesch ts->tv_nsec = 0; 234*8d0c12a8SStefan Roesch } 235*8d0c12a8SStefan Roesch } 236*8d0c12a8SStefan Roesch 237*8d0c12a8SStefan Roesch iowq->napi_busy_poll_to = poll_to; 238*8d0c12a8SStefan Roesch } 239*8d0c12a8SStefan Roesch 240*8d0c12a8SStefan Roesch /* 241*8d0c12a8SStefan Roesch * __io_napi_busy_loop() - execute busy poll loop 242*8d0c12a8SStefan Roesch * @ctx: pointer to io-uring context structure 243*8d0c12a8SStefan Roesch * @iowq: pointer to io wait queue 244*8d0c12a8SStefan Roesch * 245*8d0c12a8SStefan Roesch * Execute the busy poll loop and merge the spliced off list. 246*8d0c12a8SStefan Roesch */ 247*8d0c12a8SStefan Roesch void __io_napi_busy_loop(struct io_ring_ctx *ctx, struct io_wait_queue *iowq) 248*8d0c12a8SStefan Roesch { 249*8d0c12a8SStefan Roesch iowq->napi_prefer_busy_poll = READ_ONCE(ctx->napi_prefer_busy_poll); 250*8d0c12a8SStefan Roesch 251*8d0c12a8SStefan Roesch if (!(ctx->flags & IORING_SETUP_SQPOLL) && iowq->napi_busy_poll_to) 252*8d0c12a8SStefan Roesch io_napi_blocking_busy_loop(ctx, iowq); 253*8d0c12a8SStefan Roesch } 254*8d0c12a8SStefan Roesch 255*8d0c12a8SStefan Roesch #endif 256