From: Stanislav Kinsburskiy <skinsbur...@virtuozzo.com> This helpers will be used later to initialize per-container connector.
Signed-off-by: Stanislav Kinsburskiy <skinsbur...@virtuozzo.com> Reviewed-by: Andrey Ryabinin <aryabi...@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 <khore...@virtuozzo.com> (cherry picked from vz8 commit 010b6038d20f9e33753584bf53bf60954781233b) Signed-off-by: Pavel Tikhomirov <ptikhomi...@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 _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel