diff options
Diffstat (limited to 'net/ipv6/xfrm6_policy.c')
| -rw-r--r-- | net/ipv6/xfrm6_policy.c | 52 | 
1 files changed, 47 insertions, 5 deletions
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 12827374433..4ef7bdb6544 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -320,7 +320,51 @@ static struct ctl_table xfrm6_policy_table[] = {  	{ }  }; -static struct ctl_table_header *sysctl_hdr; +static int __net_init xfrm6_net_init(struct net *net) +{ +	struct ctl_table *table; +	struct ctl_table_header *hdr; + +	table = xfrm6_policy_table; +	if (!net_eq(net, &init_net)) { +		table = kmemdup(table, sizeof(xfrm6_policy_table), GFP_KERNEL); +		if (!table) +			goto err_alloc; + +		table[0].data = &net->xfrm.xfrm6_dst_ops.gc_thresh; +	} + +	hdr = register_net_sysctl(net, "net/ipv6", table); +	if (!hdr) +		goto err_reg; + +	net->ipv6.sysctl.xfrm6_hdr = hdr; +	return 0; + +err_reg: +	if (!net_eq(net, &init_net)) +		kfree(table); +err_alloc: +	return -ENOMEM; +} + +static void __net_exit xfrm6_net_exit(struct net *net) +{ +	struct ctl_table *table; + +	if (net->ipv6.sysctl.xfrm6_hdr == NULL) +		return; + +	table = net->ipv6.sysctl.xfrm6_hdr->ctl_table_arg; +	unregister_net_sysctl_table(net->ipv6.sysctl.xfrm6_hdr); +	if (!net_eq(net, &init_net)) +		kfree(table); +} + +static struct pernet_operations xfrm6_net_ops = { +	.init	= xfrm6_net_init, +	.exit	= xfrm6_net_exit, +};  #endif  int __init xfrm6_init(void) @@ -339,8 +383,7 @@ int __init xfrm6_init(void)  		goto out_policy;  #ifdef CONFIG_SYSCTL -	sysctl_hdr = register_net_sysctl(&init_net, "net/ipv6", -					 xfrm6_policy_table); +	register_pernet_subsys(&xfrm6_net_ops);  #endif  out:  	return ret; @@ -352,8 +395,7 @@ out_policy:  void xfrm6_fini(void)  {  #ifdef CONFIG_SYSCTL -	if (sysctl_hdr) -		unregister_net_sysctl_table(sysctl_hdr); +	unregister_pernet_subsys(&xfrm6_net_ops);  #endif  	xfrm6_policy_fini();  	xfrm6_state_fini();  |