[Devel] [PATCH VZ10 4/8] ve/net: thread owning ve through copy_net_ns

Vasileios Almpanis vasileios.almpanis at virtuozzo.com
Thu Apr 30 11:19:21 MSK 2026


Reviewed-by: Vasileios Almpanis <vasileios.almpanis at virtuozzo.com>

On 4/29/26 3:41 PM, Pavel Tikhomirov wrote:
> Add new_ve parameter to copy_net_ns(). NULL preserves the existing
> behaviour of taking current ve via get_exec_env().
>
> This will be used to derive correct ownership of newly created net
> namespace in case of simultaneous creation of new ve namespace and net
> namespace, were we would like new net namespace having the new ve as an
> owner.
>
> While on it, move ve reference count handling from setup_net() to
> copy_net_ns(), since we already handle dec/inc_netns_avail() up there.
> This way we don't need to thread it also to setup_net(). That is
> also consistent with how user_ns is threaded.
>
> The init_net.owner_ve is now set explicitly to &ve0 in net_ns_init()
> since setup_net() no longer does it for the boot-time call.
>
> There is no change in behaviour yet: create_new_namespaces() still uses
> NULL.
>
> https://virtuozzo.atlassian.net/browse/VSTOR-129744
> Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
> Feature: ve: ve generic structures
> ---
>   include/net/net_namespace.h |  7 +++++--
>   kernel/nsproxy.c            |  3 ++-
>   net/core/net_namespace.c    | 33 +++++++++++++++++++++++----------
>   3 files changed, 30 insertions(+), 13 deletions(-)
>
> diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
> index ed077747f710..dd0edb96f0ee 100644
> --- a/include/net/net_namespace.h
> +++ b/include/net/net_namespace.h
> @@ -203,9 +203,11 @@ struct net {
>   /* Init's network namespace */
>   extern struct net init_net;
>   
> +struct ve_struct;
> +
>   #ifdef CONFIG_NET_NS
>   struct net *copy_net_ns(unsigned long flags, struct user_namespace *user_ns,
> -			struct net *old_net);
> +			struct net *old_net, struct ve_struct *new_ve);
>   
>   void net_ns_get_ownership(const struct net *net, kuid_t *uid, kgid_t *gid);
>   
> @@ -218,7 +220,8 @@ struct net *get_net_ns_by_fd(int fd);
>   #include <linux/sched.h>
>   #include <linux/nsproxy.h>
>   static inline struct net *copy_net_ns(unsigned long flags,
> -	struct user_namespace *user_ns, struct net *old_net)
> +	struct user_namespace *user_ns, struct net *old_net,
> +	struct ve_struct *new_ve)
>   {
>   	if (flags & CLONE_NEWNET)
>   		return ERR_PTR(-EINVAL);
> diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c
> index 12de23ec80bf..1d0e8f9d98a3 100644
> --- a/kernel/nsproxy.c
> +++ b/kernel/nsproxy.c
> @@ -109,7 +109,8 @@ static struct nsproxy *create_new_namespaces(unsigned long flags,
>   		goto out_cgroup;
>   	}
>   
> -	new_nsp->net_ns = copy_net_ns(flags, user_ns, tsk->nsproxy->net_ns);
> +	new_nsp->net_ns = copy_net_ns(flags, user_ns, tsk->nsproxy->net_ns,
> +				      NULL);
>   	if (IS_ERR(new_nsp->net_ns)) {
>   		err = PTR_ERR(new_nsp->net_ns);
>   		goto out_net;
> diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
> index 40e74d956bc2..3738e5274cd9 100644
> --- a/net/core/net_namespace.c
> +++ b/net/core/net_namespace.c
> @@ -352,10 +352,6 @@ static __net_init int setup_net(struct net *net)
>   	LIST_HEAD(dev_kill_list);
>   	int error = 0;
>   
> -#ifdef CONFIG_VE
> -	net->owner_ve = get_ve(get_exec_env());
> -#endif
> -
>   	preempt_disable();
>   	net->net_cookie = gen_cookie_next(&net_cookie);
>   	preempt_enable();
> @@ -400,9 +396,6 @@ static __net_init int setup_net(struct net *net)
>   		ops_free_list(ops, &net_exit_list);
>   
>   	rcu_barrier();
> -#ifdef CONFIG_VE
> -	put_ve(net->owner_ve);
> -#endif
>   	goto out;
>   }
>   
> @@ -505,9 +498,10 @@ static void inc_netns_avail(struct ve_struct *ve)
>   #endif
>   
>   struct net *copy_net_ns(unsigned long flags,
> -			struct user_namespace *user_ns, struct net *old_net)
> +			struct user_namespace *user_ns, struct net *old_net,
> +			struct ve_struct *new_ve)
>   {
> -	struct ve_struct *ve = get_exec_env();
> +	struct ve_struct *ve;
>   	struct ucounts *ucounts;
>   	struct net *net;
>   	int rv;
> @@ -515,6 +509,14 @@ struct net *copy_net_ns(unsigned long flags,
>   	if (!(flags & CLONE_NEWNET))
>   		return get_net(old_net);
>   
> +	/*
> +	 * The ve that should own the new netns. When called from
> +	 * copy_namespaces()/unshare_nsproxy_namespaces() with a freshly
> +	 * created CLONE_NEWVE in flight, @new_ve is supplied by the
> +	 * caller because get_exec_env() still resolves to the parent ve.
> +	 */
> +	ve = new_ve ?: get_exec_env();
> +
>   	ucounts = inc_net_namespaces(user_ns);
>   	if (!ucounts)
>   		return ERR_PTR(-ENOSPC);
> @@ -538,16 +540,23 @@ struct net *copy_net_ns(unsigned long flags,
>   	preinit_net(net, user_ns);
>   	net->ucounts = ucounts;
>   	get_user_ns(user_ns);
> +#ifdef CONFIG_VE
> +	net->owner_ve = get_ve(ve);
> +#endif
>   
>   	rv = down_read_killable(&pernet_ops_rwsem);
>   	if (rv < 0)
> -		goto put_userns;
> +		goto put_owner_ve;
>   
>   	rv = setup_net(net);
>   
>   	up_read(&pernet_ops_rwsem);
>   
>   	if (rv < 0) {
> +put_owner_ve:
> +#ifdef CONFIG_VE
> +		put_ve(net->owner_ve);
> +#endif
>   put_userns:
>   #ifdef CONFIG_KEYS
>   		key_remove_domain(net->key_domain);
> @@ -1261,6 +1270,10 @@ void __init net_ns_init(void)
>   #endif
>   	preinit_net(&init_net, &init_user_ns);
>   
> +#ifdef CONFIG_VE
> +	init_net.owner_ve = get_ve(&ve0);
> +#endif
> +
>   	down_write(&pernet_ops_rwsem);
>   	if (setup_net(&init_net))
>   		panic("Could not setup the initial network namespace");

-- 
Best regards, Vasileios Almpanis
Software Developer, Virtuozzo.



More information about the Devel mailing list