forked from Minki/linux
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: Jarek Poplawski <jarkao2@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
f7a54c13c7
commit
f6f9b93f16
@ -217,6 +217,14 @@ static inline spinlock_t *qdisc_root_lock(struct Qdisc *qdisc)
|
||||
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)
|
||||
{
|
||||
return qdisc->dev_queue->dev;
|
||||
|
@ -830,9 +830,16 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue,
|
||||
sch->stab = stab;
|
||||
}
|
||||
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,
|
||||
qdisc_root_lock(sch),
|
||||
tca[TCA_RATE]);
|
||||
root_lock, tca[TCA_RATE]);
|
||||
if (err) {
|
||||
/*
|
||||
* Any broken qdiscs that would require
|
||||
@ -884,7 +891,8 @@ static int qdisc_change(struct Qdisc *sch, struct nlattr **tca)
|
||||
|
||||
if (tca[TCA_RATE])
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1839,7 +1839,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
|
||||
|
||||
if (tca[TCA_RATE])
|
||||
gen_replace_estimator(&cl->bstats, &cl->rate_est,
|
||||
qdisc_root_lock(sch),
|
||||
qdisc_root_sleeping_lock(sch),
|
||||
tca[TCA_RATE]);
|
||||
return 0;
|
||||
}
|
||||
@ -1930,7 +1930,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
|
||||
|
||||
if (tca[TCA_RATE])
|
||||
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;
|
||||
return 0;
|
||||
|
@ -1045,7 +1045,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
|
||||
|
||||
if (tca[TCA_RATE])
|
||||
gen_replace_estimator(&cl->bstats, &cl->rate_est,
|
||||
qdisc_root_lock(sch),
|
||||
qdisc_root_sleeping_lock(sch),
|
||||
tca[TCA_RATE]);
|
||||
return 0;
|
||||
}
|
||||
@ -1104,7 +1104,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
|
||||
|
||||
if (tca[TCA_RATE])
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1372,7 +1372,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
|
||||
goto failure;
|
||||
|
||||
gen_new_estimator(&cl->bstats, &cl->rate_est,
|
||||
qdisc_root_lock(sch),
|
||||
qdisc_root_sleeping_lock(sch),
|
||||
tca[TCA_RATE] ? : &est.nla);
|
||||
cl->refcnt = 1;
|
||||
cl->children = 0;
|
||||
@ -1427,7 +1427,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
|
||||
} else {
|
||||
if (tca[TCA_RATE])
|
||||
gen_replace_estimator(&cl->bstats, &cl->rate_est,
|
||||
qdisc_root_lock(sch),
|
||||
qdisc_root_sleeping_lock(sch),
|
||||
tca[TCA_RATE]);
|
||||
sch_tree_lock(sch);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user