diff options
Diffstat (limited to 'net/sched')
-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 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 | ||
311 | static 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) | |||
315 | static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr) | 325 | static 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 | ||
562 | static int netem_dump(struct Qdisc *sch, struct sk_buff *skb) | 576 | static int netem_dump(struct Qdisc *sch, struct sk_buff *skb) |