From: Eric Dumazet <eric.dumazet@gmail.com>
To: Arun Sharma <asharma@fb.com>
Cc: Maximilian Engelhardt <maxi@daemonizer.de>,
linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
StuStaNet Vorstand <vorstand@stusta.mhn.de>
Subject: Re: Kernel crash after using new Intel NIC (igb)
Date: Wed, 25 May 2011 04:44:29 +0200 [thread overview]
Message-ID: <1306291469.3305.11.camel@edumazet-laptop> (raw)
In-Reply-To: <20110524213327.GA3917@dev1756.snc6.facebook.com>
Le mardi 24 mai 2011 à 14:33 -0700, Arun Sharma a écrit :
> On Thu, May 12, 2011 at 11:15:53PM +0200, Eric Dumazet wrote:
> >
> > Probably not.
> >
> > What gives slub_nomerge=1 for you ?
> >
>
> It took me a while to get a new kernel on a large enough sample
> of machines to get some data.
>
> Like you observed in the other thread, this is unlikely to be a random
> memory corruption.
>
> The panics stopped after we moved the list_empty() check under the lock.
>
> --- a/net/ipv4/inetpeer.c
> +++ b/net/ipv4/inetpeer.c
> @@ -154,11 +154,11 @@ void __init inet_initpeers(void)
> /* Called with or without local BH being disabled. */
> static void unlink_from_unused(struct inet_peer *p)
> {
> + spin_lock_bh(&unused_peers.lock);
> if (!list_empty(&p->unused)) {
> - spin_lock_bh(&unused_peers.lock);
> list_del_init(&p->unused);
> - spin_unlock_bh(&unused_peers.lock);
> }
> + spin_unlock_bh(&unused_peers.lock);
> }
>
> static int addr_compare(const struct inetpeer_addr *a,
>
> The idea being that the list gets corrupted under some kind of a race
> condition. Two threads racing on list_empty() and executing
> list_del_init() seems harmless.
>
> There is probably a different race condition that is mitigated by doing
> the list_empty() check under the lock.
>
Hmm, thanks for the report. Are you running x86 or another arch ?
We probably need some sort of memory barrier.
However, locking this central lock makes the thing too slow, I'll try to
use an atomic_inc_return on p->refcnt instead. (and then lock
unused_peers.lock if we got a 0->1 transition)
I am testing following patch :
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
index 9df4e63..43aacbf 100644
--- a/net/ipv4/inetpeer.c
+++ b/net/ipv4/inetpeer.c
@@ -154,11 +154,9 @@ void __init inet_initpeers(void)
/* Called with or without local BH being disabled. */
static void unlink_from_unused(struct inet_peer *p)
{
- if (!list_empty(&p->unused)) {
- spin_lock_bh(&unused_peers.lock);
- list_del_init(&p->unused);
- spin_unlock_bh(&unused_peers.lock);
- }
+ spin_lock_bh(&unused_peers.lock);
+ list_del_init(&p->unused);
+ spin_unlock_bh(&unused_peers.lock);
}
static int addr_compare(const struct inetpeer_addr *a,
@@ -213,10 +211,11 @@ static int addr_compare(const struct inetpeer_addr *a,
* We exit from this function if number of links exceeds PEER_MAXDEPTH
*/
static struct inet_peer *lookup_rcu(const struct inetpeer_addr *daddr,
- struct inet_peer_base *base)
+ struct inet_peer_base *base,
+ int *newrefcnt)
{
struct inet_peer *u = rcu_dereference(base->root);
- int count = 0;
+ int old, new, count = 0;
while (u != peer_avl_empty) {
int cmp = addr_compare(daddr, &u->daddr);
@@ -226,8 +225,16 @@ static struct inet_peer *lookup_rcu(const struct inetpeer_addr *daddr,
* distinction between an unused entry (refcnt=0) and
* a freed one.
*/
- if (unlikely(!atomic_add_unless(&u->refcnt, 1, -1)))
- u = NULL;
+ while (1) {
+ old = atomic_read(&u->refcnt);
+ if (old == -1)
+ return NULL;
+ new = old + 1;
+ if (atomic_cmpxchg(&u->refcnt,
+ old, new) == old)
+ break;
+ }
+ *newrefcnt = new;
return u;
}
if (cmp == -1)
@@ -465,14 +472,14 @@ struct inet_peer *inet_getpeer(struct inetpeer_addr *daddr, int create)
struct inet_peer_base *base = family_to_base(daddr->family);
struct inet_peer *p;
unsigned int sequence;
- int invalidated;
+ int invalidated, newrefcnt = 0;
/* Look up for the address quickly, lockless.
* Because of a concurrent writer, we might not find an existing entry.
*/
rcu_read_lock();
sequence = read_seqbegin(&base->lock);
- p = lookup_rcu(daddr, base);
+ p = lookup_rcu(daddr, base, &newrefcnt);
invalidated = read_seqretry(&base->lock, sequence);
rcu_read_unlock();
@@ -480,7 +487,8 @@ struct inet_peer *inet_getpeer(struct inetpeer_addr *daddr, int create)
/* The existing node has been found.
* Remove the entry from unused list if it was there.
*/
- unlink_from_unused(p);
+ if (newrefcnt == 1)
+ unlink_from_unused(p);
return p;
}
@@ -494,10 +502,11 @@ struct inet_peer *inet_getpeer(struct inetpeer_addr *daddr, int create)
write_seqlock_bh(&base->lock);
p = lookup(daddr, stack, base);
if (p != peer_avl_empty) {
- atomic_inc(&p->refcnt);
+ newrefcnt = atomic_inc_return(&p->refcnt);
write_sequnlock_bh(&base->lock);
/* Remove the entry from unused list if it was there. */
- unlink_from_unused(p);
+ if (newrefcnt == 1)
+ unlink_from_unused(p);
return p;
}
p = create ? kmem_cache_alloc(peer_cachep, GFP_ATOMIC) : NULL;
next prev parent reply other threads:[~2011-05-25 2:44 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-04-24 22:32 Kernel crash after using new Intel NIC (igb) Maximilian Engelhardt
2011-04-26 23:34 ` Wyborny, Carolyn
2011-04-27 11:46 ` Maximilian Engelhardt
2011-04-27 12:04 ` Eric Dumazet
2011-04-27 4:24 ` Eric Dumazet
2011-04-27 4:32 ` Eric Dumazet
2011-04-27 11:51 ` Maximilian Engelhardt
2011-05-12 21:10 ` Arun Sharma
2011-05-12 21:15 ` Eric Dumazet
2011-05-24 21:33 ` Arun Sharma
2011-05-25 2:44 ` Eric Dumazet [this message]
2011-05-25 6:06 ` Arun Sharma
2011-05-25 6:35 ` Eric Dumazet
2011-05-26 15:06 ` Ben Hutchings
2011-05-26 19:30 ` Arun Sharma
2011-05-26 19:47 ` Eric Dumazet
2011-05-26 21:48 ` Arun Sharma
2011-05-26 22:01 ` Eric Dumazet
2011-05-27 0:09 ` Arun Sharma
2011-05-27 3:27 ` Eric Dumazet
2011-05-27 7:56 ` Yann Dupont
2011-05-27 17:40 ` David Miller
2011-05-27 17:52 ` Arun Sharma
2011-05-27 19:56 ` Eric Dumazet
2011-05-27 21:14 ` Arun Sharma
2011-05-28 5:41 ` Eric Dumazet
2011-05-28 18:04 ` Ingo Molnar
2011-05-29 7:33 ` Eric Dumazet
2011-05-29 7:38 ` Ingo Molnar
2011-05-29 7:43 ` Eric Dumazet
2011-05-29 12:33 ` Ingo Molnar
2011-05-30 18:34 ` Arun Sharma
2011-05-31 10:50 ` Ingo Molnar
2011-07-13 13:38 ` Maximilian Engelhardt
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1306291469.3305.11.camel@edumazet-laptop \
--to=eric.dumazet@gmail.com \
--cc=asharma@fb.com \
--cc=linux-kernel@vger.kernel.org \
--cc=maxi@daemonizer.de \
--cc=netdev@vger.kernel.org \
--cc=vorstand@stusta.mhn.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox