diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2010-03-31 07:06:04 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-04-01 18:38:48 -0700 |
commit | 5d944c640b4ae5f37c537acf491c2f0eb89fa0d6 (patch) | |
tree | 9195a0135ec21c1c06ff4d46e8cf7924e2c364c0 /include/net | |
parent | d4fc6dbb5ae51430e35b2005f6d68938861f8d8b (diff) | |
download | kernel_samsung_smdk4412-5d944c640b4ae5f37c537acf491c2f0eb89fa0d6.zip kernel_samsung_smdk4412-5d944c640b4ae5f37c537acf491c2f0eb89fa0d6.tar.gz kernel_samsung_smdk4412-5d944c640b4ae5f37c537acf491c2f0eb89fa0d6.tar.bz2 |
gen_estimator: deadlock fix
One of my test machine got a deadlock during "tc" sessions,
adding/deleting classes & filters, using traffic estimators.
After some analysis, I believe we have a potential use after free case
in est_timer() :
spin_lock(e->stats_lock); << HERE >>
read_lock(&est_lock);
if (e->bstats == NULL) << TEST >>
goto skip;
Test is done a bit late, because after estimator is killed, and before
rcu grace period elapsed, we might already have freed/reuse memory where
e->stats_locks points to (some qdisc->q.lock)
A possible fix is to respect a rcu grace period at Qdisc dismantle time.
On 64bit, sizeof(struct Qdisc) is exactly 192 bytes. Adding 16 bytes to
it (for struct rcu_head) is a problem because it might change
performance, given QDISC_ALIGNTO is 32 bytes.
This is why I also change QDISC_ALIGNTO to 64 bytes, to satisfy most
current alignment requirements.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include/net')
-rw-r--r-- | include/net/pkt_sched.h | 2 | ||||
-rw-r--r-- | include/net/sch_generic.h | 1 |
2 files changed, 2 insertions, 1 deletions
diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index b6cdc33..9d4d87c 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -12,7 +12,7 @@ struct qdisc_walker { int (*fn)(struct Qdisc *, unsigned long cl, struct qdisc_walker *); }; -#define QDISC_ALIGNTO 32 +#define QDISC_ALIGNTO 64 #define QDISC_ALIGN(len) (((len) + QDISC_ALIGNTO-1) & ~(QDISC_ALIGNTO-1)) static inline void *qdisc_priv(struct Qdisc *q) diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 67dc08e..03ca5d8 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -73,6 +73,7 @@ struct Qdisc { struct sk_buff_head q; struct gnet_stats_basic_packed bstats; struct gnet_stats_queue qstats; + struct rcu_head rcu_head; }; struct Qdisc_class_ops { |