diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/core/net_namespace.c | 131 |
1 files changed, 68 insertions, 63 deletions
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 4e52921ade09..d5bf8b28bbf4 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c | |||
@@ -22,65 +22,6 @@ static struct kmem_cache *net_cachep; | |||
22 | struct net init_net; | 22 | struct net init_net; |
23 | EXPORT_SYMBOL_GPL(init_net); | 23 | EXPORT_SYMBOL_GPL(init_net); |
24 | 24 | ||
25 | static struct net *net_alloc(void) | ||
26 | { | ||
27 | return kmem_cache_zalloc(net_cachep, GFP_KERNEL); | ||
28 | } | ||
29 | |||
30 | static void net_free(struct net *net) | ||
31 | { | ||
32 | if (!net) | ||
33 | return; | ||
34 | |||
35 | if (unlikely(atomic_read(&net->use_count) != 0)) { | ||
36 | printk(KERN_EMERG "network namespace not free! Usage: %d\n", | ||
37 | atomic_read(&net->use_count)); | ||
38 | return; | ||
39 | } | ||
40 | |||
41 | kmem_cache_free(net_cachep, net); | ||
42 | } | ||
43 | |||
44 | static void cleanup_net(struct work_struct *work) | ||
45 | { | ||
46 | struct pernet_operations *ops; | ||
47 | struct net *net; | ||
48 | |||
49 | net = container_of(work, struct net, work); | ||
50 | |||
51 | mutex_lock(&net_mutex); | ||
52 | |||
53 | /* Don't let anyone else find us. */ | ||
54 | rtnl_lock(); | ||
55 | list_del(&net->list); | ||
56 | rtnl_unlock(); | ||
57 | |||
58 | /* Run all of the network namespace exit methods */ | ||
59 | list_for_each_entry_reverse(ops, &pernet_list, list) { | ||
60 | if (ops->exit) | ||
61 | ops->exit(net); | ||
62 | } | ||
63 | |||
64 | mutex_unlock(&net_mutex); | ||
65 | |||
66 | /* Ensure there are no outstanding rcu callbacks using this | ||
67 | * network namespace. | ||
68 | */ | ||
69 | rcu_barrier(); | ||
70 | |||
71 | /* Finally it is safe to free my network namespace structure */ | ||
72 | net_free(net); | ||
73 | } | ||
74 | |||
75 | |||
76 | void __put_net(struct net *net) | ||
77 | { | ||
78 | /* Cleanup the network namespace in process context */ | ||
79 | INIT_WORK(&net->work, cleanup_net); | ||
80 | schedule_work(&net->work); | ||
81 | } | ||
82 | EXPORT_SYMBOL_GPL(__put_net); | ||
83 | |||
84 | /* | 25 | /* |
85 | * setup_net runs the initializers for the network namespace object. | 26 | * setup_net runs the initializers for the network namespace object. |
86 | */ | 27 | */ |
@@ -117,6 +58,12 @@ out_undo: | |||
117 | goto out; | 58 | goto out; |
118 | } | 59 | } |
119 | 60 | ||
61 | #ifdef CONFIG_NET_NS | ||
62 | static struct net *net_alloc(void) | ||
63 | { | ||
64 | return kmem_cache_zalloc(net_cachep, GFP_KERNEL); | ||
65 | } | ||
66 | |||
120 | struct net *copy_net_ns(unsigned long flags, struct net *old_net) | 67 | struct net *copy_net_ns(unsigned long flags, struct net *old_net) |
121 | { | 68 | { |
122 | struct net *new_net = NULL; | 69 | struct net *new_net = NULL; |
@@ -127,10 +74,6 @@ struct net *copy_net_ns(unsigned long flags, struct net *old_net) | |||
127 | if (!(flags & CLONE_NEWNET)) | 74 | if (!(flags & CLONE_NEWNET)) |
128 | return old_net; | 75 | return old_net; |
129 | 76 | ||
130 | #ifndef CONFIG_NET_NS | ||
131 | return ERR_PTR(-EINVAL); | ||
132 | #endif | ||
133 | |||
134 | err = -ENOMEM; | 77 | err = -ENOMEM; |
135 | new_net = net_alloc(); | 78 | new_net = net_alloc(); |
136 | if (!new_net) | 79 | if (!new_net) |
@@ -157,6 +100,68 @@ out: | |||
157 | return new_net; | 100 | return new_net; |
158 | } | 101 | } |
159 | 102 | ||
103 | static void net_free(struct net *net) | ||
104 | { | ||
105 | if (!net) | ||
106 | return; | ||
107 | |||
108 | if (unlikely(atomic_read(&net->use_count) != 0)) { | ||
109 | printk(KERN_EMERG "network namespace not free! Usage: %d\n", | ||
110 | atomic_read(&net->use_count)); | ||
111 | return; | ||
112 | } | ||
113 | |||
114 | kmem_cache_free(net_cachep, net); | ||
115 | } | ||
116 | |||
117 | static void cleanup_net(struct work_struct *work) | ||
118 | { | ||
119 | struct pernet_operations *ops; | ||
120 | struct net *net; | ||
121 | |||
122 | net = container_of(work, struct net, work); | ||
123 | |||
124 | mutex_lock(&net_mutex); | ||
125 | |||
126 | /* Don't let anyone else find us. */ | ||
127 | rtnl_lock(); | ||
128 | list_del(&net->list); | ||
129 | rtnl_unlock(); | ||
130 | |||
131 | /* Run all of the network namespace exit methods */ | ||
132 | list_for_each_entry_reverse(ops, &pernet_list, list) { | ||
133 | if (ops->exit) | ||
134 | ops->exit(net); | ||
135 | } | ||
136 | |||
137 | mutex_unlock(&net_mutex); | ||
138 | |||
139 | /* Ensure there are no outstanding rcu callbacks using this | ||
140 | * network namespace. | ||
141 | */ | ||
142 | rcu_barrier(); | ||
143 | |||
144 | /* Finally it is safe to free my network namespace structure */ | ||
145 | net_free(net); | ||
146 | } | ||
147 | |||
148 | void __put_net(struct net *net) | ||
149 | { | ||
150 | /* Cleanup the network namespace in process context */ | ||
151 | INIT_WORK(&net->work, cleanup_net); | ||
152 | schedule_work(&net->work); | ||
153 | } | ||
154 | EXPORT_SYMBOL_GPL(__put_net); | ||
155 | |||
156 | #else | ||
157 | struct net *copy_net_ns(unsigned long flags, struct net *old_net) | ||
158 | { | ||
159 | if (flags & CLONE_NEWNET) | ||
160 | return ERR_PTR(-EINVAL); | ||
161 | return old_net; | ||
162 | } | ||
163 | #endif | ||
164 | |||
160 | static int __init net_ns_init(void) | 165 | static int __init net_ns_init(void) |
161 | { | 166 | { |
162 | int err; | 167 | int err; |