lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-Id: <20080714.155928.254035359.davem@davemloft.net>
Date:	Mon, 14 Jul 2008 15:59:28 -0700 (PDT)
From:	David Miller <davem@...emloft.net>
To:	netdev@...r.kernel.org
Subject: [PATCH 4/14]: pkt_sched: Make classful ->graft() three stage.


In order to unwind from errors we need to split the ->graft()
operation for classful qdiscs into three seperate operations.

1) Prepare.

   This validates arguments, and allocated any resources if
   necessary.

2) Commit.

   This actually commits the graft operation, it must not fail.

3) Cancel.

   This undoes the operations done by a Prepare.  It frees
   any resources allocated by Prepare.  This is only invoked
   if the Commit was not performed.

This is part of the plan to replicate qdisc changes across
more than one netdev_queue.  It will be done in three
phases.  Allocate qdiscs, prepare grafts, and if all goes
well commit them.

Signed-off-by: David S. Miller <davem@...emloft.net>
---
 include/net/sch_generic.h |    9 +++++-
 net/sched/sch_api.c       |    8 +++++-
 net/sched/sch_atm.c       |   28 +++++++++++++++-----
 net/sched/sch_cbq.c       |   61 ++++++++++++++++++++++++++++----------------
 net/sched/sch_dsmark.c    |   40 ++++++++++++++++++++---------
 net/sched/sch_hfsc.c      |   45 +++++++++++++++++++++++---------
 net/sched/sch_htb.c       |   59 ++++++++++++++++++++++++++++++-------------
 net/sched/sch_ingress.c   |    8 +++---
 net/sched/sch_netem.c     |   20 ++++++++++++---
 net/sched/sch_prio.c      |   24 ++++++++++++++---
 net/sched/sch_red.c       |   21 ++++++++++++---
 net/sched/sch_tbf.c       |   20 ++++++++++++---
 12 files changed, 247 insertions(+), 96 deletions(-)

diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index b47f556..5318c37 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -56,8 +56,13 @@ struct Qdisc
 struct Qdisc_class_ops
 {
 	/* Child qdisc manipulation */
-	int			(*graft)(struct Qdisc *, unsigned long cl,
-					struct Qdisc *, struct Qdisc **);
+	void *			(*prepare_graft)(struct Qdisc *, unsigned long cl,
+						 struct Qdisc *);
+	void			(*cancel_graft)(struct Qdisc *, unsigned long cl,
+						struct Qdisc *, void *);
+	void			(*commit_graft)(struct Qdisc *, unsigned long cl,
+						struct Qdisc *, void *,
+						struct Qdisc **);
 	struct Qdisc *		(*leaf)(struct Qdisc *, unsigned long cl);
 	void			(*qlen_notify)(struct Qdisc *, unsigned long);
 
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index b0da006..fdc79b4 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -547,7 +547,13 @@ static int qdisc_graft(struct netdev_queue *dev_queue, struct Qdisc *parent,
 		if (cops) {
 			unsigned long cl = cops->get(parent, classid);
 			if (cl) {
-				err = cops->graft(parent, cl, new, old);
+				void *gp = cops->prepare_graft(parent, cl, new);
+
+				err = 0;
+				if (IS_ERR(gp))
+					err = PTR_ERR(gp);
+				else
+					cops->commit_graft(parent, cl, new, gp, old);
 				cops->put(parent, cl);
 			}
 		}
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c
index 0de757e..c084050 100644
--- a/net/sched/sch_atm.c
+++ b/net/sched/sch_atm.c
@@ -90,22 +90,34 @@ static inline struct atm_flow_data *lookup_flow(struct Qdisc *sch, u32 classid)
 	return flow;
 }
 
-static int atm_tc_graft(struct Qdisc *sch, unsigned long arg,
-			struct Qdisc *new, struct Qdisc **old)
+static void *atm_prepare_graft(struct Qdisc *sch, unsigned long arg,
+			       struct Qdisc *new)
 {
 	struct atm_qdisc_data *p = qdisc_priv(sch);
 	struct atm_flow_data *flow = (struct atm_flow_data *)arg;
 
-	pr_debug("atm_tc_graft(sch %p,[qdisc %p],flow %p,new %p,old %p)\n",
-		sch, p, flow, new, old);
 	if (!find_flow(p, flow))
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
+
+	return NULL;
+}
+
+static void atm_commit_graft(struct Qdisc *sch, unsigned long arg,
+			     struct Qdisc *new, void *mem,
+			     struct Qdisc **old)
+{
+	struct atm_flow_data *flow = (struct atm_flow_data *)arg;
+
 	if (!new)
 		new = &noop_qdisc;
 	*old = xchg(&flow->q, new);
 	if (*old)
 		qdisc_reset(*old);
-	return 0;
+}
+
+static void atm_cancel_graft(struct Qdisc *sch, unsigned long arg,
+			     struct Qdisc *new, void *mem)
+{
 }
 
 static struct Qdisc *atm_tc_leaf(struct Qdisc *sch, unsigned long cl)
@@ -672,7 +684,9 @@ static int atm_tc_dump(struct Qdisc *sch, struct sk_buff *skb)
 }
 
 static const struct Qdisc_class_ops atm_class_ops = {
-	.graft		= atm_tc_graft,
+	.prepare_graft	= atm_prepare_graft,
+	.commit_graft	= atm_commit_graft,
+	.cancel_graft	= atm_cancel_graft,
 	.leaf		= atm_tc_leaf,
 	.get		= atm_tc_get,
 	.put		= atm_tc_put,
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index 4efc836..224b9c0 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -1639,33 +1639,48 @@ cbq_dump_class_stats(struct Qdisc *sch, unsigned long arg,
 	return gnet_stats_copy_app(d, &cl->xstats, sizeof(cl->xstats));
 }
 
-static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
-		     struct Qdisc **old)
+static void *cbq_prepare_graft(struct Qdisc *sch, unsigned long arg,
+			       struct Qdisc *new)
 {
 	struct cbq_class *cl = (struct cbq_class*)arg;
+	void *ret = NULL;
+
+	if (!new) {
+		ret = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
+					&pfifo_qdisc_ops,
+					cl->common.classid);
+		if (!ret)
+			return ERR_PTR(-ENOBUFS);
+	}
 
-	if (cl) {
-		if (new == NULL) {
-			new = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
-						&pfifo_qdisc_ops,
-						cl->common.classid);
-			if (new == NULL)
-				return -ENOBUFS;
-		} else {
+	return ret;
+}
+
+static void cbq_commit_graft(struct Qdisc *sch, unsigned long arg,
+			     struct Qdisc *new, void *mem,
+			     struct Qdisc **old)
+{
+	struct cbq_class *cl = (struct cbq_class*)arg;
+
+	if (mem)
+		new = mem;
 #ifdef CONFIG_NET_CLS_ACT
-			if (cl->police == TC_POLICE_RECLASSIFY)
-				new->reshape_fail = cbq_reshape_fail;
+	else if (cl->police == TC_POLICE_RECLASSIFY)
+		new->reshape_fail = cbq_reshape_fail;
 #endif
-		}
-		sch_tree_lock(sch);
-		*old = xchg(&cl->q, new);
-		qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
-		qdisc_reset(*old);
-		sch_tree_unlock(sch);
 
-		return 0;
-	}
-	return -ENOENT;
+	sch_tree_lock(sch);
+	*old = xchg(&cl->q, new);
+	qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
+	qdisc_reset(*old);
+	sch_tree_unlock(sch);
+}
+
+static void cbq_cancel_graft(struct Qdisc *sch, unsigned long arg,
+			     struct Qdisc *new, void *mem)
+{
+	if (mem)
+		qdisc_destroy(mem);
 }
 
 static struct Qdisc *
@@ -2032,7 +2047,9 @@ static void cbq_walk(struct Qdisc *sch, struct qdisc_walker *arg)
 }
 
 static const struct Qdisc_class_ops cbq_class_ops = {
-	.graft		=	cbq_graft,
+	.prepare_graft	=	cbq_prepare_graft,
+	.commit_graft	=	cbq_commit_graft,
+	.cancel_graft	=	cbq_cancel_graft,
 	.leaf		=	cbq_leaf,
 	.qlen_notify	=	cbq_qlen_notify,
 	.get		=	cbq_get,
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c
index 3aafbd1..28f4e77 100644
--- a/net/sched/sch_dsmark.c
+++ b/net/sched/sch_dsmark.c
@@ -51,29 +51,43 @@ static inline int dsmark_valid_index(struct dsmark_qdisc_data *p, u16 index)
 
 /* ------------------------- Class/flow operations ------------------------- */
 
-static int dsmark_graft(struct Qdisc *sch, unsigned long arg,
-			struct Qdisc *new, struct Qdisc **old)
+static void *dsmark_prepare_graft(struct Qdisc *sch, unsigned long arg,
+				  struct Qdisc *new)
 {
-	struct dsmark_qdisc_data *p = qdisc_priv(sch);
-
-	pr_debug("dsmark_graft(sch %p,[qdisc %p],new %p,old %p)\n",
-		sch, p, new, old);
+	void *ret = NULL;
 
-	if (new == NULL) {
-		new = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
+	if (!new) {
+		ret = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
 					&pfifo_qdisc_ops,
 					sch->handle);
-		if (new == NULL)
-			new = &noop_qdisc;
+		if (!ret)
+			return ERR_PTR(-ENOBUFS);
 	}
 
+	return ret;
+}
+
+static void dsmark_commit_graft(struct Qdisc *sch, unsigned long arg,
+				struct Qdisc *new, void *mem,
+				struct Qdisc **old)
+{
+	struct dsmark_qdisc_data *p = qdisc_priv(sch);
+
+	if (!new)
+		new = mem;
+
 	sch_tree_lock(sch);
 	*old = xchg(&p->q, new);
 	qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
 	qdisc_reset(*old);
 	sch_tree_unlock(sch);
+}
 
-	return 0;
+static void dsmark_cancel_graft(struct Qdisc *sch, unsigned long arg,
+				struct Qdisc *new, void *mem)
+{
+	if (mem)
+		qdisc_destroy(mem);
 }
 
 static struct Qdisc *dsmark_leaf(struct Qdisc *sch, unsigned long arg)
@@ -474,7 +488,9 @@ nla_put_failure:
 }
 
 static const struct Qdisc_class_ops dsmark_class_ops = {
-	.graft		=	dsmark_graft,
+	.prepare_graft	=	dsmark_prepare_graft,
+	.commit_graft	=	dsmark_commit_graft,
+	.cancel_graft	=	dsmark_cancel_graft,
 	.leaf		=	dsmark_leaf,
 	.get		=	dsmark_get,
 	.put		=	dsmark_put,
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index 997d520..59be192 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -1191,29 +1191,46 @@ hfsc_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
 	return cl;
 }
 
-static int
-hfsc_graft_class(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
-		 struct Qdisc **old)
+static void *hfsc_prepare_graft(struct Qdisc *sch, unsigned long arg,
+				struct Qdisc *new)
 {
 	struct hfsc_class *cl = (struct hfsc_class *)arg;
+	void *ret = NULL;
 
-	if (cl == NULL)
-		return -ENOENT;
-	if (cl->level > 0)
-		return -EINVAL;
-	if (new == NULL) {
-		new = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
+	if (cl->level)
+		return ERR_PTR(-ENOENT);
+
+	if (!new) {
+		ret = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
 					&pfifo_qdisc_ops,
 					cl->cl_common.classid);
-		if (new == NULL)
-			new = &noop_qdisc;
+		if (!ret)
+			return ERR_PTR(-ENOBUFS);
 	}
 
+	return ret;
+}
+
+static void hfsc_commit_graft(struct Qdisc *sch, unsigned long arg,
+			      struct Qdisc *new, void *mem,
+			      struct Qdisc **old)
+{
+	struct hfsc_class *cl = (struct hfsc_class *)arg;
+
+	if (mem)
+		new = mem;
+
 	sch_tree_lock(sch);
 	hfsc_purge_queue(sch, cl);
 	*old = xchg(&cl->qdisc, new);
 	sch_tree_unlock(sch);
-	return 0;
+}
+
+static void hfsc_cancel_graft(struct Qdisc *sch, unsigned long arg,
+			      struct Qdisc *new, void *mem)
+{
+	if (mem)
+		qdisc_destroy(mem);
 }
 
 static struct Qdisc *
@@ -1713,7 +1730,9 @@ hfsc_drop(struct Qdisc *sch)
 static const struct Qdisc_class_ops hfsc_class_ops = {
 	.change		= hfsc_change_class,
 	.delete		= hfsc_delete_class,
-	.graft		= hfsc_graft_class,
+	.prepare_graft	= hfsc_prepare_graft,
+	.commit_graft	= hfsc_commit_graft,
+	.cancel_graft	= hfsc_cancel_graft,
 	.leaf		= hfsc_class_leaf,
 	.qlen_notify	= hfsc_qlen_notify,
 	.get		= hfsc_get_class,
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index c8ca54c..292129d 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -1122,27 +1122,48 @@ htb_dump_class_stats(struct Qdisc *sch, unsigned long arg, struct gnet_dump *d)
 	return gnet_stats_copy_app(d, &cl->xstats, sizeof(cl->xstats));
 }
 
-static int htb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
-		     struct Qdisc **old)
+static void *htb_prepare_graft(struct Qdisc *sch, unsigned long arg,
+			       struct Qdisc *new)
 {
 	struct htb_class *cl = (struct htb_class *)arg;
+	void *ret = NULL;
 
-	if (cl && !cl->level) {
-		if (new == NULL &&
-		    (new = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
-					     &pfifo_qdisc_ops,
-					     cl->common.classid))
-		    == NULL)
-			return -ENOBUFS;
-		sch_tree_lock(sch);
-		if ((*old = xchg(&cl->un.leaf.q, new)) != NULL) {
-			qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
-			qdisc_reset(*old);
-		}
-		sch_tree_unlock(sch);
-		return 0;
+	if (cl->level)
+		return ERR_PTR(-ENOENT);
+
+	if (!new) {
+		ret = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
+					&pfifo_qdisc_ops,
+					cl->common.classid);
+		if (!ret)
+			return ERR_PTR(-ENOBUFS);
+	}
+
+	return ret;
+}
+
+static void htb_commit_graft(struct Qdisc *sch, unsigned long arg,
+			     struct Qdisc *new, void *mem,
+			     struct Qdisc **old)
+{
+	struct htb_class *cl = (struct htb_class*)arg;
+
+	if (mem)
+		new = mem;
+
+	sch_tree_lock(sch);
+	if ((*old = xchg(&cl->un.leaf.q, new)) != NULL) {
+		qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
+		qdisc_reset(*old);
 	}
-	return -ENOENT;
+	sch_tree_unlock(sch);
+}
+
+static void htb_cancel_graft(struct Qdisc *sch, unsigned long arg,
+			     struct Qdisc *new, void *mem)
+{
+	if (mem)
+		qdisc_destroy(mem);
 }
 
 static struct Qdisc *htb_leaf(struct Qdisc *sch, unsigned long arg)
@@ -1536,7 +1557,9 @@ static void htb_walk(struct Qdisc *sch, struct qdisc_walker *arg)
 }
 
 static const struct Qdisc_class_ops htb_class_ops = {
-	.graft		=	htb_graft,
+	.prepare_graft	=	htb_prepare_graft,
+	.commit_graft	=	htb_commit_graft,
+	.cancel_graft	=	htb_cancel_graft,
 	.leaf		=	htb_leaf,
 	.qlen_notify	=	htb_qlen_notify,
 	.get		=	htb_get,
diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c
index 956c80a..1cfb57e 100644
--- a/net/sched/sch_ingress.c
+++ b/net/sched/sch_ingress.c
@@ -22,10 +22,10 @@ struct ingress_qdisc_data {
 
 /* ------------------------- Class/flow operations ------------------------- */
 
-static int ingress_graft(struct Qdisc *sch, unsigned long arg,
-			 struct Qdisc *new, struct Qdisc **old)
+static void *ingress_prepare_graft(struct Qdisc *sch, unsigned long arg,
+				   struct Qdisc *new)
 {
-	return -EOPNOTSUPP;
+	return ERR_PTR(-EOPNOTSUPP);
 }
 
 static struct Qdisc *ingress_leaf(struct Qdisc *sch, unsigned long arg)
@@ -123,7 +123,7 @@ nla_put_failure:
 }
 
 static const struct Qdisc_class_ops ingress_class_ops = {
-	.graft		=	ingress_graft,
+	.prepare_graft	=	ingress_prepare_graft,
 	.leaf		=	ingress_leaf,
 	.get		=	ingress_get,
 	.put		=	ingress_put,
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index bc585f2..180c1e4 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -615,8 +615,15 @@ static int netem_dump_class(struct Qdisc *sch, unsigned long cl,
 	return 0;
 }
 
-static int netem_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
-		     struct Qdisc **old)
+static void *netem_prepare_graft(struct Qdisc *sch, unsigned long arg,
+				 struct Qdisc *new)
+{
+	return NULL;
+}
+
+static void netem_commit_graft(struct Qdisc *sch, unsigned long arg,
+			       struct Qdisc *new, void *mem,
+			       struct Qdisc **old)
 {
 	struct netem_sched_data *q = qdisc_priv(sch);
 
@@ -628,8 +635,11 @@ static int netem_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
 	qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
 	qdisc_reset(*old);
 	sch_tree_unlock(sch);
+}
 
-	return 0;
+static void netem_cancel_graft(struct Qdisc *sch, unsigned long arg,
+			       struct Qdisc *new, void *mem)
+{
 }
 
 static struct Qdisc *netem_leaf(struct Qdisc *sch, unsigned long arg)
@@ -676,7 +686,9 @@ static struct tcf_proto **netem_find_tcf(struct Qdisc *sch, unsigned long cl)
 }
 
 static const struct Qdisc_class_ops netem_class_ops = {
-	.graft		=	netem_graft,
+	.prepare_graft	=	netem_prepare_graft,
+	.commit_graft	=	netem_commit_graft,
+	.cancel_graft	=	netem_cancel_graft,
 	.leaf		=	netem_leaf,
 	.get		=	netem_get,
 	.put		=	netem_put,
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index 536ca47..ba3b261 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -269,14 +269,23 @@ nla_put_failure:
 	return -1;
 }
 
-static int prio_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
-		      struct Qdisc **old)
+static void *prio_prepare_graft(struct Qdisc *sch, unsigned long arg,
+				struct Qdisc *new)
 {
 	struct prio_sched_data *q = qdisc_priv(sch);
 	unsigned long band = arg - 1;
 
 	if (band >= q->bands)
-		return -EINVAL;
+		return ERR_PTR(-EINVAL);
+	return NULL;
+}
+
+static void prio_commit_graft(struct Qdisc *sch, unsigned long arg,
+			      struct Qdisc *new, void *mem,
+			      struct Qdisc **old)
+{
+	struct prio_sched_data *q = qdisc_priv(sch);
+	unsigned long band = arg - 1;
 
 	if (new == NULL)
 		new = &noop_qdisc;
@@ -287,8 +296,11 @@ static int prio_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
 	qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
 	qdisc_reset(*old);
 	sch_tree_unlock(sch);
+}
 
-	return 0;
+static void prio_cancel_graft(struct Qdisc *sch, unsigned long arg,
+			      struct Qdisc *new, void *mem)
+{
 }
 
 static struct Qdisc *
@@ -401,7 +413,9 @@ static struct tcf_proto ** prio_find_tcf(struct Qdisc *sch, unsigned long cl)
 }
 
 static const struct Qdisc_class_ops prio_class_ops = {
-	.graft		=	prio_graft,
+	.prepare_graft	=	prio_prepare_graft,
+	.commit_graft	=	prio_commit_graft,
+	.cancel_graft	=	prio_cancel_graft,
 	.leaf		=	prio_leaf,
 	.get		=	prio_get,
 	.put		=	prio_put,
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c
index 77098ac..c106e0e 100644
--- a/net/sched/sch_red.c
+++ b/net/sched/sch_red.c
@@ -283,8 +283,15 @@ static int red_dump_class(struct Qdisc *sch, unsigned long cl,
 	return 0;
 }
 
-static int red_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
-		     struct Qdisc **old)
+static void *red_prepare_graft(struct Qdisc *sch, unsigned long arg,
+			       struct Qdisc *new)
+{
+	return NULL;
+}
+
+static void red_commit_graft(struct Qdisc *sch, unsigned long arg,
+			     struct Qdisc *new, void *mem,
+			     struct Qdisc **old)
 {
 	struct red_sched_data *q = qdisc_priv(sch);
 
@@ -296,7 +303,11 @@ static int red_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
 	qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
 	qdisc_reset(*old);
 	sch_tree_unlock(sch);
-	return 0;
+}
+
+static void red_cancel_graft(struct Qdisc *sch, unsigned long arg,
+			     struct Qdisc *new, void *mem)
+{
 }
 
 static struct Qdisc *red_leaf(struct Qdisc *sch, unsigned long arg)
@@ -344,7 +355,9 @@ static struct tcf_proto **red_find_tcf(struct Qdisc *sch, unsigned long cl)
 }
 
 static const struct Qdisc_class_ops red_class_ops = {
-	.graft		=	red_graft,
+	.prepare_graft	=	red_prepare_graft,
+	.commit_graft	=	red_commit_graft,
+	.cancel_graft	=	red_cancel_graft,
 	.leaf		=	red_leaf,
 	.get		=	red_get,
 	.put		=	red_put,
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
index 444c227..1afea06 100644
--- a/net/sched/sch_tbf.c
+++ b/net/sched/sch_tbf.c
@@ -394,8 +394,15 @@ static int tbf_dump_class(struct Qdisc *sch, unsigned long cl,
 	return 0;
 }
 
-static int tbf_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
-		     struct Qdisc **old)
+static void *tbf_prepare_graft(struct Qdisc *sch, unsigned long arg,
+			       struct Qdisc *new)
+{
+	return NULL;
+}
+
+static void tbf_commit_graft(struct Qdisc *sch, unsigned long arg,
+			     struct Qdisc *new, void *mem,
+			     struct Qdisc **old)
 {
 	struct tbf_sched_data *q = qdisc_priv(sch);
 
@@ -407,8 +414,11 @@ static int tbf_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
 	qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
 	qdisc_reset(*old);
 	sch_tree_unlock(sch);
+}
 
-	return 0;
+static void tbf_cancel_graft(struct Qdisc *sch, unsigned long arg,
+			     struct Qdisc *new, void *mem)
+{
 }
 
 static struct Qdisc *tbf_leaf(struct Qdisc *sch, unsigned long arg)
@@ -456,7 +466,9 @@ static struct tcf_proto **tbf_find_tcf(struct Qdisc *sch, unsigned long cl)
 
 static const struct Qdisc_class_ops tbf_class_ops =
 {
-	.graft		=	tbf_graft,
+	.prepare_graft	=	tbf_prepare_graft,
+	.commit_graft	=	tbf_commit_graft,
+	.cancel_graft	=	tbf_cancel_graft,
 	.leaf		=	tbf_leaf,
 	.get		=	tbf_get,
 	.put		=	tbf_put,
-- 
1.5.6.2.255.gbed62

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ