Commit f6f9b93f authored by Jarek Poplawski's avatar Jarek Poplawski Committed by David S. Miller

pkt_sched: Fix gen_estimator locks

While passing a qdisc root lock to gen_new_estimator() and
gen_replace_estimator() dev could be deactivated or even before
grafting proper root qdisc as qdisc_sleeping (e.g. qdisc_create), so
using qdisc_root_lock() is not enough. This patch adds
qdisc_root_sleeping_lock() for this, plus additional checks, where
necessary.
Signed-off-by: default avatarJarek Poplawski <jarkao2@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f7a54c13
...@@ -217,6 +217,14 @@ static inline spinlock_t *qdisc_root_lock(struct Qdisc *qdisc) ...@@ -217,6 +217,14 @@ static inline spinlock_t *qdisc_root_lock(struct Qdisc *qdisc)
return qdisc_lock(root); return qdisc_lock(root);
} }
static inline spinlock_t *qdisc_root_sleeping_lock(struct Qdisc *qdisc)
{
struct Qdisc *root = qdisc_root_sleeping(qdisc);
ASSERT_RTNL();
return qdisc_lock(root);
}
static inline struct net_device *qdisc_dev(struct Qdisc *qdisc) static inline struct net_device *qdisc_dev(struct Qdisc *qdisc)
{ {
return qdisc->dev_queue->dev; return qdisc->dev_queue->dev;
......
...@@ -830,9 +830,16 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue, ...@@ -830,9 +830,16 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue,
sch->stab = stab; sch->stab = stab;
} }
if (tca[TCA_RATE]) { if (tca[TCA_RATE]) {
spinlock_t *root_lock;
if ((sch->parent != TC_H_ROOT) &&
!(sch->flags & TCQ_F_INGRESS))
root_lock = qdisc_root_sleeping_lock(sch);
else
root_lock = qdisc_lock(sch);
err = gen_new_estimator(&sch->bstats, &sch->rate_est, err = gen_new_estimator(&sch->bstats, &sch->rate_est,
qdisc_root_lock(sch), root_lock, tca[TCA_RATE]);
tca[TCA_RATE]);
if (err) { if (err) {
/* /*
* Any broken qdiscs that would require * Any broken qdiscs that would require
...@@ -884,7 +891,8 @@ static int qdisc_change(struct Qdisc *sch, struct nlattr **tca) ...@@ -884,7 +891,8 @@ static int qdisc_change(struct Qdisc *sch, struct nlattr **tca)
if (tca[TCA_RATE]) if (tca[TCA_RATE])
gen_replace_estimator(&sch->bstats, &sch->rate_est, gen_replace_estimator(&sch->bstats, &sch->rate_est,
qdisc_root_lock(sch), tca[TCA_RATE]); qdisc_root_sleeping_lock(sch),
tca[TCA_RATE]);
return 0; return 0;
} }
......
...@@ -1839,7 +1839,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t ...@@ -1839,7 +1839,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
if (tca[TCA_RATE]) if (tca[TCA_RATE])
gen_replace_estimator(&cl->bstats, &cl->rate_est, gen_replace_estimator(&cl->bstats, &cl->rate_est,
qdisc_root_lock(sch), qdisc_root_sleeping_lock(sch),
tca[TCA_RATE]); tca[TCA_RATE]);
return 0; return 0;
} }
...@@ -1930,7 +1930,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t ...@@ -1930,7 +1930,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
if (tca[TCA_RATE]) if (tca[TCA_RATE])
gen_new_estimator(&cl->bstats, &cl->rate_est, gen_new_estimator(&cl->bstats, &cl->rate_est,
qdisc_root_lock(sch), tca[TCA_RATE]); qdisc_root_sleeping_lock(sch), tca[TCA_RATE]);
*arg = (unsigned long)cl; *arg = (unsigned long)cl;
return 0; return 0;
......
...@@ -1045,7 +1045,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, ...@@ -1045,7 +1045,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
if (tca[TCA_RATE]) if (tca[TCA_RATE])
gen_replace_estimator(&cl->bstats, &cl->rate_est, gen_replace_estimator(&cl->bstats, &cl->rate_est,
qdisc_root_lock(sch), qdisc_root_sleeping_lock(sch),
tca[TCA_RATE]); tca[TCA_RATE]);
return 0; return 0;
} }
...@@ -1104,7 +1104,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, ...@@ -1104,7 +1104,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
if (tca[TCA_RATE]) if (tca[TCA_RATE])
gen_new_estimator(&cl->bstats, &cl->rate_est, gen_new_estimator(&cl->bstats, &cl->rate_est,
qdisc_root_lock(sch), tca[TCA_RATE]); qdisc_root_sleeping_lock(sch), tca[TCA_RATE]);
*arg = (unsigned long)cl; *arg = (unsigned long)cl;
return 0; return 0;
} }
......
...@@ -1372,7 +1372,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, ...@@ -1372,7 +1372,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
goto failure; goto failure;
gen_new_estimator(&cl->bstats, &cl->rate_est, gen_new_estimator(&cl->bstats, &cl->rate_est,
qdisc_root_lock(sch), qdisc_root_sleeping_lock(sch),
tca[TCA_RATE] ? : &est.nla); tca[TCA_RATE] ? : &est.nla);
cl->refcnt = 1; cl->refcnt = 1;
cl->children = 0; cl->children = 0;
...@@ -1427,7 +1427,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, ...@@ -1427,7 +1427,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
} else { } else {
if (tca[TCA_RATE]) if (tca[TCA_RATE])
gen_replace_estimator(&cl->bstats, &cl->rate_est, gen_replace_estimator(&cl->bstats, &cl->rate_est,
qdisc_root_lock(sch), qdisc_root_sleeping_lock(sch),
tca[TCA_RATE]); tca[TCA_RATE]);
sch_tree_lock(sch); sch_tree_lock(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