Commit 885842d8 authored by David S. Miller's avatar David S. Miller

Merge branch 'Replacing-net_mutex-with-rw_semaphore'

Kirill Tkhai says:

====================
Replacing net_mutex with rw_semaphore

this is the third version of the patchset introducing net_sem
instead of net_mutex. The patchset adds net_sem in addition
to net_mutex and allows pernet_operations to be "async". This
flag means, the pernet_operations methods are safe to be
executed with any other pernet_operations (un)initializing
another net.

If there are only async pernet_operations in the system,
net_mutex is not used either for setup_net() or for cleanup_net().

The pernet_operations converted in this patchset allow
to create minimal .config to have network working, and
the changes improve the performance like you may see
below:

    %for i in {1..10000}; do unshare -n bash -c exit; done

    *before*
    real 1m40,377s
    user 0m9,672s
    sys 0m19,928s

    *after*
    real 0m17,007s
    user 0m5,311s
    sys 0m11,779

    (5.8 times faster)

In the future, when all pernet_operations become async,
we'll just remove this "async" field tree-wide.

All the new logic is concentrated in patches [1-5/32].
The rest of patches converts specific operations:
review, rationale of they can be converted, and setting
of async flag.

Kirill

v3: Improved patches descriptions. Added comment into [5/32].
Added [32/32] converting netlink_tap_net_ops (new pernet operations
introduced in 2018).

v2: Single patch -> patchset with rationale of every conversion
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents cf19e5e2 b86b47a3
......@@ -230,4 +230,5 @@ static __net_init int loopback_net_init(struct net *net)
/* Registered in net/core/dev.c */
struct pernet_operations __net_initdata loopback_net_ops = {
.init = loopback_net_init,
.async = true,
};
......@@ -237,6 +237,7 @@ static __net_exit void proc_net_ns_exit(struct net *net)
static struct pernet_operations __net_initdata proc_net_ns_ops = {
.init = proc_net_ns_init,
.exit = proc_net_ns_exit,
.async = true,
};
int __init proc_net_init(void)
......
......@@ -36,6 +36,7 @@ extern int rtnl_is_locked(void);
extern wait_queue_head_t netdev_unregistering_wq;
extern struct mutex net_mutex;
extern struct rw_semaphore net_sem;
#ifdef CONFIG_PROVE_LOCKING
extern bool lockdep_rtnl_is_held(void);
......
......@@ -313,6 +313,12 @@ struct pernet_operations {
void (*exit_batch)(struct list_head *net_exit_list);
unsigned int *id;
size_t size;
/*
* Indicates above methods are allowed to be executed in parallel
* with methods of any other pernet_operations, i.e. they are not
* need synchronization via net_mutex.
*/
bool async;
};
/*
......
......@@ -1526,6 +1526,7 @@ static struct pernet_operations audit_net_ops __net_initdata = {
.exit = audit_net_exit,
.id = &audit_net_id,
.size = sizeof(struct audit_net),
.async = true,
};
/* Initialize audit support at boot time. */
......
......@@ -650,6 +650,7 @@ static void uevent_net_exit(struct net *net)
static struct pernet_operations uevent_net_ops = {
.init = uevent_net_init,
.exit = uevent_net_exit,
.async = true,
};
static int __init kobject_uevent_init(void)
......
......@@ -8833,6 +8833,7 @@ static void __net_exit netdev_exit(struct net *net)
static struct pernet_operations __net_initdata netdev_net_ops = {
.init = netdev_init,
.exit = netdev_exit,
.async = true,
};
static void __net_exit default_device_exit(struct net *net)
......@@ -8933,6 +8934,7 @@ static void __net_exit default_device_exit_batch(struct list_head *net_list)
static struct pernet_operations __net_initdata default_device_ops = {
.exit = default_device_exit,
.exit_batch = default_device_exit_batch,
.async = true,
};
/*
......
......@@ -171,6 +171,7 @@ static void __net_exit fib_notifier_net_exit(struct net *net)
static struct pernet_operations fib_notifier_net_ops = {
.init = fib_notifier_net_init,
.exit = fib_notifier_net_exit,
.async = true,
};
static int __init fib_notifier_init(void)
......
......@@ -1030,6 +1030,7 @@ static void __net_exit fib_rules_net_exit(struct net *net)
static struct pernet_operations fib_rules_net_ops = {
.init = fib_rules_net_init,
.exit = fib_rules_net_exit,
.async = true,
};
static int __init fib_rules_init(void)
......
......@@ -349,6 +349,7 @@ static void __net_exit dev_proc_net_exit(struct net *net)
static struct pernet_operations __net_initdata dev_proc_ops = {
.init = dev_proc_net_init,
.exit = dev_proc_net_exit,
.async = true,
};
static int dev_mc_seq_show(struct seq_file *seq, void *v)
......@@ -405,6 +406,7 @@ static void __net_exit dev_mc_net_exit(struct net *net)
static struct pernet_operations __net_initdata dev_mc_net_ops = {
.init = dev_mc_net_init,
.exit = dev_mc_net_exit,
.async = true,
};
int __init dev_proc_init(void)
......
......@@ -29,6 +29,7 @@
static LIST_HEAD(pernet_list);
static struct list_head *first_device = &pernet_list;
/* Used only if there are !async pernet_operations registered */
DEFINE_MUTEX(net_mutex);
LIST_HEAD(net_namespace_list);
......@@ -41,6 +42,12 @@ struct net init_net = {
EXPORT_SYMBOL(init_net);
static bool init_net_initialized;
static unsigned nr_sync_pernet_ops;
/*
* net_sem: protects: pernet_list, net_generic_ids, nr_sync_pernet_ops,
* init_net_initialized and first_device pointer.
*/
DECLARE_RWSEM(net_sem);
#define MIN_PERNET_OPS_ID \
((sizeof(struct net_generic) + sizeof(void *) - 1) / sizeof(void *))
......@@ -65,11 +72,10 @@ static int net_assign_generic(struct net *net, unsigned int id, void *data)
{
struct net_generic *ng, *old_ng;
BUG_ON(!mutex_is_locked(&net_mutex));
BUG_ON(id < MIN_PERNET_OPS_ID);
old_ng = rcu_dereference_protected(net->gen,
lockdep_is_held(&net_mutex));
lockdep_is_held(&net_sem));
if (old_ng->s.len > id) {
old_ng->ptr[id] = data;
return 0;
......@@ -286,7 +292,7 @@ struct net *get_net_ns_by_id(struct net *net, int id)
*/
static __net_init int setup_net(struct net *net, struct user_namespace *user_ns)
{
/* Must be called with net_mutex held */
/* Must be called with net_sem held */
const struct pernet_operations *ops, *saved_ops;
int error = 0;
LIST_HEAD(net_exit_list);
......@@ -303,6 +309,9 @@ static __net_init int setup_net(struct net *net, struct user_namespace *user_ns)
if (error < 0)
goto out_undo;
}
rtnl_lock();
list_add_tail_rcu(&net->list, &net_namespace_list);
rtnl_unlock();
out:
return error;
......@@ -331,6 +340,7 @@ static int __net_init net_defaults_init_net(struct net *net)
static struct pernet_operations net_defaults_ops = {
.init = net_defaults_init_net,
.async = true,
};
static __init int net_defaults_init(void)
......@@ -408,32 +418,32 @@ struct net *copy_net_ns(unsigned long flags,
net = net_alloc();
if (!net) {
dec_net_namespaces(ucounts);
return ERR_PTR(-ENOMEM);
rv = -ENOMEM;
goto dec_ucounts;
}
refcount_set(&net->passive, 1);
net->ucounts = ucounts;
get_user_ns(user_ns);
rv = down_read_killable(&net_sem);
if (rv < 0)
goto put_userns;
if (nr_sync_pernet_ops) {
rv = mutex_lock_killable(&net_mutex);
if (rv < 0) {
net_free(net);
dec_net_namespaces(ucounts);
put_user_ns(user_ns);
return ERR_PTR(rv);
if (rv < 0)
goto up_read;
}
net->ucounts = ucounts;
rv = setup_net(net, user_ns);
if (rv == 0) {
rtnl_lock();
list_add_tail_rcu(&net->list, &net_namespace_list);
rtnl_unlock();
}
if (nr_sync_pernet_ops)
mutex_unlock(&net_mutex);
up_read:
up_read(&net_sem);
if (rv < 0) {
dec_net_namespaces(ucounts);
put_userns:
put_user_ns(user_ns);
net_drop_ns(net);
dec_ucounts:
dec_net_namespaces(ucounts);
return ERR_PTR(rv);
}
return net;
......@@ -481,6 +491,8 @@ static void cleanup_net(struct work_struct *work)
list_replace_init(&cleanup_list, &net_kill_list);
spin_unlock_irq(&cleanup_list_lock);
down_read(&net_sem);
if (nr_sync_pernet_ops)
mutex_lock(&net_mutex);
/* Don't let anyone else find us. */
......@@ -516,11 +528,14 @@ static void cleanup_net(struct work_struct *work)
list_for_each_entry_reverse(ops, &pernet_list, list)
ops_exit_list(ops, &net_exit_list);
if (nr_sync_pernet_ops)
mutex_unlock(&net_mutex);
/* Free the net generic variables */
list_for_each_entry_reverse(ops, &pernet_list, list)
ops_free_list(ops, &net_exit_list);
mutex_unlock(&net_mutex);
up_read(&net_sem);
/* Ensure there are no outstanding rcu callbacks using this
* network namespace.
......@@ -547,8 +562,10 @@ static void cleanup_net(struct work_struct *work)
*/
void net_ns_barrier(void)
{
down_write(&net_sem);
mutex_lock(&net_mutex);
mutex_unlock(&net_mutex);
up_write(&net_sem);
}
EXPORT_SYMBOL(net_ns_barrier);
......@@ -633,6 +650,7 @@ static __net_exit void net_ns_net_exit(struct net *net)
static struct pernet_operations __net_initdata net_ns_ops = {
.init = net_ns_net_init,
.exit = net_ns_net_exit,
.async = true,
};
static const struct nla_policy rtnl_net_policy[NETNSA_MAX + 1] = {
......@@ -875,17 +893,12 @@ static int __init net_ns_init(void)
rcu_assign_pointer(init_net.gen, ng);
mutex_lock(&net_mutex);
down_write(&net_sem);
if (setup_net(&init_net, &init_user_ns))
panic("Could not setup the initial network namespace");
init_net_initialized = true;
rtnl_lock();
list_add_tail_rcu(&init_net.list, &net_namespace_list);
rtnl_unlock();
mutex_unlock(&net_mutex);
up_write(&net_sem);
register_pernet_subsys(&net_ns_ops);
......@@ -989,6 +1002,9 @@ static int register_pernet_operations(struct list_head *list,
rcu_barrier();
if (ops->id)
ida_remove(&net_generic_ids, *ops->id);
} else if (!ops->async) {
pr_info_once("Pernet operations %ps are sync.\n", ops);
nr_sync_pernet_ops++;
}
return error;
......@@ -996,7 +1012,8 @@ static int register_pernet_operations(struct list_head *list,
static void unregister_pernet_operations(struct pernet_operations *ops)
{
if (!ops->async)
BUG_ON(nr_sync_pernet_ops-- == 0);
__unregister_pernet_operations(ops);
rcu_barrier();
if (ops->id)
......@@ -1025,9 +1042,9 @@ static void unregister_pernet_operations(struct pernet_operations *ops)
int register_pernet_subsys(struct pernet_operations *ops)
{
int error;
mutex_lock(&net_mutex);
down_write(&net_sem);
error = register_pernet_operations(first_device, ops);
mutex_unlock(&net_mutex);
up_write(&net_sem);
return error;
}
EXPORT_SYMBOL_GPL(register_pernet_subsys);
......@@ -1043,9 +1060,9 @@ EXPORT_SYMBOL_GPL(register_pernet_subsys);
*/
void unregister_pernet_subsys(struct pernet_operations *ops)
{
mutex_lock(&net_mutex);
down_write(&net_sem);
unregister_pernet_operations(ops);
mutex_unlock(&net_mutex);
up_write(&net_sem);
}
EXPORT_SYMBOL_GPL(unregister_pernet_subsys);
......@@ -1071,11 +1088,11 @@ EXPORT_SYMBOL_GPL(unregister_pernet_subsys);
int register_pernet_device(struct pernet_operations *ops)
{
int error;
mutex_lock(&net_mutex);
down_write(&net_sem);
error = register_pernet_operations(&pernet_list, ops);
if (!error && (first_device == &pernet_list))
first_device = &ops->list;
mutex_unlock(&net_mutex);
up_write(&net_sem);
return error;
}
EXPORT_SYMBOL_GPL(register_pernet_device);
......@@ -1091,11 +1108,11 @@ EXPORT_SYMBOL_GPL(register_pernet_device);
*/
void unregister_pernet_device(struct pernet_operations *ops)
{
mutex_lock(&net_mutex);
down_write(&net_sem);
if (&ops->list == first_device)
first_device = first_device->next;
unregister_pernet_operations(ops);
mutex_unlock(&net_mutex);
up_write(&net_sem);
}
EXPORT_SYMBOL_GPL(unregister_pernet_device);
......
......@@ -454,11 +454,11 @@ static void rtnl_lock_unregistering_all(void)
void rtnl_link_unregister(struct rtnl_link_ops *ops)
{
/* Close the race with cleanup_net() */
mutex_lock(&net_mutex);
down_write(&net_sem);
rtnl_lock_unregistering_all();
__rtnl_link_unregister(ops);
rtnl_unlock();
mutex_unlock(&net_mutex);
up_write(&net_sem);
}
EXPORT_SYMBOL_GPL(rtnl_link_unregister);
......@@ -4724,6 +4724,7 @@ static void __net_exit rtnetlink_net_exit(struct net *net)
static struct pernet_operations rtnetlink_net_ops = {
.init = rtnetlink_net_init,
.exit = rtnetlink_net_exit,
.async = true,
};
void __init rtnetlink_init(void)
......
......@@ -3112,6 +3112,7 @@ static void __net_exit sock_inuse_exit_net(struct net *net)
static struct pernet_operations net_inuse_ops = {
.init = sock_inuse_init_net,
.exit = sock_inuse_exit_net,
.async = true,
};
static __init int net_inuse_init(void)
......@@ -3385,6 +3386,7 @@ static __net_exit void proto_exit_net(struct net *net)
static __net_initdata struct pernet_operations proto_net_ops = {
.init = proto_init_net,
.exit = proto_exit_net,
.async = true,
};
static int __init proto_init(void)
......
......@@ -328,6 +328,7 @@ static void __net_exit diag_net_exit(struct net *net)
static struct pernet_operations diag_net_ops = {
.init = diag_net_init,
.exit = diag_net_exit,
.async = true,
};
static int __init sock_diag_init(void)
......
......@@ -572,6 +572,7 @@ static __net_exit void sysctl_core_net_exit(struct net *net)
static __net_initdata struct pernet_operations sysctl_core_ops = {
.init = sysctl_core_net_init,
.exit = sysctl_core_net_exit,
.async = true,
};
static __init int sysctl_core_init(void)
......
......@@ -1735,6 +1735,7 @@ static __net_exit void ipv4_mib_exit_net(struct net *net)
static __net_initdata struct pernet_operations ipv4_mib_ops = {
.init = ipv4_mib_init_net,
.exit = ipv4_mib_exit_net,
.async = true,
};
static int __init init_ipv4_mibs(void)
......@@ -1788,6 +1789,7 @@ static __net_exit void inet_exit_net(struct net *net)
static __net_initdata struct pernet_operations af_inet_ops = {
.init = inet_init_net,
.exit = inet_exit_net,
.async = true,
};
static int __init init_inet_pernet_ops(void)
......
......@@ -1447,6 +1447,7 @@ static void __net_exit arp_net_exit(struct net *net)
static struct pernet_operations arp_net_ops = {
.init = arp_net_init,
.exit = arp_net_exit,
.async = true,
};
static int __init arp_proc_init(void)
......
......@@ -2469,6 +2469,7 @@ static __net_exit void devinet_exit_net(struct net *net)
static __net_initdata struct pernet_operations devinet_ops = {
.init = devinet_init_net,
.exit = devinet_exit_net,
.async = true,
};
static struct rtnl_af_ops inet_af_ops __read_mostly = {
......
......@@ -1362,6 +1362,7 @@ static void __net_exit fib_net_exit(struct net *net)
static struct pernet_operations fib_net_ops = {
.init = fib_net_init,
.exit = fib_net_exit,
.async = true,
};
void __init ip_fib_init(void)
......
......@@ -1257,6 +1257,7 @@ static int __net_init icmp_sk_init(struct net *net)
static struct pernet_operations __net_initdata icmp_sk_ops = {
.init = icmp_sk_init,
.exit = icmp_sk_exit,
.async = true,
};
int __init icmp_init(void)
......
......@@ -3028,6 +3028,7 @@ static void __net_exit igmp_net_exit(struct net *net)
static struct pernet_operations igmp_net_ops = {
.init = igmp_net_init,
.exit = igmp_net_exit,
.async = true,
};
#endif
......
......@@ -885,6 +885,7 @@ static void __net_exit ipv4_frags_exit_net(struct net *net)
static struct pernet_operations ip4_frags_ops = {
.init = ipv4_frags_init_net,
.exit = ipv4_frags_exit_net,
.async = true,
};
void __init ipfrag_init(void)
......
......@@ -3327,6 +3327,7 @@ static void __net_exit ipmr_net_exit(struct net *net)
static struct pernet_operations ipmr_net_ops = {
.init = ipmr_net_init,
.exit = ipmr_net_exit,
.async = true,
};
int __init ip_mr_init(void)
......
......@@ -1204,6 +1204,7 @@ static void __net_exit ping_v4_proc_exit_net(struct net *net)
static struct pernet_operations ping_v4_net_ops = {
.init = ping_v4_proc_init_net,
.exit = ping_v4_proc_exit_net,
.async = true,
};
int __init ping_proc_init(void)
......
......@@ -549,6 +549,7 @@ static __net_exit void ip_proc_exit_net(struct net *net)
static __net_initdata struct pernet_operations ip_proc_ops = {
.init = ip_proc_init_net,
.exit = ip_proc_exit_net,
.async = true,
};
int __init ip_misc_proc_init(void)
......
......@@ -1156,6 +1156,7 @@ static __net_exit void raw_exit_net(struct net *net)
static __net_initdata struct pernet_operations raw_net_ops = {
.init = raw_init_net,
.exit = raw_exit_net,
.async = true,
};
int __init raw_proc_init(void)
......
......@@ -417,6 +417,7 @@ static void __net_exit ip_rt_do_proc_exit(struct net *net)
static struct pernet_operations ip_rt_proc_ops __net_initdata = {
.init = ip_rt_do_proc_init,
.exit = ip_rt_do_proc_exit,
.async = true,
};
static int __init ip_rt_proc_init(void)
......@@ -2994,6 +2995,7 @@ static __net_exit void sysctl_route_net_exit(struct net *net)
static __net_initdata struct pernet_operations sysctl_route_ops = {
.init = sysctl_route_net_init,
.exit = sysctl_route_net_exit,
.async = true,
};
#endif
......@@ -3007,6 +3009,7 @@ static __net_init int rt_genid_init(struct net *net)
static __net_initdata struct pernet_operations rt_genid_ops = {
.init = rt_genid_init,
.async = true,
};
static int __net_init ipv4_inetpeer_init(struct net *net)
......@@ -3032,6 +3035,7 @@ static void __net_exit ipv4_inetpeer_exit(struct net *net)
static __net_initdata struct pernet_operations ipv4_inetpeer_ops = {
.init = ipv4_inetpeer_init,
.exit = ipv4_inetpeer_exit,
.async = true,
};
#ifdef CONFIG_IP_ROUTE_CLASSID
......
......@@ -1219,6 +1219,7 @@ static __net_exit void ipv4_sysctl_exit_net(struct net *net)
static __net_initdata struct pernet_operations ipv4_sysctl_ops = {
.init = ipv4_sysctl_init_net,
.exit = ipv4_sysctl_exit_net,
.async = true,
};
static __init int sysctl_ipv4_init(void)
......
......@@ -2387,6 +2387,7 @@ static void __net_exit tcp4_proc_exit_net(struct net *net)
static struct pernet_operations tcp4_net_ops = {
.init = tcp4_proc_init_net,
.exit = tcp4_proc_exit_net,
.async = true,
};
int __init tcp4_proc_init(void)
......@@ -2573,6 +2574,7 @@ static struct pernet_operations __net_initdata tcp_sk_ops = {
.init = tcp_sk_init,
.exit = tcp_sk_exit,
.exit_batch = tcp_sk_exit_batch,
.async = true,
};
void __init tcp_v4_init(void)
......
......@@ -1024,6 +1024,7 @@ static void __net_exit tcp_net_metrics_exit_batch(struct list_head *net_exit_lis
static __net_initdata struct pernet_operations tcp_net_metrics_ops = {
.init = tcp_net_metrics_init,
.exit_batch = tcp_net_metrics_exit_batch,
.async = true,
};
void __init tcp_metrics_init(void)
......
......@@ -2757,6 +2757,7 @@ static void __net_exit udp4_proc_exit_net(struct net *net)
static struct pernet_operations udp4_net_ops = {
.init = udp4_proc_init_net,
.exit = udp4_proc_exit_net,
.async = true,
};
int __init udp4_proc_init(void)
......
......@@ -104,6 +104,7 @@ static void __net_exit udplite4_proc_exit_net(struct net *net)
static struct pernet_operations udplite4_net_ops = {
.init = udplite4_proc_init_net,
.exit = udplite4_proc_exit_net,
.async = true,
};
static __init int udplite4_proc_init(void)
......
......@@ -365,6 +365,7 @@ static void __net_exit xfrm4_net_exit(struct net *net)
static struct pernet_operations __net_initdata xfrm4_net_ops = {
.init = xfrm4_net_init,
.exit = xfrm4_net_exit,
.async = true,
};
static void __init xfrm4_policy_init(void)
......
......@@ -6550,6 +6550,7 @@ static void __net_exit addrconf_exit_net(struct net *net)
static struct pernet_operations addrconf_ops = {
.init = addrconf_init_net,
.exit = addrconf_exit_net,
.async = true,
};
static struct rtnl_af_ops inet6_ops __read_mostly = {
......
......@@ -629,6 +629,7 @@ static void __net_exit netfilter_net_exit(struct net *net)
static struct pernet_operations netfilter_net_ops = {
.init = netfilter_net_init,
.exit = netfilter_net_exit,
.async = true,
};
int __init netfilter_init(void)
......
......@@ -577,6 +577,7 @@ static void __net_exit nf_log_net_exit(struct net *net)
static struct pernet_operations nf_log_net_ops = {
.init = nf_log_net_init,
.exit = nf_log_net_exit,
.async = true,
};
int __init netfilter_log_init(void)
......
......@@ -253,6 +253,7 @@ static struct pernet_operations netlink_tap_net_ops = {
.exit = netlink_tap_exit_net,
.id = &netlink_tap_net_id,
.size = sizeof(struct netlink_tap_net),
.async = true,
};
static bool netlink_filter_tap(const struct sk_buff *skb)
......@@ -2723,6 +2724,7 @@ static void __init netlink_add_usersock_entry(void)
static struct pernet_operations __net_initdata netlink_net_ops = {
.init = netlink_net_init,
.exit = netlink_net_exit,
.async = true,
};
static inline u32 netlink_hash(const void *data, u32 len, u32 seed)
......
......@@ -1035,6 +1035,7 @@ static void __net_exit genl_pernet_exit(struct net *net)
static struct pernet_operations genl_pernet_ops = {
.init = genl_pernet_init,
.exit = genl_pernet_exit,
.async = true,
};
static int __init genl_init(void)
......
......@@ -4557,6 +4557,7 @@ static void __net_exit packet_net_exit(struct net *net)
static struct pernet_operations packet_net_ops = {
.init = packet_net_init,
.exit = packet_net_exit,
.async = true,
};
......
......@@ -1454,6 +1454,7 @@ static struct pernet_operations tcf_action_net_ops = {
.exit = tcf_action_net_exit,
.id = &tcf_action_net_id,
.size = sizeof(struct tcf_action_net),
.async = true,
};
static int __init tc_action_init(void)
......
......@@ -2128,6 +2128,7 @@ static void __net_exit psched_net_exit(struct net *net)
static struct pernet_operations psched_net_ops = {
.init = psched_net_init,
.exit = psched_net_exit,
.async = true,
};
static int __init pktsched_init(void)
......
......@@ -89,6 +89,7 @@ static void __net_exit sysctl_net_exit(struct net *net)
static struct pernet_operations sysctl_pernet_ops = {
.init = sysctl_net_init,
.exit = sysctl_net_exit,
.async = true,
};
static struct ctl_table_header *net_header;
......
......@@ -2913,6 +2913,7 @@ static void __net_exit unix_net_exit(struct net *net)
static struct pernet_operations unix_net_ops = {
.init = unix_net_init,
.exit = unix_net_exit,
.async = true,
};
static int __init af_unix_init(void)
......
......@@ -390,6 +390,7 @@ static void __net_exit wext_pernet_exit(struct net *net)
static struct pernet_operations wext_pernet_ops = {
.init = wext_pernet_init,
.exit = wext_pernet_exit,
.async = true,
};
static int __init wireless_nlevent_init(void)
......
......@@ -2982,6 +2982,7 @@ static void __net_exit xfrm_net_exit(struct net *net)
static struct pernet_operations __net_initdata xfrm_net_ops = {
.init = xfrm_net_init,
.exit = xfrm_net_exit,
.async = true,
};
void __init xfrm_init(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment