diff options
| author | James Morris <james.l.morris@oracle.com> | 2017-11-29 12:47:41 +1100 | 
|---|---|---|
| committer | James Morris <james.l.morris@oracle.com> | 2017-11-29 12:47:41 +1100 | 
| commit | cf40a76e7d5874bb25f4404eecc58a2e033af885 (patch) | |
| tree | 8fd81cbea03c87b3d41d7ae5b1d11eadd35d6ef5 /net/sched/cls_tcindex.c | |
| parent | ab5348c9c23cd253f5902980d2d8fe067dc24c82 (diff) | |
| parent | 4fbd8d194f06c8a3fd2af1ce560ddb31f7ec8323 (diff) | |
Merge tag 'v4.15-rc1' into next-seccomp
Linux 4.15-rc1
Diffstat (limited to 'net/sched/cls_tcindex.c')
| -rw-r--r-- | net/sched/cls_tcindex.c | 123 | 
1 files changed, 89 insertions, 34 deletions
| diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c index 8a8a58357c39..67467ae24c97 100644 --- a/net/sched/cls_tcindex.c +++ b/net/sched/cls_tcindex.c @@ -13,6 +13,7 @@  #include <net/act_api.h>  #include <net/netlink.h>  #include <net/pkt_cls.h> +#include <net/sch_generic.h>  /*   * Passing parameters to the root seems to be done more awkwardly than really @@ -27,14 +28,20 @@  struct tcindex_filter_result {  	struct tcf_exts		exts;  	struct tcf_result	res; -	struct rcu_head		rcu; +	union { +		struct work_struct	work; +		struct rcu_head		rcu; +	};  };  struct tcindex_filter {  	u16 key;  	struct tcindex_filter_result result;  	struct tcindex_filter __rcu *next; -	struct rcu_head rcu; +	union { +		struct work_struct work; +		struct rcu_head rcu; +	};  }; @@ -52,7 +59,7 @@ struct tcindex_data {  static inline int tcindex_filter_is_set(struct tcindex_filter_result *r)  { -	return tcf_exts_is_predicative(&r->exts) || r->res.classid; +	return tcf_exts_has_actions(&r->exts) || r->res.classid;  }  static struct tcindex_filter_result *tcindex_lookup(struct tcindex_data *p, @@ -90,9 +97,11 @@ static int tcindex_classify(struct sk_buff *skb, const struct tcf_proto *tp,  	f = tcindex_lookup(p, key);  	if (!f) { +		struct Qdisc *q = tcf_block_q(tp->chain->block); +  		if (!p->fall_through)  			return -1; -		res->classid = TC_H_MAKE(TC_H_MAJ(tp->q->handle), key); +		res->classid = TC_H_MAKE(TC_H_MAJ(q->handle), key);  		res->class = 0;  		pr_debug("alg 0x%x\n", res->classid);  		return 0; @@ -104,16 +113,16 @@ static int tcindex_classify(struct sk_buff *skb, const struct tcf_proto *tp,  } -static unsigned long tcindex_get(struct tcf_proto *tp, u32 handle) +static void *tcindex_get(struct tcf_proto *tp, u32 handle)  {  	struct tcindex_data *p = rtnl_dereference(tp->root);  	struct tcindex_filter_result *r;  	pr_debug("tcindex_get(tp %p,handle 0x%08x)\n", tp, handle);  	if (p->perfect && handle >= p->alloc_hash) -		return 0; +		return NULL;  	r = tcindex_lookup(p, handle); -	return r && tcindex_filter_is_set(r) ? (unsigned long) r : 0UL; +	return r && tcindex_filter_is_set(r) ? r : NULL;  }  static int tcindex_init(struct tcf_proto *tp) @@ -133,12 +142,46 @@ static int tcindex_init(struct tcf_proto *tp)  	return 0;  } +static void __tcindex_destroy_rexts(struct tcindex_filter_result *r) +{ +	tcf_exts_destroy(&r->exts); +	tcf_exts_put_net(&r->exts); +} + +static void tcindex_destroy_rexts_work(struct work_struct *work) +{ +	struct tcindex_filter_result *r; + +	r = container_of(work, struct tcindex_filter_result, work); +	rtnl_lock(); +	__tcindex_destroy_rexts(r); +	rtnl_unlock(); +} +  static void tcindex_destroy_rexts(struct rcu_head *head)  {  	struct tcindex_filter_result *r;  	r = container_of(head, struct tcindex_filter_result, rcu); -	tcf_exts_destroy(&r->exts); +	INIT_WORK(&r->work, tcindex_destroy_rexts_work); +	tcf_queue_work(&r->work); +} + +static void __tcindex_destroy_fexts(struct tcindex_filter *f) +{ +	tcf_exts_destroy(&f->result.exts); +	tcf_exts_put_net(&f->result.exts); +	kfree(f); +} + +static void tcindex_destroy_fexts_work(struct work_struct *work) +{ +	struct tcindex_filter *f = container_of(work, struct tcindex_filter, +						work); + +	rtnl_lock(); +	__tcindex_destroy_fexts(f); +	rtnl_unlock();  }  static void tcindex_destroy_fexts(struct rcu_head *head) @@ -146,18 +189,18 @@ static void tcindex_destroy_fexts(struct rcu_head *head)  	struct tcindex_filter *f = container_of(head, struct tcindex_filter,  						rcu); -	tcf_exts_destroy(&f->result.exts); -	kfree(f); +	INIT_WORK(&f->work, tcindex_destroy_fexts_work); +	tcf_queue_work(&f->work);  } -static int tcindex_delete(struct tcf_proto *tp, unsigned long arg, bool *last) +static int tcindex_delete(struct tcf_proto *tp, void *arg, bool *last)  {  	struct tcindex_data *p = rtnl_dereference(tp->root); -	struct tcindex_filter_result *r = (struct tcindex_filter_result *) arg; +	struct tcindex_filter_result *r = arg;  	struct tcindex_filter __rcu **walk;  	struct tcindex_filter *f = NULL; -	pr_debug("tcindex_delete(tp %p,arg 0x%lx),p %p\n", tp, arg, p); +	pr_debug("tcindex_delete(tp %p,arg %p),p %p\n", tp, arg, p);  	if (p->perfect) {  		if (!r->res.class)  			return -ENOENT; @@ -182,18 +225,24 @@ found:  	 * grace period, since converted-to-rcu actions are relying on that  	 * in cleanup() callback  	 */ -	if (f) -		call_rcu(&f->rcu, tcindex_destroy_fexts); -	else -		call_rcu(&r->rcu, tcindex_destroy_rexts); +	if (f) { +		if (tcf_exts_get_net(&f->result.exts)) +			call_rcu(&f->rcu, tcindex_destroy_fexts); +		else +			__tcindex_destroy_fexts(f); +	} else { +		if (tcf_exts_get_net(&r->exts)) +			call_rcu(&r->rcu, tcindex_destroy_rexts); +		else +			__tcindex_destroy_rexts(r); +	}  	*last = false;  	return 0;  }  static int tcindex_destroy_element(struct tcf_proto *tp, -				   unsigned long arg, -				   struct tcf_walker *walker) +				   void *arg, struct tcf_walker *walker)  {  	bool last; @@ -419,9 +468,9 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,  	}  	if (old_r) -		tcf_exts_change(tp, &r->exts, &e); +		tcf_exts_change(&r->exts, &e);  	else -		tcf_exts_change(tp, &cr.exts, &e); +		tcf_exts_change(&cr.exts, &e);  	if (old_r && old_r != r) {  		err = tcindex_filter_result_init(old_r); @@ -439,7 +488,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,  		struct tcindex_filter *nfp;  		struct tcindex_filter __rcu **fp; -		tcf_exts_change(tp, &f->result.exts, &r->exts); +		tcf_exts_change(&f->result.exts, &r->exts);  		fp = cp->h + (handle % cp->hash);  		for (nfp = rtnl_dereference(*fp); @@ -471,17 +520,17 @@ errout:  static int  tcindex_change(struct net *net, struct sk_buff *in_skb,  	       struct tcf_proto *tp, unsigned long base, u32 handle, -	       struct nlattr **tca, unsigned long *arg, bool ovr) +	       struct nlattr **tca, void **arg, bool ovr)  {  	struct nlattr *opt = tca[TCA_OPTIONS];  	struct nlattr *tb[TCA_TCINDEX_MAX + 1];  	struct tcindex_data *p = rtnl_dereference(tp->root); -	struct tcindex_filter_result *r = (struct tcindex_filter_result *) *arg; +	struct tcindex_filter_result *r = *arg;  	int err;  	pr_debug("tcindex_change(tp %p,handle 0x%08x,tca %p,arg %p),opt %p," -	    "p %p,r %p,*arg 0x%lx\n", -	    tp, handle, tca, arg, opt, p, r, arg ? *arg : 0L); +	    "p %p,r %p,*arg %p\n", +	    tp, handle, tca, arg, opt, p, r, arg ? *arg : NULL);  	if (!opt)  		return 0; @@ -506,9 +555,7 @@ static void tcindex_walk(struct tcf_proto *tp, struct tcf_walker *walker)  			if (!p->perfect[i].res.class)  				continue;  			if (walker->count >= walker->skip) { -				if (walker->fn(tp, -				    (unsigned long) (p->perfect+i), walker) -				     < 0) { +				if (walker->fn(tp, p->perfect + i, walker) < 0) {  					walker->stop = 1;  					return;  				} @@ -522,8 +569,7 @@ static void tcindex_walk(struct tcf_proto *tp, struct tcf_walker *walker)  		for (f = rtnl_dereference(p->h[i]); f; f = next) {  			next = rtnl_dereference(f->next);  			if (walker->count >= walker->skip) { -				if (walker->fn(tp, (unsigned long) &f->result, -				    walker) < 0) { +				if (walker->fn(tp, &f->result, walker) < 0) {  					walker->stop = 1;  					return;  				} @@ -548,14 +594,14 @@ static void tcindex_destroy(struct tcf_proto *tp)  } -static int tcindex_dump(struct net *net, struct tcf_proto *tp, unsigned long fh, +static int tcindex_dump(struct net *net, struct tcf_proto *tp, void *fh,  			struct sk_buff *skb, struct tcmsg *t)  {  	struct tcindex_data *p = rtnl_dereference(tp->root); -	struct tcindex_filter_result *r = (struct tcindex_filter_result *) fh; +	struct tcindex_filter_result *r = fh;  	struct nlattr *nest; -	pr_debug("tcindex_dump(tp %p,fh 0x%lx,skb %p,t %p),p %p,r %p\n", +	pr_debug("tcindex_dump(tp %p,fh %p,skb %p,t %p),p %p,r %p\n",  		 tp, fh, skb, t, p, r);  	pr_debug("p->perfect %p p->h %p\n", p->perfect, p->h); @@ -610,6 +656,14 @@ nla_put_failure:  	return -1;  } +static void tcindex_bind_class(void *fh, u32 classid, unsigned long cl) +{ +	struct tcindex_filter_result *r = fh; + +	if (r && r->res.classid == classid) +		r->res.class = cl; +} +  static struct tcf_proto_ops cls_tcindex_ops __read_mostly = {  	.kind		=	"tcindex",  	.classify	=	tcindex_classify, @@ -620,6 +674,7 @@ static struct tcf_proto_ops cls_tcindex_ops __read_mostly = {  	.delete		=	tcindex_delete,  	.walk		=	tcindex_walk,  	.dump		=	tcindex_dump, +	.bind_class	=	tcindex_bind_class,  	.owner		=	THIS_MODULE,  }; | 
