aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorstephen hemminger <shemminger@vyatta.com>2011-02-23 08:04:18 -0500
committerDavid S. Miller <davem@davemloft.net>2011-02-25 01:11:54 -0500
commit6373a9a286bdd955a76924cee88a2f8f784988b1 (patch)
tree9d49a02cbb695c1eeaa7867c649e22c901248447
parent861d7f745f37506bbd90227e97b95baf2a5fac34 (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>
-rw-r--r--net/sched/sch_netem.c22
1 files changed, 18 insertions, 4 deletions
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index d367783f6920..86dad1eee549 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -308,6 +308,16 @@ static void netem_reset(struct Qdisc *sch)
308 qdisc_watchdog_cancel(&q->watchdog); 308 qdisc_watchdog_cancel(&q->watchdog);
309} 309}
310 310
311static void dist_free(struct disttable *d)
312{
313 if (d) {
314 if (is_vmalloc_addr(d))
315 vfree(d);
316 else
317 kfree(d);
318 }
319}
320
311/* 321/*
312 * Distribution data is a variable size payload containing 322 * Distribution data is a variable size payload containing
313 * signed 16 bit values. 323 * signed 16 bit values.
@@ -315,16 +325,20 @@ static void netem_reset(struct Qdisc *sch)
315static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr) 325static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr)
316{ 326{
317 struct netem_sched_data *q = qdisc_priv(sch); 327 struct netem_sched_data *q = qdisc_priv(sch);
318 unsigned long n = nla_len(attr)/sizeof(__s16); 328 size_t n = nla_len(attr)/sizeof(__s16);
319 const __s16 *data = nla_data(attr); 329 const __s16 *data = nla_data(attr);
320 spinlock_t *root_lock; 330 spinlock_t *root_lock;
321 struct disttable *d; 331 struct disttable *d;
322 int i; 332 int i;
333 size_t s;
323 334
324 if (n > 65536) 335 if (n > 65536)
325 return -EINVAL; 336 return -EINVAL;
326 337
327 d = kmalloc(sizeof(*d) + n*sizeof(d->table[0]), GFP_KERNEL); 338 s = sizeof(struct disttable) + n * sizeof(s16);
339 d = kmalloc(s, GFP_KERNEL);
340 if (!d)
341 d = vmalloc(s);
328 if (!d) 342 if (!d)
329 return -ENOMEM; 343 return -ENOMEM;
330 344
@@ -335,7 +349,7 @@ static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr)
335 root_lock = qdisc_root_sleeping_lock(sch); 349 root_lock = qdisc_root_sleeping_lock(sch);
336 350
337 spin_lock_bh(root_lock); 351 spin_lock_bh(root_lock);
338 kfree(q->delay_dist); 352 dist_free(q->delay_dist);
339 q->delay_dist = d; 353 q->delay_dist = d;
340 spin_unlock_bh(root_lock); 354 spin_unlock_bh(root_lock);
341 return 0; 355 return 0;
@@ -556,7 +570,7 @@ static void netem_destroy(struct Qdisc *sch)
556 570
557 qdisc_watchdog_cancel(&q->watchdog); 571 qdisc_watchdog_cancel(&q->watchdog);
558 qdisc_destroy(q->qdisc); 572 qdisc_destroy(q->qdisc);
559 kfree(q->delay_dist); 573 dist_free(q->delay_dist);
560} 574}
561 575
562static int netem_dump(struct Qdisc *sch, struct sk_buff *skb) 576static int netem_dump(struct Qdisc *sch, struct sk_buff *skb)