Skip to content

Commit 9edb9cc

Browse files
Kirill TkhaiNagarathnam Muthusamy
authored andcommitted
net: Allow pernet_operations to be executed in parallel
This adds new pernet_operations::async flag to indicate operations, which ->init(), ->exit() and ->exit_batch() methods are allowed to be executed in parallel with the methods of any other pernet_operations. When there are only asynchronous pernet_operations in the system, net_mutex won't be taken for a net construction and destruction. Also, remove BUG_ON(mutex_is_locked()) from net_assign_generic() without replacing with the equivalent net_sem check, as there is one more lockdep assert below. v3: Add comment near net_mutex. Suggested-by: Eric W. Biederman <[email protected]> Signed-off-by: Kirill Tkhai <[email protected]> Acked-by: Andrei Vagin <[email protected]> Signed-off-by: David S. Miller <[email protected]> (cherry picked from commit 447cd7a) Orabug: 28900385 Signed-off-by: Nagarathnam Muthusamy <[email protected]> Reviewed-by: Darren Kenny <[email protected]>
1 parent 8366eb4 commit 9edb9cc

File tree

2 files changed

+26
-10
lines changed

2 files changed

+26
-10
lines changed

include/net/net_namespace.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,12 @@ struct pernet_operations {
313313
void (*exit_batch)(struct list_head *net_exit_list);
314314
unsigned int *id;
315315
size_t size;
316+
/*
317+
* Indicates above methods are allowed to be executed in parallel
318+
* with methods of any other pernet_operations, i.e. they are not
319+
* need synchronization via net_mutex.
320+
*/
321+
bool async;
316322
};
317323

318324
/*

net/core/net_namespace.c

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
static LIST_HEAD(pernet_list);
3131
static struct list_head *first_device = &pernet_list;
32+
/* Used only if there are !async pernet_operations registered */
3233
DEFINE_MUTEX(net_mutex);
3334

3435
LIST_HEAD(net_namespace_list);
@@ -41,8 +42,9 @@ struct net init_net = {
4142
EXPORT_SYMBOL(init_net);
4243

4344
static bool init_net_initialized;
45+
static unsigned nr_sync_pernet_ops;
4446
/*
45-
* net_sem: protects: pernet_list, net_generic_ids,
47+
* net_sem: protects: pernet_list, net_generic_ids, nr_sync_pernet_ops,
4648
* init_net_initialized and first_device pointer.
4749
*/
4850
DECLARE_RWSEM(net_sem);
@@ -70,11 +72,10 @@ static int net_assign_generic(struct net *net, unsigned int id, void *data)
7072
{
7173
struct net_generic *ng, *old_ng;
7274

73-
BUG_ON(!mutex_is_locked(&net_mutex));
7475
BUG_ON(id < MIN_PERNET_OPS_ID);
7576

7677
old_ng = rcu_dereference_protected(net->gen,
77-
lockdep_is_held(&net_mutex));
78+
lockdep_is_held(&net_sem));
7879
if (old_ng->s.len > id) {
7980
old_ng->ptr[id] = data;
8081
return 0;
@@ -418,11 +419,14 @@ struct net *copy_net_ns(unsigned long flags,
418419
rv = down_read_killable(&net_sem);
419420
if (rv < 0)
420421
goto put_userns;
421-
rv = mutex_lock_killable(&net_mutex);
422-
if (rv < 0)
423-
goto up_read;
422+
if (nr_sync_pernet_ops) {
423+
rv = mutex_lock_killable(&net_mutex);
424+
if (rv < 0)
425+
goto up_read;
426+
}
424427
rv = setup_net(net, user_ns);
425-
mutex_unlock(&net_mutex);
428+
if (nr_sync_pernet_ops)
429+
mutex_unlock(&net_mutex);
426430
up_read:
427431
up_read(&net_sem);
428432
if (rv < 0) {
@@ -452,7 +456,8 @@ static void cleanup_net(struct work_struct *work)
452456
spin_unlock_irq(&cleanup_list_lock);
453457

454458
down_read(&net_sem);
455-
mutex_lock(&net_mutex);
459+
if (nr_sync_pernet_ops)
460+
mutex_lock(&net_mutex);
456461

457462
/* Don't let anyone else find us. */
458463
rtnl_lock();
@@ -488,7 +493,8 @@ static void cleanup_net(struct work_struct *work)
488493
list_for_each_entry_reverse(ops, &pernet_list, list)
489494
ops_exit_list(ops, &net_exit_list);
490495

491-
mutex_unlock(&net_mutex);
496+
if (nr_sync_pernet_ops)
497+
mutex_unlock(&net_mutex);
492498

493499
/* Free the net generic variables */
494500
list_for_each_entry_reverse(ops, &pernet_list, list)
@@ -960,14 +966,18 @@ static int register_pernet_operations(struct list_head *list,
960966
rcu_barrier();
961967
if (ops->id)
962968
ida_remove(&net_generic_ids, *ops->id);
969+
} else if (!ops->async) {
970+
pr_info_once("Pernet operations %ps are sync.\n", ops);
971+
nr_sync_pernet_ops++;
963972
}
964973

965974
return error;
966975
}
967976

968977
static void unregister_pernet_operations(struct pernet_operations *ops)
969978
{
970-
979+
if (!ops->async)
980+
BUG_ON(nr_sync_pernet_ops-- == 0);
971981
__unregister_pernet_operations(ops);
972982
rcu_barrier();
973983
if (ops->id)

0 commit comments

Comments
 (0)