diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 3143c847bddb..f2416b530c9a 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2518,6 +2518,7 @@ extern int netdev_flow_limit_table_len; */ struct softnet_data { struct list_head poll_list; + struct napi_struct *current_napi; struct sk_buff_head process_queue; /* stats */ @@ -3012,6 +3013,7 @@ struct sk_buff *napi_get_frags(struct napi_struct *napi); gro_result_t napi_gro_frags(struct napi_struct *napi); struct packet_offload *gro_find_receive_by_type(__be16 type); struct packet_offload *gro_find_complete_by_type(__be16 type); +extern struct napi_struct *get_current_napi_context(void); static inline void napi_free_frags(struct napi_struct *napi) { diff --git a/net/core/dev.c b/net/core/dev.c index ae00b894e675..49dd68d2dbfb 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4557,8 +4557,7 @@ static int process_backlog(struct napi_struct *napi, int quota) local_irq_disable(); input_queue_head_incr(sd); if (++work >= quota) { - local_irq_enable(); - return work; + goto state_changed; } } @@ -4575,14 +4574,17 @@ static int process_backlog(struct napi_struct *napi, int quota) napi->state = 0; rps_unlock(sd); - break; + goto state_changed; } skb_queue_splice_tail_init(&sd->input_pkt_queue, &sd->process_queue); rps_unlock(sd); } +state_changed: local_irq_enable(); + napi_gro_flush(napi, false); + sd->current_napi = NULL; return work; } @@ -4618,10 +4620,13 @@ EXPORT_SYMBOL(__napi_schedule_irqoff); void __napi_complete(struct napi_struct *n) { + struct softnet_data *sd = &__get_cpu_var(softnet_data); + BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state)); list_del_init(&n->poll_list); smp_mb__before_atomic(); + sd->current_napi = NULL; clear_bit(NAPI_STATE_SCHED, &n->state); } EXPORT_SYMBOL(__napi_complete); @@ -4775,6 +4780,16 @@ void netif_napi_del(struct napi_struct *napi) EXPORT_SYMBOL(netif_napi_del); static int napi_poll(struct napi_struct *n, struct list_head *repoll) + +struct napi_struct *get_current_napi_context(void) +{ + struct softnet_data *sd = &__get_cpu_var(softnet_data); + + return sd->current_napi; +} +EXPORT_SYMBOL(get_current_napi_context); + +static void net_rx_action(struct softirq_action *h) { void *have; int work, weight; @@ -4793,6 +4808,7 @@ static int napi_poll(struct napi_struct *n, struct list_head *repoll) */ work = 0; if (test_bit(NAPI_STATE_SCHED, &n->state)) { + sd->current_napi = n; work = n->poll(n, weight); trace_napi_poll(n); }