aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorstephen hemminger <shemminger@vyatta.com>2011-02-02 10:19:51 -0500
committerDavid S. Miller <davem@davemloft.net>2011-02-02 23:51:20 -0500
commit119b3d386985fcd477b3131190c041516a73f83a (patch)
tree5a21a8c6d46efbbc604d5a1d53aa67c19076d4ab
parentb299e4f001cfa16205f9121f4630970049652268 (diff)
sfq: deadlock in error path
The change to allow divisor to be a parameter (in 2.6.38-rc1) commit 817fb15dfd988d8dda916ee04fa506f0c466b9d6 introduced a possible deadlock caught by sparse. The scheduler tree lock was left locked in the case of an incorrect divisor value. Simplest fix is to move test outside of lock which also solves problem of partial update. Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Acked-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/sched/sch_sfq.c9
1 files changed, 5 insertions, 4 deletions
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 4cff44235773..c2e628dfaacc 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -491,17 +491,18 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt)
491 if (opt->nla_len < nla_attr_size(sizeof(*ctl))) 491 if (opt->nla_len < nla_attr_size(sizeof(*ctl)))
492 return -EINVAL; 492 return -EINVAL;
493 493
494 if (ctl->divisor &&
495 (!is_power_of_2(ctl->divisor) || ctl->divisor > 65536))
496 return -EINVAL;
497
494 sch_tree_lock(sch); 498 sch_tree_lock(sch);
495 q->quantum = ctl->quantum ? : psched_mtu(qdisc_dev(sch)); 499 q->quantum = ctl->quantum ? : psched_mtu(qdisc_dev(sch));
496 q->scaled_quantum = SFQ_ALLOT_SIZE(q->quantum); 500 q->scaled_quantum = SFQ_ALLOT_SIZE(q->quantum);
497 q->perturb_period = ctl->perturb_period * HZ; 501 q->perturb_period = ctl->perturb_period * HZ;
498 if (ctl->limit) 502 if (ctl->limit)
499 q->limit = min_t(u32, ctl->limit, SFQ_DEPTH - 1); 503 q->limit = min_t(u32, ctl->limit, SFQ_DEPTH - 1);
500 if (ctl->divisor) { 504 if (ctl->divisor)
501 if (!is_power_of_2(ctl->divisor) || ctl->divisor > 65536)
502 return -EINVAL;
503 q->divisor = ctl->divisor; 505 q->divisor = ctl->divisor;
504 }
505 qlen = sch->q.qlen; 506 qlen = sch->q.qlen;
506 while (sch->q.qlen > q->limit) 507 while (sch->q.qlen > q->limit)
507 sfq_drop(sch); 508 sfq_drop(sch);