aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/net_namespace.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/core/net_namespace.c')
-rw-r--r--net/core/net_namespace.c64
1 files changed, 34 insertions, 30 deletions
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index ea489db1bc2..2772ed11bec 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -29,6 +29,20 @@ EXPORT_SYMBOL(init_net);
29 29
30#define INITIAL_NET_GEN_PTRS 13 /* +1 for len +2 for rcu_head */ 30#define INITIAL_NET_GEN_PTRS 13 /* +1 for len +2 for rcu_head */
31 31
32static unsigned int max_gen_ptrs = INITIAL_NET_GEN_PTRS;
33
34static struct net_generic *net_alloc_generic(void)
35{
36 struct net_generic *ng;
37 size_t generic_size = offsetof(struct net_generic, ptr[max_gen_ptrs]);
38
39 ng = kzalloc(generic_size, GFP_KERNEL);
40 if (ng)
41 ng->len = max_gen_ptrs;
42
43 return ng;
44}
45
32static int net_assign_generic(struct net *net, int id, void *data) 46static int net_assign_generic(struct net *net, int id, void *data)
33{ 47{
34 struct net_generic *ng, *old_ng; 48 struct net_generic *ng, *old_ng;
@@ -42,8 +56,7 @@ static int net_assign_generic(struct net *net, int id, void *data)
42 if (old_ng->len >= id) 56 if (old_ng->len >= id)
43 goto assign; 57 goto assign;
44 58
45 ng = kzalloc(sizeof(struct net_generic) + 59 ng = net_alloc_generic();
46 id * sizeof(void *), GFP_KERNEL);
47 if (ng == NULL) 60 if (ng == NULL)
48 return -ENOMEM; 61 return -ENOMEM;
49 62
@@ -58,7 +71,6 @@ static int net_assign_generic(struct net *net, int id, void *data)
58 * the old copy for kfree after a grace period. 71 * the old copy for kfree after a grace period.
59 */ 72 */
60 73
61 ng->len = id;
62 memcpy(&ng->ptr, &old_ng->ptr, old_ng->len * sizeof(void*)); 74 memcpy(&ng->ptr, &old_ng->ptr, old_ng->len * sizeof(void*));
63 75
64 rcu_assign_pointer(net->gen, ng); 76 rcu_assign_pointer(net->gen, ng);
@@ -70,21 +82,29 @@ assign:
70 82
71static int ops_init(const struct pernet_operations *ops, struct net *net) 83static int ops_init(const struct pernet_operations *ops, struct net *net)
72{ 84{
73 int err; 85 int err = -ENOMEM;
86 void *data = NULL;
87
74 if (ops->id && ops->size) { 88 if (ops->id && ops->size) {
75 void *data = kzalloc(ops->size, GFP_KERNEL); 89 data = kzalloc(ops->size, GFP_KERNEL);
76 if (!data) 90 if (!data)
77 return -ENOMEM; 91 goto out;
78 92
79 err = net_assign_generic(net, *ops->id, data); 93 err = net_assign_generic(net, *ops->id, data);
80 if (err) { 94 if (err)
81 kfree(data); 95 goto cleanup;
82 return err;
83 }
84 } 96 }
97 err = 0;
85 if (ops->init) 98 if (ops->init)
86 return ops->init(net); 99 err = ops->init(net);
87 return 0; 100 if (!err)
101 return 0;
102
103cleanup:
104 kfree(data);
105
106out:
107 return err;
88} 108}
89 109
90static void ops_free(const struct pernet_operations *ops, struct net *net) 110static void ops_free(const struct pernet_operations *ops, struct net *net)
@@ -159,18 +179,6 @@ out_undo:
159 goto out; 179 goto out;
160} 180}
161 181
162static struct net_generic *net_alloc_generic(void)
163{
164 struct net_generic *ng;
165 size_t generic_size = sizeof(struct net_generic) +
166 INITIAL_NET_GEN_PTRS * sizeof(void *);
167
168 ng = kzalloc(generic_size, GFP_KERNEL);
169 if (ng)
170 ng->len = INITIAL_NET_GEN_PTRS;
171
172 return ng;
173}
174 182
175#ifdef CONFIG_NET_NS 183#ifdef CONFIG_NET_NS
176static struct kmem_cache *net_cachep; 184static struct kmem_cache *net_cachep;
@@ -446,12 +454,7 @@ static void __unregister_pernet_operations(struct pernet_operations *ops)
446static int __register_pernet_operations(struct list_head *list, 454static int __register_pernet_operations(struct list_head *list,
447 struct pernet_operations *ops) 455 struct pernet_operations *ops)
448{ 456{
449 int err = 0; 457 return ops_init(ops, &init_net);
450 err = ops_init(ops, &init_net);
451 if (err)
452 ops_free(ops, &init_net);
453 return err;
454
455} 458}
456 459
457static void __unregister_pernet_operations(struct pernet_operations *ops) 460static void __unregister_pernet_operations(struct pernet_operations *ops)
@@ -481,6 +484,7 @@ again:
481 } 484 }
482 return error; 485 return error;
483 } 486 }
487 max_gen_ptrs = max_t(unsigned int, max_gen_ptrs, *ops->id);
484 } 488 }
485 error = __register_pernet_operations(list, ops); 489 error = __register_pernet_operations(list, ops);
486 if (error) { 490 if (error) {