]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
inet: frag: don't re-use chainlist for evictor
authorFlorian Westphal <fw@strlen.de>
Thu, 23 Jul 2015 10:05:37 +0000 (12:05 +0200)
committerChuck Anderson <chuck.anderson@oracle.com>
Mon, 12 Dec 2016 01:38:40 +0000 (17:38 -0800)
commit 65ba1f1ec0eff ("inet: frags: fix a race between inet_evict_bucket
and inet_frag_kill") describes the bug, but the fix doesn't work reliably.

Problem is that ->flags member can be set on other cpu without chainlock
being held by that task, i.e. the RMW-Cycle can clear INET_FRAG_EVICTED
bit after we put the element on the evictor private list.

We can crash when walking the 'private' evictor list since an element can
be deleted from list underneath the evictor.

Join work with Nikolay Alexandrov.

Fixes: b13d3cbfb8e8 ("inet: frag: move eviction of queues to work queue")
Reported-by: Johan Schuijt <johan@transip.nl>
Tested-by: Frank Schreuder <fschreuder@transip.nl>
Signed-off-by: Nikolay Alexandrov <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 d1fe19444d82e399e38c1594c71b850eca8e9de0)
Signed-off-by: Todd Vierling <todd.vierling@oracle.com>
include/net/inet_frag.h
net/ipv4/inet_fragment.c

index 8d1765577acca21f698813ee8359a39d76680b7e..3242bfdb850d37024c7a9e892f7c1a51151ff98d 100644 (file)
@@ -45,6 +45,7 @@ enum {
  * @flags: fragment queue flags
  * @max_size: (ipv4 only) maximum received fragment size with IP_DF set
  * @net: namespace that this frag belongs to
+ * @list_evictor: list of queues to forcefully evict (e.g. due to low memory)
  */
 struct inet_frag_queue {
        spinlock_t              lock;
@@ -59,6 +60,7 @@ struct inet_frag_queue {
        __u8                    flags;
        u16                     max_size;
        struct netns_frags      *net;
+       struct hlist_node       list_evictor;
 };
 
 #define INETFRAGS_HASHSZ       1024
index 5e346a082e5ff05b58cfebb64917ee26001d809d..172234864fec73801b639d68d1dbe634f3892c43 100644 (file)
@@ -151,14 +151,13 @@ evict_again:
                }
 
                fq->flags |= INET_FRAG_EVICTED;
-               hlist_del(&fq->list);
-               hlist_add_head(&fq->list, &expired);
+               hlist_add_head(&fq->list_evictor, &expired);
                ++evicted;
        }
 
        spin_unlock(&hb->chain_lock);
 
-       hlist_for_each_entry_safe(fq, n, &expired, list)
+       hlist_for_each_entry_safe(fq, n, &expired, list_evictor)
                f->frag_expire((unsigned long) fq);
 
        return evicted;
@@ -284,8 +283,7 @@ static inline void fq_unlink(struct inet_frag_queue *fq, struct inet_frags *f)
        struct inet_frag_bucket *hb;
 
        hb = get_frag_bucket_locked(fq, f);
-       if (!(fq->flags & INET_FRAG_EVICTED))
-               hlist_del(&fq->list);
+       hlist_del(&fq->list);
        spin_unlock(&hb->chain_lock);
 }