netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] tc: check for errors from gen_replace_estimator
@ 2008-11-25 18:16 Stephen Hemminger
  2008-11-25 18:21 ` [PATCH 2/2] tc: policing requires a rate estimator Stephen Hemminger
  2008-11-25 18:28 ` [PATCH 1/2] tc: check for errors from gen_replace_estimator Patrick McHardy
  0 siblings, 2 replies; 18+ messages in thread
From: Stephen Hemminger @ 2008-11-25 18:16 UTC (permalink / raw)
  To: David Miller, Patrick McHardy; +Cc: netdev

gen_replace_estimator can return errors, but they were being ignored.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>


--- a/net/sched/act_police.c	2008-11-25 10:02:05.000000000 -0800
+++ b/net/sched/act_police.c	2008-11-25 10:15:50.000000000 -0800
@@ -185,14 +185,21 @@ override:
 		if (parm->peakrate.rate) {
 			P_tab = qdisc_get_rtab(&parm->peakrate,
 					       tb[TCA_POLICE_PEAKRATE]);
-			if (P_tab == NULL) {
-				qdisc_put_rtab(R_tab);
+			if (P_tab == NULL)
 				goto failure;
-			}
 		}
 	}
-	/* No failure allowed after this point */
+
 	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 */
 	if (R_tab != NULL) {
 		qdisc_put_rtab(police->tcfp_R_tab);
 		police->tcfp_R_tab = R_tab;
@@ -217,10 +224,6 @@ override:
 
 	if (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);
 	if (ret != ACT_P_CREATED)
@@ -238,7 +241,13 @@ override:
 	a->priv = police;
 	return ret;
 
+failure_unlock:
+	spin_unlock_bh(&police->tcf_lock);
 failure:
+	if (P_tab)
+		qdisc_put_rtab(P_tab);
+	if (R_tab)
+		qdisc_put_rtab(R_tab);
 	if (ret == ACT_P_CREATED)
 		kfree(police);
 	return err;
--- a/net/sched/sch_api.c	2008-11-25 10:02:05.000000000 -0800
+++ b/net/sched/sch_api.c	2008-11-25 10:07:21.000000000 -0800
@@ -897,10 +897,10 @@ static int qdisc_change(struct Qdisc *sc
 	sch->stab = stab;
 
 	if (tca[TCA_RATE])
-		gen_replace_estimator(&sch->bstats, &sch->rate_est,
-				      qdisc_root_sleeping_lock(sch),
-				      tca[TCA_RATE]);
-	return 0;
+		err = gen_replace_estimator(&sch->bstats, &sch->rate_est,
+					    qdisc_root_sleeping_lock(sch),
+					    tca[TCA_RATE]);
+	return err;
 }
 
 struct check_loop_arg
--- a/net/sched/sch_cbq.c	2008-11-25 10:02:05.000000000 -0800
+++ b/net/sched/sch_cbq.c	2008-11-25 10:07:21.000000000 -0800
@@ -1806,10 +1806,10 @@ cbq_change_class(struct Qdisc *sch, u32 
 		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;
+			err = gen_replace_estimator(&cl->bstats, &cl->rate_est,
+						    qdisc_root_sleeping_lock(sch),
+						    tca[TCA_RATE]);
+		return err;
 	}
 
 	if (parentid == TC_H_ROOT)
--- a/net/sched/sch_drr.c	2008-11-25 10:02:05.000000000 -0800
+++ b/net/sched/sch_drr.c	2008-11-25 10:07:21.000000000 -0800
@@ -88,10 +88,10 @@ static int drr_change_class(struct Qdisc
 		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;
+			err = gen_replace_estimator(&cl->bstats, &cl->rate_est,
+						    qdisc_root_sleeping_lock(sch),
+						    tca[TCA_RATE]);
+		return err;
 	}
 
 	cl = kzalloc(sizeof(struct drr_class), GFP_KERNEL);
@@ -106,10 +106,15 @@ static int drr_change_class(struct Qdisc
 	if (cl->qdisc == NULL)
 		cl->qdisc = &noop_qdisc;
 
-	if (tca[TCA_RATE])
-		gen_replace_estimator(&cl->bstats, &cl->rate_est,
-				      qdisc_root_sleeping_lock(sch),
-				      tca[TCA_RATE]);
+	if (tca[TCA_RATE]) {
+		err = gen_replace_estimator(&cl->bstats, &cl->rate_est,
+					    qdisc_root_sleeping_lock(sch),
+					    tca[TCA_RATE]);
+		if (err) {
+			kfree(cl);
+			return err;
+		}
+	}
 
 	sch_tree_lock(sch);
 	qdisc_class_hash_insert(&q->clhash, &cl->common);
--- a/net/sched/sch_hfsc.c	2008-11-25 10:02:05.000000000 -0800
+++ b/net/sched/sch_hfsc.c	2008-11-25 10:07:21.000000000 -0800
@@ -1035,10 +1035,10 @@ hfsc_change_class(struct Qdisc *sch, u32
 		sch_tree_unlock(sch);
 
 		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),
 					      tca[TCA_RATE]);
-		return 0;
+		return err;
 	}
 
 	if (parentid == TC_H_ROOT)

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 2/2] tc: policing requires a rate estimator
  2008-11-25 18:16 [PATCH 1/2] tc: check for errors from gen_replace_estimator Stephen Hemminger
@ 2008-11-25 18:21 ` Stephen Hemminger
  2008-11-25 18:32   ` Patrick McHardy
                     ` (2 more replies)
  2008-11-25 18:28 ` [PATCH 1/2] tc: check for errors from gen_replace_estimator Patrick McHardy
  1 sibling, 3 replies; 18+ messages in thread
From: Stephen Hemminger @ 2008-11-25 18:21 UTC (permalink / raw)
  To: David Miller, Patrick McHardy; +Cc: netdev

Found that while trying average rate policing, it was possible to
request average rate policing without a rate estimator. This results
in no policing which is harmless but incorrect.

Since policing could be setup in two steps, need to check
in the kernel.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>


---
 include/net/gen_stats.h  |    1 +
 net/core/gen_estimator.c |   30 +++++++++++++++++++++++++++---
 net/sched/act_police.c   |   16 ++++++++++++----
 3 files changed, 40 insertions(+), 7 deletions(-)

--- a/net/sched/act_police.c	2008-11-25 10:15:50.000000000 -0800
+++ b/net/sched/act_police.c	2008-11-25 10:17:54.000000000 -0800
@@ -182,6 +182,12 @@ override:
 		R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE]);
 		if (R_tab == NULL)
 			goto failure;
+
+		if (!est && !gen_estimator_active(&police->tcf_rate_est)) {
+			err = -EINVAL;
+			goto failure;
+		}
+
 		if (parm->peakrate.rate) {
 			P_tab = qdisc_get_rtab(&parm->peakrate,
 					       tb[TCA_POLICE_PEAKRATE]);
--- a/include/net/gen_stats.h	2008-11-25 10:14:52.000000000 -0800
+++ b/include/net/gen_stats.h	2008-11-25 10:16:52.000000000 -0800
@@ -45,5 +45,6 @@ extern void gen_kill_estimator(struct gn
 extern int gen_replace_estimator(struct gnet_stats_basic *bstats,
 				 struct gnet_stats_rate_est *rate_est,
 				 spinlock_t *stats_lock, struct nlattr *opt);
+extern int gen_estimator_active(const struct gnet_stats_rate_est *rate_est);
 
 #endif
--- a/net/core/gen_estimator.c	2008-11-25 10:14:52.000000000 -0800
+++ b/net/core/gen_estimator.c	2008-11-25 10:16:52.000000000 -0800
@@ -242,6 +242,7 @@ int gen_new_estimator(struct gnet_stats_
 
 	return 0;
 }
+EXPORT_SYMBOL(gen_new_estimator);
 
 static void __gen_kill_estimator(struct rcu_head *head)
 {
@@ -275,6 +276,7 @@ void gen_kill_estimator(struct gnet_stat
 		call_rcu(&e->e_rcu, __gen_kill_estimator);
 	}
 }
+EXPORT_SYMBOL(gen_kill_estimator);
 
 /**
  * gen_replace_estimator - replace rate estimator configuration
@@ -295,8 +297,30 @@ int gen_replace_estimator(struct gnet_st
 	gen_kill_estimator(bstats, rate_est);
 	return gen_new_estimator(bstats, rate_est, stats_lock, opt);
 }
+EXPORT_SYMBOL(gen_replace_estimator);
+
+/**
+ * gen_estimator_active - test if estimator is currently in use
+ * @rate_est: rate estimator statistics
+ *
+ * Returns 1 if estimator is active, and 0 if not.
+ */
+int gen_estimator_active(const struct gnet_stats_rate_est *rate_est)
+{
+	int idx;
+	struct gen_estimator *e;
 
+	ASSERT_RTNL();
 
-EXPORT_SYMBOL(gen_kill_estimator);
-EXPORT_SYMBOL(gen_new_estimator);
-EXPORT_SYMBOL(gen_replace_estimator);
+	for (idx=0; idx <= EST_MAX_INTERVAL; idx++) {
+		if (!elist[idx].timer.function)
+			continue;
+
+		list_for_each_entry(e, &elist[idx].list, list) {
+			if (e->rate_est == rate_est)
+				return 1;
+		}
+	}
+	return 0;
+}
+EXPORT_SYMBOL(gen_estimator_active);

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1/2] tc: check for errors from gen_replace_estimator
  2008-11-25 18:16 [PATCH 1/2] tc: check for errors from gen_replace_estimator Stephen Hemminger
  2008-11-25 18:21 ` [PATCH 2/2] tc: policing requires a rate estimator Stephen Hemminger
@ 2008-11-25 18:28 ` Patrick McHardy
  2008-11-25 18:57   ` [PATCH 1a/2] tc: propogate errors from tcf_hash_create Stephen Hemminger
  2008-11-25 18:58   ` [PATCH 1b/2] tc: check for errors in gen_rate_estimator creation Stephen Hemminger
  1 sibling, 2 replies; 18+ messages in thread
From: Patrick McHardy @ 2008-11-25 18:28 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: David Miller, netdev

Stephen Hemminger wrote:
> gen_replace_estimator can return errors, but they were being ignored.
> 
> --- a/net/sched/sch_hfsc.c	2008-11-25 10:02:05.000000000 -0800
> +++ b/net/sched/sch_hfsc.c	2008-11-25 10:07:21.000000000 -0800
> @@ -1035,10 +1035,10 @@ hfsc_change_class(struct Qdisc *sch, u32
>  		sch_tree_unlock(sch);
>  
>  		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),
>  					      tca[TCA_RATE]);
> -		return 0;
> +		return err;

At this point we've already made changes to the class, so
returning an error without undoing them is wrong.

I'd suggest to move the estimator replacement up a bit, the
other changes can't fail.

There's also gen_new_estimator() that should be treated
similary for consistency.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/2] tc: policing requires a rate estimator
  2008-11-25 18:21 ` [PATCH 2/2] tc: policing requires a rate estimator Stephen Hemminger
@ 2008-11-25 18:32   ` Patrick McHardy
  2008-11-25 18:33     ` Stephen Hemminger
  2008-11-26  5:14   ` David Miller
  2008-11-26 11:10   ` [PATCH] pkt_sched: gen_estimator: Optimize gen_estimator_active() Jarek Poplawski
  2 siblings, 1 reply; 18+ messages in thread
From: Patrick McHardy @ 2008-11-25 18:32 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: David Miller, netdev

Stephen Hemminger wrote:
> Found that while trying average rate policing, it was possible to
> request average rate policing without a rate estimator. This results
> in no policing which is harmless but incorrect.
> 
> Since policing could be setup in two steps, need to check
> in the kernel.
> 
> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
> 
> 
> ---
>  include/net/gen_stats.h  |    1 +
>  net/core/gen_estimator.c |   30 +++++++++++++++++++++++++++---
>  net/sched/act_police.c   |   16 ++++++++++++----
>  3 files changed, 40 insertions(+), 7 deletions(-)
> 
> --- a/net/sched/act_police.c	2008-11-25 10:15:50.000000000 -0800
> +++ b/net/sched/act_police.c	2008-11-25 10:17:54.000000000 -0800
> @@ -182,6 +182,12 @@ override:
>  		R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE]);
>  		if (R_tab == NULL)
>  			goto failure;
> +
> +		if (!est && !gen_estimator_active(&police->tcf_rate_est)) {
> +			err = -EINVAL;
> +			goto failure;

This leaks the R_tab reference.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/2] tc: policing requires a rate estimator
  2008-11-25 18:32   ` Patrick McHardy
@ 2008-11-25 18:33     ` Stephen Hemminger
  2008-11-25 18:38       ` Patrick McHardy
  0 siblings, 1 reply; 18+ messages in thread
From: Stephen Hemminger @ 2008-11-25 18:33 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: David Miller, netdev

On Tue, 25 Nov 2008 19:32:13 +0100
Patrick McHardy <kaber@trash.net> wrote:

> Stephen Hemminger wrote:
> > Found that while trying average rate policing, it was possible to
> > request average rate policing without a rate estimator. This results
> > in no policing which is harmless but incorrect.
> > 
> > Since policing could be setup in two steps, need to check
> > in the kernel.
> > 
> > Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
> > 
> > 
> > ---
> >  include/net/gen_stats.h  |    1 +
> >  net/core/gen_estimator.c |   30 +++++++++++++++++++++++++++---
> >  net/sched/act_police.c   |   16 ++++++++++++----
> >  3 files changed, 40 insertions(+), 7 deletions(-)
> > 
> > --- a/net/sched/act_police.c	2008-11-25 10:15:50.000000000 -0800
> > +++ b/net/sched/act_police.c	2008-11-25 10:17:54.000000000 -0800
> > @@ -182,6 +182,12 @@ override:
> >  		R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE]);
> >  		if (R_tab == NULL)
> >  			goto failure;
> > +
> > +		if (!est && !gen_estimator_active(&police->tcf_rate_est)) {
> > +			err = -EINVAL;
> > +			goto failure;
> 
> This leaks the R_tab reference.

The previous patch added a put at the failure: tag.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/2] tc: policing requires a rate estimator
  2008-11-25 18:33     ` Stephen Hemminger
@ 2008-11-25 18:38       ` Patrick McHardy
  0 siblings, 0 replies; 18+ messages in thread
From: Patrick McHardy @ 2008-11-25 18:38 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: David Miller, netdev

Stephen Hemminger wrote:
> On Tue, 25 Nov 2008 19:32:13 +0100
> Patrick McHardy <kaber@trash.net> wrote:
> 
>>>
>>> --- a/net/sched/act_police.c	2008-11-25 10:15:50.000000000 -0800
>>> +++ b/net/sched/act_police.c	2008-11-25 10:17:54.000000000 -0800
>>> @@ -182,6 +182,12 @@ override:
>>>  		R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE]);
>>>  		if (R_tab == NULL)
>>>  			goto failure;
>>> +
>>> +		if (!est && !gen_estimator_active(&police->tcf_rate_est)) {
>>> +			err = -EINVAL;
>>> +			goto failure;
>> This leaks the R_tab reference.
> 
> The previous patch added a put at the failure: tag.

I missed that, sorry.


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 1a/2] tc: propogate errors from tcf_hash_create
  2008-11-25 18:28 ` [PATCH 1/2] tc: check for errors from gen_replace_estimator Patrick McHardy
@ 2008-11-25 18:57   ` Stephen Hemminger
  2008-11-26  5:12     ` David Miller
  2008-11-25 18:58   ` [PATCH 1b/2] tc: check for errors in gen_rate_estimator creation Stephen Hemminger
  1 sibling, 1 reply; 18+ messages in thread
From: Stephen Hemminger @ 2008-11-25 18:57 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: David Miller, netdev

Allow tcf_hash_create to return different errors on estimator failure.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>

---
 net/sched/act_api.c     |   18 +++++++++++++-----
 net/sched/act_gact.c    |    4 ++--
 net/sched/act_ipt.c     |    4 ++--
 net/sched/act_mirred.c  |    4 ++--
 net/sched/act_nat.c     |    4 ++--
 net/sched/act_pedit.c   |    4 ++--
 net/sched/act_simple.c  |    4 ++--
 net/sched/act_skbedit.c |    4 ++--
 8 files changed, 27 insertions(+), 19 deletions(-)

--- a/net/sched/act_api.c	2008-11-25 10:47:48.000000000 -0800
+++ b/net/sched/act_api.c	2008-11-25 10:50:56.000000000 -0800
@@ -214,12 +214,14 @@ struct tcf_common *tcf_hash_check(u32 in
 }
 EXPORT_SYMBOL(tcf_hash_check);
 
-struct tcf_common *tcf_hash_create(u32 index, struct nlattr *est, struct tc_action *a, int size, int bind, u32 *idx_gen, struct tcf_hashinfo *hinfo)
+struct tcf_common *tcf_hash_create(u32 index, struct nlattr *est,
+				   struct tc_action *a, int size, int bind,
+				   u32 *idx_gen, struct tcf_hashinfo *hinfo)
 {
 	struct tcf_common *p = kzalloc(size, GFP_KERNEL);
 
 	if (unlikely(!p))
-		return p;
+		return ERR_PTR(-ENOMEM);
 	p->tcfc_refcnt = 1;
 	if (bind)
 		p->tcfc_bindcnt = 1;
@@ -228,9 +230,15 @@ struct tcf_common *tcf_hash_create(u32 i
 	p->tcfc_index = index ? index : tcf_hash_new_index(idx_gen, hinfo);
 	p->tcfc_tm.install = jiffies;
 	p->tcfc_tm.lastuse = jiffies;
-	if (est)
-		gen_new_estimator(&p->tcfc_bstats, &p->tcfc_rate_est,
-				  &p->tcfc_lock, est);
+	if (est) {
+		int err = gen_new_estimator(&p->tcfc_bstats, &p->tcfc_rate_est,
+					    &p->tcfc_lock, est);
+		if (err) {
+			kfree(p);
+			return ERR_PTR(err);
+		}
+	}
+
 	a->priv = (void *) p;
 	return p;
 }
--- a/net/sched/act_gact.c	2008-11-25 10:47:48.000000000 -0800
+++ b/net/sched/act_gact.c	2008-11-25 10:52:19.000000000 -0800
@@ -88,8 +88,8 @@ static int tcf_gact_init(struct nlattr *
 	if (!pc) {
 		pc = tcf_hash_create(parm->index, est, a, sizeof(*gact),
 				     bind, &gact_idx_gen, &gact_hash_info);
-		if (unlikely(!pc))
-			return -ENOMEM;
+		if (IS_ERR(pc))
+		    return PTR_ERR(pc);
 		ret = ACT_P_CREATED;
 	} else {
 		if (!ovr) {
--- a/net/sched/act_ipt.c	2008-11-25 10:47:48.000000000 -0800
+++ b/net/sched/act_ipt.c	2008-11-25 10:52:31.000000000 -0800
@@ -136,8 +136,8 @@ static int tcf_ipt_init(struct nlattr *n
 	if (!pc) {
 		pc = tcf_hash_create(index, est, a, sizeof(*ipt), bind,
 				     &ipt_idx_gen, &ipt_hash_info);
-		if (unlikely(!pc))
-			return -ENOMEM;
+		if (IS_ERR(pc))
+		    return PTR_ERR(pc);
 		ret = ACT_P_CREATED;
 	} else {
 		if (!ovr) {
--- a/net/sched/act_mirred.c	2008-11-25 10:47:48.000000000 -0800
+++ b/net/sched/act_mirred.c	2008-11-25 10:52:25.000000000 -0800
@@ -105,8 +105,8 @@ static int tcf_mirred_init(struct nlattr
 			return -EINVAL;
 		pc = tcf_hash_create(parm->index, est, a, sizeof(*m), bind,
 				     &mirred_idx_gen, &mirred_hash_info);
-		if (unlikely(!pc))
-			return -ENOMEM;
+		if (IS_ERR(pc))
+		    return PTR_ERR(pc);
 		ret = ACT_P_CREATED;
 	} else {
 		if (!ovr) {
--- a/net/sched/act_nat.c	2008-11-25 10:47:48.000000000 -0800
+++ b/net/sched/act_nat.c	2008-11-25 10:52:37.000000000 -0800
@@ -68,8 +68,8 @@ static int tcf_nat_init(struct nlattr *n
 	if (!pc) {
 		pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind,
 				     &nat_idx_gen, &nat_hash_info);
-		if (unlikely(!pc))
-			return -ENOMEM;
+		if (IS_ERR(pc))
+		    return PTR_ERR(pc);
 		p = to_tcf_nat(pc);
 		ret = ACT_P_CREATED;
 	} else {
--- a/net/sched/act_pedit.c	2008-11-25 10:47:48.000000000 -0800
+++ b/net/sched/act_pedit.c	2008-11-25 10:52:44.000000000 -0800
@@ -68,8 +68,8 @@ static int tcf_pedit_init(struct nlattr 
 			return -EINVAL;
 		pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind,
 				     &pedit_idx_gen, &pedit_hash_info);
-		if (unlikely(!pc))
-			return -ENOMEM;
+		if (IS_ERR(pc))
+		    return PTR_ERR(pc);
 		p = to_pedit(pc);
 		keys = kmalloc(ksize, GFP_KERNEL);
 		if (keys == NULL) {
--- a/net/sched/act_simple.c	2008-11-25 10:47:48.000000000 -0800
+++ b/net/sched/act_simple.c	2008-11-25 10:52:51.000000000 -0800
@@ -124,8 +124,8 @@ static int tcf_simp_init(struct nlattr *
 	if (!pc) {
 		pc = tcf_hash_create(parm->index, est, a, sizeof(*d), bind,
 				     &simp_idx_gen, &simp_hash_info);
-		if (unlikely(!pc))
-			return -ENOMEM;
+		if (IS_ERR(pc))
+		    return PTR_ERR(pc);
 
 		d = to_defact(pc);
 		ret = alloc_defdata(d, defdata);
--- a/net/sched/act_skbedit.c	2008-11-25 10:47:48.000000000 -0800
+++ b/net/sched/act_skbedit.c	2008-11-25 10:53:11.000000000 -0800
@@ -104,8 +104,8 @@ static int tcf_skbedit_init(struct nlatt
 	if (!pc) {
 		pc = tcf_hash_create(parm->index, est, a, sizeof(*d), bind,
 				     &skbedit_idx_gen, &skbedit_hash_info);
-		if (unlikely(!pc))
-			return -ENOMEM;
+		if (IS_ERR(pc))
+		    return PTR_ERR(pc);
 
 		d = to_skbedit(pc);
 		ret = ACT_P_CREATED;

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 1b/2] tc: check for errors in gen_rate_estimator creation
  2008-11-25 18:28 ` [PATCH 1/2] tc: check for errors from gen_replace_estimator Patrick McHardy
  2008-11-25 18:57   ` [PATCH 1a/2] tc: propogate errors from tcf_hash_create Stephen Hemminger
@ 2008-11-25 18:58   ` Stephen Hemminger
  2008-11-25 19:05     ` Patrick McHardy
  1 sibling, 1 reply; 18+ messages in thread
From: Stephen Hemminger @ 2008-11-25 18:58 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: David Miller, netdev

The functions gen_new_estimator and gen_replace_estimator can return errors,
but they were being ignored.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>


---
 net/sched/act_police.c |   25 +++++++++++++++++--------
 net/sched/sch_api.c    |   12 ++++++++----
 net/sched/sch_cbq.c    |   33 ++++++++++++++++++++++++---------
 net/sched/sch_drr.c    |   26 ++++++++++++++++++--------
 net/sched/sch_hfsc.c   |   12 ++++++++----
 net/sched/sch_htb.c    |   22 +++++++++++++++-------
 6 files changed, 90 insertions(+), 40 deletions(-)

--- a/net/sched/act_police.c	2008-11-25 10:51:47.000000000 -0800
+++ b/net/sched/act_police.c	2008-11-25 10:54:16.000000000 -0800
@@ -185,14 +185,21 @@ override:
 		if (parm->peakrate.rate) {
 			P_tab = qdisc_get_rtab(&parm->peakrate,
 					       tb[TCA_POLICE_PEAKRATE]);
-			if (P_tab == NULL) {
-				qdisc_put_rtab(R_tab);
+			if (P_tab == NULL)
 				goto failure;
-			}
 		}
 	}
-	/* No failure allowed after this point */
+
 	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 */
 	if (R_tab != NULL) {
 		qdisc_put_rtab(police->tcfp_R_tab);
 		police->tcfp_R_tab = R_tab;
@@ -217,10 +224,6 @@ override:
 
 	if (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);
 	if (ret != ACT_P_CREATED)
@@ -238,7 +241,13 @@ override:
 	a->priv = police;
 	return ret;
 
+failure_unlock:
+	spin_unlock_bh(&police->tcf_lock);
 failure:
+	if (P_tab)
+		qdisc_put_rtab(P_tab);
+	if (R_tab)
+		qdisc_put_rtab(R_tab);
 	if (ret == ACT_P_CREATED)
 		kfree(police);
 	return err;
--- a/net/sched/sch_api.c	2008-11-25 10:51:47.000000000 -0800
+++ b/net/sched/sch_api.c	2008-11-25 10:54:16.000000000 -0800
@@ -887,6 +887,14 @@ static int qdisc_change(struct Qdisc *sc
 			return err;
 	}
 
+	if (tca[TCA_RATE]) {
+		err = gen_replace_estimator(&sch->bstats, &sch->rate_est,
+					    qdisc_root_sleeping_lock(sch),
+					    tca[TCA_RATE]);
+		if (err)
+			return err;
+	}
+
 	if (tca[TCA_STAB]) {
 		stab = qdisc_get_stab(tca[TCA_STAB]);
 		if (IS_ERR(stab))
@@ -896,10 +904,6 @@ static int qdisc_change(struct Qdisc *sc
 	qdisc_put_stab(sch->stab);
 	sch->stab = stab;
 
-	if (tca[TCA_RATE])
-		gen_replace_estimator(&sch->bstats, &sch->rate_est,
-				      qdisc_root_sleeping_lock(sch),
-				      tca[TCA_RATE]);
 	return 0;
 }
 
--- a/net/sched/sch_cbq.c	2008-11-25 10:51:47.000000000 -0800
+++ b/net/sched/sch_cbq.c	2008-11-25 10:56:15.000000000 -0800
@@ -1765,11 +1765,23 @@ cbq_change_class(struct Qdisc *sch, u32 
 		}
 
 		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)
 				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 */
 		sch_tree_lock(sch);
 
@@ -1805,10 +1817,6 @@ cbq_change_class(struct Qdisc *sch, u32 
 
 		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;
 	}
 
@@ -1855,6 +1863,17 @@ cbq_change_class(struct Qdisc *sch, u32 
 	cl = kzalloc(sizeof(*cl), GFP_KERNEL);
 	if (cl == NULL)
 		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;
 	rtab = NULL;
 	cl->refcnt = 1;
@@ -1896,10 +1915,6 @@ cbq_change_class(struct Qdisc *sch, u32 
 
 	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;
 	return 0;
 
--- a/net/sched/sch_drr.c	2008-11-25 10:51:47.000000000 -0800
+++ b/net/sched/sch_drr.c	2008-11-25 10:54:16.000000000 -0800
@@ -82,15 +82,19 @@ static int drr_change_class(struct Qdisc
 		quantum = psched_mtu(qdisc_dev(sch));
 
 	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);
 		if (tb[TCA_DRR_QUANTUM])
 			cl->quantum = quantum;
 		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;
 	}
 
@@ -106,10 +110,16 @@ static int drr_change_class(struct Qdisc
 	if (cl->qdisc == NULL)
 		cl->qdisc = &noop_qdisc;
 
-	if (tca[TCA_RATE])
-		gen_replace_estimator(&cl->bstats, &cl->rate_est,
-				      qdisc_root_sleeping_lock(sch),
-				      tca[TCA_RATE]);
+	if (tca[TCA_RATE]) {
+		err = gen_replace_estimator(&cl->bstats, &cl->rate_est,
+					    qdisc_root_sleeping_lock(sch),
+					    tca[TCA_RATE]);
+		if (err) {
+			qdisc_destroy(cl->qdisc);
+			kfree(cl);
+			return err;
+		}
+	}
 
 	sch_tree_lock(sch);
 	qdisc_class_hash_insert(&q->clhash, &cl->common);
--- a/net/sched/sch_hfsc.c	2008-11-25 10:51:47.000000000 -0800
+++ b/net/sched/sch_hfsc.c	2008-11-25 10:54:16.000000000 -0800
@@ -1018,6 +1018,14 @@ hfsc_change_class(struct Qdisc *sch, u32
 		}
 		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);
 		if (rsc != NULL)
 			hfsc_change_rsc(cl, rsc, cur_time);
@@ -1034,10 +1042,6 @@ hfsc_change_class(struct Qdisc *sch, u32
 		}
 		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;
 	}
 
--- a/net/sched/sch_htb.c	2008-11-25 10:51:47.000000000 -0800
+++ b/net/sched/sch_htb.c	2008-11-25 10:54:16.000000000 -0800
@@ -1332,9 +1332,14 @@ static int htb_change_class(struct Qdisc
 		if ((cl = kzalloc(sizeof(*cl), GFP_KERNEL)) == NULL)
 			goto failure;
 
-		gen_new_estimator(&cl->bstats, &cl->rate_est,
-				  qdisc_root_sleeping_lock(sch),
-				  tca[TCA_RATE] ? : &est.nla);
+		err = gen_new_estimator(&cl->bstats, &cl->rate_est,
+					qdisc_root_sleeping_lock(sch),
+					tca[TCA_RATE] ? : &est.nla);
+		if (err) {
+			kfree(cl);
+			goto failure;
+		}
+
 		cl->refcnt = 1;
 		cl->children = 0;
 		INIT_LIST_HEAD(&cl->un.leaf.drop_list);
@@ -1386,10 +1391,13 @@ static int htb_change_class(struct Qdisc
 		if (parent)
 			parent->children++;
 	} else {
-		if (tca[TCA_RATE])
-			gen_replace_estimator(&cl->bstats, &cl->rate_est,
-					      qdisc_root_sleeping_lock(sch),
-					      tca[TCA_RATE]);
+		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);
 	}
 

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1b/2] tc: check for errors in gen_rate_estimator creation
  2008-11-25 18:58   ` [PATCH 1b/2] tc: check for errors in gen_rate_estimator creation Stephen Hemminger
@ 2008-11-25 19:05     ` Patrick McHardy
  2008-11-25 19:14       ` Stephen Hemminger
  0 siblings, 1 reply; 18+ messages in thread
From: Patrick McHardy @ 2008-11-25 19:05 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: David Miller, netdev

Stephen Hemminger wrote:
> The functions gen_new_estimator and gen_replace_estimator can return errors,
> but they were being ignored.
> 
> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
> 
> 
> ---
> --- a/net/sched/sch_api.c	2008-11-25 10:51:47.000000000 -0800
> +++ b/net/sched/sch_api.c	2008-11-25 10:54:16.000000000 -0800
> @@ -887,6 +887,14 @@ static int qdisc_change(struct Qdisc *sc
>  			return err;
>  	}
>  
> +	if (tca[TCA_RATE]) {
> +		err = gen_replace_estimator(&sch->bstats, &sch->rate_est,
> +					    qdisc_root_sleeping_lock(sch),
> +					    tca[TCA_RATE]);
> +		if (err)
> +			return err;

This appears to have the same problem as in HFSC unless I missed more
code movement - changes to the qdisc have already been performed.

> --- a/net/sched/sch_hfsc.c	2008-11-25 10:51:47.000000000 -0800
> +++ b/net/sched/sch_hfsc.c	2008-11-25 10:54:16.000000000 -0800
> @@ -1018,6 +1018,14 @@ hfsc_change_class(struct Qdisc *sch, u32
>  		}
>  		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);
>  		if (rsc != NULL)
>  			hfsc_change_rsc(cl, rsc, cur_time);
> @@ -1034,10 +1042,6 @@ hfsc_change_class(struct Qdisc *sch, u32
>  		}
>  		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;
>  	}

There's a gen_new_estimator() a few lines below that is still unchecked.

The remaining ones look fine.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1b/2] tc: check for errors in gen_rate_estimator creation
  2008-11-25 19:05     ` Patrick McHardy
@ 2008-11-25 19:14       ` Stephen Hemminger
  2008-11-25 19:19         ` Patrick McHardy
  0 siblings, 1 reply; 18+ messages in thread
From: Stephen Hemminger @ 2008-11-25 19:14 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: David Miller, netdev

On Tue, 25 Nov 2008 20:05:46 +0100
Patrick McHardy <kaber@trash.net> wrote:

> Stephen Hemminger wrote:
> > The functions gen_new_estimator and gen_replace_estimator can return errors,
> > but they were being ignored.
> > 
> > Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
> > 
> > 
> > ---
> > --- a/net/sched/sch_api.c	2008-11-25 10:51:47.000000000 -0800
> > +++ b/net/sched/sch_api.c	2008-11-25 10:54:16.000000000 -0800
> > @@ -887,6 +887,14 @@ static int qdisc_change(struct Qdisc *sc
> >  			return err;
> >  	}
> >  
> > +	if (tca[TCA_RATE]) {
> > +		err = gen_replace_estimator(&sch->bstats, &sch->rate_est,
> > +					    qdisc_root_sleeping_lock(sch),
> > +					    tca[TCA_RATE]);
> > +		if (err)
> > +			return err;
> 
> This appears to have the same problem as in HFSC unless I missed more
> code movement - changes to the qdisc have already been performed.

That is not fixable since both change and replace_estimator are non-unwindable,
and either one could fail. Could split checking and initialization out of gen_new_estimator,
but is it worth it??

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1b/2] tc: check for errors in gen_rate_estimator creation
  2008-11-25 19:14       ` Stephen Hemminger
@ 2008-11-25 19:19         ` Patrick McHardy
  2008-11-25 19:25           ` Stephen Hemminger
  0 siblings, 1 reply; 18+ messages in thread
From: Patrick McHardy @ 2008-11-25 19:19 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: David Miller, netdev

Stephen Hemminger wrote:
> On Tue, 25 Nov 2008 20:05:46 +0100
> Patrick McHardy <kaber@trash.net> wrote:
> 
>> Stephen Hemminger wrote:
>>> The functions gen_new_estimator and gen_replace_estimator can return errors,
>>> but they were being ignored.
>>>
>>> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
>>>
>>>
>>> ---
>>> --- a/net/sched/sch_api.c	2008-11-25 10:51:47.000000000 -0800
>>> +++ b/net/sched/sch_api.c	2008-11-25 10:54:16.000000000 -0800
>>> @@ -887,6 +887,14 @@ static int qdisc_change(struct Qdisc *sc
>>>  			return err;
>>>  	}
>>>  
>>> +	if (tca[TCA_RATE]) {
>>> +		err = gen_replace_estimator(&sch->bstats, &sch->rate_est,
>>> +					    qdisc_root_sleeping_lock(sch),
>>> +					    tca[TCA_RATE]);
>>> +		if (err)
>>> +			return err;
>> This appears to have the same problem as in HFSC unless I missed more
>> code movement - changes to the qdisc have already been performed.
> 
> That is not fixable since both change and replace_estimator are non-unwindable,
> and either one could fail. Could split checking and initialization out of gen_new_estimator,
> but is it worth it??

Probably not. I'd suggest to not return the estimator error in
this spot instead.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1b/2] tc: check for errors in gen_rate_estimator creation
  2008-11-25 19:19         ` Patrick McHardy
@ 2008-11-25 19:25           ` Stephen Hemminger
  2008-11-26  5:13             ` David Miller
  0 siblings, 1 reply; 18+ messages in thread
From: Stephen Hemminger @ 2008-11-25 19:25 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: David Miller, netdev

The functions gen_new_estimator and gen_replace_estimator can return errors,
but they were being ignored.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>

---
 net/sched/act_police.c |   25 +++++++++++++++++--------
 net/sched/sch_api.c    |    7 +++++--
 net/sched/sch_cbq.c    |   33 ++++++++++++++++++++++++---------
 net/sched/sch_drr.c    |   26 ++++++++++++++++++--------
 net/sched/sch_hfsc.c   |   25 ++++++++++++++++++-------
 net/sched/sch_htb.c    |   22 +++++++++++++++-------
 6 files changed, 97 insertions(+), 41 deletions(-)

--- a/net/sched/act_police.c	2008-11-25 10:51:47.000000000 -0800
+++ b/net/sched/act_police.c	2008-11-25 10:54:16.000000000 -0800
@@ -185,14 +185,21 @@ override:
 		if (parm->peakrate.rate) {
 			P_tab = qdisc_get_rtab(&parm->peakrate,
 					       tb[TCA_POLICE_PEAKRATE]);
-			if (P_tab == NULL) {
-				qdisc_put_rtab(R_tab);
+			if (P_tab == NULL)
 				goto failure;
-			}
 		}
 	}
-	/* No failure allowed after this point */
+
 	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 */
 	if (R_tab != NULL) {
 		qdisc_put_rtab(police->tcfp_R_tab);
 		police->tcfp_R_tab = R_tab;
@@ -217,10 +224,6 @@ override:
 
 	if (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);
 	if (ret != ACT_P_CREATED)
@@ -238,7 +241,13 @@ override:
 	a->priv = police;
 	return ret;
 
+failure_unlock:
+	spin_unlock_bh(&police->tcf_lock);
 failure:
+	if (P_tab)
+		qdisc_put_rtab(P_tab);
+	if (R_tab)
+		qdisc_put_rtab(R_tab);
 	if (ret == ACT_P_CREATED)
 		kfree(police);
 	return err;
--- a/net/sched/sch_api.c	2008-11-25 10:51:47.000000000 -0800
+++ b/net/sched/sch_api.c	2008-11-25 11:23:19.000000000 -0800
@@ -897,9 +897,12 @@ static int qdisc_change(struct Qdisc *sc
 	sch->stab = stab;
 
 	if (tca[TCA_RATE])
+		/* NB: ignores errors from replace_estimator
+		   because change can't be undone. */
 		gen_replace_estimator(&sch->bstats, &sch->rate_est,
-				      qdisc_root_sleeping_lock(sch),
-				      tca[TCA_RATE]);
+					    qdisc_root_sleeping_lock(sch),
+					    tca[TCA_RATE]);
+
 	return 0;
 }
 
--- a/net/sched/sch_cbq.c	2008-11-25 10:51:47.000000000 -0800
+++ b/net/sched/sch_cbq.c	2008-11-25 10:56:15.000000000 -0800
@@ -1765,11 +1765,23 @@ cbq_change_class(struct Qdisc *sch, u32 
 		}
 
 		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)
 				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 */
 		sch_tree_lock(sch);
 
@@ -1805,10 +1817,6 @@ cbq_change_class(struct Qdisc *sch, u32 
 
 		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;
 	}
 
@@ -1855,6 +1863,17 @@ cbq_change_class(struct Qdisc *sch, u32 
 	cl = kzalloc(sizeof(*cl), GFP_KERNEL);
 	if (cl == NULL)
 		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;
 	rtab = NULL;
 	cl->refcnt = 1;
@@ -1896,10 +1915,6 @@ cbq_change_class(struct Qdisc *sch, u32 
 
 	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;
 	return 0;
 
--- a/net/sched/sch_drr.c	2008-11-25 10:51:47.000000000 -0800
+++ b/net/sched/sch_drr.c	2008-11-25 10:54:16.000000000 -0800
@@ -82,15 +82,19 @@ static int drr_change_class(struct Qdisc
 		quantum = psched_mtu(qdisc_dev(sch));
 
 	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);
 		if (tb[TCA_DRR_QUANTUM])
 			cl->quantum = quantum;
 		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;
 	}
 
@@ -106,10 +110,16 @@ static int drr_change_class(struct Qdisc
 	if (cl->qdisc == NULL)
 		cl->qdisc = &noop_qdisc;
 
-	if (tca[TCA_RATE])
-		gen_replace_estimator(&cl->bstats, &cl->rate_est,
-				      qdisc_root_sleeping_lock(sch),
-				      tca[TCA_RATE]);
+	if (tca[TCA_RATE]) {
+		err = gen_replace_estimator(&cl->bstats, &cl->rate_est,
+					    qdisc_root_sleeping_lock(sch),
+					    tca[TCA_RATE]);
+		if (err) {
+			qdisc_destroy(cl->qdisc);
+			kfree(cl);
+			return err;
+		}
+	}
 
 	sch_tree_lock(sch);
 	qdisc_class_hash_insert(&q->clhash, &cl->common);
--- a/net/sched/sch_hfsc.c	2008-11-25 10:51:47.000000000 -0800
+++ b/net/sched/sch_hfsc.c	2008-11-25 11:08:27.000000000 -0800
@@ -1018,6 +1018,14 @@ hfsc_change_class(struct Qdisc *sch, u32
 		}
 		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);
 		if (rsc != NULL)
 			hfsc_change_rsc(cl, rsc, cur_time);
@@ -1034,10 +1042,6 @@ hfsc_change_class(struct Qdisc *sch, u32
 		}
 		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;
 	}
 
@@ -1063,6 +1067,16 @@ hfsc_change_class(struct Qdisc *sch, u32
 	if (cl == NULL)
 		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)
 		hfsc_change_rsc(cl, rsc, 0);
 	if (fsc != NULL)
@@ -1093,9 +1107,6 @@ hfsc_change_class(struct Qdisc *sch, u32
 
 	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;
 	return 0;
 }
--- a/net/sched/sch_htb.c	2008-11-25 10:51:47.000000000 -0800
+++ b/net/sched/sch_htb.c	2008-11-25 10:54:16.000000000 -0800
@@ -1332,9 +1332,14 @@ static int htb_change_class(struct Qdisc
 		if ((cl = kzalloc(sizeof(*cl), GFP_KERNEL)) == NULL)
 			goto failure;
 
-		gen_new_estimator(&cl->bstats, &cl->rate_est,
-				  qdisc_root_sleeping_lock(sch),
-				  tca[TCA_RATE] ? : &est.nla);
+		err = gen_new_estimator(&cl->bstats, &cl->rate_est,
+					qdisc_root_sleeping_lock(sch),
+					tca[TCA_RATE] ? : &est.nla);
+		if (err) {
+			kfree(cl);
+			goto failure;
+		}
+
 		cl->refcnt = 1;
 		cl->children = 0;
 		INIT_LIST_HEAD(&cl->un.leaf.drop_list);
@@ -1386,10 +1391,13 @@ static int htb_change_class(struct Qdisc
 		if (parent)
 			parent->children++;
 	} else {
-		if (tca[TCA_RATE])
-			gen_replace_estimator(&cl->bstats, &cl->rate_est,
-					      qdisc_root_sleeping_lock(sch),
-					      tca[TCA_RATE]);
+		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);
 	}
 

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1a/2] tc: propogate errors from tcf_hash_create
  2008-11-25 18:57   ` [PATCH 1a/2] tc: propogate errors from tcf_hash_create Stephen Hemminger
@ 2008-11-26  5:12     ` David Miller
  0 siblings, 0 replies; 18+ messages in thread
From: David Miller @ 2008-11-26  5:12 UTC (permalink / raw)
  To: shemminger; +Cc: kaber, netdev

From: Stephen Hemminger <shemminger@vyatta.com>
Date: Tue, 25 Nov 2008 10:57:27 -0800

> Allow tcf_hash_create to return different errors on estimator failure.
> 
> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>

Applied.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 1b/2] tc: check for errors in gen_rate_estimator creation
  2008-11-25 19:25           ` Stephen Hemminger
@ 2008-11-26  5:13             ` David Miller
  0 siblings, 0 replies; 18+ messages in thread
From: David Miller @ 2008-11-26  5:13 UTC (permalink / raw)
  To: shemminger; +Cc: kaber, netdev

From: Stephen Hemminger <shemminger@vyatta.com>
Date: Tue, 25 Nov 2008 11:25:37 -0800

> The functions gen_new_estimator and gen_replace_estimator can return errors,
> but they were being ignored.
> 
> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>

Applied.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 2/2] tc: policing requires a rate estimator
  2008-11-25 18:21 ` [PATCH 2/2] tc: policing requires a rate estimator Stephen Hemminger
  2008-11-25 18:32   ` Patrick McHardy
@ 2008-11-26  5:14   ` David Miller
  2008-11-26 11:10   ` [PATCH] pkt_sched: gen_estimator: Optimize gen_estimator_active() Jarek Poplawski
  2 siblings, 0 replies; 18+ messages in thread
From: David Miller @ 2008-11-26  5:14 UTC (permalink / raw)
  To: shemminger; +Cc: kaber, netdev

From: Stephen Hemminger <shemminger@vyatta.com>
Date: Tue, 25 Nov 2008 10:21:13 -0800

> Found that while trying average rate policing, it was possible to
> request average rate policing without a rate estimator. This results
> in no policing which is harmless but incorrect.
> 
> Since policing could be setup in two steps, need to check
> in the kernel.
> 
> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>

Applied.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH] pkt_sched: gen_estimator: Optimize gen_estimator_active()
  2008-11-25 18:21 ` [PATCH 2/2] tc: policing requires a rate estimator Stephen Hemminger
  2008-11-25 18:32   ` Patrick McHardy
  2008-11-26  5:14   ` David Miller
@ 2008-11-26 11:10   ` Jarek Poplawski
  2008-11-26 16:29     ` Stephen Hemminger
  2008-11-26 23:24     ` David Miller
  2 siblings, 2 replies; 18+ messages in thread
From: Jarek Poplawski @ 2008-11-26 11:10 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: David Miller, Patrick McHardy, netdev

pkt_sched: gen_estimator: Optimize gen_estimator_active()

Since all other gen_estimator functions use bstats and rate_est params
together, and searching for them is optimized now, let's use this also
in gen_estimator_active(). The return type of gen_estimator_active()
is changed to bool, and gen_find_node() parameters to const, btw.

In tcf_act_police_locate() a check for ACT_P_CREATED is added before
calling gen_estimator_active().

Signed-off-by: Jarek Poplawski <jarkao2@gmail.com>
---

 include/net/gen_stats.h  |    4 ++--
 net/core/gen_estimator.c |   25 ++++++++-----------------
 net/sched/act_police.c   |    4 +++-
 3 files changed, 13 insertions(+), 20 deletions(-)

diff --git a/include/net/gen_stats.h b/include/net/gen_stats.h
index dcf5bfa..d136b52 100644
--- a/include/net/gen_stats.h
+++ b/include/net/gen_stats.h
@@ -45,6 +45,6 @@ extern void gen_kill_estimator(struct gnet_stats_basic *bstats,
 extern int gen_replace_estimator(struct gnet_stats_basic *bstats,
 				 struct gnet_stats_rate_est *rate_est,
 				 spinlock_t *stats_lock, struct nlattr *opt);
-extern int gen_estimator_active(const struct gnet_stats_rate_est *rate_est);
-
+extern bool gen_estimator_active(const struct gnet_stats_basic *bstats,
+				 const struct gnet_stats_rate_est *rate_est);
 #endif
diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c
index 3885550..9cc9f95 100644
--- a/net/core/gen_estimator.c
+++ b/net/core/gen_estimator.c
@@ -163,8 +163,9 @@ static void gen_add_node(struct gen_estimator *est)
 	rb_insert_color(&est->node, &est_root);
 }
 
-static struct gen_estimator *gen_find_node(struct gnet_stats_basic *bstats,
-					   struct gnet_stats_rate_est *rate_est)
+static
+struct gen_estimator *gen_find_node(const struct gnet_stats_basic *bstats,
+				    const struct gnet_stats_rate_est *rate_est)
 {
 	struct rb_node *p = est_root.rb_node;
 
@@ -301,26 +302,16 @@ EXPORT_SYMBOL(gen_replace_estimator);
 
 /**
  * gen_estimator_active - test if estimator is currently in use
+ * @bstats: basic statistics
  * @rate_est: rate estimator statistics
  *
- * Returns 1 if estimator is active, and 0 if not.
+ * Returns true if estimator is active, and false if not.
  */
-int gen_estimator_active(const struct gnet_stats_rate_est *rate_est)
+bool gen_estimator_active(const struct gnet_stats_basic *bstats,
+			  const struct gnet_stats_rate_est *rate_est)
 {
-	int idx;
-	struct gen_estimator *e;
-
 	ASSERT_RTNL();
 
-	for (idx=0; idx <= EST_MAX_INTERVAL; idx++) {
-		if (!elist[idx].timer.function)
-			continue;
-
-		list_for_each_entry(e, &elist[idx].list, list) {
-			if (e->rate_est == rate_est)
-				return 1;
-		}
-	}
-	return 0;
+	return gen_find_node(bstats, rate_est) != NULL;
 }
 EXPORT_SYMBOL(gen_estimator_active);
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index 40df1d0..40f9a81 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -183,7 +183,9 @@ override:
 		if (R_tab == NULL)
 			goto failure;
 
-		if (!est && !gen_estimator_active(&police->tcf_rate_est)) {
+		if (!est && (ret == ACT_P_CREATED ||
+			     !gen_estimator_active(&police->tcf_bstats,
+						   &police->tcf_rate_est))) {
 			err = -EINVAL;
 			goto failure;
 		}

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH] pkt_sched: gen_estimator: Optimize gen_estimator_active()
  2008-11-26 11:10   ` [PATCH] pkt_sched: gen_estimator: Optimize gen_estimator_active() Jarek Poplawski
@ 2008-11-26 16:29     ` Stephen Hemminger
  2008-11-26 23:24     ` David Miller
  1 sibling, 0 replies; 18+ messages in thread
From: Stephen Hemminger @ 2008-11-26 16:29 UTC (permalink / raw)
  To: Jarek Poplawski; +Cc: David Miller, Patrick McHardy, netdev

On Wed, 26 Nov 2008 11:10:22 +0000
Jarek Poplawski <jarkao2@gmail.com> wrote:

> pkt_sched: gen_estimator: Optimize gen_estimator_active()
> 
> Since all other gen_estimator functions use bstats and rate_est params
> together, and searching for them is optimized now, let's use this also
> in gen_estimator_active(). The return type of gen_estimator_active()
> is changed to bool, and gen_find_node() parameters to const, btw.
> 
> In tcf_act_police_locate() a check for ACT_P_CREATED is added before
> calling gen_estimator_active().
> 
> Signed-off-by: Jarek Poplawski <jarkao2@gmail.com>

yeah sure, i just coded the obvious way.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] pkt_sched: gen_estimator: Optimize gen_estimator_active()
  2008-11-26 11:10   ` [PATCH] pkt_sched: gen_estimator: Optimize gen_estimator_active() Jarek Poplawski
  2008-11-26 16:29     ` Stephen Hemminger
@ 2008-11-26 23:24     ` David Miller
  1 sibling, 0 replies; 18+ messages in thread
From: David Miller @ 2008-11-26 23:24 UTC (permalink / raw)
  To: jarkao2; +Cc: shemminger, kaber, netdev

From: Jarek Poplawski <jarkao2@gmail.com>
Date: Wed, 26 Nov 2008 11:10:22 +0000

> pkt_sched: gen_estimator: Optimize gen_estimator_active()
> 
> Since all other gen_estimator functions use bstats and rate_est params
> together, and searching for them is optimized now, let's use this also
> in gen_estimator_active(). The return type of gen_estimator_active()
> is changed to bool, and gen_find_node() parameters to const, btw.
> 
> In tcf_act_police_locate() a check for ACT_P_CREATED is added before
> calling gen_estimator_active().
> 
> Signed-off-by: Jarek Poplawski <jarkao2@gmail.com>

Applied, thanks Jarek.

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2008-11-26 23:24 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-11-25 18:16 [PATCH 1/2] tc: check for errors from gen_replace_estimator Stephen Hemminger
2008-11-25 18:21 ` [PATCH 2/2] tc: policing requires a rate estimator Stephen Hemminger
2008-11-25 18:32   ` Patrick McHardy
2008-11-25 18:33     ` Stephen Hemminger
2008-11-25 18:38       ` Patrick McHardy
2008-11-26  5:14   ` David Miller
2008-11-26 11:10   ` [PATCH] pkt_sched: gen_estimator: Optimize gen_estimator_active() Jarek Poplawski
2008-11-26 16:29     ` Stephen Hemminger
2008-11-26 23:24     ` David Miller
2008-11-25 18:28 ` [PATCH 1/2] tc: check for errors from gen_replace_estimator Patrick McHardy
2008-11-25 18:57   ` [PATCH 1a/2] tc: propogate errors from tcf_hash_create Stephen Hemminger
2008-11-26  5:12     ` David Miller
2008-11-25 18:58   ` [PATCH 1b/2] tc: check for errors in gen_rate_estimator creation Stephen Hemminger
2008-11-25 19:05     ` Patrick McHardy
2008-11-25 19:14       ` Stephen Hemminger
2008-11-25 19:19         ` Patrick McHardy
2008-11-25 19:25           ` Stephen Hemminger
2008-11-26  5:13             ` David Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).