From 8ba14953de85e80bb9dbb95204e0668106826f46 Mon Sep 17 00:00:00 2001 From: Subash Abhinov Kasiviswanathan Date: Wed, 1 Nov 2017 15:32:41 -0600 Subject: [PATCH] ANDROID: GKI: net: Add the get current NAPI context API Commit 69235aa80090 ("net: Remove the get current NAPI context API") removed the definition of get_current_napi_context() as rmnet_data was no longer using it. However, the rmnet_data change to use its NAPI in multiple contexts was prone to race in hotplug scenarios. Add back get_current_napi_context() and current_napi to the softnet_data struct. Signed-off-by: Subash Abhinov Kasiviswanathan (cherry picked from commit 05b3252cf566eb04c7c5484c912ae6f8f9fb1dd5) [surenb cherry-picked from 05b3252cf566 net: Add the get current NAPI context API to fix ABI diffs caused by get_current_napi_context function] Bug: 151108843 Test: build Signed-off-by: Suren Baghdasaryan Change-Id: I4d5b81c734e4a5daa2fae3cb7d6538821d46ff64 Merged-In: I4d5b81c734e4a5daa2fae3cb7d6538821d46ff64 --- include/linux/netdevice.h | 2 ++ net/core/dev.c | 21 +++++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 84bbdcbb199a..37d383bf27eb 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2949,6 +2949,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 */ @@ -3551,6 +3552,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 c1a3baf16957..a26dcc7a2789 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5842,8 +5842,7 @@ static int process_backlog(struct napi_struct *napi, int quota) rcu_read_unlock(); input_queue_head_incr(sd); if (++work >= quota) - return work; - + goto state_changed; } local_irq_disable(); @@ -5867,6 +5866,10 @@ static int process_backlog(struct napi_struct *napi, int quota) local_irq_enable(); } +state_changed: + napi_gro_flush(napi, false); + sd->current_napi = NULL; + return work; } @@ -5962,9 +5965,12 @@ bool napi_complete_done(struct napi_struct *n, int work_done) HRTIMER_MODE_REL_PINNED); } if (unlikely(!list_empty(&n->poll_list))) { + struct softnet_data *sd = this_cpu_ptr(&softnet_data); + /* If n->poll_list is not empty, we need to mask irqs */ local_irq_save(flags); list_del_init(&n->poll_list); + sd->current_napi = NULL; local_irq_restore(flags); } @@ -6242,6 +6248,14 @@ void netif_napi_del(struct napi_struct *napi) } EXPORT_SYMBOL(netif_napi_del); +struct napi_struct *get_current_napi_context(void) +{ + struct softnet_data *sd = this_cpu_ptr(&softnet_data); + + return sd->current_napi; +} +EXPORT_SYMBOL(get_current_napi_context); + static int napi_poll(struct napi_struct *n, struct list_head *repoll) { void *have; @@ -6261,6 +6275,9 @@ static int napi_poll(struct napi_struct *n, struct list_head *repoll) */ work = 0; if (test_bit(NAPI_STATE_SCHED, &n->state)) { + struct softnet_data *sd = this_cpu_ptr(&softnet_data); + + sd->current_napi = n; work = n->poll(n, weight); trace_napi_poll(n, work, weight); }