mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-12 00:00:00 +00:00
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 <ebiederm@xmission.com> Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com> Acked-by: Andrei Vagin <avagin@virtuozzo.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
bcab1ddd9b
commit
447cd7a0d7
@ -313,6 +313,12 @@ struct pernet_operations {
|
||||
void (*exit_batch)(struct list_head *net_exit_list);
|
||||
unsigned int *id;
|
||||
size_t size;
|
||||
/*
|
||||
* Indicates above methods are allowed to be executed in parallel
|
||||
* with methods of any other pernet_operations, i.e. they are not
|
||||
* need synchronization via net_mutex.
|
||||
*/
|
||||
bool async;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
static LIST_HEAD(pernet_list);
|
||||
static struct list_head *first_device = &pernet_list;
|
||||
/* Used only if there are !async pernet_operations registered */
|
||||
DEFINE_MUTEX(net_mutex);
|
||||
|
||||
LIST_HEAD(net_namespace_list);
|
||||
@ -41,8 +42,9 @@ struct net init_net = {
|
||||
EXPORT_SYMBOL(init_net);
|
||||
|
||||
static bool init_net_initialized;
|
||||
static unsigned nr_sync_pernet_ops;
|
||||
/*
|
||||
* net_sem: protects: pernet_list, net_generic_ids,
|
||||
* net_sem: protects: pernet_list, net_generic_ids, nr_sync_pernet_ops,
|
||||
* init_net_initialized and first_device pointer.
|
||||
*/
|
||||
DECLARE_RWSEM(net_sem);
|
||||
@ -70,11 +72,10 @@ static int net_assign_generic(struct net *net, unsigned int id, void *data)
|
||||
{
|
||||
struct net_generic *ng, *old_ng;
|
||||
|
||||
BUG_ON(!mutex_is_locked(&net_mutex));
|
||||
BUG_ON(id < MIN_PERNET_OPS_ID);
|
||||
|
||||
old_ng = rcu_dereference_protected(net->gen,
|
||||
lockdep_is_held(&net_mutex));
|
||||
lockdep_is_held(&net_sem));
|
||||
if (old_ng->s.len > id) {
|
||||
old_ng->ptr[id] = data;
|
||||
return 0;
|
||||
@ -426,11 +427,14 @@ struct net *copy_net_ns(unsigned long flags,
|
||||
rv = down_read_killable(&net_sem);
|
||||
if (rv < 0)
|
||||
goto put_userns;
|
||||
rv = mutex_lock_killable(&net_mutex);
|
||||
if (rv < 0)
|
||||
goto up_read;
|
||||
if (nr_sync_pernet_ops) {
|
||||
rv = mutex_lock_killable(&net_mutex);
|
||||
if (rv < 0)
|
||||
goto up_read;
|
||||
}
|
||||
rv = setup_net(net, user_ns);
|
||||
mutex_unlock(&net_mutex);
|
||||
if (nr_sync_pernet_ops)
|
||||
mutex_unlock(&net_mutex);
|
||||
up_read:
|
||||
up_read(&net_sem);
|
||||
if (rv < 0) {
|
||||
@ -487,7 +491,8 @@ static void cleanup_net(struct work_struct *work)
|
||||
spin_unlock_irq(&cleanup_list_lock);
|
||||
|
||||
down_read(&net_sem);
|
||||
mutex_lock(&net_mutex);
|
||||
if (nr_sync_pernet_ops)
|
||||
mutex_lock(&net_mutex);
|
||||
|
||||
/* Don't let anyone else find us. */
|
||||
rtnl_lock();
|
||||
@ -522,7 +527,8 @@ static void cleanup_net(struct work_struct *work)
|
||||
list_for_each_entry_reverse(ops, &pernet_list, list)
|
||||
ops_exit_list(ops, &net_exit_list);
|
||||
|
||||
mutex_unlock(&net_mutex);
|
||||
if (nr_sync_pernet_ops)
|
||||
mutex_unlock(&net_mutex);
|
||||
|
||||
/* Free the net generic variables */
|
||||
list_for_each_entry_reverse(ops, &pernet_list, list)
|
||||
@ -994,6 +1000,9 @@ again:
|
||||
rcu_barrier();
|
||||
if (ops->id)
|
||||
ida_remove(&net_generic_ids, *ops->id);
|
||||
} else if (!ops->async) {
|
||||
pr_info_once("Pernet operations %ps are sync.\n", ops);
|
||||
nr_sync_pernet_ops++;
|
||||
}
|
||||
|
||||
return error;
|
||||
@ -1001,7 +1010,8 @@ again:
|
||||
|
||||
static void unregister_pernet_operations(struct pernet_operations *ops)
|
||||
{
|
||||
|
||||
if (!ops->async)
|
||||
BUG_ON(nr_sync_pernet_ops-- == 0);
|
||||
__unregister_pernet_operations(ops);
|
||||
rcu_barrier();
|
||||
if (ops->id)
|
||||
|
Loading…
x
Reference in New Issue
Block a user