* [PATCH net 0/4] inet: ip defrag bug fixes
@ 2015-07-23 10:05 Florian Westphal
2015-07-23 10:05 ` [PATCH net 1/4] inet: frag: don't re-use chainlist for evictor Florian Westphal
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Florian Westphal @ 2015-07-23 10:05 UTC (permalink / raw)
To: netdev; +Cc: Johan Schuijt, Frank Schreuder, Nikolay Aleksandrov
Johan Schuijt and Frank Schreuder reported crash and softlockup after the
inet workqueue eviction change:
general protection fault: 0000 [#1] SMP
CPU: 0 PID: 4 Comm: kworker/0:0 Not tainted 3.18.18-transip-1.5 #1
Workqueue: events inet_frag_worker
task: ffff880224935130 ti: ffff880224938000 task.ti: ffff880224938000
RIP: 0010:[<ffffffff8149288c>] [<ffffffff8149288c>] inet_evict_bucket+0xfc/0x160
RSP: 0018:ffff88022493bd58 EFLAGS: 00010286
RAX: ffff88021f4f3e80 RBX: dead000000100100 RCX: 000000000000006b
RDX: 000000000000006c RSI: ffff88021f4f3e80 RDI: dead0000001000a8
RBP: 0000000000000002 R08: ffff880222273900 R09: ffff880036e49200
R10: ffff8800c6e86500 R11: ffff880036f45500 R12: ffffffff81a87100
R13: ffff88022493bd70 R14: 0000000000000000 R15: ffff8800c9b26280
[..]
Call Trace:
[<ffffffff814929e0>] ? inet_frag_worker+0x60/0x210
[<ffffffff8107e3a2>] ? process_one_work+0x142/0x3b0
[<ffffffff8107eb94>] ? worker_thread+0x114/0x440
[..]
A second issue results in softlockup since the evictor may restart the
eviction loop for a (potentially) unlimited number of times while local
softirqs are disabled.
Frank reports that test system remained stable for 14 hours of testing
(before, crash occured within half an hour in their setup).
Florian Westphal (3):
inet: frag: don't re-use chainlist for evictor
inet: frag: change *_frag_mem_limit functions to take netns_frags as argument
inet: frag: don't wait for timer deletion when evicting
Nikolay Aleksandrov (1):
inet: frags: remove INET_FRAG_EVICTED and use list_evictor for the test
include/net/inet_frag.h | 17 ++++++++-----
net/ieee802154/6lowpan/reassembly.c | 6 ++--
net/ipv4/inet_fragment.c | 40 ++++++++++++--------------------
net/ipv4/ip_fragment.c | 12 ++++-----
net/ipv6/netfilter/nf_conntrack_reasm.c | 6 ++--
net/ipv6/reassembly.c | 8 +++---
6 files changed, 42 insertions(+), 47 deletions(-)
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH net 1/4] inet: frag: don't re-use chainlist for evictor
2015-07-23 10:05 [PATCH net 0/4] inet: ip defrag bug fixes Florian Westphal
@ 2015-07-23 10:05 ` Florian Westphal
2015-07-23 10:05 ` [PATCH net 2/4] inet: frag: change *_frag_mem_limit functions to take netns_frags as argument Florian Westphal
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Florian Westphal @ 2015-07-23 10:05 UTC (permalink / raw)
To: netdev
Cc: Johan Schuijt, Frank Schreuder, Nikolay Aleksandrov,
Florian Westphal
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>
---
include/net/inet_frag.h | 2 ++
net/ipv4/inet_fragment.c | 8 +++-----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h
index e1300b3..56a3a56 100644
--- a/include/net/inet_frag.h
+++ b/include/net/inet_frag.h
@@ -45,6 +45,7 @@ enum {
* @flags: fragment queue flags
* @max_size: maximum received fragment size
* @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
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
index 5e346a0..1722348 100644
--- a/net/ipv4/inet_fragment.c
+++ b/net/ipv4/inet_fragment.c
@@ -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);
}
--
2.0.5
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH net 2/4] inet: frag: change *_frag_mem_limit functions to take netns_frags as argument
2015-07-23 10:05 [PATCH net 0/4] inet: ip defrag bug fixes Florian Westphal
2015-07-23 10:05 ` [PATCH net 1/4] inet: frag: don't re-use chainlist for evictor Florian Westphal
@ 2015-07-23 10:05 ` Florian Westphal
2015-07-23 10:05 ` [PATCH net 3/4] inet: frag: don't wait for timer deletion when evicting Florian Westphal
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Florian Westphal @ 2015-07-23 10:05 UTC (permalink / raw)
To: netdev
Cc: Johan Schuijt, Frank Schreuder, Nikolay Aleksandrov,
Florian Westphal
Followup patch will call it after inet_frag_queue was freed, so q->net
doesn't work anymore (but netf = q->net; free(q); mem_limit(netf) would).
Tested-by: Frank Schreuder <fschreuder@transip.nl>
Signed-off-by: Florian Westphal <fw@strlen.de>
---
include/net/inet_frag.h | 8 ++++----
net/ieee802154/6lowpan/reassembly.c | 6 +++---
net/ipv4/inet_fragment.c | 4 ++--
net/ipv4/ip_fragment.c | 10 +++++-----
net/ipv6/netfilter/nf_conntrack_reasm.c | 6 +++---
net/ipv6/reassembly.c | 6 +++---
6 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h
index 56a3a56..e71ca17 100644
--- a/include/net/inet_frag.h
+++ b/include/net/inet_frag.h
@@ -141,14 +141,14 @@ static inline int frag_mem_limit(struct netns_frags *nf)
return percpu_counter_read(&nf->mem);
}
-static inline void sub_frag_mem_limit(struct inet_frag_queue *q, int i)
+static inline void sub_frag_mem_limit(struct netns_frags *nf, int i)
{
- __percpu_counter_add(&q->net->mem, -i, frag_percpu_counter_batch);
+ __percpu_counter_add(&nf->mem, -i, frag_percpu_counter_batch);
}
-static inline void add_frag_mem_limit(struct inet_frag_queue *q, int i)
+static inline void add_frag_mem_limit(struct netns_frags *nf, int i)
{
- __percpu_counter_add(&q->net->mem, i, frag_percpu_counter_batch);
+ __percpu_counter_add(&nf->mem, i, frag_percpu_counter_batch);
}
static inline void init_frag_mem_limit(struct netns_frags *nf)
diff --git a/net/ieee802154/6lowpan/reassembly.c b/net/ieee802154/6lowpan/reassembly.c
index f46e4d1..214d44a 100644
--- a/net/ieee802154/6lowpan/reassembly.c
+++ b/net/ieee802154/6lowpan/reassembly.c
@@ -207,7 +207,7 @@ found:
} else {
fq->q.meat += skb->len;
}
- add_frag_mem_limit(&fq->q, skb->truesize);
+ add_frag_mem_limit(fq->q.net, skb->truesize);
if (fq->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) &&
fq->q.meat == fq->q.len) {
@@ -287,7 +287,7 @@ static int lowpan_frag_reasm(struct lowpan_frag_queue *fq, struct sk_buff *prev,
clone->data_len = clone->len;
head->data_len -= clone->len;
head->len -= clone->len;
- add_frag_mem_limit(&fq->q, clone->truesize);
+ add_frag_mem_limit(fq->q.net, clone->truesize);
}
WARN_ON(head == NULL);
@@ -310,7 +310,7 @@ static int lowpan_frag_reasm(struct lowpan_frag_queue *fq, struct sk_buff *prev,
}
fp = next;
}
- sub_frag_mem_limit(&fq->q, sum_truesize);
+ sub_frag_mem_limit(fq->q.net, sum_truesize);
head->next = NULL;
head->dev = dev;
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
index 1722348..4473232 100644
--- a/net/ipv4/inet_fragment.c
+++ b/net/ipv4/inet_fragment.c
@@ -328,7 +328,7 @@ void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f)
fp = xp;
}
sum = sum_truesize + f->qsize;
- sub_frag_mem_limit(q, sum);
+ sub_frag_mem_limit(q->net, sum);
if (f->destructor)
f->destructor(q);
@@ -388,7 +388,7 @@ static struct inet_frag_queue *inet_frag_alloc(struct netns_frags *nf,
q->net = nf;
f->constructor(q, arg);
- add_frag_mem_limit(q, f->qsize);
+ add_frag_mem_limit(nf, f->qsize);
setup_timer(&q->timer, f->frag_expire, (unsigned long)q);
spin_lock_init(&q->lock);
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 31f71b1..b4a77d02 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -309,7 +309,7 @@ static int ip_frag_reinit(struct ipq *qp)
kfree_skb(fp);
fp = xp;
} while (fp);
- sub_frag_mem_limit(&qp->q, sum_truesize);
+ sub_frag_mem_limit(qp->q.net, sum_truesize);
qp->q.flags = 0;
qp->q.len = 0;
@@ -455,7 +455,7 @@ found:
qp->q.fragments = next;
qp->q.meat -= free_it->len;
- sub_frag_mem_limit(&qp->q, free_it->truesize);
+ sub_frag_mem_limit(qp->q.net, free_it->truesize);
kfree_skb(free_it);
}
}
@@ -479,7 +479,7 @@ found:
qp->q.stamp = skb->tstamp;
qp->q.meat += skb->len;
qp->ecn |= ecn;
- add_frag_mem_limit(&qp->q, skb->truesize);
+ add_frag_mem_limit(qp->q.net, skb->truesize);
if (offset == 0)
qp->q.flags |= INET_FRAG_FIRST_IN;
@@ -587,7 +587,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
head->len -= clone->len;
clone->csum = 0;
clone->ip_summed = head->ip_summed;
- add_frag_mem_limit(&qp->q, clone->truesize);
+ add_frag_mem_limit(qp->q.net, clone->truesize);
}
skb_push(head, head->data - skb_network_header(head));
@@ -615,7 +615,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
}
fp = next;
}
- sub_frag_mem_limit(&qp->q, sum_truesize);
+ sub_frag_mem_limit(qp->q.net, sum_truesize);
head->next = NULL;
head->dev = dev;
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 6f187c8..6d02498 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -348,7 +348,7 @@ found:
fq->ecn |= ecn;
if (payload_len > fq->q.max_size)
fq->q.max_size = payload_len;
- add_frag_mem_limit(&fq->q, skb->truesize);
+ add_frag_mem_limit(fq->q.net, skb->truesize);
/* The first fragment.
* nhoffset is obtained from the first fragment, of course.
@@ -430,7 +430,7 @@ nf_ct_frag6_reasm(struct frag_queue *fq, struct net_device *dev)
clone->ip_summed = head->ip_summed;
NFCT_FRAG6_CB(clone)->orig = NULL;
- add_frag_mem_limit(&fq->q, clone->truesize);
+ add_frag_mem_limit(fq->q.net, clone->truesize);
}
/* We have to remove fragment header from datagram and to relocate
@@ -454,7 +454,7 @@ nf_ct_frag6_reasm(struct frag_queue *fq, struct net_device *dev)
head->csum = csum_add(head->csum, fp->csum);
head->truesize += fp->truesize;
}
- sub_frag_mem_limit(&fq->q, head->truesize);
+ sub_frag_mem_limit(fq->q.net, head->truesize);
head->ignore_df = 1;
head->next = NULL;
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 8ffa2c8..5c3bbca 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -330,7 +330,7 @@ found:
fq->q.stamp = skb->tstamp;
fq->q.meat += skb->len;
fq->ecn |= ecn;
- add_frag_mem_limit(&fq->q, skb->truesize);
+ add_frag_mem_limit(fq->q.net, skb->truesize);
/* The first fragment.
* nhoffset is obtained from the first fragment, of course.
@@ -443,7 +443,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
head->len -= clone->len;
clone->csum = 0;
clone->ip_summed = head->ip_summed;
- add_frag_mem_limit(&fq->q, clone->truesize);
+ add_frag_mem_limit(fq->q.net, clone->truesize);
}
/* We have to remove fragment header from datagram and to relocate
@@ -481,7 +481,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
}
fp = next;
}
- sub_frag_mem_limit(&fq->q, sum_truesize);
+ sub_frag_mem_limit(fq->q.net, sum_truesize);
head->next = NULL;
head->dev = dev;
--
2.0.5
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH net 3/4] inet: frag: don't wait for timer deletion when evicting
2015-07-23 10:05 [PATCH net 0/4] inet: ip defrag bug fixes Florian Westphal
2015-07-23 10:05 ` [PATCH net 1/4] inet: frag: don't re-use chainlist for evictor Florian Westphal
2015-07-23 10:05 ` [PATCH net 2/4] inet: frag: change *_frag_mem_limit functions to take netns_frags as argument Florian Westphal
@ 2015-07-23 10:05 ` Florian Westphal
2015-07-23 10:05 ` [PATCH net 4/4] inet: frags: remove INET_FRAG_EVICTED and use list_evictor for the test Florian Westphal
2015-07-27 4:00 ` [PATCH net 0/4] inet: ip defrag bug fixes David Miller
4 siblings, 0 replies; 6+ messages in thread
From: Florian Westphal @ 2015-07-23 10:05 UTC (permalink / raw)
To: netdev
Cc: Johan Schuijt, Frank Schreuder, Nikolay Aleksandrov,
Florian Westphal
Frank reports 'NMI watchdog: BUG: soft lockup' errors when
load is high. Instead of (potentially) unbounded restarts of the
eviction process, just skip to the next entry.
One caveat is that, when a netns is exiting, a timer may still be running
by the time inet_evict_bucket returns.
We use the frag memory accounting to wait for outstanding timers,
so that when we free the percpu counter we can be sure no running
timer will trip over it.
Reported-and-tested-by: Frank Schreuder <fschreuder@transip.nl>
Signed-off-by: Florian Westphal <fw@strlen.de>
---
net/ipv4/inet_fragment.c | 29 +++++++++++------------------
1 file changed, 11 insertions(+), 18 deletions(-)
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
index 4473232..a00ca4c 100644
--- a/net/ipv4/inet_fragment.c
+++ b/net/ipv4/inet_fragment.c
@@ -131,24 +131,14 @@ inet_evict_bucket(struct inet_frags *f, struct inet_frag_bucket *hb)
unsigned int evicted = 0;
HLIST_HEAD(expired);
-evict_again:
spin_lock(&hb->chain_lock);
hlist_for_each_entry_safe(fq, n, &hb->chain, list) {
if (!inet_fragq_should_evict(fq))
continue;
- if (!del_timer(&fq->timer)) {
- /* q expiring right now thus increment its refcount so
- * it won't be freed under us and wait until the timer
- * has finished executing then destroy it
- */
- atomic_inc(&fq->refcnt);
- spin_unlock(&hb->chain_lock);
- del_timer_sync(&fq->timer);
- inet_frag_put(fq, f);
- goto evict_again;
- }
+ if (!del_timer(&fq->timer))
+ continue;
fq->flags |= INET_FRAG_EVICTED;
hlist_add_head(&fq->list_evictor, &expired);
@@ -239,18 +229,20 @@ void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f)
int i;
nf->low_thresh = 0;
- local_bh_disable();
evict_again:
+ local_bh_disable();
seq = read_seqbegin(&f->rnd_seqlock);
for (i = 0; i < INETFRAGS_HASHSZ ; i++)
inet_evict_bucket(f, &f->hash[i]);
- if (read_seqretry(&f->rnd_seqlock, seq))
- goto evict_again;
-
local_bh_enable();
+ cond_resched();
+
+ if (read_seqretry(&f->rnd_seqlock, seq) ||
+ percpu_counter_sum(&nf->mem))
+ goto evict_again;
percpu_counter_destroy(&nf->mem);
}
@@ -284,6 +276,7 @@ static inline void fq_unlink(struct inet_frag_queue *fq, struct inet_frags *f)
hb = get_frag_bucket_locked(fq, f);
hlist_del(&fq->list);
+ fq->flags |= INET_FRAG_COMPLETE;
spin_unlock(&hb->chain_lock);
}
@@ -295,7 +288,6 @@ void inet_frag_kill(struct inet_frag_queue *fq, struct inet_frags *f)
if (!(fq->flags & INET_FRAG_COMPLETE)) {
fq_unlink(fq, f);
atomic_dec(&fq->refcnt);
- fq->flags |= INET_FRAG_COMPLETE;
}
}
EXPORT_SYMBOL(inet_frag_kill);
@@ -328,11 +320,12 @@ void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f)
fp = xp;
}
sum = sum_truesize + f->qsize;
- sub_frag_mem_limit(q->net, sum);
if (f->destructor)
f->destructor(q);
kmem_cache_free(f->frags_cachep, q);
+
+ sub_frag_mem_limit(nf, sum);
}
EXPORT_SYMBOL(inet_frag_destroy);
--
2.0.5
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH net 4/4] inet: frags: remove INET_FRAG_EVICTED and use list_evictor for the test
2015-07-23 10:05 [PATCH net 0/4] inet: ip defrag bug fixes Florian Westphal
` (2 preceding siblings ...)
2015-07-23 10:05 ` [PATCH net 3/4] inet: frag: don't wait for timer deletion when evicting Florian Westphal
@ 2015-07-23 10:05 ` Florian Westphal
2015-07-27 4:00 ` [PATCH net 0/4] inet: ip defrag bug fixes David Miller
4 siblings, 0 replies; 6+ messages in thread
From: Florian Westphal @ 2015-07-23 10:05 UTC (permalink / raw)
To: netdev
Cc: Johan Schuijt, Frank Schreuder, Nikolay Aleksandrov,
Florian Westphal
From: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
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>
---
include/net/inet_frag.h | 7 +++++--
net/ipv4/inet_fragment.c | 1 -
net/ipv4/ip_fragment.c | 2 +-
net/ipv6/reassembly.c | 2 +-
4 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h
index e71ca17..53eead2 100644
--- a/include/net/inet_frag.h
+++ b/include/net/inet_frag.h
@@ -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
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
index a00ca4c..d0a7c03 100644
--- a/net/ipv4/inet_fragment.c
+++ b/net/ipv4/inet_fragment.c
@@ -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;
}
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index b4a77d02..921138f 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -202,7 +202,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;
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 5c3bbca..f1159bb 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -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);
--
2.0.5
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH net 0/4] inet: ip defrag bug fixes
2015-07-23 10:05 [PATCH net 0/4] inet: ip defrag bug fixes Florian Westphal
` (3 preceding siblings ...)
2015-07-23 10:05 ` [PATCH net 4/4] inet: frags: remove INET_FRAG_EVICTED and use list_evictor for the test Florian Westphal
@ 2015-07-27 4:00 ` David Miller
4 siblings, 0 replies; 6+ messages in thread
From: David Miller @ 2015-07-27 4:00 UTC (permalink / raw)
To: fw; +Cc: netdev, johan, fschreuder, nikolay
From: Florian Westphal <fw@strlen.de>
Date: Thu, 23 Jul 2015 12:05:36 +0200
> Johan Schuijt and Frank Schreuder reported crash and softlockup after the
> inet workqueue eviction change:
>
> general protection fault: 0000 [#1] SMP
> CPU: 0 PID: 4 Comm: kworker/0:0 Not tainted 3.18.18-transip-1.5 #1
> Workqueue: events inet_frag_worker
> task: ffff880224935130 ti: ffff880224938000 task.ti: ffff880224938000
> RIP: 0010:[<ffffffff8149288c>] [<ffffffff8149288c>] inet_evict_bucket+0xfc/0x160
> RSP: 0018:ffff88022493bd58 EFLAGS: 00010286
> RAX: ffff88021f4f3e80 RBX: dead000000100100 RCX: 000000000000006b
> RDX: 000000000000006c RSI: ffff88021f4f3e80 RDI: dead0000001000a8
> RBP: 0000000000000002 R08: ffff880222273900 R09: ffff880036e49200
> R10: ffff8800c6e86500 R11: ffff880036f45500 R12: ffffffff81a87100
> R13: ffff88022493bd70 R14: 0000000000000000 R15: ffff8800c9b26280
> [..]
> Call Trace:
> [<ffffffff814929e0>] ? inet_frag_worker+0x60/0x210
> [<ffffffff8107e3a2>] ? process_one_work+0x142/0x3b0
> [<ffffffff8107eb94>] ? worker_thread+0x114/0x440
> [..]
>
> A second issue results in softlockup since the evictor may restart the
> eviction loop for a (potentially) unlimited number of times while local
> softirqs are disabled.
>
> Frank reports that test system remained stable for 14 hours of testing
> (before, crash occured within half an hour in their setup).
Looks great, series applied, thanks everyone.
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2015-07-27 4:00 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-07-23 10:05 [PATCH net 0/4] inet: ip defrag bug fixes Florian Westphal
2015-07-23 10:05 ` [PATCH net 1/4] inet: frag: don't re-use chainlist for evictor Florian Westphal
2015-07-23 10:05 ` [PATCH net 2/4] inet: frag: change *_frag_mem_limit functions to take netns_frags as argument Florian Westphal
2015-07-23 10:05 ` [PATCH net 3/4] inet: frag: don't wait for timer deletion when evicting Florian Westphal
2015-07-23 10:05 ` [PATCH net 4/4] inet: frags: remove INET_FRAG_EVICTED and use list_evictor for the test Florian Westphal
2015-07-27 4:00 ` [PATCH net 0/4] inet: ip defrag bug fixes David Miller
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).