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>
This commit is contained in:
committed by
David S. Miller
parent
5f0a6e2d50
commit
bb52c7acf8
@ -488,7 +488,7 @@ static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
s = sizeof(struct disttable) + n * sizeof(s16);
|
s = sizeof(struct disttable) + n * sizeof(s16);
|
||||||
d = kmalloc(s, GFP_KERNEL);
|
d = kmalloc(s, GFP_KERNEL | __GFP_NOWARN);
|
||||||
if (!d)
|
if (!d)
|
||||||
d = vmalloc(s);
|
d = vmalloc(s);
|
||||||
if (!d)
|
if (!d)
|
||||||
@ -501,9 +501,10 @@ static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr)
|
|||||||
root_lock = qdisc_root_sleeping_lock(sch);
|
root_lock = qdisc_root_sleeping_lock(sch);
|
||||||
|
|
||||||
spin_lock_bh(root_lock);
|
spin_lock_bh(root_lock);
|
||||||
dist_free(q->delay_dist);
|
swap(q->delay_dist, d);
|
||||||
q->delay_dist = d;
|
|
||||||
spin_unlock_bh(root_lock);
|
spin_unlock_bh(root_lock);
|
||||||
|
|
||||||
|
dist_free(d);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user