Commit 71bcb09a authored by Stephen Hemminger's avatar Stephen Hemminger Committed by David S. Miller

tc: check for errors in gen_rate_estimator creation

The functions gen_new_estimator and gen_replace_estimator can return
errors, but they were being ignored.
Signed-off-by: default avatarStephen Hemminger <shemminger@vyatta.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0e991ec6
...@@ -185,14 +185,21 @@ override: ...@@ -185,14 +185,21 @@ override:
if (parm->peakrate.rate) { if (parm->peakrate.rate) {
P_tab = qdisc_get_rtab(&parm->peakrate, P_tab = qdisc_get_rtab(&parm->peakrate,
tb[TCA_POLICE_PEAKRATE]); tb[TCA_POLICE_PEAKRATE]);
if (P_tab == NULL) { if (P_tab == NULL)
qdisc_put_rtab(R_tab);
goto failure; goto failure;
} }
} }
spin_lock_bh(&police->tcf_lock);
if (est) {
err = gen_replace_estimator(&police->tcf_bstats,
&police->tcf_rate_est,
&police->tcf_lock, est);
if (err)
goto failure_unlock;
} }
/* No failure allowed after this point */ /* No failure allowed after this point */
spin_lock_bh(&police->tcf_lock);
if (R_tab != NULL) { if (R_tab != NULL) {
qdisc_put_rtab(police->tcfp_R_tab); qdisc_put_rtab(police->tcfp_R_tab);
police->tcfp_R_tab = R_tab; police->tcfp_R_tab = R_tab;
...@@ -217,10 +224,6 @@ override: ...@@ -217,10 +224,6 @@ override:
if (tb[TCA_POLICE_AVRATE]) if (tb[TCA_POLICE_AVRATE])
police->tcfp_ewma_rate = nla_get_u32(tb[TCA_POLICE_AVRATE]); police->tcfp_ewma_rate = nla_get_u32(tb[TCA_POLICE_AVRATE]);
if (est)
gen_replace_estimator(&police->tcf_bstats,
&police->tcf_rate_est,
&police->tcf_lock, est);
spin_unlock_bh(&police->tcf_lock); spin_unlock_bh(&police->tcf_lock);
if (ret != ACT_P_CREATED) if (ret != ACT_P_CREATED)
...@@ -238,7 +241,13 @@ override: ...@@ -238,7 +241,13 @@ override:
a->priv = police; a->priv = police;
return ret; return ret;
failure_unlock:
spin_unlock_bh(&police->tcf_lock);
failure: failure:
if (P_tab)
qdisc_put_rtab(P_tab);
if (R_tab)
qdisc_put_rtab(R_tab);
if (ret == ACT_P_CREATED) if (ret == ACT_P_CREATED)
kfree(police); kfree(police);
return err; return err;
......
...@@ -880,9 +880,12 @@ static int qdisc_change(struct Qdisc *sch, struct nlattr **tca) ...@@ -880,9 +880,12 @@ static int qdisc_change(struct Qdisc *sch, struct nlattr **tca)
sch->stab = stab; sch->stab = stab;
if (tca[TCA_RATE]) if (tca[TCA_RATE])
/* NB: ignores errors from replace_estimator
because change can't be undone. */
gen_replace_estimator(&sch->bstats, &sch->rate_est, gen_replace_estimator(&sch->bstats, &sch->rate_est,
qdisc_root_sleeping_lock(sch), qdisc_root_sleeping_lock(sch),
tca[TCA_RATE]); tca[TCA_RATE]);
return 0; return 0;
} }
......
...@@ -1765,11 +1765,23 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t ...@@ -1765,11 +1765,23 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
} }
if (tb[TCA_CBQ_RATE]) { if (tb[TCA_CBQ_RATE]) {
rtab = qdisc_get_rtab(nla_data(tb[TCA_CBQ_RATE]), tb[TCA_CBQ_RTAB]); rtab = qdisc_get_rtab(nla_data(tb[TCA_CBQ_RATE]),
tb[TCA_CBQ_RTAB]);
if (rtab == NULL) if (rtab == NULL)
return -EINVAL; return -EINVAL;
} }
if (tca[TCA_RATE]) {
err = gen_replace_estimator(&cl->bstats, &cl->rate_est,
qdisc_root_sleeping_lock(sch),
tca[TCA_RATE]);
if (err) {
if (rtab)
qdisc_put_rtab(rtab);
return err;
}
}
/* Change class parameters */ /* Change class parameters */
sch_tree_lock(sch); sch_tree_lock(sch);
...@@ -1805,10 +1817,6 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t ...@@ -1805,10 +1817,6 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
sch_tree_unlock(sch); sch_tree_unlock(sch);
if (tca[TCA_RATE])
gen_replace_estimator(&cl->bstats, &cl->rate_est,
qdisc_root_sleeping_lock(sch),
tca[TCA_RATE]);
return 0; return 0;
} }
...@@ -1855,6 +1863,17 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t ...@@ -1855,6 +1863,17 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
cl = kzalloc(sizeof(*cl), GFP_KERNEL); cl = kzalloc(sizeof(*cl), GFP_KERNEL);
if (cl == NULL) if (cl == NULL)
goto failure; goto failure;
if (tca[TCA_RATE]) {
err = gen_new_estimator(&cl->bstats, &cl->rate_est,
qdisc_root_sleeping_lock(sch),
tca[TCA_RATE]);
if (err) {
kfree(cl);
goto failure;
}
}
cl->R_tab = rtab; cl->R_tab = rtab;
rtab = NULL; rtab = NULL;
cl->refcnt = 1; cl->refcnt = 1;
...@@ -1896,10 +1915,6 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t ...@@ -1896,10 +1915,6 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
qdisc_class_hash_grow(sch, &q->clhash); qdisc_class_hash_grow(sch, &q->clhash);
if (tca[TCA_RATE])
gen_new_estimator(&cl->bstats, &cl->rate_est,
qdisc_root_sleeping_lock(sch), tca[TCA_RATE]);
*arg = (unsigned long)cl; *arg = (unsigned long)cl;
return 0; return 0;
......
...@@ -82,15 +82,19 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid, ...@@ -82,15 +82,19 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
quantum = psched_mtu(qdisc_dev(sch)); quantum = psched_mtu(qdisc_dev(sch));
if (cl != NULL) { if (cl != NULL) {
if (tca[TCA_RATE]) {
err = gen_replace_estimator(&cl->bstats, &cl->rate_est,
qdisc_root_sleeping_lock(sch),
tca[TCA_RATE]);
if (err)
return err;
}
sch_tree_lock(sch); sch_tree_lock(sch);
if (tb[TCA_DRR_QUANTUM]) if (tb[TCA_DRR_QUANTUM])
cl->quantum = quantum; cl->quantum = quantum;
sch_tree_unlock(sch); sch_tree_unlock(sch);
if (tca[TCA_RATE])
gen_replace_estimator(&cl->bstats, &cl->rate_est,
qdisc_root_sleeping_lock(sch),
tca[TCA_RATE]);
return 0; return 0;
} }
...@@ -106,10 +110,16 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid, ...@@ -106,10 +110,16 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
if (cl->qdisc == NULL) if (cl->qdisc == NULL)
cl->qdisc = &noop_qdisc; cl->qdisc = &noop_qdisc;
if (tca[TCA_RATE]) if (tca[TCA_RATE]) {
gen_replace_estimator(&cl->bstats, &cl->rate_est, err = gen_replace_estimator(&cl->bstats, &cl->rate_est,
qdisc_root_sleeping_lock(sch), qdisc_root_sleeping_lock(sch),
tca[TCA_RATE]); tca[TCA_RATE]);
if (err) {
qdisc_destroy(cl->qdisc);
kfree(cl);
return err;
}
}
sch_tree_lock(sch); sch_tree_lock(sch);
qdisc_class_hash_insert(&q->clhash, &cl->common); qdisc_class_hash_insert(&q->clhash, &cl->common);
......
...@@ -1018,6 +1018,14 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, ...@@ -1018,6 +1018,14 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
} }
cur_time = psched_get_time(); cur_time = psched_get_time();
if (tca[TCA_RATE]) {
err = gen_replace_estimator(&cl->bstats, &cl->rate_est,
qdisc_root_sleeping_lock(sch),
tca[TCA_RATE]);
if (err)
return err;
}
sch_tree_lock(sch); sch_tree_lock(sch);
if (rsc != NULL) if (rsc != NULL)
hfsc_change_rsc(cl, rsc, cur_time); hfsc_change_rsc(cl, rsc, cur_time);
...@@ -1034,10 +1042,6 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, ...@@ -1034,10 +1042,6 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
} }
sch_tree_unlock(sch); sch_tree_unlock(sch);
if (tca[TCA_RATE])
gen_replace_estimator(&cl->bstats, &cl->rate_est,
qdisc_root_sleeping_lock(sch),
tca[TCA_RATE]);
return 0; return 0;
} }
...@@ -1063,6 +1067,16 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, ...@@ -1063,6 +1067,16 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
if (cl == NULL) if (cl == NULL)
return -ENOBUFS; return -ENOBUFS;
if (tca[TCA_RATE]) {
err = gen_new_estimator(&cl->bstats, &cl->rate_est,
qdisc_root_sleeping_lock(sch),
tca[TCA_RATE]);
if (err) {
kfree(cl);
return err;
}
}
if (rsc != NULL) if (rsc != NULL)
hfsc_change_rsc(cl, rsc, 0); hfsc_change_rsc(cl, rsc, 0);
if (fsc != NULL) if (fsc != NULL)
...@@ -1093,9 +1107,6 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, ...@@ -1093,9 +1107,6 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
qdisc_class_hash_grow(sch, &q->clhash); qdisc_class_hash_grow(sch, &q->clhash);
if (tca[TCA_RATE])
gen_new_estimator(&cl->bstats, &cl->rate_est,
qdisc_root_sleeping_lock(sch), tca[TCA_RATE]);
*arg = (unsigned long)cl; *arg = (unsigned long)cl;
return 0; return 0;
} }
......
...@@ -1332,9 +1332,14 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, ...@@ -1332,9 +1332,14 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
if ((cl = kzalloc(sizeof(*cl), GFP_KERNEL)) == NULL) if ((cl = kzalloc(sizeof(*cl), GFP_KERNEL)) == NULL)
goto failure; goto failure;
gen_new_estimator(&cl->bstats, &cl->rate_est, err = gen_new_estimator(&cl->bstats, &cl->rate_est,
qdisc_root_sleeping_lock(sch), qdisc_root_sleeping_lock(sch),
tca[TCA_RATE] ? : &est.nla); tca[TCA_RATE] ? : &est.nla);
if (err) {
kfree(cl);
goto failure;
}
cl->refcnt = 1; cl->refcnt = 1;
cl->children = 0; cl->children = 0;
INIT_LIST_HEAD(&cl->un.leaf.drop_list); INIT_LIST_HEAD(&cl->un.leaf.drop_list);
...@@ -1386,10 +1391,13 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, ...@@ -1386,10 +1391,13 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
if (parent) if (parent)
parent->children++; parent->children++;
} else { } else {
if (tca[TCA_RATE]) if (tca[TCA_RATE]) {
gen_replace_estimator(&cl->bstats, &cl->rate_est, err = gen_replace_estimator(&cl->bstats, &cl->rate_est,
qdisc_root_sleeping_lock(sch), qdisc_root_sleeping_lock(sch),
tca[TCA_RATE]); tca[TCA_RATE]);
if (err)
return err;
}
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