diff options
author | stephen hemminger <shemminger@vyatta.com> | 2011-02-23 13:04:18 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-02-24 22:11:54 -0800 |
commit | 6373a9a286bdd955a76924cee88a2f8f784988b1 (patch) | |
tree | 9d49a02cbb695c1eeaa7867c649e22c901248447 /net/sched/sch_netem.c | |
parent | 861d7f745f37506bbd90227e97b95baf2a5fac34 (diff) |
netem: use vmalloc for distribution table
The netem probability table can be large (up to 64K bytes)
which may be too large to allocate in one contiguous chunk.
Signed-off-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.c | 22 |
1 files changed, 18 insertions, 4 deletions
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index d367783f692..86dad1eee54 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -308,6 +308,16 @@ static void netem_reset(struct Qdisc *sch) qdisc_watchdog_cancel(&q->watchdog); } +static void dist_free(struct disttable *d) +{ + if (d) { + if (is_vmalloc_addr(d)) + vfree(d); + else + kfree(d); + } +} + /* * Distribution data is a variable size payload containing * signed 16 bit values. @@ -315,16 +325,20 @@ static void netem_reset(struct Qdisc *sch) static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr) { struct netem_sched_data *q = qdisc_priv(sch); - unsigned long n = nla_len(attr)/sizeof(__s16); + size_t n = nla_len(attr)/sizeof(__s16); const __s16 *data = nla_data(attr); spinlock_t *root_lock; struct disttable *d; int i; + size_t s; if (n > 65536) return -EINVAL; - d = kmalloc(sizeof(*d) + n*sizeof(d->table[0]), GFP_KERNEL); + s = sizeof(struct disttable) + n * sizeof(s16); + d = kmalloc(s, GFP_KERNEL); + if (!d) + d = vmalloc(s); if (!d) return -ENOMEM; @@ -335,7 +349,7 @@ static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr) root_lock = qdisc_root_sleeping_lock(sch); spin_lock_bh(root_lock); - kfree(q->delay_dist); + dist_free(q->delay_dist); q->delay_dist = d; spin_unlock_bh(root_lock); return 0; @@ -556,7 +570,7 @@ static void netem_destroy(struct Qdisc *sch) qdisc_watchdog_cancel(&q->watchdog); qdisc_destroy(q->qdisc); - kfree(q->delay_dist); + dist_free(q->delay_dist); } static int netem_dump(struct Qdisc *sch, struct sk_buff *skb) |