[PATCH net-next v3 00/32] Replacing net_mutex with rw_semaphore

STALE3126d

Revision v3 of 3 in this series.

36 messages, 3 authors, 2018-02-26 · open the first message on its own page

[PATCH net-next v3 00/32] Replacing net_mutex with rw_semaphore

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:26:03

Hi,

this is the third version of the patchset introducing net_sem
instead of net_mutex. The patchset adds net_sem in addition
to net_mutex and allows pernet_operations to be "async". This
flag means, the pernet_operations methods are safe to be
executed with any other pernet_operations (un)initializing
another net.

If there are only async pernet_operations in the system,
net_mutex is not used either for setup_net() or for cleanup_net().

The pernet_operations converted in this patchset allow
to create minimal .config to have network working, and
the changes improve the performance like you may see
below:

    %for i in {1..10000}; do unshare -n bash -c exit; done
    
    *before*
    real 1m40,377s
    user 0m9,672s
    sys 0m19,928s
    
    *after*
    real 0m17,007s
    user 0m5,311s
    sys 0m11,779
    
    (5.8 times faster)

In the future, when all pernet_operations become async,
we'll just remove this "async" field tree-wide.

All the new logic is concentrated in patches [1-5/32].
The rest of patches converts specific operations:
review, rationale of they can be converted, and setting
of async flag.

Kirill

v3: Improved patches descriptions. Added comment into [5/32].
Added [32/32] converting netlink_tap_net_ops (new pernet operations
introduced in 2018).

v2: Single patch -> patchset with rationale of every conversion

---

Kirill Tkhai (32):
      net: Assign net to net_namespace_list in setup_net()
      net: Cleanup in copy_net_ns()
      net: Introduce net_sem for protection of pernet_list
      net: Move mutex_unlock() in cleanup_net() up
      net: Allow pernet_operations to be executed in parallel
      net: Convert proc_net_ns_ops
      net: Convert net_ns_ops methods
      net: Convert sysctl_pernet_ops
      net: Convert netfilter_net_ops
      net: Convert nf_log_net_ops
      net: Convert net_inuse_ops
      net: Convert net_defaults_ops
      net: Convert netlink_net_ops
      net: Convert rtnetlink_net_ops
      net: Convert audit_net_ops
      net: Convert uevent_net_ops
      net: Convert proto_net_ops
      net: Convert pernet_subsys ops, registered via net_dev_init()
      net: Convert fib_* pernet_operations, registered via subsys_initcall
      net: Convert subsys_initcall() registered pernet_operations from net/sched
      net: Convert genl_pernet_ops
      net: Convert wext_pernet_ops
      net: Convert sysctl_core_ops
      net: Convert pernet_subsys, registered from inet_init()
      net: Convert unix_net_ops
      net: Convert packet_net_ops
      net: Convert ipv4_sysctl_ops
      net: Convert addrconf_ops
      net: Convert loopback_net_ops
      net: Convert default_device_ops
      net: Convert diag_net_ops
      net: Convert netlink_tap_net_ops


 drivers/net/loopback.c      |    1 
 fs/proc/proc_net.c          |    1 
 include/linux/rtnetlink.h   |    1 
 include/net/net_namespace.h |    6 +++
 kernel/audit.c              |    1 
 lib/kobject_uevent.c        |    1 
 net/core/dev.c              |    2 +
 net/core/fib_notifier.c     |    1 
 net/core/fib_rules.c        |    1 
 net/core/net-procfs.c       |    2 +
 net/core/net_namespace.c    |   95 +++++++++++++++++++++++++------------------
 net/core/rtnetlink.c        |    5 +-
 net/core/sock.c             |    2 +
 net/core/sock_diag.c        |    1 
 net/core/sysctl_net_core.c  |    1 
 net/ipv4/af_inet.c          |    2 +
 net/ipv4/arp.c              |    1 
 net/ipv4/devinet.c          |    1 
 net/ipv4/fib_frontend.c     |    1 
 net/ipv4/icmp.c             |    1 
 net/ipv4/igmp.c             |    1 
 net/ipv4/ip_fragment.c      |    1 
 net/ipv4/ipmr.c             |    1 
 net/ipv4/ping.c             |    1 
 net/ipv4/proc.c             |    1 
 net/ipv4/raw.c              |    1 
 net/ipv4/route.c            |    4 ++
 net/ipv4/sysctl_net_ipv4.c  |    1 
 net/ipv4/tcp_ipv4.c         |    2 +
 net/ipv4/tcp_metrics.c      |    1 
 net/ipv4/udp.c              |    1 
 net/ipv4/udplite.c          |    1 
 net/ipv4/xfrm4_policy.c     |    1 
 net/ipv6/addrconf.c         |    1 
 net/netfilter/core.c        |    1 
 net/netfilter/nf_log.c      |    1 
 net/netlink/af_netlink.c    |    2 +
 net/netlink/genetlink.c     |    1 
 net/packet/af_packet.c      |    1 
 net/sched/act_api.c         |    1 
 net/sched/sch_api.c         |    1 
 net/sysctl_net.c            |    1 
 net/unix/af_unix.c          |    1 
 net/wireless/wext-core.c    |    1 
 net/xfrm/xfrm_policy.c      |    1 
 45 files changed, 116 insertions(+), 41 deletions(-)

[PATCH net-next v3 01/32] net: Assign net to net_namespace_list in setup_net()

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:26:12

This patch merges two repeating pieces of code in one,
and they will live in setup_net() now.

The only change is that assignment:

	init_net_initialized = true;

becomes reordered with:

	list_add_tail_rcu(&net->list, &net_namespace_list);

The order does not have visible effect, and it is a simple
cleanup because of:

init_net_initialized is used in !CONFIG_NET_NS case
to order proc_net_ns_ops registration occuring at boot time:

	start_kernel()->proc_root_init()->proc_net_init(),
with
	net_ns_init()->setup_net(&init_net, &init_user_ns)

also occuring in boot time from the same init_task.

When there are no another tasks to race with them,
for the single task it does not matter, which order
two sequential independent loads should be made.
So we make them reordered.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 net/core/net_namespace.c |   13 +++----------
 1 file changed, 3 insertions(+), 10 deletions(-)
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 3cad5f51afd3..1180c217895a 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -303,6 +303,9 @@ static __net_init int setup_net(struct net *net, struct user_namespace *user_ns)
 		if (error < 0)
 			goto out_undo;
 	}
+	rtnl_lock();
+	list_add_tail_rcu(&net->list, &net_namespace_list);
+	rtnl_unlock();
 out:
 	return error;
 
@@ -424,11 +427,6 @@ struct net *copy_net_ns(unsigned long flags,
 
 	net->ucounts = ucounts;
 	rv = setup_net(net, user_ns);
-	if (rv == 0) {
-		rtnl_lock();
-		list_add_tail_rcu(&net->list, &net_namespace_list);
-		rtnl_unlock();
-	}
 	mutex_unlock(&net_mutex);
 	if (rv < 0) {
 		dec_net_namespaces(ucounts);
@@ -880,11 +878,6 @@ static int __init net_ns_init(void)
 		panic("Could not setup the initial network namespace");
 
 	init_net_initialized = true;
-
-	rtnl_lock();
-	list_add_tail_rcu(&init_net.list, &net_namespace_list);
-	rtnl_unlock();
-
 	mutex_unlock(&net_mutex);
 
 	register_pernet_subsys(&net_ns_ops);

[PATCH net-next v3 02/32] net: Cleanup in copy_net_ns()

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:26:24

Line up destructors actions in the revers order
to constructors. Next patches will add more actions,
and this will be comfortable, if there is the such
order.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 net/core/net_namespace.c |   20 +++++++++-----------
 1 file changed, 9 insertions(+), 11 deletions(-)
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 1180c217895a..81384386f91b 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -411,27 +411,25 @@ struct net *copy_net_ns(unsigned long flags,
 
 	net = net_alloc();
 	if (!net) {
-		dec_net_namespaces(ucounts);
-		return ERR_PTR(-ENOMEM);
+		rv = -ENOMEM;
+		goto dec_ucounts;
 	}
-
+	refcount_set(&net->passive, 1);
+	net->ucounts = ucounts;
 	get_user_ns(user_ns);
 
 	rv = mutex_lock_killable(&net_mutex);
-	if (rv < 0) {
-		net_free(net);
-		dec_net_namespaces(ucounts);
-		put_user_ns(user_ns);
-		return ERR_PTR(rv);
-	}
+	if (rv < 0)
+		goto put_userns;
 
-	net->ucounts = ucounts;
 	rv = setup_net(net, user_ns);
 	mutex_unlock(&net_mutex);
 	if (rv < 0) {
-		dec_net_namespaces(ucounts);
+put_userns:
 		put_user_ns(user_ns);
 		net_drop_ns(net);
+dec_ucounts:
+		dec_net_namespaces(ucounts);
 		return ERR_PTR(rv);
 	}
 	return net;

[PATCH net-next v3 03/32] net: Introduce net_sem for protection of pernet_list

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:26:34

Currently, the mutex is mostly used to protect pernet operations
list. It orders setup_net() and cleanup_net() with parallel
{un,}register_pernet_operations() calls, so ->exit{,batch} methods
of the same pernet operations are executed for a dying net, as
were used to call ->init methods, even after the net namespace
is unlinked from net_namespace_list in cleanup_net().

But there are several problems with scalability. The first one
is that more than one net can't be created or destroyed
at the same moment on the node. For big machines with many cpus
running many containers it's very sensitive.

The second one is that it's need to synchronize_rcu() after net
is removed from net_namespace_list():

Destroy net_ns:
cleanup_net()
  mutex_lock(&net_mutex)
  list_del_rcu(&net->list)
  synchronize_rcu()                                  <--- Sleep there for ages
  list_for_each_entry_reverse(ops, &pernet_list, list)
    ops_exit_list(ops, &net_exit_list)
  list_for_each_entry_reverse(ops, &pernet_list, list)
    ops_free_list(ops, &net_exit_list)
  mutex_unlock(&net_mutex)

This primitive is not fast, especially on the systems with many processors
and/or when preemptible RCU is enabled in config. So, all the time, while
cleanup_net() is waiting for RCU grace period, creation of new net namespaces
is not possible, the tasks, who makes it, are sleeping on the same mutex:

Create net_ns:
copy_net_ns()
  mutex_lock_killable(&net_mutex)                    <--- Sleep there for ages

I observed 20-30 seconds hangs of "unshare -n" on ordinary 8-cpu laptop
with preemptible RCU enabled after CRIU tests round is finished.

The solution is to convert net_mutex to the rw_semaphore and add fine grain
locks to really small number of pernet_operations, what really need them.

Then, pernet_operations::init/::exit methods, modifying the net-related data,
will require down_read() locking only, while down_write() will be used
for changing pernet_list (i.e., when modules are being loaded and unloaded).

This gives signify performance increase, after all patch set is applied,
like you may see here:

%for i in {1..10000}; do unshare -n bash -c exit; done

*before*
real 1m40,377s
user 0m9,672s
sys 0m19,928s

*after*
real 0m17,007s
user 0m5,311s
sys 0m11,779

(5.8 times faster)

This patch starts replacing net_mutex to net_sem. It adds rw_semaphore,
describes the variables it protects, and makes to use, where appropriate.
net_mutex is still present, and next patches will kick it out step-by-step.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 include/linux/rtnetlink.h |    1 +
 net/core/net_namespace.c  |   39 ++++++++++++++++++++++++++-------------
 net/core/rtnetlink.c      |    4 ++--
 3 files changed, 29 insertions(+), 15 deletions(-)
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 1fdcde96eb65..e9ee9ad0a681 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -36,6 +36,7 @@ extern int rtnl_is_locked(void);
 
 extern wait_queue_head_t netdev_unregistering_wq;
 extern struct mutex net_mutex;
+extern struct rw_semaphore net_sem;
 
 #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 81384386f91b..e89b2b7abd36 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -41,6 +41,11 @@ struct net init_net = {
 EXPORT_SYMBOL(init_net);
 
 static bool init_net_initialized;
+/*
+ * net_sem: protects: pernet_list, net_generic_ids,
+ * init_net_initialized and first_device pointer.
+ */
+DECLARE_RWSEM(net_sem);
 
 #define MIN_PERNET_OPS_ID	\
 	((sizeof(struct net_generic) + sizeof(void *) - 1) / sizeof(void *))
@@ -286,7 +291,7 @@ struct net *get_net_ns_by_id(struct net *net, int id)
  */
 static __net_init int setup_net(struct net *net, struct user_namespace *user_ns)
 {
-	/* Must be called with net_mutex held */
+	/* Must be called with net_sem held */
 	const struct pernet_operations *ops, *saved_ops;
 	int error = 0;
 	LIST_HEAD(net_exit_list);
@@ -418,12 +423,16 @@ struct net *copy_net_ns(unsigned long flags,
 	net->ucounts = ucounts;
 	get_user_ns(user_ns);
 
-	rv = mutex_lock_killable(&net_mutex);
+	rv = down_read_killable(&net_sem);
 	if (rv < 0)
 		goto put_userns;
-
+	rv = mutex_lock_killable(&net_mutex);
+	if (rv < 0)
+		goto up_read;
 	rv = setup_net(net, user_ns);
 	mutex_unlock(&net_mutex);
+up_read:
+	up_read(&net_sem);
 	if (rv < 0) {
 put_userns:
 		put_user_ns(user_ns);
@@ -477,6 +486,7 @@ static void cleanup_net(struct work_struct *work)
 	list_replace_init(&cleanup_list, &net_kill_list);
 	spin_unlock_irq(&cleanup_list_lock);
 
+	down_read(&net_sem);
 	mutex_lock(&net_mutex);
 
 	/* Don't let anyone else find us. */
@@ -517,6 +527,7 @@ static void cleanup_net(struct work_struct *work)
 		ops_free_list(ops, &net_exit_list);
 
 	mutex_unlock(&net_mutex);
+	up_read(&net_sem);
 
 	/* Ensure there are no outstanding rcu callbacks using this
 	 * network namespace.
@@ -543,8 +554,10 @@ static void cleanup_net(struct work_struct *work)
  */
 void net_ns_barrier(void)
 {
+	down_write(&net_sem);
 	mutex_lock(&net_mutex);
 	mutex_unlock(&net_mutex);
+	up_write(&net_sem);
 }
 EXPORT_SYMBOL(net_ns_barrier);
 
@@ -871,12 +884,12 @@ static int __init net_ns_init(void)
 
 	rcu_assign_pointer(init_net.gen, ng);
 
-	mutex_lock(&net_mutex);
+	down_write(&net_sem);
 	if (setup_net(&init_net, &init_user_ns))
 		panic("Could not setup the initial network namespace");
 
 	init_net_initialized = true;
-	mutex_unlock(&net_mutex);
+	up_write(&net_sem);
 
 	register_pernet_subsys(&net_ns_ops);
 
@@ -1016,9 +1029,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_sem);
 	error =  register_pernet_operations(first_device, ops);
-	mutex_unlock(&net_mutex);
+	up_write(&net_sem);
 	return error;
 }
 EXPORT_SYMBOL_GPL(register_pernet_subsys);
@@ -1034,9 +1047,9 @@ EXPORT_SYMBOL_GPL(register_pernet_subsys);
  */
 void unregister_pernet_subsys(struct pernet_operations *ops)
 {
-	mutex_lock(&net_mutex);
+	down_write(&net_sem);
 	unregister_pernet_operations(ops);
-	mutex_unlock(&net_mutex);
+	up_write(&net_sem);
 }
 EXPORT_SYMBOL_GPL(unregister_pernet_subsys);
 
@@ -1062,11 +1075,11 @@ EXPORT_SYMBOL_GPL(unregister_pernet_subsys);
 int register_pernet_device(struct pernet_operations *ops)
 {
 	int error;
-	mutex_lock(&net_mutex);
+	down_write(&net_sem);
 	error = register_pernet_operations(&pernet_list, ops);
 	if (!error && (first_device == &pernet_list))
 		first_device = &ops->list;
-	mutex_unlock(&net_mutex);
+	up_write(&net_sem);
 	return error;
 }
 EXPORT_SYMBOL_GPL(register_pernet_device);
@@ -1082,11 +1095,11 @@ EXPORT_SYMBOL_GPL(register_pernet_device);
  */
 void unregister_pernet_device(struct pernet_operations *ops)
 {
-	mutex_lock(&net_mutex);
+	down_write(&net_sem);
 	if (&ops->list == first_device)
 		first_device = first_device->next;
 	unregister_pernet_operations(ops);
-	mutex_unlock(&net_mutex);
+	up_write(&net_sem);
 }
 EXPORT_SYMBOL_GPL(unregister_pernet_device);
 
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index bc290413a49d..257e7bbaffba 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -454,11 +454,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_sem);
 	rtnl_lock_unregistering_all();
 	__rtnl_link_unregister(ops);
 	rtnl_unlock();
-	mutex_unlock(&net_mutex);
+	up_write(&net_sem);
 }
 EXPORT_SYMBOL_GPL(rtnl_link_unregister);
 

[PATCH net-next v3 04/32] net: Move mutex_unlock() in cleanup_net() up

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:26:41

net_sem protects from pernet_list changing, while
ops_free_list() makes simple kfree(), and it can't
race with other pernet_operations callbacks.

So we may release net_mutex earlier then it was.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 net/core/net_namespace.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index e89b2b7abd36..f8453c438798 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -522,11 +522,12 @@ 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);
+
 	/* Free the net generic variables */
 	list_for_each_entry_reverse(ops, &pernet_list, list)
 		ops_free_list(ops, &net_exit_list);
 
-	mutex_unlock(&net_mutex);
 	up_read(&net_sem);
 
 	/* Ensure there are no outstanding rcu callbacks using this

[PATCH net-next v3 05/32] net: Allow pernet_operations to be executed in parallel

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:26:49

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 <redacted>
Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 include/net/net_namespace.h |    6 ++++++
 net/core/net_namespace.c    |   30 ++++++++++++++++++++----------
 2 files changed, 26 insertions(+), 10 deletions(-)
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index f306b2aa15a4..9158ec1ad06f 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -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;
 };
 
 /*
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index f8453c438798..2a01ff32d9c7 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -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 @@ static int register_pernet_operations(struct list_head *list,
 		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 @@ static int register_pernet_operations(struct list_head *list,
 
 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)

[PATCH net-next v3 06/32] net: Convert proc_net_ns_ops

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:27:04

This patch starts to convert pernet_subsys, registered
before initcalls.

proc_net_ns_ops::proc_net_ns_init()/proc_net_ns_exit()
{un,}register pernet net->proc_net and ->proc_net_stat.

Constructors and destructors of another pernet_operations
are not interested in foreign net's proc_net and proc_net_stat.
Proc filesystem privitives are synchronized on proc_subdir_lock.

So, proc_net_ns_ops methods are able to be executed
in parallel with methods of any other pernet operations.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 fs/proc/proc_net.c |    1 +
 1 file changed, 1 insertion(+)
diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c
index 68c06ae7888c..da6f8733c9c5 100644
--- a/fs/proc/proc_net.c
+++ b/fs/proc/proc_net.c
@@ -237,6 +237,7 @@ static __net_exit void proc_net_ns_exit(struct net *net)
 static struct pernet_operations __net_initdata proc_net_ns_ops = {
 	.init = proc_net_ns_init,
 	.exit = proc_net_ns_exit,
+	.async = true,
 };
 
 int __init proc_net_init(void)

[PATCH net-next v3 07/32] net: Convert net_ns_ops methods

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:27:11

This patch starts to convert pernet_subsys, registered
from pure initcalls.

net_ns_ops::net_ns_net_init/net_ns_net_init, methods use only
ida_simple_* functions, which are not need a synchronization.
They are synchronized by idr subsystem.

So, net_ns_ops methods are able to be executed
in parallel with methods of other pernet operations.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 net/core/net_namespace.c |    1 +
 1 file changed, 1 insertion(+)
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 2a01ff32d9c7..e21c564c8c00 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -649,6 +649,7 @@ static __net_exit void net_ns_net_exit(struct net *net)
 static struct pernet_operations __net_initdata net_ns_ops = {
 	.init = net_ns_net_init,
 	.exit = net_ns_net_exit,
+	.async = true,
 };
 
 static const struct nla_policy rtnl_net_policy[NETNSA_MAX + 1] = {

[PATCH net-next v3 08/32] net: Convert sysctl_pernet_ops

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:27:22

This patch starts to convert pernet_subsys, registered
from core initcalls.

Methods sysctl_net_init() and sysctl_net_exit() initialize
net::sysctls table of a namespace.

pernet_operations::init()/exit() methods from the rest
of the list do not touch net::sysctls of strangers,
so it's safe to execute sysctl_pernet_ops's methods
in parallel with any other pernet_operations.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 net/sysctl_net.c |    1 +
 1 file changed, 1 insertion(+)
diff --git a/net/sysctl_net.c b/net/sysctl_net.c
index 9aed6fe1bf1a..f424539829b7 100644
--- a/net/sysctl_net.c
+++ b/net/sysctl_net.c
@@ -89,6 +89,7 @@ static void __net_exit sysctl_net_exit(struct net *net)
 static struct pernet_operations sysctl_pernet_ops = {
 	.init = sysctl_net_init,
 	.exit = sysctl_net_exit,
+	.async = true,
 };
 
 static struct ctl_table_header *net_header;

[PATCH net-next v3 09/32] net: Convert netfilter_net_ops

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:27:28

Methods netfilter_net_init() and netfilter_net_exit()
initialize net::nf::hooks and change net-related proc
directory of net. Another pernet_operations are not
interested in forein net::nf::hooks or proc entries,
so it's safe to make them executed in parallel with
methods of other pernet operations.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 net/netfilter/core.c |    1 +
 1 file changed, 1 insertion(+)
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index 0f6b8172fb9a..d72cc786c7b7 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -629,6 +629,7 @@ static void __net_exit netfilter_net_exit(struct net *net)
 static struct pernet_operations netfilter_net_ops = {
 	.init = netfilter_net_init,
 	.exit = netfilter_net_exit,
+	.async = true,
 };
 
 int __init netfilter_init(void)

[PATCH net-next v3 10/32] net: Convert nf_log_net_ops

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:27:38

The pernet_operations would have had a problem in parallel
execution with others, if init_net had been able to released.
But it's not, and the rest is safe for that.
There is memory allocation, which nobody else interested in,
and sysctl registration. So, we make them async.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 net/netfilter/nf_log.c |    1 +
 1 file changed, 1 insertion(+)
diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c
index c2c1b16b7538..1ba3da51050d 100644
--- a/net/netfilter/nf_log.c
+++ b/net/netfilter/nf_log.c
@@ -577,6 +577,7 @@ static void __net_exit nf_log_net_exit(struct net *net)
 static struct pernet_operations nf_log_net_ops = {
 	.init = nf_log_net_init,
 	.exit = nf_log_net_exit,
+	.async = true,
 };
 
 int __init netfilter_log_init(void)

[PATCH net-next v3 11/32] net: Convert net_inuse_ops

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:27:49

net_inuse_ops methods expose statistics in /proc.
No one from the rest of pernet_subsys or pernet_device
lists touch net::core::inuse.

So, it's safe to make net_inuse_ops async.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 net/core/sock.c |    1 +
 1 file changed, 1 insertion(+)
diff --git a/net/core/sock.c b/net/core/sock.c
index 04e5e27c9b81..f2bf69b86c58 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -3112,6 +3112,7 @@ static void __net_exit sock_inuse_exit_net(struct net *net)
 static struct pernet_operations net_inuse_ops = {
 	.init = sock_inuse_init_net,
 	.exit = sock_inuse_exit_net,
+	.async = true,
 };
 
 static __init int net_inuse_init(void)

[PATCH net-next v3 12/32] net: Convert net_defaults_ops

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:27:57

net_defaults_ops introduce only net_defaults_init_net method,
and it acts on net::core::sysctl_somaxconn, which
is not interesting for the rest of pernet_subsys and
pernet_device lists. Then, make them async.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 net/core/net_namespace.c |    1 +
 1 file changed, 1 insertion(+)
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index e21c564c8c00..bcab9a938d6f 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -340,6 +340,7 @@ static int __net_init net_defaults_init_net(struct net *net)
 
 static struct pernet_operations net_defaults_ops = {
 	.init = net_defaults_init_net,
+	.async = true,
 };
 
 static __init int net_defaults_init(void)

[PATCH net-next v3 13/32] net: Convert netlink_net_ops

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:28:14

The methods of netlink_net_ops create and destroy "netlink"
file, which are not interesting for foreigh pernet_operations.
So, netlink_net_ops may safely be made async.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 net/netlink/af_netlink.c |    1 +
 1 file changed, 1 insertion(+)
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 3c8af14330b5..b3065908e146 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -2723,6 +2723,7 @@ static void __init netlink_add_usersock_entry(void)
 static struct pernet_operations __net_initdata netlink_net_ops = {
 	.init = netlink_net_init,
 	.exit = netlink_net_exit,
+	.async = true,
 };
 
 static inline u32 netlink_hash(const void *data, u32 len, u32 seed)

[PATCH net-next v3 14/32] net: Convert rtnetlink_net_ops

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:28:21

rtnetlink_net_init() and rtnetlink_net_exit()
create and destroy netlink socket net::rtnl.

The socket is used to send rtnl notification via
rtnl_net_notifyid(). There is no a problem
to create and destroy it in parallel with other
pernet operations, as we link net in setup_net()
after the socket is created, and destroy
in cleanup_net() after net is unhashed from all
the lists and there is no RCU references on it.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 net/core/rtnetlink.c |    1 +
 1 file changed, 1 insertion(+)
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 257e7bbaffba..67f375cfb982 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -4724,6 +4724,7 @@ static void __net_exit rtnetlink_net_exit(struct net *net)
 static struct pernet_operations rtnetlink_net_ops = {
 	.init = rtnetlink_net_init,
 	.exit = rtnetlink_net_exit,
+	.async = true,
 };
 
 void __init rtnetlink_init(void)

[PATCH net-next v3 15/32] net: Convert audit_net_ops

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:28:30

This patch starts to convert pernet_subsys, registered
from postcore initcalls.

audit_net_init() creates netlink socket, while audit_net_exit()
destroys it. The rest of the pernet_list are not interested
in the socket, so we make audit_net_ops async.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 kernel/audit.c |    1 +
 1 file changed, 1 insertion(+)
diff --git a/kernel/audit.c b/kernel/audit.c
index 227db99b0f19..5e49b614d0e6 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -1526,6 +1526,7 @@ static struct pernet_operations audit_net_ops __net_initdata = {
 	.exit = audit_net_exit,
 	.id = &audit_net_id,
 	.size = sizeof(struct audit_net),
+	.async = true,
 };
 
 /* Initialize audit support at boot time. */

[PATCH net-next v3 16/32] net: Convert uevent_net_ops

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:28:43

uevent_net_init() and uevent_net_exit() create and
destroy netlink socket, and these actions serialized
in netlink code.

Parallel execution with other pernet_operations
makes the socket disappear earlier from uevent_sock_list
on ->exit. As userspace can't be interested in broadcast
messages of dying net, and, as I see, no one in kernel
listen them, we may safely make uevent_net_ops async.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 lib/kobject_uevent.c |    1 +
 1 file changed, 1 insertion(+)
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index 9fe6ec8fda28..9539d7ab3ea8 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -650,6 +650,7 @@ static void uevent_net_exit(struct net *net)
 static struct pernet_operations uevent_net_ops = {
 	.init	= uevent_net_init,
 	.exit	= uevent_net_exit,
+	.async  = true,
 };
 
 static int __init kobject_uevent_init(void)

[PATCH net-next v3 17/32] net: Convert proto_net_ops

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:28:51

This patch starts to convert pernet_subsys, registered
from subsys initcalls.

It seems safe to be executed in parallel with others,
as it's only creates/destoyes proc entry,
which nobody else is not interested in.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 net/core/sock.c |    1 +
 1 file changed, 1 insertion(+)
diff --git a/net/core/sock.c b/net/core/sock.c
index f2bf69b86c58..e90d461748f0 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -3386,6 +3386,7 @@ static __net_exit void proto_exit_net(struct net *net)
 static __net_initdata struct pernet_operations proto_net_ops = {
 	.init = proto_init_net,
 	.exit = proto_exit_net,
+	.async = true,
 };
 
 static int __init proto_init(void)

[PATCH net-next v3 18/32] net: Convert pernet_subsys ops, registered via net_dev_init()

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:29:01

There are:
1)dev_proc_ops and dev_mc_net_ops, which create and destroy
pernet proc file and not interesting for another net namespaces;
2)netdev_net_ops, which creates pernet hashes, which are not
touched by another pernet_operations.

So, make them async.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 net/core/dev.c        |    1 +
 net/core/net-procfs.c |    2 ++
 2 files changed, 3 insertions(+)
diff --git a/net/core/dev.c b/net/core/dev.c
index dda9d7b9a840..dc7506f00a66 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -8833,6 +8833,7 @@ static void __net_exit netdev_exit(struct net *net)
 static struct pernet_operations __net_initdata netdev_net_ops = {
 	.init = netdev_init,
 	.exit = netdev_exit,
+	.async = true,
 };
 
 static void __net_exit default_device_exit(struct net *net)
diff --git a/net/core/net-procfs.c b/net/core/net-procfs.c
index e010bb800d7b..65b51e778782 100644
--- a/net/core/net-procfs.c
+++ b/net/core/net-procfs.c
@@ -349,6 +349,7 @@ static void __net_exit dev_proc_net_exit(struct net *net)
 static struct pernet_operations __net_initdata dev_proc_ops = {
 	.init = dev_proc_net_init,
 	.exit = dev_proc_net_exit,
+	.async = true,
 };
 
 static int dev_mc_seq_show(struct seq_file *seq, void *v)
@@ -405,6 +406,7 @@ static void __net_exit dev_mc_net_exit(struct net *net)
 static struct pernet_operations __net_initdata dev_mc_net_ops = {
 	.init = dev_mc_net_init,
 	.exit = dev_mc_net_exit,
+	.async = true,
 };
 
 int __init dev_proc_init(void)

[PATCH net-next v3 19/32] net: Convert fib_* pernet_operations, registered via subsys_initcall

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:29:12

Both of them create and initialize lists, which are not touched
by another foreing pernet_operations.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 net/core/fib_notifier.c |    1 +
 net/core/fib_rules.c    |    1 +
 2 files changed, 2 insertions(+)
diff --git a/net/core/fib_notifier.c b/net/core/fib_notifier.c
index 0c048bdeb016..5ace0705a3f9 100644
--- a/net/core/fib_notifier.c
+++ b/net/core/fib_notifier.c
@@ -171,6 +171,7 @@ static void __net_exit fib_notifier_net_exit(struct net *net)
 static struct pernet_operations fib_notifier_net_ops = {
 	.init = fib_notifier_net_init,
 	.exit = fib_notifier_net_exit,
+	.async = true,
 };
 
 static int __init fib_notifier_init(void)
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index 98e1066c3d55..cb071b8e8d17 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -1030,6 +1030,7 @@ static void __net_exit fib_rules_net_exit(struct net *net)
 static struct pernet_operations fib_rules_net_ops = {
 	.init = fib_rules_net_init,
 	.exit = fib_rules_net_exit,
+	.async = true,
 };
 
 static int __init fib_rules_init(void)

[PATCH net-next v3 20/32] net: Convert subsys_initcall() registered pernet_operations from net/sched

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:29:21

psched_net_ops only creates and destroyes /proc entry,
and safe to be executed in parallel with any foreigh
pernet_operations.

tcf_action_net_ops initializes and destructs tcf_action_net::egdev_ht,
which is not touched by foreign pernet_operations.

So, make them async.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 net/sched/act_api.c |    1 +
 net/sched/sch_api.c |    1 +
 2 files changed, 2 insertions(+)
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index eba6682727dd..4886ea4a7d6e 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -1454,6 +1454,7 @@ static struct pernet_operations tcf_action_net_ops = {
 	.exit = tcf_action_net_exit,
 	.id = &tcf_action_net_id,
 	.size = sizeof(struct tcf_action_net),
+	.async = true,
 };
 
 static int __init tc_action_init(void)
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index d512f49ee83c..27e672c12492 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -2128,6 +2128,7 @@ static void __net_exit psched_net_exit(struct net *net)
 static struct pernet_operations psched_net_ops = {
 	.init = psched_net_init,
 	.exit = psched_net_exit,
+	.async = true,
 };
 
 static int __init pktsched_init(void)

[PATCH net-next v3 21/32] net: Convert genl_pernet_ops

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:29:31

This pernet_operations create and destroy net::genl_sock.
Foreign pernet_operations don't touch it.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 net/netlink/genetlink.c |    1 +
 1 file changed, 1 insertion(+)
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index 6f02499ef007..a6f63a5faee7 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -1035,6 +1035,7 @@ static void __net_exit genl_pernet_exit(struct net *net)
 static struct pernet_operations genl_pernet_ops = {
 	.init = genl_pernet_init,
 	.exit = genl_pernet_exit,
+	.async = true,
 };
 
 static int __init genl_init(void)

[PATCH net-next v3 22/32] net: Convert wext_pernet_ops

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:29:41

These pernet_operations initialize and purge net::wext_nlevents
queue, and are not touched by foreign pernet_operations.

Mark them async.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 net/wireless/wext-core.c |    1 +
 1 file changed, 1 insertion(+)
diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c
index 9efbfc753347..bc7064486b15 100644
--- a/net/wireless/wext-core.c
+++ b/net/wireless/wext-core.c
@@ -390,6 +390,7 @@ static void __net_exit wext_pernet_exit(struct net *net)
 static struct pernet_operations wext_pernet_ops = {
 	.init = wext_pernet_init,
 	.exit = wext_pernet_exit,
+	.async = true,
 };
 
 static int __init wireless_nlevent_init(void)

[PATCH net-next v3 23/32] net: Convert sysctl_core_ops

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:29:49

These pernet_operations register and destroy sysctl
directory, and it's not interesting for foreign
pernet_operations.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 net/core/sysctl_net_core.c |    1 +
 1 file changed, 1 insertion(+)
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index f2d0462611c3..d714f65782b7 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -572,6 +572,7 @@ static __net_exit void sysctl_core_net_exit(struct net *net)
 static __net_initdata struct pernet_operations sysctl_core_ops = {
 	.init = sysctl_core_net_init,
 	.exit = sysctl_core_net_exit,
+	.async = true,
 };
 
 static __init int sysctl_core_init(void)

[PATCH net-next v3 24/32] net: Convert pernet_subsys, registered from inet_init()

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:29:58

arp_net_ops just addr/removes /proc entry.

devinet_ops allocates and frees duplicate of init_net tables
and (un)registers sysctl entries.

fib_net_ops allocates and frees pernet tables, creates/destroys
netlink socket and (un)initializes /proc entries. Foreign
pernet_operations do not touch them.

ip_rt_proc_ops only modifies pernet /proc entries.

xfrm_net_ops creates/destroys /proc entries, allocates/frees
pernet statistics, hashes and tables, and (un)initializes
sysctl files. These are not touched by foreigh pernet_operations

xfrm4_net_ops allocates/frees private pernet memory, and
configures sysctls.

sysctl_route_ops creates/destroys sysctls.

rt_genid_ops only initializes fields of just allocated net.

ipv4_inetpeer_ops allocated/frees net private memory.

igmp_net_ops just creates/destroys /proc files and socket,
noone else interested in.

tcp_sk_ops seems to be safe, because tcp_sk_init() does not
depend on any other pernet_operations modifications. Iteration
over hash table in inet_twsk_purge() is made under RCU lock,
and it's safe to iterate the table this way. Removing from
the table happen from inet_twsk_deschedule_put(), but this
function is safe without any extern locks, as it's synchronized
inside itself. There are many examples, it's used in different
context. So, it's safe to leave tcp_sk_exit_batch() unlocked.

tcp_net_metrics_ops is synchronized on tcp_metrics_lock and safe.

udplite4_net_ops only creates/destroys pernet /proc file.

icmp_sk_ops creates percpu sockets, not touched by foreign
pernet_operations.

ipmr_net_ops creates/destroys pernet fib tables, (un)registers
fib rules and /proc files. This seem to be safe to execute
in parallel with foreign pernet_operations.

af_inet_ops just sets up default parameters of newly created net.

ipv4_mib_ops creates and destroys pernet percpu statistics.

raw_net_ops, tcp4_net_ops, udp4_net_ops, ping_v4_net_ops
and ip_proc_ops only create/destroy pernet /proc files.

ip4_frags_ops creates and destroys sysctl file.

So, it's safe to make the pernet_operations async.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 net/ipv4/af_inet.c      |    2 ++
 net/ipv4/arp.c          |    1 +
 net/ipv4/devinet.c      |    1 +
 net/ipv4/fib_frontend.c |    1 +
 net/ipv4/icmp.c         |    1 +
 net/ipv4/igmp.c         |    1 +
 net/ipv4/ip_fragment.c  |    1 +
 net/ipv4/ipmr.c         |    1 +
 net/ipv4/ping.c         |    1 +
 net/ipv4/proc.c         |    1 +
 net/ipv4/raw.c          |    1 +
 net/ipv4/route.c        |    4 ++++
 net/ipv4/tcp_ipv4.c     |    2 ++
 net/ipv4/tcp_metrics.c  |    1 +
 net/ipv4/udp.c          |    1 +
 net/ipv4/udplite.c      |    1 +
 net/ipv4/xfrm4_policy.c |    1 +
 net/xfrm/xfrm_policy.c  |    1 +
 18 files changed, 23 insertions(+)
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index f98e2f0db841..e8c7fad8c329 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1735,6 +1735,7 @@ static __net_exit void ipv4_mib_exit_net(struct net *net)
 static __net_initdata struct pernet_operations ipv4_mib_ops = {
 	.init = ipv4_mib_init_net,
 	.exit = ipv4_mib_exit_net,
+	.async = true,
 };
 
 static int __init init_ipv4_mibs(void)
@@ -1788,6 +1789,7 @@ static __net_exit void inet_exit_net(struct net *net)
 static __net_initdata struct pernet_operations af_inet_ops = {
 	.init = inet_init_net,
 	.exit = inet_exit_net,
+	.async = true,
 };
 
 static int __init init_inet_pernet_ops(void)
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index f28f06c91ead..7dc9de8444a9 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -1447,6 +1447,7 @@ static void __net_exit arp_net_exit(struct net *net)
 static struct pernet_operations arp_net_ops = {
 	.init = arp_net_init,
 	.exit = arp_net_exit,
+	.async = true,
 };
 
 static int __init arp_proc_init(void)
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 40f001782c1b..5ae0d1f097ca 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -2469,6 +2469,7 @@ static __net_exit void devinet_exit_net(struct net *net)
 static __net_initdata struct pernet_operations devinet_ops = {
 	.init = devinet_init_net,
 	.exit = devinet_exit_net,
+	.async = true,
 };
 
 static struct rtnl_af_ops inet_af_ops __read_mostly = {
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index f05afaf3235c..ac71c3d496c0 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -1362,6 +1362,7 @@ static void __net_exit fib_net_exit(struct net *net)
 static struct pernet_operations fib_net_ops = {
 	.init = fib_net_init,
 	.exit = fib_net_exit,
+	.async = true,
 };
 
 void __init ip_fib_init(void)
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 1617604c9284..cc56efa64d5c 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -1257,6 +1257,7 @@ static int __net_init icmp_sk_init(struct net *net)
 static struct pernet_operations __net_initdata icmp_sk_ops = {
        .init = icmp_sk_init,
        .exit = icmp_sk_exit,
+       .async = true,
 };
 
 int __init icmp_init(void)
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index f2402581fef1..c2743763777e 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -3028,6 +3028,7 @@ static void __net_exit igmp_net_exit(struct net *net)
 static struct pernet_operations igmp_net_ops = {
 	.init = igmp_net_init,
 	.exit = igmp_net_exit,
+	.async = true,
 };
 #endif
 
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index bbf1b94942c0..5e843ae5e468 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -885,6 +885,7 @@ static void __net_exit ipv4_frags_exit_net(struct net *net)
 static struct pernet_operations ip4_frags_ops = {
 	.init = ipv4_frags_init_net,
 	.exit = ipv4_frags_exit_net,
+	.async = true,
 };
 
 void __init ipfrag_init(void)
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index b05689bbba31..7c7ac9d32e77 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -3327,6 +3327,7 @@ static void __net_exit ipmr_net_exit(struct net *net)
 static struct pernet_operations ipmr_net_ops = {
 	.init = ipmr_net_init,
 	.exit = ipmr_net_exit,
+	.async = true,
 };
 
 int __init ip_mr_init(void)
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index b8f0db54b197..0164def9c808 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -1204,6 +1204,7 @@ static void __net_exit ping_v4_proc_exit_net(struct net *net)
 static struct pernet_operations ping_v4_net_ops = {
 	.init = ping_v4_proc_init_net,
 	.exit = ping_v4_proc_exit_net,
+	.async = true,
 };
 
 int __init ping_proc_init(void)
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index dc5edc8f7564..fdabc70283b6 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -549,6 +549,7 @@ static __net_exit void ip_proc_exit_net(struct net *net)
 static __net_initdata struct pernet_operations ip_proc_ops = {
 	.init = ip_proc_init_net,
 	.exit = ip_proc_exit_net,
+	.async = true,
 };
 
 int __init ip_misc_proc_init(void)
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 9b367fc48d7d..54648d20bf0f 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -1156,6 +1156,7 @@ static __net_exit void raw_exit_net(struct net *net)
 static __net_initdata struct pernet_operations raw_net_ops = {
 	.init = raw_init_net,
 	.exit = raw_exit_net,
+	.async = true,
 };
 
 int __init raw_proc_init(void)
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 49cc1c1df1ba..9376ed69ffeb 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -417,6 +417,7 @@ static void __net_exit ip_rt_do_proc_exit(struct net *net)
 static struct pernet_operations ip_rt_proc_ops __net_initdata =  {
 	.init = ip_rt_do_proc_init,
 	.exit = ip_rt_do_proc_exit,
+	.async = true,
 };
 
 static int __init ip_rt_proc_init(void)
@@ -2994,6 +2995,7 @@ static __net_exit void sysctl_route_net_exit(struct net *net)
 static __net_initdata struct pernet_operations sysctl_route_ops = {
 	.init = sysctl_route_net_init,
 	.exit = sysctl_route_net_exit,
+	.async = true,
 };
 #endif
 
@@ -3007,6 +3009,7 @@ static __net_init int rt_genid_init(struct net *net)
 
 static __net_initdata struct pernet_operations rt_genid_ops = {
 	.init = rt_genid_init,
+	.async = true,
 };
 
 static int __net_init ipv4_inetpeer_init(struct net *net)
@@ -3032,6 +3035,7 @@ static void __net_exit ipv4_inetpeer_exit(struct net *net)
 static __net_initdata struct pernet_operations ipv4_inetpeer_ops = {
 	.init	=	ipv4_inetpeer_init,
 	.exit	=	ipv4_inetpeer_exit,
+	.async	=	true,
 };
 
 #ifdef CONFIG_IP_ROUTE_CLASSID
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index f8ad397e285e..ac16795486ea 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -2387,6 +2387,7 @@ static void __net_exit tcp4_proc_exit_net(struct net *net)
 static struct pernet_operations tcp4_net_ops = {
 	.init = tcp4_proc_init_net,
 	.exit = tcp4_proc_exit_net,
+	.async = true,
 };
 
 int __init tcp4_proc_init(void)
@@ -2573,6 +2574,7 @@ static struct pernet_operations __net_initdata tcp_sk_ops = {
        .init	   = tcp_sk_init,
        .exit	   = tcp_sk_exit,
        .exit_batch = tcp_sk_exit_batch,
+       .async	   = true,
 };
 
 void __init tcp_v4_init(void)
diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c
index 03b51cdcc731..aa6fea9f3328 100644
--- a/net/ipv4/tcp_metrics.c
+++ b/net/ipv4/tcp_metrics.c
@@ -1024,6 +1024,7 @@ static void __net_exit tcp_net_metrics_exit_batch(struct list_head *net_exit_lis
 static __net_initdata struct pernet_operations tcp_net_metrics_ops = {
 	.init		=	tcp_net_metrics_init,
 	.exit_batch	=	tcp_net_metrics_exit_batch,
+	.async		=	true,
 };
 
 void __init tcp_metrics_init(void)
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index bfaefe560b5c..ac5fac0e59b1 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -2757,6 +2757,7 @@ static void __net_exit udp4_proc_exit_net(struct net *net)
 static struct pernet_operations udp4_net_ops = {
 	.init = udp4_proc_init_net,
 	.exit = udp4_proc_exit_net,
+	.async = true,
 };
 
 int __init udp4_proc_init(void)
diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c
index f96614e9b9a5..72f2c3806408 100644
--- a/net/ipv4/udplite.c
+++ b/net/ipv4/udplite.c
@@ -104,6 +104,7 @@ static void __net_exit udplite4_proc_exit_net(struct net *net)
 static struct pernet_operations udplite4_net_ops = {
 	.init = udplite4_proc_init_net,
 	.exit = udplite4_proc_exit_net,
+	.async = true,
 };
 
 static __init int udplite4_proc_init(void)
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 05017e2c849c..753f526cf9db 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -365,6 +365,7 @@ static void __net_exit xfrm4_net_exit(struct net *net)
 static struct pernet_operations __net_initdata xfrm4_net_ops = {
 	.init	= xfrm4_net_init,
 	.exit	= xfrm4_net_exit,
+	.async	= true,
 };
 
 static void __init xfrm4_policy_init(void)
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 7a23078132cf..77d9d1ab05ce 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -2982,6 +2982,7 @@ static void __net_exit xfrm_net_exit(struct net *net)
 static struct pernet_operations __net_initdata xfrm_net_ops = {
 	.init = xfrm_net_init,
 	.exit = xfrm_net_exit,
+	.async = true,
 };
 
 void __init xfrm_init(void)

[PATCH net-next v3 25/32] net: Convert unix_net_ops

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:30:05

These pernet_operations are just create and destroy
/proc and sysctl entries, and are not touched by
foreign pernet_operations.

So, we are able to make them async.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 net/unix/af_unix.c |    1 +
 1 file changed, 1 insertion(+)
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 723698416242..e3eb8806b3e4 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -2913,6 +2913,7 @@ static void __net_exit unix_net_exit(struct net *net)
 static struct pernet_operations unix_net_ops = {
 	.init = unix_net_init,
 	.exit = unix_net_exit,
+	.async = true,
 };
 
 static int __init af_unix_init(void)

[PATCH net-next v3 26/32] net: Convert packet_net_ops

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:30:16

These pernet_operations just create and destroy /proc entry,
and another operations do not touch it.

Also, nobody else are interested in foreign net::packet::sklist.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 net/packet/af_packet.c |    1 +
 1 file changed, 1 insertion(+)
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 616cb9c18f88..2c5a6fe5d749 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -4557,6 +4557,7 @@ static void __net_exit packet_net_exit(struct net *net)
 static struct pernet_operations packet_net_ops = {
 	.init = packet_net_init,
 	.exit = packet_net_exit,
+	.async = true,
 };
 
 

[PATCH net-next v3 27/32] net: Convert ipv4_sysctl_ops

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:30:25

These pernet_operations create and destroy sysctl,
which are not touched by anybody else.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 net/ipv4/sysctl_net_ipv4.c |    1 +
 1 file changed, 1 insertion(+)
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 93e172118a94..89683d868b37 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -1219,6 +1219,7 @@ static __net_exit void ipv4_sysctl_exit_net(struct net *net)
 static __net_initdata struct pernet_operations ipv4_sysctl_ops = {
 	.init = ipv4_sysctl_init_net,
 	.exit = ipv4_sysctl_exit_net,
+	.async = true,
 };
 
 static __init int sysctl_ipv4_init(void)

[PATCH net-next v3 28/32] net: Convert addrconf_ops

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:30:32

These pernet_operations (un)register sysctl, which
are not touched by anybody else.

So, it's safe to make them async.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 net/ipv6/addrconf.c |    1 +
 1 file changed, 1 insertion(+)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index e1846b97ee69..8c17f8d8d5d9 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -6550,6 +6550,7 @@ static void __net_exit addrconf_exit_net(struct net *net)
 static struct pernet_operations addrconf_ops = {
 	.init = addrconf_init_net,
 	.exit = addrconf_exit_net,
+	.async = true,
 };
 
 static struct rtnl_af_ops inet6_ops __read_mostly = {

[PATCH net-next v3 29/32] net: Convert loopback_net_ops

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:30:39

These pernet_operations have only init() method. It allocates
memory for net_device, calls register_netdev() and assigns
net::loopback_dev.

register_netdev() is allowed be used without additional locks,
as it's synchronized on rtnl_lock(). There are many examples
of using this functon directly from ioctl().

The only difference, compared to ioctl(), is that net is not
completely alive at this moment. But it looks like, there is
no way for parallel pernet_operations to dereference
the net_device, as the most of struct net_device lists,
where it's linked, are related to net, and the net is not liked.

The exceptions are net_device::unreg_list, close_list, todo_list,
used for unregistration, and ::link_watch_list, where net_device
may be linked to global lists.

Unregistration of loopback_dev obviously can't happen, when
loopback_net_init() is executing, as the net as alive. It occurs
in default_device_ops, which currently requires net_mutex,
and it behaves as a barrier at the moment. It will be considered
in next patch.

Speaking about link_watch_list, it seems, there is no way
for loopback_dev at time of registration to be linked in lweventlist
and be available for another pernet_operations.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 drivers/net/loopback.c |    1 +
 1 file changed, 1 insertion(+)
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 30612497643c..b97a907ea5aa 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -230,4 +230,5 @@ static __net_init int loopback_net_init(struct net *net)
 /* Registered in net/core/dev.c */
 struct pernet_operations __net_initdata loopback_net_ops = {
 	.init = loopback_net_init,
+	.async = true,
 };

[PATCH net-next v3 30/32] net: Convert default_device_ops

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:30:49

These pernet operations consist of exit() and exit_batch() methods.

default_device_exit() moves not-local and virtual devices to init_net.
There is nothing exciting, because this may happen in any time
on a working system, and rtnl_lock() and synchronize_net() protect
us from all cases of external dereference.

The same for default_device_exit_batch(). Similar unregisteration
may happen in any time on a system. Here several lists (like todo_list),
which are accessed under rtnl_lock(). After rtnl_unlock() and
netdev_run_todo() all the devices are flushed.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 net/core/dev.c |    1 +
 1 file changed, 1 insertion(+)
diff --git a/net/core/dev.c b/net/core/dev.c
index dc7506f00a66..df5241c8eda1 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -8934,6 +8934,7 @@ static void __net_exit default_device_exit_batch(struct list_head *net_list)
 static struct pernet_operations __net_initdata default_device_ops = {
 	.exit = default_device_exit,
 	.exit_batch = default_device_exit_batch,
+	.async = true,
 };
 
 /*

[PATCH net-next v3 31/32] net: Convert diag_net_ops

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:30:59

These pernet operations just create and destroy netlink
socket. The socket is pernet and else operations don't
touch it.

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 net/core/sock_diag.c |    1 +
 1 file changed, 1 insertion(+)
diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c
index 146b50e30659..aee5642affd9 100644
--- a/net/core/sock_diag.c
+++ b/net/core/sock_diag.c
@@ -328,6 +328,7 @@ static void __net_exit diag_net_exit(struct net *net)
 static struct pernet_operations diag_net_ops = {
 	.init = diag_net_init,
 	.exit = diag_net_exit,
+	.async = true,
 };
 
 static int __init sock_diag_init(void)

[PATCH net-next v3 32/32] net: Convert netlink_tap_net_ops

From: Kirill Tkhai <hidden>
Date: 2018-02-13 09:31:09

These pernet_operations init just allocated net memory,
and they obviously can be executed in parallel in any
others.

v3: New

Signed-off-by: Kirill Tkhai <redacted>
Acked-by: Andrei Vagin <redacted>
---
 net/netlink/af_netlink.c |    1 +
 1 file changed, 1 insertion(+)
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index b3065908e146..63cb55d3c2fd 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -253,6 +253,7 @@ static struct pernet_operations netlink_tap_net_ops = {
 	.exit = netlink_tap_exit_net,
 	.id   = &netlink_tap_net_id,
 	.size = sizeof(struct netlink_tap_net),
+	.async = true,
 };
 
 static bool netlink_filter_tap(const struct sk_buff *skb)

Re: [PATCH net-next v3 00/32] Replacing net_mutex with rw_semaphore

From: David Miller <davem@davemloft.net>
Date: 2018-02-13 15:54:47

From: Kirill Tkhai <redacted>
Date: Tue, 13 Feb 2018 12:25:51 +0300
this is the third version of the patchset introducing net_sem
instead of net_mutex. The patchset adds net_sem in addition
to net_mutex and allows pernet_operations to be "async". This
flag means, the pernet_operations methods are safe to be
executed with any other pernet_operations (un)initializing
another net.

If there are only async pernet_operations in the system,
net_mutex is not used either for setup_net() or for cleanup_net().

The pernet_operations converted in this patchset allow
to create minimal .config to have network working, and
the changes improve the performance like you may see
below:

    %for i in {1..10000}; do unshare -n bash -c exit; done
    
    *before*
    real 1m40,377s
    user 0m9,672s
    sys 0m19,928s
    
    *after*
    real 0m17,007s
    user 0m5,311s
    sys 0m11,779
    
    (5.8 times faster)

In the future, when all pernet_operations become async,
we'll just remove this "async" field tree-wide.

All the new logic is concentrated in patches [1-5/32].
The rest of patches converts specific operations:
review, rationale of they can be converted, and setting
of async flag.

Kirill

v3: Improved patches descriptions. Added comment into [5/32].
Added [32/32] converting netlink_tap_net_ops (new pernet operations
introduced in 2018).

v2: Single patch -> patchset with rationale of every conversion
Series applied, thank you.

[lkp-robot] [net] 37b927536f: kernel_BUG_at_net/core/net_namespace.c

From: kernel test robot <hidden>
Date: 2018-02-26 02:06:23

FYI, we noticed the following commit (built with gcc-7):

commit: 37b927536f46b27de240934db9580c3d3eba9937 ("net: Introduce net_sem for protection of pernet_list")
url: https://github.com/0day-ci/linux/commits/Kirill-Tkhai/Replacing-net_mutex-with-rw_semaphore/20180215-064145


in testcase: trinity
with following parameters:

	runtime: 300s

test-description: Trinity is a linux system call fuzz tester.
test-url: http://codemonkey.org.uk/projects/trinity/


on test machine: qemu-system-x86_64 -enable-kvm -m 512M

caused below changes (please refer to attached dmesg/kmsg for entire log/backtrace):


+------------------------------------------+------------+------------+
|                                          | b6d8347bf7 | 37b927536f |
+------------------------------------------+------------+------------+
| boot_successes                           | 8          | 0          |
| boot_failures                            | 0          | 8          |
| kernel_BUG_at_net/core/net_namespace.c   | 0          | 8          |
| invalid_opcode:#[##]                     | 0          | 8          |
| RIP:ops_init                             | 0          | 8          |
| Kernel_panic-not_syncing:Fatal_exception | 0          | 8          |
+------------------------------------------+------------+------------+



[    0.258559] kernel BUG at net/core/net_namespace.c:73!
[    0.260018] invalid opcode: 0000 [#1]
[    0.261073] Modules linked in:
[    0.262005] CPU: 0 PID: 1 Comm: swapper Not tainted 4.15.0-05871-g37b9275 #1
[    0.263875] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014
[    0.266084] RIP: 0010:ops_init+0x101/0x120
[    0.267233] RSP: 0000:ffffc9000000be00 EFLAGS: 00010246
[    0.268647] RAX: 0000000000000000 RBX: ffffffff823280a0 RCX: 0000000000000000
[    0.270000] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff88001c602180
[    0.270000] RBP: ffff88001c602140 R08: ffffffff82323d00 R09: ffff88001c602140
[    0.270000] R10: ffffffff82323308 R11: ffffffff827ff64d R12: ffffffff82323400
[    0.270000] R13: 0000000000000003 R14: ffffffff826e17b9 R15: 0000000000000000
[    0.270000] FS:  0000000000000000(0000) GS:ffffffff82235000(0000) knlGS:0000000000000000
[    0.270000] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[    0.270000] CR2: 0000000000000000 CR3: 0000000002213000 CR4: 00000000000006b0
[    0.270000] Call Trace:
[    0.270000]  ? set_debug_rodata+0x11/0x11
[    0.270000]  register_pernet_operations+0x101/0x1e0
[    0.270000]  register_pernet_subsys+0x24/0x40
[    0.270000]  netlink_proto_init+0x143/0x160
[    0.270000]  ? eth_offload_init+0x14/0x14
[    0.270000]  do_one_initcall+0x4d/0x190
[    0.270000]  kernel_init_freeable+0x10e/0x190
[    0.270000]  ? rest_init+0xa0/0xa0
[    0.270000]  kernel_init+0xa/0xf0
[    0.270000]  ret_from_fork+0x3a/0x50
[    0.270000] Code: 8d 14 c5 e8 ff ff ff e8 be 14 11 00 4b 89 2c ef 49 8d 7e 08 4d 89 bc 24 50 06 00 00 be 08 00 00 00 e8 34 22 95 ff e9 77 ff ff ff <0f> 0b 0f 0b b8 f4 ff ff ff eb 91 b8 f4 ff ff ff e9 77 ff ff ff 
[    0.270000] RIP: ops_init+0x101/0x120 RSP: ffffc9000000be00
[    0.270013] ---[ end trace e0045ead2b146f98 ]---


To reproduce:

        git clone https://github.com/intel/lkp-tests.git
        cd lkp-tests
        bin/lkp qemu -k <bzImage> job-script  # job-script is attached in this email



Thanks,
Xiaolong

Re: [lkp-robot] [net] 37b927536f: kernel_BUG_at_net/core/net_namespace.c

From: Kirill Tkhai <hidden>
Date: 2018-02-26 09:40:45

On 26.02.2018 05:04, kernel test robot wrote:
FYI, we noticed the following commit (built with gcc-7):

commit: 37b927536f46b27de240934db9580c3d3eba9937 ("net: Introduce net_sem for protection of pernet_list")
url: https://github.com/0day-ci/linux/commits/Kirill-Tkhai/Replacing-net_mutex-with-rw_semaphore/20180215-064145


in testcase: trinity
with following parameters:

	runtime: 300s

test-description: Trinity is a linux system call fuzz tester.
test-url: http://codemonkey.org.uk/projects/trinity/


on test machine: qemu-system-x86_64 -enable-kvm -m 512M

caused below changes (please refer to attached dmesg/kmsg for entire log/backtrace):


+------------------------------------------+------------+------------+
|                                          | b6d8347bf7 | 37b927536f |
+------------------------------------------+------------+------------+
| boot_successes                           | 8          | 0          |
| boot_failures                            | 0          | 8          |
| kernel_BUG_at_net/core/net_namespace.c   | 0          | 8          |
| invalid_opcode:#[##]                     | 0          | 8          |
| RIP:ops_init                             | 0          | 8          |
| Kernel_panic-not_syncing:Fatal_exception | 0          | 8          |
+------------------------------------------+------------+------------+



[    0.258559] kernel BUG at net/core/net_namespace.c:73!
[    0.260018] invalid opcode: 0000 [#1]
[    0.261073] Modules linked in:
[    0.262005] CPU: 0 PID: 1 Comm: swapper Not tainted 4.15.0-05871-g37b9275 #1
[    0.263875] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014
[    0.266084] RIP: 0010:ops_init+0x101/0x120
[    0.267233] RSP: 0000:ffffc9000000be00 EFLAGS: 00010246
[    0.268647] RAX: 0000000000000000 RBX: ffffffff823280a0 RCX: 0000000000000000
[    0.270000] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff88001c602180
[    0.270000] RBP: ffff88001c602140 R08: ffffffff82323d00 R09: ffff88001c602140
[    0.270000] R10: ffffffff82323308 R11: ffffffff827ff64d R12: ffffffff82323400
[    0.270000] R13: 0000000000000003 R14: ffffffff826e17b9 R15: 0000000000000000
[    0.270000] FS:  0000000000000000(0000) GS:ffffffff82235000(0000) knlGS:0000000000000000
[    0.270000] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[    0.270000] CR2: 0000000000000000 CR3: 0000000002213000 CR4: 00000000000006b0
[    0.270000] Call Trace:
[    0.270000]  ? set_debug_rodata+0x11/0x11
[    0.270000]  register_pernet_operations+0x101/0x1e0
[    0.270000]  register_pernet_subsys+0x24/0x40
[    0.270000]  netlink_proto_init+0x143/0x160
[    0.270000]  ? eth_offload_init+0x14/0x14
[    0.270000]  do_one_initcall+0x4d/0x190
[    0.270000]  kernel_init_freeable+0x10e/0x190
[    0.270000]  ? rest_init+0xa0/0xa0
[    0.270000]  kernel_init+0xa/0xf0
[    0.270000]  ret_from_fork+0x3a/0x50
[    0.270000] Code: 8d 14 c5 e8 ff ff ff e8 be 14 11 00 4b 89 2c ef 49 8d 7e 08 4d 89 bc 24 50 06 00 00 be 08 00 00 00 e8 34 22 95 ff e9 77 ff ff ff <0f> 0b 0f 0b b8 f4 ff ff ff eb 91 b8 f4 ff ff ff e9 77 ff ff ff 
[    0.270000] RIP: ops_init+0x101/0x120 RSP: ffffc9000000be00
[    0.270013] ---[ end trace e0045ead2b146f98 ]---
There was the check:

	BUG_ON(!mutex_is_locked(&net_mutex));
 
which was killed in one of next commits of this patchset:

	commit 447cd7a0d7d1e5b4486e99cce289654fec9951e3
	Author: Kirill Tkhai [off-list ref]
	Date:   Tue Feb 13 12:26:44 2018 +0300

	net: Allow pernet_operations to be executed in parallel

So, the whole patchset as an atomic change is safe; and the only thing
is the hunk removing the BUG_ON() had to go in another patch.

Anyway, thanks for testing, Xiaolong.

Kirill
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help