Skip to content

Commit 72ad937

Browse files
ebiedermdavem330
authored andcommitted
net: Add support for batching network namespace cleanups
- Add exit_list to struct net to support building lists of network namespaces to cleanup. - Add exit_batch to pernet_operations to allow running operations only once during a network namespace exit. Instead of once per network namespace. - Factor opt ops_exit_list and ops_exit_free so the logic with cleanup up a network namespace does not need to be duplicated. Signed-off-by: Eric W. Biederman <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 8153a10 commit 72ad937

File tree

2 files changed

+63
-61
lines changed

2 files changed

+63
-61
lines changed

include/net/net_namespace.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ struct net {
4343
#endif
4444
struct list_head list; /* list of network namespaces */
4545
struct list_head cleanup_list; /* namespaces on death row */
46+
struct list_head exit_list; /* Use only net_mutex */
4647

4748
struct proc_dir_entry *proc_net;
4849
struct proc_dir_entry *proc_net_stat;
@@ -236,6 +237,7 @@ struct pernet_operations {
236237
struct list_head list;
237238
int (*init)(struct net *net);
238239
void (*exit)(struct net *net);
240+
void (*exit_batch)(struct list_head *net_exit_list);
239241
int *id;
240242
size_t size;
241243
};

net/core/net_namespace.c

Lines changed: 61 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,36 @@ static void ops_free(const struct pernet_operations *ops, struct net *net)
7070
}
7171
}
7272

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+
73103
/*
74104
* setup_net runs the initializers for the network namespace object.
75105
*/
@@ -78,6 +108,7 @@ static __net_init int setup_net(struct net *net)
78108
/* Must be called with net_mutex held */
79109
const struct pernet_operations *ops, *saved_ops;
80110
int error = 0;
111+
LIST_HEAD(net_exit_list);
81112

82113
atomic_set(&net->count, 1);
83114

@@ -97,21 +128,14 @@ static __net_init int setup_net(struct net *net)
97128
/* Walk through the list backwards calling the exit functions
98129
* for the pernet modules whose init functions did not fail.
99130
*/
131+
list_add(&net->exit_list, &net_exit_list);
100132
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+
112136
ops = saved_ops;
113137
list_for_each_entry_continue_reverse(ops, &pernet_list, list)
114-
ops_free(ops, net);
138+
ops_free_list(ops, &net_exit_list);
115139

116140
rcu_barrier();
117141
goto out;
@@ -207,6 +231,7 @@ static void cleanup_net(struct work_struct *work)
207231
const struct pernet_operations *ops;
208232
struct net *net, *tmp;
209233
LIST_HEAD(net_kill_list);
234+
LIST_HEAD(net_exit_list);
210235

211236
/* Atomically snapshot the list of namespaces to cleanup */
212237
spin_lock_irq(&cleanup_list_lock);
@@ -217,8 +242,10 @@ static void cleanup_net(struct work_struct *work)
217242

218243
/* Don't let anyone else find us. */
219244
rtnl_lock();
220-
list_for_each_entry(net, &net_kill_list, cleanup_list)
245+
list_for_each_entry(net, &net_kill_list, cleanup_list) {
221246
list_del_rcu(&net->list);
247+
list_add_tail(&net->exit_list, &net_exit_list);
248+
}
222249
rtnl_unlock();
223250

224251
/*
@@ -229,27 +256,12 @@ static void cleanup_net(struct work_struct *work)
229256
synchronize_rcu();
230257

231258
/* 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+
246262
/* 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);
253265

254266
mutex_unlock(&net_mutex);
255267

@@ -259,8 +271,8 @@ static void cleanup_net(struct work_struct *work)
259271
rcu_barrier();
260272

261273
/* 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);
264276
net_free(net);
265277
}
266278
}
@@ -348,52 +360,39 @@ pure_initcall(net_ns_init);
348360
static int __register_pernet_operations(struct list_head *list,
349361
struct pernet_operations *ops)
350362
{
351-
struct net *net, *undo_net;
363+
struct net *net;
352364
int error;
365+
LIST_HEAD(net_exit_list);
353366

354367
list_add_tail(&ops->list, list);
355368
if (ops->init || (ops->id && ops->size)) {
356369
for_each_net(net) {
357370
error = ops_init(ops, net);
358371
if (error)
359372
goto out_undo;
373+
list_add_tail(&net->exit_list, &net_exit_list);
360374
}
361375
}
362376
return 0;
363377

364378
out_undo:
365379
/* If I have an error cleanup all namespaces I initialized */
366380
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);
383383
return error;
384384
}
385385

386386
static void __unregister_pernet_operations(struct pernet_operations *ops)
387387
{
388388
struct net *net;
389+
LIST_HEAD(net_exit_list);
389390

390391
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);
397396
}
398397

399398
#else
@@ -411,9 +410,10 @@ static int __register_pernet_operations(struct list_head *list,
411410

412411
static void __unregister_pernet_operations(struct pernet_operations *ops)
413412
{
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);
417417
}
418418

419419
#endif /* CONFIG_NET_NS */

0 commit comments

Comments
 (0)