Re: [PATCH 4.14 stable v2 1/5] ipv6: frags: fix a lockdep false positive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Sorry for the late reply.
I am starting the TAHI test on the 4.14 v2 patch today and reply with
results before Mon morning.
The test is long running so we let it run overnight.

On Tue, Apr 23, 2019 at 11:48 AM Peter Oskolkov <posk@xxxxxxxxxx> wrote:
>
> From: Eric Dumazet <edumazet@xxxxxxxxxx>
>
> [ Upstream commit 415787d7799f4fccbe8d49cb0b8e5811be6b0389 ]
>
> 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.
>
> Signed-off-by: Eric Dumazet <edumazet@xxxxxxxxxx>
> Signed-off-by: David S. Miller <davem@xxxxxxxxxxxxx>
> ---
>  net/ipv6/reassembly.c | 23 ++++++++++++-----------
>  1 file changed, 12 insertions(+), 11 deletions(-)
>
> diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
> index 2a8c680b67cd..f75e9e711c31 100644
> --- a/net/ipv6/reassembly.c
> +++ b/net/ipv6/reassembly.c
> @@ -170,7 +170,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;
> @@ -186,11 +187,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, ip6_dst_idev(skb_dst(skb)),
> -                               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;
>         }
>
> @@ -221,10 +218,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, ip6_dst_idev(skb_dst(skb)),
> -                                       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) {
> @@ -536,15 +530,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, ip6_dst_idev(skb_dst(skb)),
> +                                       IPSTATS_MIB_INHDRERRORS);
> +                       icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, prob_offset);
> +               }
>                 return ret;
>         }
>
> --
> 2.21.0.593.g511ec345e18-goog
>



[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux