diff options
Diffstat (limited to 'net/sched/act_api.c')
| -rw-r--r-- | net/sched/act_api.c | 19 | 
1 files changed, 11 insertions, 8 deletions
diff --git a/net/sched/act_api.c b/net/sched/act_api.c index c9102172ce3b..a512b18c0088 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -341,22 +341,25 @@ int tcf_register_action(struct tc_action_ops *act,  	if (!act->act || !act->dump || !act->init || !act->walk || !act->lookup)  		return -EINVAL; +	/* We have to register pernet ops before making the action ops visible, +	 * otherwise tcf_action_init_1() could get a partially initialized +	 * netns. +	 */ +	ret = register_pernet_subsys(ops); +	if (ret) +		return ret; +  	write_lock(&act_mod_lock);  	list_for_each_entry(a, &act_base, head) {  		if (act->type == a->type || (strcmp(act->kind, a->kind) == 0)) {  			write_unlock(&act_mod_lock); +			unregister_pernet_subsys(ops);  			return -EEXIST;  		}  	}  	list_add_tail(&act->head, &act_base);  	write_unlock(&act_mod_lock); -	ret = register_pernet_subsys(ops); -	if (ret) { -		tcf_unregister_action(act, ops); -		return ret; -	} -  	return 0;  }  EXPORT_SYMBOL(tcf_register_action); @@ -367,8 +370,6 @@ int tcf_unregister_action(struct tc_action_ops *act,  	struct tc_action_ops *a;  	int err = -ENOENT; -	unregister_pernet_subsys(ops); -  	write_lock(&act_mod_lock);  	list_for_each_entry(a, &act_base, head) {  		if (a == act) { @@ -378,6 +379,8 @@ int tcf_unregister_action(struct tc_action_ops *act,  		}  	}  	write_unlock(&act_mod_lock); +	if (!err) +		unregister_pernet_subsys(ops);  	return err;  }  EXPORT_SYMBOL(tcf_unregister_action);  |