diff options
Diffstat (limited to 'net/sched/sch_hfsc.c')
| -rw-r--r-- | net/sched/sch_hfsc.c | 94 | 
1 files changed, 48 insertions, 46 deletions
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index e817aa00441..5090708ba38 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -113,7 +113,7 @@ enum hfsc_class_flags  struct hfsc_class  { -	u32		classid;	/* class id */ +	struct Qdisc_class_common cl_common;  	unsigned int	refcnt;		/* usage count */  	struct gnet_stats_basic bstats; @@ -134,7 +134,6 @@ struct hfsc_class  	struct rb_node vt_node;		/* parent's vt_tree member */  	struct rb_root cf_tree;		/* active children sorted by cl_f */  	struct rb_node cf_node;		/* parent's cf_heap member */ -	struct list_head hlist;		/* hash list member */  	struct list_head dlist;		/* drop list member */  	u64	cl_total;		/* total work in bytes */ @@ -177,13 +176,11 @@ struct hfsc_class  	unsigned long	cl_nactive;	/* number of active children */  }; -#define HFSC_HSIZE	16 -  struct hfsc_sched  {  	u16	defcls;				/* default class id */  	struct hfsc_class root;			/* root class */ -	struct list_head clhash[HFSC_HSIZE];	/* class hash */ +	struct Qdisc_class_hash clhash;		/* class hash */  	struct rb_root eligible;		/* eligible tree */  	struct list_head droplist;		/* active leaf class list (for  						   dropping) */ @@ -933,26 +930,16 @@ hfsc_adjust_levels(struct hfsc_class *cl)  	} while ((cl = cl->cl_parent) != NULL);  } -static inline unsigned int -hfsc_hash(u32 h) -{ -	h ^= h >> 8; -	h ^= h >> 4; - -	return h & (HFSC_HSIZE - 1); -} -  static inline struct hfsc_class *  hfsc_find_class(u32 classid, struct Qdisc *sch)  {  	struct hfsc_sched *q = qdisc_priv(sch); -	struct hfsc_class *cl; +	struct Qdisc_class_common *clc; -	list_for_each_entry(cl, &q->clhash[hfsc_hash(classid)], hlist) { -		if (cl->classid == classid) -			return cl; -	} -	return NULL; +	clc = qdisc_class_find(&q->clhash, classid); +	if (clc == NULL) +		return NULL; +	return container_of(clc, struct hfsc_class, cl_common);  }  static void @@ -1032,7 +1019,8 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,  	if (cl != NULL) {  		if (parentid) { -			if (cl->cl_parent && cl->cl_parent->classid != parentid) +			if (cl->cl_parent && +			    cl->cl_parent->cl_common.classid != parentid)  				return -EINVAL;  			if (cl->cl_parent == NULL && parentid != TC_H_ROOT)  				return -EINVAL; @@ -1057,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, -					      &sch->dev->queue_lock, +					      qdisc_root_lock(sch),  					      tca[TCA_RATE]);  		return 0;  	} @@ -1091,11 +1079,12 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,  	if (usc != NULL)  		hfsc_change_usc(cl, usc, 0); +	cl->cl_common.classid = classid;  	cl->refcnt    = 1; -	cl->classid   = classid;  	cl->sched     = q;  	cl->cl_parent = parent; -	cl->qdisc = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid); +	cl->qdisc = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, +				      &pfifo_qdisc_ops, classid);  	if (cl->qdisc == NULL)  		cl->qdisc = &noop_qdisc;  	INIT_LIST_HEAD(&cl->children); @@ -1103,7 +1092,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,  	cl->cf_tree = RB_ROOT;  	sch_tree_lock(sch); -	list_add_tail(&cl->hlist, &q->clhash[hfsc_hash(classid)]); +	qdisc_class_hash_insert(&q->clhash, &cl->cl_common);  	list_add_tail(&cl->siblings, &parent->children);  	if (parent->level == 0)  		hfsc_purge_queue(sch, parent); @@ -1111,9 +1100,11 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,  	cl->cl_pcvtoff = parent->cl_cvtoff;  	sch_tree_unlock(sch); +	qdisc_class_hash_grow(sch, &q->clhash); +  	if (tca[TCA_RATE])  		gen_new_estimator(&cl->bstats, &cl->rate_est, -				  &sch->dev->queue_lock, tca[TCA_RATE]); +				  qdisc_root_lock(sch), tca[TCA_RATE]);  	*arg = (unsigned long)cl;  	return 0;  } @@ -1145,7 +1136,7 @@ hfsc_delete_class(struct Qdisc *sch, unsigned long arg)  	hfsc_adjust_levels(cl->cl_parent);  	hfsc_purge_queue(sch, cl); -	list_del(&cl->hlist); +	qdisc_class_hash_remove(&q->clhash, &cl->cl_common);  	if (--cl->refcnt == 0)  		hfsc_destroy_class(sch, cl); @@ -1211,8 +1202,9 @@ hfsc_graft_class(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,  	if (cl->level > 0)  		return -EINVAL;  	if (new == NULL) { -		new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, -					cl->classid); +		new = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, +					&pfifo_qdisc_ops, +					cl->cl_common.classid);  		if (new == NULL)  			new = &noop_qdisc;  	} @@ -1345,8 +1337,9 @@ hfsc_dump_class(struct Qdisc *sch, unsigned long arg, struct sk_buff *skb,  	struct hfsc_class *cl = (struct hfsc_class *)arg;  	struct nlattr *nest; -	tcm->tcm_parent = cl->cl_parent ? cl->cl_parent->classid : TC_H_ROOT; -	tcm->tcm_handle = cl->classid; +	tcm->tcm_parent = cl->cl_parent ? cl->cl_parent->cl_common.classid : +					  TC_H_ROOT; +	tcm->tcm_handle = cl->cl_common.classid;  	if (cl->level == 0)  		tcm->tcm_info = cl->qdisc->handle; @@ -1390,14 +1383,16 @@ static void  hfsc_walk(struct Qdisc *sch, struct qdisc_walker *arg)  {  	struct hfsc_sched *q = qdisc_priv(sch); +	struct hlist_node *n;  	struct hfsc_class *cl;  	unsigned int i;  	if (arg->stop)  		return; -	for (i = 0; i < HFSC_HSIZE; i++) { -		list_for_each_entry(cl, &q->clhash[i], hlist) { +	for (i = 0; i < q->clhash.hashsize; i++) { +		hlist_for_each_entry(cl, n, &q->clhash.hash[i], +				     cl_common.hnode) {  			if (arg->count < arg->skip) {  				arg->count++;  				continue; @@ -1433,23 +1428,25 @@ hfsc_init_qdisc(struct Qdisc *sch, struct nlattr *opt)  {  	struct hfsc_sched *q = qdisc_priv(sch);  	struct tc_hfsc_qopt *qopt; -	unsigned int i; +	int err;  	if (opt == NULL || nla_len(opt) < sizeof(*qopt))  		return -EINVAL;  	qopt = nla_data(opt);  	q->defcls = qopt->defcls; -	for (i = 0; i < HFSC_HSIZE; i++) -		INIT_LIST_HEAD(&q->clhash[i]); +	err = qdisc_class_hash_init(&q->clhash); +	if (err < 0) +		return err;  	q->eligible = RB_ROOT;  	INIT_LIST_HEAD(&q->droplist);  	skb_queue_head_init(&q->requeue); +	q->root.cl_common.classid = sch->handle;  	q->root.refcnt  = 1; -	q->root.classid = sch->handle;  	q->root.sched   = q; -	q->root.qdisc = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, +	q->root.qdisc = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, +					  &pfifo_qdisc_ops,  					  sch->handle);  	if (q->root.qdisc == NULL)  		q->root.qdisc = &noop_qdisc; @@ -1457,7 +1454,8 @@ hfsc_init_qdisc(struct Qdisc *sch, struct nlattr *opt)  	q->root.vt_tree = RB_ROOT;  	q->root.cf_tree = RB_ROOT; -	list_add(&q->root.hlist, &q->clhash[hfsc_hash(q->root.classid)]); +	qdisc_class_hash_insert(&q->clhash, &q->root.cl_common); +	qdisc_class_hash_grow(sch, &q->clhash);  	qdisc_watchdog_init(&q->watchdog, sch); @@ -1520,10 +1518,11 @@ hfsc_reset_qdisc(struct Qdisc *sch)  {  	struct hfsc_sched *q = qdisc_priv(sch);  	struct hfsc_class *cl; +	struct hlist_node *n;  	unsigned int i; -	for (i = 0; i < HFSC_HSIZE; i++) { -		list_for_each_entry(cl, &q->clhash[i], hlist) +	for (i = 0; i < q->clhash.hashsize; i++) { +		hlist_for_each_entry(cl, n, &q->clhash.hash[i], cl_common.hnode)  			hfsc_reset_class(cl);  	}  	__skb_queue_purge(&q->requeue); @@ -1537,17 +1536,20 @@ static void  hfsc_destroy_qdisc(struct Qdisc *sch)  {  	struct hfsc_sched *q = qdisc_priv(sch); -	struct hfsc_class *cl, *next; +	struct hlist_node *n, *next; +	struct hfsc_class *cl;  	unsigned int i; -	for (i = 0; i < HFSC_HSIZE; i++) { -		list_for_each_entry(cl, &q->clhash[i], hlist) +	for (i = 0; i < q->clhash.hashsize; i++) { +		hlist_for_each_entry(cl, n, &q->clhash.hash[i], cl_common.hnode)  			tcf_destroy_chain(&cl->filter_list);  	} -	for (i = 0; i < HFSC_HSIZE; i++) { -		list_for_each_entry_safe(cl, next, &q->clhash[i], hlist) +	for (i = 0; i < q->clhash.hashsize; i++) { +		hlist_for_each_entry_safe(cl, n, next, &q->clhash.hash[i], +					  cl_common.hnode)  			hfsc_destroy_class(sch, cl);  	} +	qdisc_class_hash_destroy(&q->clhash);  	__skb_queue_purge(&q->requeue);  	qdisc_watchdog_cancel(&q->watchdog);  }  |