From: Herbert Xu <[EMAIL PROTECTED]> Date: Sat, 08 Apr 2006 13:46:25 +1000
> David S. Miller <[EMAIL PROTECTED]> wrote: > > From: Zach Brown <[EMAIL PROTECTED]> > > Date: Fri, 07 Apr 2006 16:59:01 -0700 > > > >> b) Just calculate the hashes under the lock, we're already doing lots of > >> work there anyway. > > > > I think this is the best way to go. Then we don't need to think > > about it, and frankly I think the "recheck hash rnd after getting > > lock" idea would turn out to be more expensive :) > > Agreed. We should also fix up ip_frag_create/ip_frag_intern by getting > rid of the hash argument and recomputing it in ip_frag_intern. I got tired of waiting for Zach to cook up a patch so I tossed the following into my tree :-) diff-tree 55c0022e53452360064ea264c41410c70565d9f8 (from 19910d1aec0b2b96ff4b4a93e2aed0d32643e850) Author: David S. Miller <[EMAIL PROTECTED]> Date: Sun Apr 9 22:43:55 2006 -0700 [IPV4] ip_fragment: Always compute hash with ipfrag_lock held. Otherwise we could compute an inaccurate hash due to the random seed changing. Noticed by Zach Brown and patch is based upon some feedback from Herbert Xu. Signed-off-by: David S. Miller <[EMAIL PROTECTED]> diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 2a8adda..da734c4 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -304,13 +304,17 @@ out: /* Creation primitives. */ -static struct ipq *ip_frag_intern(unsigned int hash, struct ipq *qp_in) +static struct ipq *ip_frag_intern(struct ipq *qp_in) { struct ipq *qp; #ifdef CONFIG_SMP struct hlist_node *n; #endif + unsigned int hash; + write_lock(&ipfrag_lock); + hash = ipqhashfn(qp_in->id, qp_in->saddr, qp_in->daddr, + qp_in->protocol); #ifdef CONFIG_SMP /* With SMP race we have to recheck hash table, because * such entry could be created on other cpu, while we @@ -345,7 +349,7 @@ #endif } /* Add an entry to the 'ipq' queue for a newly received IP datagram. */ -static struct ipq *ip_frag_create(unsigned hash, struct iphdr *iph, u32 user) +static struct ipq *ip_frag_create(struct iphdr *iph, u32 user) { struct ipq *qp; @@ -371,7 +375,7 @@ static struct ipq *ip_frag_create(unsign spin_lock_init(&qp->lock); atomic_set(&qp->refcnt, 1); - return ip_frag_intern(hash, qp); + return ip_frag_intern(qp); out_nomem: LIMIT_NETDEBUG(KERN_ERR "ip_frag_create: no memory left !\n"); @@ -387,11 +391,12 @@ static inline struct ipq *ip_find(struct __u32 saddr = iph->saddr; __u32 daddr = iph->daddr; __u8 protocol = iph->protocol; - unsigned int hash = ipqhashfn(id, saddr, daddr, protocol); + unsigned int hash; struct ipq *qp; struct hlist_node *n; read_lock(&ipfrag_lock); + hash = ipqhashfn(id, saddr, daddr, protocol); hlist_for_each_entry(qp, n, &ipq_hash[hash], list) { if(qp->id == id && qp->saddr == saddr && @@ -405,7 +410,7 @@ static inline struct ipq *ip_find(struct } read_unlock(&ipfrag_lock); - return ip_frag_create(hash, iph, user); + return ip_frag_create(iph, user); } /* Is the fragment too far ahead to be part of ipq? */ - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html