]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
inet: frags: remove INET_FRAG_EVICTED and use list_evictor for the test
authorNikolay Aleksandrov <nikolay@cumulusnetworks.com>
Thu, 23 Jul 2015 10:05:40 +0000 (12:05 +0200)
committerChuck Anderson <chuck.anderson@oracle.com>
Mon, 12 Dec 2016 01:40:47 +0000 (17:40 -0800)
We can simply remove the INET_FRAG_EVICTED flag to avoid all the flags
race conditions with the evictor and use a participation test for the
evictor list, when we're at that point (after inet_frag_kill) in the
timer there're 2 possible cases:

1. The evictor added the entry to its evictor list while the timer was
waiting for the chainlock
or
2. The timer unchained the entry and the evictor won't see it

In both cases we should be able to see list_evictor correctly due
to the sync on the chainlock.

Joint work with Florian Westphal.

Tested-by: Frank Schreuder <fschreuder@transip.nl>
Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
Orabug: 23633320
(cherry picked from commit caaecdd3d3f8ec0ea9906c54b1dd8ec8316d26b9)
Signed-off-by: Todd Vierling <todd.vierling@oracle.com>
include/net/inet_frag.h
net/ipv4/inet_fragment.c
net/ipv4/ip_fragment.c
net/ipv6/reassembly.c

index a01e38afc82aeb121f6ff1690d6241e6d8600a17..2f3246d1b2b156c340ee687e8fc0e9bd3e252bb0 100644 (file)
@@ -21,13 +21,11 @@ struct netns_frags {
  * @INET_FRAG_FIRST_IN: first fragment has arrived
  * @INET_FRAG_LAST_IN: final fragment has arrived
  * @INET_FRAG_COMPLETE: frag queue has been processed and is due for destruction
- * @INET_FRAG_EVICTED: frag queue is being evicted
  */
 enum {
        INET_FRAG_FIRST_IN      = BIT(0),
        INET_FRAG_LAST_IN       = BIT(1),
        INET_FRAG_COMPLETE      = BIT(2),
-       INET_FRAG_EVICTED       = BIT(3)
 };
 
 /**
@@ -127,6 +125,11 @@ static inline void inet_frag_put(struct inet_frag_queue *q, struct inet_frags *f
                inet_frag_destroy(q, f);
 }
 
+static inline bool inet_frag_evicting(struct inet_frag_queue *q)
+{
+       return !hlist_unhashed(&q->list_evictor);
+}
+
 /* Memory Tracking Functions. */
 
 /* The default percpu_counter batch size is not big enough to scale to
index a00ca4c00c3576e63fae319f4cc3f2e7056bb371..d0a7c0319e3d1b1b73f828717062b6fbbd3be27d 100644 (file)
@@ -140,7 +140,6 @@ inet_evict_bucket(struct inet_frags *f, struct inet_frag_bucket *hb)
                if (!del_timer(&fq->timer))
                        continue;
 
-               fq->flags |= INET_FRAG_EVICTED;
                hlist_add_head(&fq->list_evictor, &expired);
                ++evicted;
        }
index 8b8b41e430f9e89479676ece46e0f5f7e291810f..5b7e53aa1b98540453dd73f5fbdaa2ebfffcc528 100644 (file)
@@ -192,7 +192,7 @@ static void ip_expire(unsigned long arg)
        ipq_kill(qp);
        IP_INC_STATS_BH(net, IPSTATS_MIB_REASMFAILS);
 
-       if (!(qp->q.flags & INET_FRAG_EVICTED)) {
+       if (!inet_frag_evicting(&qp->q)) {
                struct sk_buff *head = qp->q.fragments;
                const struct iphdr *iph;
                int err;
index 5c3bbca6a15047e7627b2a7ebf59bb11827304b9..f1159bb76e0a54fb55a3e8e382a6cb80c7a929f9 100644 (file)
@@ -144,7 +144,7 @@ void ip6_expire_frag_queue(struct net *net, struct frag_queue *fq,
 
        IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
 
-       if (fq->q.flags & INET_FRAG_EVICTED)
+       if (inet_frag_evicting(&fq->q))
                goto out_rcu_unlock;
 
        IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT);