netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH (regression)] Fragments: fix race between inet_frag_find and inet_frag_secret_rebuild
@ 2008-06-24 10:43 Pavel Emelyanov
  2008-06-24 18:07 ` Jarek Poplawski
  0 siblings, 1 reply; 6+ messages in thread
From: Pavel Emelyanov @ 2008-06-24 10:43 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

The problem is that while we work w/o the inet_frags.lock even
read-locked the secret rebuild timer may occur (on another CPU,
since BHs are still disables in the inet_frag_find) and change 
the rnd seed for ipv4/6 fragments.

It was caused by my patch fd9e63544cac30a34c951f0ec958038f0529e244
([INET]: Omit double hash calculations in xxx_frag_intern) late 
in the 2.6.24 kernel, so this should probably be queued to -stable.

Signed-off-by: Pavel Emelyanov <xemul@openvz.org>

---

diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
index 4ed429b..0546a0b 100644
--- a/net/ipv4/inet_fragment.c
+++ b/net/ipv4/inet_fragment.c
@@ -192,14 +192,21 @@ EXPORT_SYMBOL(inet_frag_evictor);
 
 static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf,
 		struct inet_frag_queue *qp_in, struct inet_frags *f,
-		unsigned int hash, void *arg)
+		void *arg)
 {
 	struct inet_frag_queue *qp;
 #ifdef CONFIG_SMP
 	struct hlist_node *n;
 #endif
+	unsigned int hash;
 
 	write_lock(&f->lock);
+	/*
+	 * While we stayed w/o the lock other CPU could update
+	 * the rnd seed, so we need to re-calculate the hash
+	 * chain. Fortunatelly the qp_in can be used to get one.
+	 */
+	hash = f->hashfn(qp_in);
 #ifdef CONFIG_SMP
 	/* With SMP race we have to recheck hash table, because
 	 * such entry could be created on other cpu, while we
@@ -247,7 +254,7 @@ static struct inet_frag_queue *inet_frag_alloc(struct netns_frags *nf,
 }
 
 static struct inet_frag_queue *inet_frag_create(struct netns_frags *nf,
-		struct inet_frags *f, void *arg, unsigned int hash)
+		struct inet_frags *f, void *arg)
 {
 	struct inet_frag_queue *q;
 
@@ -255,7 +262,7 @@ static struct inet_frag_queue *inet_frag_create(struct netns_frags *nf,
 	if (q == NULL)
 		return NULL;
 
-	return inet_frag_intern(nf, q, f, hash, arg);
+	return inet_frag_intern(nf, q, f, arg);
 }
 
 struct inet_frag_queue *inet_frag_find(struct netns_frags *nf,
@@ -264,7 +271,6 @@ struct inet_frag_queue *inet_frag_find(struct netns_frags *nf,
 	struct inet_frag_queue *q;
 	struct hlist_node *n;
 
-	read_lock(&f->lock);
 	hlist_for_each_entry(q, n, &f->hash[hash], list) {
 		if (q->net == nf && f->match(q, key)) {
 			atomic_inc(&q->refcnt);
@@ -274,6 +280,6 @@ struct inet_frag_queue *inet_frag_find(struct netns_frags *nf,
 	}
 	read_unlock(&f->lock);
 
-	return inet_frag_create(nf, f, key, hash);
+	return inet_frag_create(nf, f, key);
 }
 EXPORT_SYMBOL(inet_frag_find);
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index cd6ce6a..37221f6 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -229,6 +229,8 @@ static inline struct ipq *ip_find(struct net *net, struct iphdr *iph, u32 user)
 
 	arg.iph = iph;
 	arg.user = user;
+
+	read_lock(&ip4_frags.lock);
 	hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol);
 
 	q = inet_frag_find(&net->ipv4.frags, &ip4_frags, &arg, hash);
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index e65e26e..cf20bc4 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -207,9 +207,10 @@ fq_find(__be32 id, struct in6_addr *src, struct in6_addr *dst)
 	arg.id = id;
 	arg.src = src;
 	arg.dst = dst;
+
+	read_lock_bh(&nf_frags.lock);
 	hash = ip6qhashfn(id, src, dst);
 
-	local_bh_disable();
 	q = inet_frag_find(&nf_init_frags, &nf_frags, &arg, hash);
 	local_bh_enable();
 	if (q == NULL)
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 798cabc..a60d7d1 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -247,6 +247,8 @@ fq_find(struct net *net, __be32 id, struct in6_addr *src, struct in6_addr *dst,
 	arg.id = id;
 	arg.src = src;
 	arg.dst = dst;
+
+	read_lock(&ip6_frags.lock);
 	hash = ip6qhashfn(id, src, dst);
 
 	q = inet_frag_find(&net->ipv6.frags, &ip6_frags, &arg, hash);

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH (regression)] Fragments: fix race between inet_frag_find and   inet_frag_secret_rebuild
  2008-06-24 10:43 [PATCH (regression)] Fragments: fix race between inet_frag_find and inet_frag_secret_rebuild Pavel Emelyanov
@ 2008-06-24 18:07 ` Jarek Poplawski
  2008-06-25  6:42   ` Pavel Emelyanov
  2008-06-28  3:06   ` David Miller
  0 siblings, 2 replies; 6+ messages in thread
From: Jarek Poplawski @ 2008-06-24 18:07 UTC (permalink / raw)
  To: Pavel Emelyanov; +Cc: David Miller, Linux Netdev List

Pavel Emelyanov wrote, On 06/24/2008 12:43 PM:

> The problem is that while we work w/o the inet_frags.lock even
> read-locked the secret rebuild timer may occur (on another CPU,
- since BHs are still disables in the inet_frag_find) and change 

+ since BHs are still disabled in the inet_frag_find) and change 

> the rnd seed for ipv4/6 fragments.
> 
> It was caused by my patch fd9e63544cac30a34c951f0ec958038f0529e244
> ([INET]: Omit double hash calculations in xxx_frag_intern) late 
> in the 2.6.24 kernel, so this should probably be queued to -stable.
> 
> Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
> 
> ---
> 
> diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
> index 4ed429b..0546a0b 100644
> --- a/net/ipv4/inet_fragment.c
> +++ b/net/ipv4/inet_fragment.c
> @@ -192,14 +192,21 @@ EXPORT_SYMBOL(inet_frag_evictor);
>  
>  static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf,
>  		struct inet_frag_queue *qp_in, struct inet_frags *f,
> -		unsigned int hash, void *arg)
> +		void *arg)
>  {
>  	struct inet_frag_queue *qp;
>  #ifdef CONFIG_SMP
>  	struct hlist_node *n;
>  #endif
> +	unsigned int hash;
>  
>  	write_lock(&f->lock);
> +	/*
> +	 * While we stayed w/o the lock other CPU could update
> +	 * the rnd seed, so we need to re-calculate the hash
> +	 * chain. Fortunatelly the qp_in can be used to get one.
> +	 */
> +	hash = f->hashfn(qp_in);
>  #ifdef CONFIG_SMP
>  	/* With SMP race we have to recheck hash table, because
>  	 * such entry could be created on other cpu, while we

Maybe it's a matter of taste: since there is this "#ifdef CONFIG_SMP",
and the new comment concerns with "other CPU", why this re-calculation
isn't done only for SMP? And, btw., probably __acquires/__releases
annotations could be added with this patch.

Regards,
Jarek P.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH (regression)] Fragments: fix race between inet_frag_find and   inet_frag_secret_rebuild
  2008-06-24 18:07 ` Jarek Poplawski
@ 2008-06-25  6:42   ` Pavel Emelyanov
  2008-06-25  7:09     ` David Miller
  2008-06-25  9:37     ` Jarek Poplawski
  2008-06-28  3:06   ` David Miller
  1 sibling, 2 replies; 6+ messages in thread
From: Pavel Emelyanov @ 2008-06-25  6:42 UTC (permalink / raw)
  To: Jarek Poplawski; +Cc: David Miller, Linux Netdev List

Jarek Poplawski wrote:
> Pavel Emelyanov wrote, On 06/24/2008 12:43 PM:
> 
>> The problem is that while we work w/o the inet_frags.lock even
>> read-locked the secret rebuild timer may occur (on another CPU,
> - since BHs are still disables in the inet_frag_find) and change 
> 
> + since BHs are still disabled in the inet_frag_find) and change 
> 
>> the rnd seed for ipv4/6 fragments.
>>
>> It was caused by my patch fd9e63544cac30a34c951f0ec958038f0529e244
>> ([INET]: Omit double hash calculations in xxx_frag_intern) late 
>> in the 2.6.24 kernel, so this should probably be queued to -stable.
>>
>> Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
>>
>> ---
>>
>> diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
>> index 4ed429b..0546a0b 100644
>> --- a/net/ipv4/inet_fragment.c
>> +++ b/net/ipv4/inet_fragment.c
>> @@ -192,14 +192,21 @@ EXPORT_SYMBOL(inet_frag_evictor);
>>  
>>  static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf,
>>  		struct inet_frag_queue *qp_in, struct inet_frags *f,
>> -		unsigned int hash, void *arg)
>> +		void *arg)
>>  {
>>  	struct inet_frag_queue *qp;
>>  #ifdef CONFIG_SMP
>>  	struct hlist_node *n;
>>  #endif
>> +	unsigned int hash;
>>  
>>  	write_lock(&f->lock);
>> +	/*
>> +	 * While we stayed w/o the lock other CPU could update
>> +	 * the rnd seed, so we need to re-calculate the hash
>> +	 * chain. Fortunatelly the qp_in can be used to get one.
>> +	 */
>> +	hash = f->hashfn(qp_in);
>>  #ifdef CONFIG_SMP
>>  	/* With SMP race we have to recheck hash table, because
>>  	 * such entry could be created on other cpu, while we
> 
> Maybe it's a matter of taste: since there is this "#ifdef CONFIG_SMP",
> and the new comment concerns with "other CPU", why this re-calculation
> isn't done only for SMP? 

Because the hash value is required also *outside* this ifdef and adding
a fancier logic is probably not good for a -rc7 fix.

However, I will re-consider this for net-next.

> And, btw., probably __acquires/__releases annotations could be added
> with this patch.

This is also a net-next material (I hope Dave agrees with me on both).

> Regards,
> Jarek P.
> 


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH (regression)] Fragments: fix race between inet_frag_find and inet_frag_secret_rebuild
  2008-06-25  6:42   ` Pavel Emelyanov
@ 2008-06-25  7:09     ` David Miller
  2008-06-25  9:37     ` Jarek Poplawski
  1 sibling, 0 replies; 6+ messages in thread
From: David Miller @ 2008-06-25  7:09 UTC (permalink / raw)
  To: xemul; +Cc: jarkao2, netdev

From: Pavel Emelyanov <xemul@openvz.org>
Date: Wed, 25 Jun 2008 10:42:56 +0400

> Jarek Poplawski wrote:
> > Maybe it's a matter of taste: since there is this "#ifdef CONFIG_SMP",
> > and the new comment concerns with "other CPU", why this re-calculation
> > isn't done only for SMP? 
> 
> Because the hash value is required also *outside* this ifdef and adding
> a fancier logic is probably not good for a -rc7 fix.
> 
> However, I will re-consider this for net-next.
> 
> > And, btw., probably __acquires/__releases annotations could be added
> > with this patch.
> 
> This is also a net-next material (I hope Dave agrees with me on both).

I do. :-)

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH (regression)] Fragments: fix race between inet_frag_find and   inet_frag_secret_rebuild
  2008-06-25  6:42   ` Pavel Emelyanov
  2008-06-25  7:09     ` David Miller
@ 2008-06-25  9:37     ` Jarek Poplawski
  1 sibling, 0 replies; 6+ messages in thread
From: Jarek Poplawski @ 2008-06-25  9:37 UTC (permalink / raw)
  To: Pavel Emelyanov; +Cc: David Miller, Linux Netdev List

On Wed, Jun 25, 2008 at 10:42:56AM +0400, Pavel Emelyanov wrote:
> Jarek Poplawski wrote:
> > Pavel Emelyanov wrote, On 06/24/2008 12:43 PM:
> > 
> >> The problem is that while we work w/o the inet_frags.lock even
> >> read-locked the secret rebuild timer may occur (on another CPU,
> > - since BHs are still disables in the inet_frag_find) and change 
> > 
> > + since BHs are still disabled in the inet_frag_find) and change 
> > 
> >> the rnd seed for ipv4/6 fragments.
> >>
> >> It was caused by my patch fd9e63544cac30a34c951f0ec958038f0529e244
> >> ([INET]: Omit double hash calculations in xxx_frag_intern) late 
> >> in the 2.6.24 kernel, so this should probably be queued to -stable.
> >>
> >> Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
> >>
> >> ---
> >>
> >> diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
> >> index 4ed429b..0546a0b 100644
> >> --- a/net/ipv4/inet_fragment.c
> >> +++ b/net/ipv4/inet_fragment.c
> >> @@ -192,14 +192,21 @@ EXPORT_SYMBOL(inet_frag_evictor);
> >>  
> >>  static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf,
> >>  		struct inet_frag_queue *qp_in, struct inet_frags *f,
> >> -		unsigned int hash, void *arg)
> >> +		void *arg)
> >>  {
> >>  	struct inet_frag_queue *qp;
> >>  #ifdef CONFIG_SMP
> >>  	struct hlist_node *n;
> >>  #endif
> >> +	unsigned int hash;
> >>  
> >>  	write_lock(&f->lock);
> >> +	/*
> >> +	 * While we stayed w/o the lock other CPU could update
> >> +	 * the rnd seed, so we need to re-calculate the hash
> >> +	 * chain. Fortunatelly the qp_in can be used to get one.
> >> +	 */
> >> +	hash = f->hashfn(qp_in);
> >>  #ifdef CONFIG_SMP
> >>  	/* With SMP race we have to recheck hash table, because
> >>  	 * such entry could be created on other cpu, while we
> > 
> > Maybe it's a matter of taste: since there is this "#ifdef CONFIG_SMP",
> > and the new comment concerns with "other CPU", why this re-calculation
> > isn't done only for SMP? 
> 
> Because the hash value is required also *outside* this ifdef and adding
> a fancier logic is probably not good for a -rc7 fix.

I'm not sure what fancier logic do you mean: I've thought about simply
leaving the "hash" as functions argument as it is, and only adding this
recalculation under #ifdef CONFIG_SMP, but I can miss something...

Jarek P.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH (regression)] Fragments: fix race between inet_frag_find and inet_frag_secret_rebuild
  2008-06-24 18:07 ` Jarek Poplawski
  2008-06-25  6:42   ` Pavel Emelyanov
@ 2008-06-28  3:06   ` David Miller
  1 sibling, 0 replies; 6+ messages in thread
From: David Miller @ 2008-06-28  3:06 UTC (permalink / raw)
  To: jarkao2; +Cc: xemul, netdev

From: Jarek Poplawski <jarkao2@gmail.com>
Date: Tue, 24 Jun 2008 20:07:14 +0200

> Pavel Emelyanov wrote, On 06/24/2008 12:43 PM:
> 
> > The problem is that while we work w/o the inet_frags.lock even
> > read-locked the secret rebuild timer may occur (on another CPU,
> - since BHs are still disables in the inet_frag_find) and change 
> 
> + since BHs are still disabled in the inet_frag_find) and change 

I've applied Pavel's fix with this comment typo cure.

Thanks.

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2008-06-28  3:06 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-06-24 10:43 [PATCH (regression)] Fragments: fix race between inet_frag_find and inet_frag_secret_rebuild Pavel Emelyanov
2008-06-24 18:07 ` Jarek Poplawski
2008-06-25  6:42   ` Pavel Emelyanov
2008-06-25  7:09     ` David Miller
2008-06-25  9:37     ` Jarek Poplawski
2008-06-28  3:06   ` David Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).