@@ -70,6 +70,36 @@ static void ops_free(const struct pernet_operations *ops, struct net *net)
70
70
}
71
71
}
72
72
73
+ static void ops_exit_list (const struct pernet_operations * ops ,
74
+ struct list_head * net_exit_list )
75
+ {
76
+ struct net * net ;
77
+ if (ops -> exit ) {
78
+ list_for_each_entry (net , net_exit_list , exit_list )
79
+ ops -> exit (net );
80
+ }
81
+ if (& ops -> list == first_device ) {
82
+ LIST_HEAD (dev_kill_list );
83
+ rtnl_lock ();
84
+ list_for_each_entry (net , net_exit_list , exit_list )
85
+ unregister_netdevices (net , & dev_kill_list );
86
+ unregister_netdevice_many (& dev_kill_list );
87
+ rtnl_unlock ();
88
+ }
89
+ if (ops -> exit_batch )
90
+ ops -> exit_batch (net_exit_list );
91
+ }
92
+
93
+ static void ops_free_list (const struct pernet_operations * ops ,
94
+ struct list_head * net_exit_list )
95
+ {
96
+ struct net * net ;
97
+ if (ops -> size && ops -> id ) {
98
+ list_for_each_entry (net , net_exit_list , exit_list )
99
+ ops_free (ops , net );
100
+ }
101
+ }
102
+
73
103
/*
74
104
* setup_net runs the initializers for the network namespace object.
75
105
*/
@@ -78,6 +108,7 @@ static __net_init int setup_net(struct net *net)
78
108
/* Must be called with net_mutex held */
79
109
const struct pernet_operations * ops , * saved_ops ;
80
110
int error = 0 ;
111
+ LIST_HEAD (net_exit_list );
81
112
82
113
atomic_set (& net -> count , 1 );
83
114
@@ -97,21 +128,14 @@ static __net_init int setup_net(struct net *net)
97
128
/* Walk through the list backwards calling the exit functions
98
129
* for the pernet modules whose init functions did not fail.
99
130
*/
131
+ list_add (& net -> exit_list , & net_exit_list );
100
132
saved_ops = ops ;
101
- list_for_each_entry_continue_reverse (ops , & pernet_list , list ) {
102
- if (ops -> exit )
103
- ops -> exit (net );
104
- if (& ops -> list == first_device ) {
105
- LIST_HEAD (dev_kill_list );
106
- rtnl_lock ();
107
- unregister_netdevices (net , & dev_kill_list );
108
- unregister_netdevice_many (& dev_kill_list );
109
- rtnl_unlock ();
110
- }
111
- }
133
+ list_for_each_entry_continue_reverse (ops , & pernet_list , list )
134
+ ops_exit_list (ops , & net_exit_list );
135
+
112
136
ops = saved_ops ;
113
137
list_for_each_entry_continue_reverse (ops , & pernet_list , list )
114
- ops_free (ops , net );
138
+ ops_free_list (ops , & net_exit_list );
115
139
116
140
rcu_barrier ();
117
141
goto out ;
@@ -207,6 +231,7 @@ static void cleanup_net(struct work_struct *work)
207
231
const struct pernet_operations * ops ;
208
232
struct net * net , * tmp ;
209
233
LIST_HEAD (net_kill_list );
234
+ LIST_HEAD (net_exit_list );
210
235
211
236
/* Atomically snapshot the list of namespaces to cleanup */
212
237
spin_lock_irq (& cleanup_list_lock );
@@ -217,8 +242,10 @@ static void cleanup_net(struct work_struct *work)
217
242
218
243
/* Don't let anyone else find us. */
219
244
rtnl_lock ();
220
- list_for_each_entry (net , & net_kill_list , cleanup_list )
245
+ list_for_each_entry (net , & net_kill_list , cleanup_list ) {
221
246
list_del_rcu (& net -> list );
247
+ list_add_tail (& net -> exit_list , & net_exit_list );
248
+ }
222
249
rtnl_unlock ();
223
250
224
251
/*
@@ -229,27 +256,12 @@ static void cleanup_net(struct work_struct *work)
229
256
synchronize_rcu ();
230
257
231
258
/* Run all of the network namespace exit methods */
232
- list_for_each_entry_reverse (ops , & pernet_list , list ) {
233
- if (ops -> exit ) {
234
- list_for_each_entry (net , & net_kill_list , cleanup_list )
235
- ops -> exit (net );
236
- }
237
- if (& ops -> list == first_device ) {
238
- LIST_HEAD (dev_kill_list );
239
- rtnl_lock ();
240
- list_for_each_entry (net , & net_kill_list , cleanup_list )
241
- unregister_netdevices (net , & dev_kill_list );
242
- unregister_netdevice_many (& dev_kill_list );
243
- rtnl_unlock ();
244
- }
245
- }
259
+ list_for_each_entry_reverse (ops , & pernet_list , list )
260
+ ops_exit_list (ops , & net_exit_list );
261
+
246
262
/* Free the net generic variables */
247
- list_for_each_entry_reverse (ops , & pernet_list , list ) {
248
- if (ops -> size && ops -> id ) {
249
- list_for_each_entry (net , & net_kill_list , cleanup_list )
250
- ops_free (ops , net );
251
- }
252
- }
263
+ list_for_each_entry_reverse (ops , & pernet_list , list )
264
+ ops_free_list (ops , & net_exit_list );
253
265
254
266
mutex_unlock (& net_mutex );
255
267
@@ -259,8 +271,8 @@ static void cleanup_net(struct work_struct *work)
259
271
rcu_barrier ();
260
272
261
273
/* Finally it is safe to free my network namespace structure */
262
- list_for_each_entry_safe (net , tmp , & net_kill_list , cleanup_list ) {
263
- list_del_init (& net -> cleanup_list );
274
+ list_for_each_entry_safe (net , tmp , & net_exit_list , exit_list ) {
275
+ list_del_init (& net -> exit_list );
264
276
net_free (net );
265
277
}
266
278
}
@@ -348,52 +360,39 @@ pure_initcall(net_ns_init);
348
360
static int __register_pernet_operations (struct list_head * list ,
349
361
struct pernet_operations * ops )
350
362
{
351
- struct net * net , * undo_net ;
363
+ struct net * net ;
352
364
int error ;
365
+ LIST_HEAD (net_exit_list );
353
366
354
367
list_add_tail (& ops -> list , list );
355
368
if (ops -> init || (ops -> id && ops -> size )) {
356
369
for_each_net (net ) {
357
370
error = ops_init (ops , net );
358
371
if (error )
359
372
goto out_undo ;
373
+ list_add_tail (& net -> exit_list , & net_exit_list );
360
374
}
361
375
}
362
376
return 0 ;
363
377
364
378
out_undo :
365
379
/* If I have an error cleanup all namespaces I initialized */
366
380
list_del (& ops -> list );
367
- if (ops -> exit ) {
368
- for_each_net (undo_net ) {
369
- if (net_eq (undo_net , net ))
370
- goto undone ;
371
- ops -> exit (undo_net );
372
- }
373
- }
374
- undone :
375
- if (ops -> size && ops -> id ) {
376
- for_each_net (undo_net ) {
377
- if (net_eq (undo_net , net ))
378
- goto freed ;
379
- ops_free (ops , undo_net );
380
- }
381
- }
382
- freed :
381
+ ops_exit_list (ops , & net_exit_list );
382
+ ops_free_list (ops , & net_exit_list );
383
383
return error ;
384
384
}
385
385
386
386
static void __unregister_pernet_operations (struct pernet_operations * ops )
387
387
{
388
388
struct net * net ;
389
+ LIST_HEAD (net_exit_list );
389
390
390
391
list_del (& ops -> list );
391
- if (ops -> exit )
392
- for_each_net (net )
393
- ops -> exit (net );
394
- if (ops -> id && ops -> size )
395
- for_each_net (net )
396
- ops_free (ops , net );
392
+ for_each_net (net )
393
+ list_add_tail (& net -> exit_list , & net_exit_list );
394
+ ops_exit_list (ops , & net_exit_list );
395
+ ops_free_list (ops , & net_exit_list );
397
396
}
398
397
399
398
#else
@@ -411,9 +410,10 @@ static int __register_pernet_operations(struct list_head *list,
411
410
412
411
static void __unregister_pernet_operations (struct pernet_operations * ops )
413
412
{
414
- if (ops -> exit )
415
- ops -> exit (& init_net );
416
- ops_free (ops , & init_net );
413
+ LIST_HEAD (net_exit_list );
414
+ list_add (& init_net .exit_list , & net_exit_list );
415
+ ops_exit_list (ops , & net_exit_list );
416
+ ops_free_list (ops , & net_exit_list );
417
417
}
418
418
419
419
#endif /* CONFIG_NET_NS */
0 commit comments