ipv6: frags: fix a lockdep false positive
Subsystems (3)
PATCH 1/1 ipv6: frags: fix a lockdep false positive
lockdep does not know that the locks used by IPv4 defrag and IPv6 reassembly units are of different classes.
It complains because of following chains :
1) sch_direct_xmit() (lock txq->_xmit_lock)
dev_hard_start_xmit()
xmit_one()
dev_queue_xmit_nit()
packet_rcv_fanout()
ip_check_defrag()
ip_defrag()
spin_lock() (lock frag queue spinlock)2) ip6_input_finish()
ipv6_frag_rcv() (lock frag queue spinlock)
ip6_frag_queue()
icmpv6_param_prob() (lock txq->_xmit_lock at some point)We could add lockdep annotations, but we also can make sure IPv6 calls icmpv6_param_prob() only after the release of the frag queue spinlock, since this naturally makes frag queue spinlock a leaf in lock hierarchy.
---
Note do David: I chose net-next because of recent changes in net-next, and because it is a false positive, but can respin for net tree if you prefer. Thanks !
net/ipv6/reassembly.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-)
net/ipv6/reassembly.c +12 -11
@@ -163,7 +163,8 @@ fq_find(struct net *net, __be32 id, const struct ipv6hdr *hdr, int iif) }static int ip6_frag_queue (struct frag_queue *fq,struct sk_buff *skb, -struct frag_hdr *fhdr,int nhoff) +struct frag_hdr *fhdr,int nhoff, +u32 *prob_offset) {struct sk_buff *prev, *next;struct net_device *dev;
@@ -179,11 +180,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, ((u8 *)(fhdr + 1) - (u8 *)(ipv6_hdr(skb) + 1)));if ((unsigned int )end >IPV6_MAXPLEN ) { -__IP6_INC_STATS (net,__in6_dev_get_safely (skb->dev), -IPSTATS_MIB_INHDRERRORS ); -icmpv6_param_prob (skb,ICMPV6_HDR_FIELD , - ((u8 *)&fhdr->frag_off - -skb_network_header (skb))); + *prob_offset = (u8 *)&fhdr->frag_off -skb_network_header (skb);return -1 ; }
@@ -214,10 +211,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,/* RFC2460 says always send parameter problem in * this case. -DaveM */ -__IP6_INC_STATS (net,__in6_dev_get_safely (skb->dev), -IPSTATS_MIB_INHDRERRORS ); -icmpv6_param_prob (skb,ICMPV6_HDR_FIELD , - offsetof(struct ipv6hdr , payload_len)); + *prob_offset = offsetof(struct ipv6hdr , payload_len);return -1 ; }if (end > fq->q.len) {
@@ -519,15 +513,22 @@ static int ipv6_frag_rcv(struct sk_buff *skb) iif = skb->dev ? skb->dev->ifindex :0 ; fq =fq_find (net, fhdr->identification, hdr, iif);if (fq) { +u32 prob_offset =0 ;int ret;spin_lock (&fq->q.lock); fq->iif = iif; - ret =ip6_frag_queue (fq, skb, fhdr,IP6CB (skb)->nhoff); + ret =ip6_frag_queue (fq, skb, fhdr,IP6CB (skb)->nhoff, + &prob_offset);spin_unlock (&fq->q.lock);inet_frag_put (&fq->q); +if (prob_offset) { +__IP6_INC_STATS (net,__in6_dev_get_safely (skb->dev), +IPSTATS_MIB_INHDRERRORS ); +icmpv6_param_prob (skb,ICMPV6_HDR_FIELD , prob_offset); + }return ret; }
Signature · 1 line
2.17.0.484.g0c8726318c-goog
From: Eric Dumazet <[email protected]>
Date: Tue, 17 Apr 2018 18:11:44 -0700
Quoted 23 lines
lockdep does not know that the locks used by IPv4 defrag and IPv6 reassembly units are of different classes.
It complains because of following chains :
1)
sch_direct_xmit()(locktxq->_xmit_lock)dev_hard_start_xmit() xmit_one() dev_queue_xmit_nit() packet_rcv_fanout() ip_check_defrag() ip_defrag() spin_lock() (lock frag queue spinlock)2)
ip6_input_finish()ipv6_frag_rcv() (lock frag queue spinlock) ip6_frag_queue() icmpv6_param_prob() (lock txq->_xmit_lock at some point)We could add lockdep annotations, but we also can make sure IPv6 calls
icmpv6_param_prob()only after the release of the frag queue spinlock, since this naturally makes frag queue spinlock a leaf in lock hierarchy.
Quoted 5 lines
Signed-off-by Eric Dumazet <[email protected]>---
Note do David: I chose net-next because of recent changes in net-next, and because it is a false positive, but can respin for net tree if you prefer. Thanks !
Yeah I think net-next is fine for this.
Applied, thanks.