aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/sch_netem.c
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2011-12-23 14:28:51 -0500
committerDavid S. Miller <davem@davemloft.net>2011-12-24 16:08:50 -0500
commitbb52c7acf871537a468433775151339f783d2e8c (patch)
treed31943c70571f28ff241234a2bffa765a1d4ef92 /net/sched/sch_netem.c
parent5f0a6e2d503896062f641639dacfe5055c2f593b (diff)
netem: dont call vfree() under spinlock and BH disabled
commit 6373a9a286 (netem: use vmalloc for distribution table) added a regression, since vfree() is called while holding a spinlock and BH being disabled. Fix this by doing the pointers swap in critical section, and freeing after spinlock release. Also add __GFP_NOWARN to the kmalloc() try, since we fallback to vmalloc(). Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Acked-by: Stephen Hemminger <shemminger@vyatta.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched/sch_netem.c')
-rw-r--r--net/sched/sch_netem.c7
1 files changed, 4 insertions, 3 deletions
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index eb3b9a86c6ed..a4ab207cdc59 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -488,7 +488,7 @@ static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr)
488 return -EINVAL; 488 return -EINVAL;
489 489
490 s = sizeof(struct disttable) + n * sizeof(s16); 490 s = sizeof(struct disttable) + n * sizeof(s16);
491 d = kmalloc(s, GFP_KERNEL); 491 d = kmalloc(s, GFP_KERNEL | __GFP_NOWARN);
492 if (!d) 492 if (!d)
493 d = vmalloc(s); 493 d = vmalloc(s);
494 if (!d) 494 if (!d)
@@ -501,9 +501,10 @@ static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr)
501 root_lock = qdisc_root_sleeping_lock(sch); 501 root_lock = qdisc_root_sleeping_lock(sch);
502 502
503 spin_lock_bh(root_lock); 503 spin_lock_bh(root_lock);
504 dist_free(q->delay_dist); 504 swap(q->delay_dist, d);
505 q->delay_dist = d;
506 spin_unlock_bh(root_lock); 505 spin_unlock_bh(root_lock);
506
507 dist_free(d);
507 return 0; 508 return 0;
508} 509}
509 510