[Devel] [PATCH RH9 03/26] connector: per-ve init and fini helpers introduced

Pavel Tikhomirov ptikhomirov at virtuozzo.com
Thu Oct 7 15:53:43 MSK 2021


From: Stanislav Kinsburskiy <skinsbursky at virtuozzo.com>

This helpers will be used later to initialize per-container connector.

Signed-off-by: Stanislav Kinsburskiy <skinsbursky at virtuozzo.com>
Reviewed-by: Andrey Ryabinin <aryabinin at virtuozzo.com>

+++
connector: avoid RCU read-side critical section in cn_init_ve()

First, netlink_kernel_create() cannot be called under rcu_read_lock()
(inside ve_net_lock()) because it sleeps.

Second, cn_init_ve() is a hook called on VE creation, VE creation is
done in a single thread, all hooks are called under a lock =>
ve cannot be destroyed during start hook execution => rcu_read_lock() is
not needed at all here.

mFixes: e7b9a7d5ce79 ("connector: per-ve init and fini helpers
introduced")
https://jira.sw.ru/browse/PSBM-93640

Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>

(cherry picked from vz8 commit 010b6038d20f9e33753584bf53bf60954781233b)
Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
---
 drivers/connector/connector.c | 54 +++++++++++++++++++++++++++++------
 1 file changed, 45 insertions(+), 9 deletions(-)

diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index a4348d68698b..8d184588d53e 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -249,41 +249,77 @@ static int __maybe_unused cn_proc_show(struct seq_file *m, void *v)
 	return 0;
 }
 
-static int cn_init(void)
+static int cn_init_ve(struct ve_struct *ve)
 {
 	struct cn_dev *dev = get_cdev(get_ve0());
 	struct netlink_kernel_cfg cfg = {
 		.groups	= CN_NETLINK_USERS + 0xf,
 		.input	= cn_rx_skb,
 	};
+	struct net *net;
+	int err;
+
+	ve->cn = kzalloc(sizeof(*ve->cn), GFP_KERNEL);
+	if (!ve->cn)
+		return -ENOMEM;
 
-	dev->nls = netlink_kernel_create(&init_net, NETLINK_CONNECTOR, &cfg);
+	/*
+	 * This is a hook, hooks are called under a single lock, so ve_ns will
+	 * not disappear, so rcu_read_lock()/unlock is not needed here.
+	 */
+	net = rcu_dereference_check(ve->ve_ns, 1)->net_ns;
+
+	err = -EIO;
+	dev->nls = netlink_kernel_create(net, NETLINK_CONNECTOR, &cfg);
 	if (!dev->nls)
-		return -EIO;
+		goto net_unlock;
 
+	err = -EINVAL;
 	dev->cbdev = cn_queue_alloc_dev("cqueue", dev->nls);
 	if (!dev->cbdev) {
 		netlink_kernel_release(dev->nls);
-		return -EINVAL;
+		goto net_unlock;
 	}
 
 	cn_already_initialized = 1;
 
-	proc_create_single("connector", S_IRUGO, init_net.proc_net, cn_proc_show);
+	proc_create_single("connector", S_IRUGO, net->proc_net, cn_proc_show);
+	err = 0;
 
-	return 0;
+net_unlock:
+	return err;
 }
 
-static void cn_fini(void)
+static void cn_fini_ve(struct ve_struct *ve)
 {
-	struct cn_dev *dev = get_cdev(get_ve0());
+	struct cn_dev *dev = get_cdev(ve);
+	struct net *net;
 
 	cn_already_initialized = 0;
 
-	remove_proc_entry("connector", init_net.proc_net);
+	/*
+	 * This is a hook called on ve stop, ve->ve_ns will be destroyed
+	 * later in the same thread, parallel ve stop is impossible,
+	 * so rcu_read_lock()/unlock is not needed here.
+	 */
+	net = rcu_dereference_check(ve->ve_ns, 1)->net_ns;
+	remove_proc_entry("connector", net->proc_net);
 
 	cn_queue_free_dev(dev->cbdev);
 	netlink_kernel_release(dev->nls);
+
+	kfree(ve->cn);
+	ve->cn = NULL;
+}
+
+static int cn_init(void)
+{
+	return cn_init_ve(get_ve0());
+}
+
+static void cn_fini(void)
+{
+	return cn_fini_ve(get_ve0());
 }
 
 subsys_initcall(cn_init);
-- 
2.31.1



More information about the Devel mailing list