Patch "net: solve a NAPI race" has been added to the 4.10-stable tree
Subsystems (3)
This is a note to let you know that I've just added the patch titled
net: solve a NAPI race
to the 4.10-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
net-solve-a-napi-race.patch
and it can be found in the queue-4.10 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From foo@baz Mon Mar 27 18:18:08 CEST 2017
From: Eric Dumazet <[email protected]>
Date: Thu, 16 Mar 2017 19:02:33 -0700
Subject: net: solve a NAPI race
From: Eric Dumazet <[email protected]>
commit 39e6c8208d7b6fb9d2047850fb3327db567b564b upstream.
While playing with mlx4 hardware timestamping of RX packets, I found that some packets were received by TCP stack with a ~200 ms delay...
Since the timestamp was provided by the NIC, and my probe was added in tcp_v4_rcv() while in BH handler, I was confident it was not a sender issue, or a drop in the network.
This would happen with a very low probability, but hurting RPC workloads.
A NAPI driver normally arms the IRQ after the napi_complete_done(), after NAPI_STATE_SCHED is cleared, so that the hard irq handler can grab it.
Problem is that if another point in the stack grabs NAPI_STATE_SCHED bit while IRQ are not disabled, we might have later an IRQ firing and finding this bit set, right before napi_complete_done() clears it.
This can happen with busy polling users, or if gro_flush_timeout is used. But some other uses of napi_schedule() in drivers can cause this as well.
thread 1 thread 2 (could be on same cpu, or not)
// busy polling or napi_watchdog()napi_schedule();
...napi->poll()
device polling:
read 2 packets from ring buffer
Additional 3rd packet is
available.
device hard irq
// does nothing becauseNAPI_STATE_SCHED bit is owned by thread 1
napi_schedule();
napi_complete_done(napi, 2);rearm_irq();
Note that rearm_irq() will not force the device to send an additional IRQ for the packet it already signaled (3rd packet in my example)
This patch adds a new NAPI_STATE_MISSED bit, that napi_schedule_prep() can set if it could not grab NAPI_STATE_SCHED
Then napi_complete_done() properly reschedules the napi to make sure we do not miss something.
Since we manipulate multiple bits at once, use cmpxchg() like in sk_busy_loop() to provide proper transactions.
In v2, I changed napi_watchdog() to use a relaxed variant of napi_schedule_prep() : No need to set NAPI_STATE_MISSED from this point.
In v3, I added more details in the changelog and clears NAPI_STATE_MISSED in busy_poll_stop()
In v4, I added the ideas given by Alexander Duyck in v3 review
--- include/linux/netdevice.h | 29 +++++----------- net/core/dev.c | 81 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 83 insertions(+), 27 deletions(-)
include/linux/netdevice.h +9 -20
@@ -330,6 +330,7 @@ struct napi_struct {enum {NAPI_STATE_SCHED ,/* Poll is scheduled */ +NAPI_STATE_MISSED ,/* reschedule a napi */ NAPI_STATE_DISABLE ,/* Disable pending */ NAPI_STATE_NPSVC ,/* Netpoll - don't dequeue from poll_list */ NAPI_STATE_HASHED ,/* In NAPI hash (busy polling possible) */
@@ -338,12 +339,13 @@ enum { };enum { -NAPIF_STATE_SCHED = (1UL <<NAPI_STATE_SCHED ), -NAPIF_STATE_DISABLE = (1UL <<NAPI_STATE_DISABLE ), -NAPIF_STATE_NPSVC = (1UL <<NAPI_STATE_NPSVC ), -NAPIF_STATE_HASHED = (1UL <<NAPI_STATE_HASHED ), -NAPIF_STATE_NO_BUSY_POLL = (1UL <<NAPI_STATE_NO_BUSY_POLL ), -NAPIF_STATE_IN_BUSY_POLL = (1UL <<NAPI_STATE_IN_BUSY_POLL ), +NAPIF_STATE_SCHED =BIT (NAPI_STATE_SCHED ), +NAPIF_STATE_MISSED =BIT (NAPI_STATE_MISSED ), +NAPIF_STATE_DISABLE =BIT (NAPI_STATE_DISABLE ), +NAPIF_STATE_NPSVC =BIT (NAPI_STATE_NPSVC ), +NAPIF_STATE_HASHED =BIT (NAPI_STATE_HASHED ), +NAPIF_STATE_NO_BUSY_POLL =BIT (NAPI_STATE_NO_BUSY_POLL ), +NAPIF_STATE_IN_BUSY_POLL =BIT (NAPI_STATE_IN_BUSY_POLL ), };enum gro_result {
@@ -413,20 +415,7 @@ static inline bool napi_disable_pending(return test_bit (NAPI_STATE_DISABLE , &n->state); } -/** -* napi_schedule_prep - check if NAPI can be scheduled -* @n: NAPI context -* -* Test if NAPI routine is already running, and if not mark -* it as running. This is used as a condition variable to -* insure only one NAPI poll instance runs. We also make -* sure there is no pending NAPI disable. -*/ -static inline bool napi_schedule_prep (struct napi_struct *n) -{ -return !napi_disable_pending (n) && - !test_and_set_bit (NAPI_STATE_SCHED , &n->state); -} +bool napi_schedule_prep (struct napi_struct *n);/** * napi_schedule - schedule NAPI poll
net/core/dev.c +74 -7
115 lines not on this page · raw message
Patches currently in stable-queue which might be from [email protected] are
queue-4.10/ipv4-provide-stronger-user-input-validation-in-nl_fib_input.patch queue-4.10/net-solve-a-napi-race.patch queue-4.10/tcp-initialize-icsk_ack.lrcvtime-at-session-start-time.patch queue-4.10/net-properly-release-sk_frag.page.patch