From 6fb255bed1c82a24931595502a8e393200c7dd52 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Sun, 16 Oct 2016 17:18:43 -0700 Subject: [PATCH] [RFC] net: convert net_mutex into a read-write lock It protects per-namespace lists of operations, which are modified only when modules are loaded or unloaded. And the kernel reads these lists to create or destroy a new network namespace. Signed-off-by: Andrei Vagin --- include/linux/rtnetlink.h | 2 +- net/core/net_namespace.c | 32 ++++++++++++++++---------------- net/core/rtnetlink.c | 4 ++-- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 57e5484..1a780a3 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -30,7 +30,7 @@ extern int rtnl_trylock(void); extern int rtnl_is_locked(void); extern wait_queue_head_t netdev_unregistering_wq; -extern struct mutex net_mutex; +extern struct rw_semaphore net_mutex; #ifdef CONFIG_PROVE_LOCKING extern bool lockdep_rtnl_is_held(void); diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 989434f..81dafce 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -27,7 +27,7 @@ static LIST_HEAD(pernet_list); static struct list_head *first_device = &pernet_list; -DEFINE_MUTEX(net_mutex); +DECLARE_RWSEM(net_mutex); LIST_HEAD(net_namespace_list); EXPORT_SYMBOL_GPL(net_namespace_list); @@ -59,7 +59,7 @@ static int net_assign_generic(struct net *net, int id, void *data) { struct net_generic *ng, *old_ng; - BUG_ON(!mutex_is_locked(&net_mutex)); + BUG_ON(!rwsem_is_locked(&net_mutex)); BUG_ON(id == 0); old_ng = rcu_dereference_protected(net->gen, @@ -379,7 +379,7 @@ struct net *copy_net_ns(unsigned long flags, get_user_ns(user_ns); - mutex_lock(&net_mutex); + down_read(&net_mutex); net->ucounts = ucounts; rv = setup_net(net, user_ns); if (rv == 0) { @@ -387,7 +387,7 @@ struct net *copy_net_ns(unsigned long flags, list_add_tail_rcu(&net->list, &net_namespace_list); rtnl_unlock(); } - mutex_unlock(&net_mutex); + up_read(&net_mutex); if (rv < 0) { dec_net_namespaces(ucounts); put_user_ns(user_ns); @@ -412,7 +412,7 @@ static void cleanup_net(struct work_struct *work) list_replace_init(&cleanup_list, &net_kill_list); spin_unlock_irq(&cleanup_list_lock); - mutex_lock(&net_mutex); + down_read(&net_mutex); /* Don't let anyone else find us. */ rtnl_lock(); @@ -452,7 +452,7 @@ static void cleanup_net(struct work_struct *work) list_for_each_entry_reverse(ops, &pernet_list, list) ops_free_list(ops, &net_exit_list); - mutex_unlock(&net_mutex); + up_read(&net_mutex); /* Ensure there are no outstanding rcu callbacks using this * network namespace. @@ -763,7 +763,7 @@ static int __init net_ns_init(void) rcu_assign_pointer(init_net.gen, ng); - mutex_lock(&net_mutex); + down_read(&net_mutex); if (setup_net(&init_net, &init_user_ns)) panic("Could not setup the initial network namespace"); @@ -773,7 +773,7 @@ static int __init net_ns_init(void) list_add_tail_rcu(&init_net.list, &net_namespace_list); rtnl_unlock(); - mutex_unlock(&net_mutex); + up_read(&net_mutex); register_pernet_subsys(&net_ns_ops); @@ -912,9 +912,9 @@ static void unregister_pernet_operations(struct pernet_operations *ops) int register_pernet_subsys(struct pernet_operations *ops) { int error; - mutex_lock(&net_mutex); + down_write(&net_mutex); error = register_pernet_operations(first_device, ops); - mutex_unlock(&net_mutex); + up_write(&net_mutex); return error; } EXPORT_SYMBOL_GPL(register_pernet_subsys); @@ -930,9 +930,9 @@ EXPORT_SYMBOL_GPL(register_pernet_subsys); */ void unregister_pernet_subsys(struct pernet_operations *ops) { - mutex_lock(&net_mutex); + down_write(&net_mutex); unregister_pernet_operations(ops); - mutex_unlock(&net_mutex); + up_write(&net_mutex); } EXPORT_SYMBOL_GPL(unregister_pernet_subsys); @@ -958,11 +958,11 @@ EXPORT_SYMBOL_GPL(unregister_pernet_subsys); int register_pernet_device(struct pernet_operations *ops) { int error; - mutex_lock(&net_mutex); + down_write(&net_mutex); error = register_pernet_operations(&pernet_list, ops); if (!error && (first_device == &pernet_list)) first_device = &ops->list; - mutex_unlock(&net_mutex); + up_write(&net_mutex); return error; } EXPORT_SYMBOL_GPL(register_pernet_device); @@ -978,11 +978,11 @@ EXPORT_SYMBOL_GPL(register_pernet_device); */ void unregister_pernet_device(struct pernet_operations *ops) { - mutex_lock(&net_mutex); + down_write(&net_mutex); if (&ops->list == first_device) first_device = first_device->next; unregister_pernet_operations(ops); - mutex_unlock(&net_mutex); + up_write(&net_mutex); } EXPORT_SYMBOL_GPL(unregister_pernet_device); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index b06d2f4..7533419 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -418,11 +418,11 @@ static void rtnl_lock_unregistering_all(void) void rtnl_link_unregister(struct rtnl_link_ops *ops) { /* Close the race with cleanup_net() */ - mutex_lock(&net_mutex); + down_write(&net_mutex); rtnl_lock_unregistering_all(); __rtnl_link_unregister(ops); rtnl_unlock(); - mutex_unlock(&net_mutex); + up_write(&net_mutex); } EXPORT_SYMBOL_GPL(rtnl_link_unregister); -- 2.7.4