Commit 119b3d38 authored by stephen hemminger's avatar stephen hemminger Committed by David S. Miller

sfq: deadlock in error path

The change to allow divisor to be a parameter (in 2.6.38-rc1)
 commit 817fb15d
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: default avatarStephen Hemminger <shemminger@vyatta.com>
Acked-by: default avatarEric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b299e4f0
...@@ -491,17 +491,18 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt) ...@@ -491,17 +491,18 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt)
if (opt->nla_len < nla_attr_size(sizeof(*ctl))) if (opt->nla_len < nla_attr_size(sizeof(*ctl)))
return -EINVAL; return -EINVAL;
if (ctl->divisor &&
(!is_power_of_2(ctl->divisor) || ctl->divisor > 65536))
return -EINVAL;
sch_tree_lock(sch); sch_tree_lock(sch);
q->quantum = ctl->quantum ? : psched_mtu(qdisc_dev(sch)); q->quantum = ctl->quantum ? : psched_mtu(qdisc_dev(sch));
q->scaled_quantum = SFQ_ALLOT_SIZE(q->quantum); q->scaled_quantum = SFQ_ALLOT_SIZE(q->quantum);
q->perturb_period = ctl->perturb_period * HZ; q->perturb_period = ctl->perturb_period * HZ;
if (ctl->limit) if (ctl->limit)
q->limit = min_t(u32, ctl->limit, SFQ_DEPTH - 1); q->limit = min_t(u32, ctl->limit, SFQ_DEPTH - 1);
if (ctl->divisor) { if (ctl->divisor)
if (!is_power_of_2(ctl->divisor) || ctl->divisor > 65536)
return -EINVAL;
q->divisor = ctl->divisor; q->divisor = ctl->divisor;
}
qlen = sch->q.qlen; qlen = sch->q.qlen;
while (sch->q.qlen > q->limit) while (sch->q.qlen > q->limit)
sfq_drop(sch); sfq_drop(sch);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment