diff options
Diffstat (limited to 'net/sched')
| -rw-r--r-- | net/sched/act_api.c | 48 | ||||
| -rw-r--r-- | net/sched/cls_api.c | 16 | ||||
| -rw-r--r-- | net/sched/sch_htb.c | 5 | ||||
| -rw-r--r-- | net/sched/sch_teql.c | 3 | 
4 files changed, 45 insertions, 27 deletions
| diff --git a/net/sched/act_api.c b/net/sched/act_api.c index b919826939e0..f6d5755d669e 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -158,7 +158,7 @@ static int __tcf_action_put(struct tc_action *p, bool bind)  	return 0;  } -int __tcf_idr_release(struct tc_action *p, bool bind, bool strict) +static int __tcf_idr_release(struct tc_action *p, bool bind, bool strict)  {  	int ret = 0; @@ -184,7 +184,18 @@ int __tcf_idr_release(struct tc_action *p, bool bind, bool strict)  	return ret;  } -EXPORT_SYMBOL(__tcf_idr_release); + +int tcf_idr_release(struct tc_action *a, bool bind) +{ +	const struct tc_action_ops *ops = a->ops; +	int ret; + +	ret = __tcf_idr_release(a, bind, false); +	if (ret == ACT_P_DELETED) +		module_put(ops->owner); +	return ret; +} +EXPORT_SYMBOL(tcf_idr_release);  static size_t tcf_action_shared_attrs_size(const struct tc_action *act)  { @@ -493,6 +504,7 @@ int tcf_idr_create(struct tc_action_net *tn, u32 index, struct nlattr *est,  	}  	p->idrinfo = idrinfo; +	__module_get(ops->owner);  	p->ops = ops;  	*a = p;  	return 0; @@ -992,7 +1004,8 @@ struct tc_action_ops *tc_action_load_ops(char *name, struct nlattr *nla,  struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,  				    struct nlattr *nla, struct nlattr *est,  				    char *name, int ovr, int bind, -				    struct tc_action_ops *a_o, bool rtnl_held, +				    struct tc_action_ops *a_o, int *init_res, +				    bool rtnl_held,  				    struct netlink_ext_ack *extack)  {  	struct nla_bitfield32 flags = { 0, 0 }; @@ -1028,6 +1041,7 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,  	}  	if (err < 0)  		goto err_out; +	*init_res = err;  	if (!name && tb[TCA_ACT_COOKIE])  		tcf_set_action_cookie(&a->act_cookie, cookie); @@ -1035,13 +1049,6 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,  	if (!name)  		a->hw_stats = hw_stats; -	/* module count goes up only when brand new policy is created -	 * if it exists and is only bound to in a_o->init() then -	 * ACT_P_CREATED is not returned (a zero is). -	 */ -	if (err != ACT_P_CREATED) -		module_put(a_o->owner); -  	return a;  err_out: @@ -1056,7 +1063,7 @@ err_out:  int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,  		    struct nlattr *est, char *name, int ovr, int bind, -		    struct tc_action *actions[], size_t *attr_size, +		    struct tc_action *actions[], int init_res[], size_t *attr_size,  		    bool rtnl_held, struct netlink_ext_ack *extack)  {  	struct tc_action_ops *ops[TCA_ACT_MAX_PRIO] = {}; @@ -1084,7 +1091,8 @@ int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,  	for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {  		act = tcf_action_init_1(net, tp, tb[i], est, name, ovr, bind, -					ops[i - 1], rtnl_held, extack); +					ops[i - 1], &init_res[i - 1], rtnl_held, +					extack);  		if (IS_ERR(act)) {  			err = PTR_ERR(act);  			goto err; @@ -1100,7 +1108,8 @@ int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,  	tcf_idr_insert_many(actions);  	*attr_size = tcf_action_full_attrs_size(sz); -	return i - 1; +	err = i - 1; +	goto err_mod;  err:  	tcf_action_destroy(actions, bind); @@ -1497,12 +1506,13 @@ static int tcf_action_add(struct net *net, struct nlattr *nla,  			  struct netlink_ext_ack *extack)  {  	size_t attr_size = 0; -	int loop, ret; +	int loop, ret, i;  	struct tc_action *actions[TCA_ACT_MAX_PRIO] = {}; +	int init_res[TCA_ACT_MAX_PRIO] = {};  	for (loop = 0; loop < 10; loop++) {  		ret = tcf_action_init(net, NULL, nla, NULL, NULL, ovr, 0, -				      actions, &attr_size, true, extack); +				      actions, init_res, &attr_size, true, extack);  		if (ret != -EAGAIN)  			break;  	} @@ -1510,8 +1520,12 @@ static int tcf_action_add(struct net *net, struct nlattr *nla,  	if (ret < 0)  		return ret;  	ret = tcf_add_notify(net, n, actions, portid, attr_size, extack); -	if (ovr) -		tcf_action_put_many(actions); + +	/* only put existing actions */ +	for (i = 0; i < TCA_ACT_MAX_PRIO; i++) +		if (init_res[i] == ACT_P_CREATED) +			actions[i] = NULL; +	tcf_action_put_many(actions);  	return ret;  } diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 13341e7fb077..340d5af86e87 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -646,7 +646,7 @@ static void tc_block_indr_cleanup(struct flow_block_cb *block_cb)  	struct net_device *dev = block_cb->indr.dev;  	struct Qdisc *sch = block_cb->indr.sch;  	struct netlink_ext_ack extack = {}; -	struct flow_block_offload bo; +	struct flow_block_offload bo = {};  	tcf_block_offload_init(&bo, dev, sch, FLOW_BLOCK_UNBIND,  			       block_cb->indr.binder_type, @@ -3040,6 +3040,7 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb,  {  #ifdef CONFIG_NET_CLS_ACT  	{ +		int init_res[TCA_ACT_MAX_PRIO] = {};  		struct tc_action *act;  		size_t attr_size = 0; @@ -3051,12 +3052,11 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb,  				return PTR_ERR(a_o);  			act = tcf_action_init_1(net, tp, tb[exts->police],  						rate_tlv, "police", ovr, -						TCA_ACT_BIND, a_o, rtnl_held, -						extack); -			if (IS_ERR(act)) { -				module_put(a_o->owner); +						TCA_ACT_BIND, a_o, init_res, +						rtnl_held, extack); +			module_put(a_o->owner); +			if (IS_ERR(act))  				return PTR_ERR(act); -			}  			act->type = exts->type = TCA_OLD_COMPAT;  			exts->actions[0] = act; @@ -3067,8 +3067,8 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb,  			err = tcf_action_init(net, tp, tb[exts->action],  					      rate_tlv, NULL, ovr, TCA_ACT_BIND, -					      exts->actions, &attr_size, -					      rtnl_held, extack); +					      exts->actions, init_res, +					      &attr_size, rtnl_held, extack);  			if (err < 0)  				return err;  			exts->nr_actions = err; diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 62e12cb41a3e..081c11d5717c 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -1675,9 +1675,10 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg,  					  cl->parent->common.classid,  					  NULL);  		if (q->offload) { -			if (new_q) +			if (new_q) {  				htb_set_lockdep_class_child(new_q); -			htb_parent_to_leaf_offload(sch, dev_queue, new_q); +				htb_parent_to_leaf_offload(sch, dev_queue, new_q); +			}  		}  	} diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index 2f1f0a378408..6af6b95bdb67 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -134,6 +134,9 @@ teql_destroy(struct Qdisc *sch)  	struct teql_sched_data *dat = qdisc_priv(sch);  	struct teql_master *master = dat->m; +	if (!master) +		return; +  	prev = master->slaves;  	if (prev) {  		do { |