summaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
Diffstat (limited to 'net/core')
-rw-r--r--net/core/dev.c2
-rw-r--r--net/core/netpoll.c10
2 files changed, 10 insertions, 2 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index 877c84834d81..6bb6470f5b7b 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4713,6 +4713,8 @@ void napi_disable(struct napi_struct *n)
while (test_and_set_bit(NAPI_STATE_SCHED, &n->state))
msleep(1);
+ while (test_and_set_bit(NAPI_STATE_NPSVC, &n->state))
+ msleep(1);
hrtimer_cancel(&n->timer);
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 6aa3db8dfc3b..8bdada242a7d 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -142,7 +142,7 @@ static void queue_process(struct work_struct *work)
*/
static int poll_one_napi(struct napi_struct *napi, int budget)
{
- int work;
+ int work = 0;
/* net_rx_action's ->poll() invocations and our's are
* synchronized by this test which is only made while
@@ -151,7 +151,12 @@ static int poll_one_napi(struct napi_struct *napi, int budget)
if (!test_bit(NAPI_STATE_SCHED, &napi->state))
return budget;
- set_bit(NAPI_STATE_NPSVC, &napi->state);
+ /* If we set this bit but see that it has already been set,
+ * that indicates that napi has been disabled and we need
+ * to abort this operation
+ */
+ if (test_and_set_bit(NAPI_STATE_NPSVC, &napi->state))
+ goto out;
work = napi->poll(napi, budget);
WARN_ONCE(work > budget, "%pF exceeded budget in poll\n", napi->poll);
@@ -159,6 +164,7 @@ static int poll_one_napi(struct napi_struct *napi, int budget)
clear_bit(NAPI_STATE_NPSVC, &napi->state);
+out:
return budget - work;
}