[Devel] [PATCH vz10 v2 7/9] fs/proc, ve: add per-VE ve.proc_permissions

Vasileios Almpanis vasileios.almpanis at virtuozzo.com
Thu Jul 16 16:34:20 MSK 2026


Patch doesn't apply using git am on rh10-6.12.0-211.30.1.14.3.vz10
Applying: fs/proc, ve: add per-VE ve.proc_permissions
error: patch failed: fs/proc/generic.c:389
error: fs/proc/generic.c: patch does not apply
Patch failed at 0007 fs/proc, ve: add per-VE ve.proc_permissions

Please rebase your patches on the latest branch

On 7/15/26 8:53 PM, Mirian Shilakadze wrote:
> Add a per-VE allowlist of /proc paths exposed through the cgroup file
> ve.proc_permissions, the procfs counterpart of ve.sysfs_permissions. Each
> proc_dir_entry gains a kmapset map keyed by VE (proc_perms_key on
> ve_struct), so the single shared proc tree yields per-VE answers. The
> filesystem agnostic leaf logic is reused from fs/ve_perms.c, this commit
> adds the proc tree walk, the locking, and the VFS hooks: visibility in
> proc_lookup_de/proc_readdir_de and a .permission inode op.
>
> Paths are written relative to the proc root like sysfs, path mask where
> mask is r/w/x or - to remove. The host (ve0) is unaffected and an empty
> list exposes nothing extra. The lock-free readers load the map under rcu
> against the writer's copy-on-write swap, and the seq read is serialised
> against the writer by proc_perms_mutex.
>
> Known limitation: a container can read its own ve.proc_permissions and
> trigger this seq read, ve.sysfs_permissions is the same today. The walk is
> bounded by the registered proc tree, not by the number of processes or
> containers. Hiding these ve cgroup files inside containers is tracked in
> VSTOR-120574.
>
> https://virtuozzo.atlassian.net/browse/VSTOR-135286
> Signed-off-by: Mirian Shilakadze<mirian.shilakadze at virtuozzo.com>
> ---
>   fs/proc/Makefile   |   1 +
>   fs/proc/generic.c  |  48 ++++++-
>   fs/proc/inode.c    |   2 +
>   fs/proc/internal.h |  25 ++++
>   fs/proc/root.c     |   1 +
>   fs/proc/ve.c       | 347 +++++++++++++++++++++++++++++++++++++++++++++
>   include/linux/ve.h |   1 +
>   kernel/ve/ve.c     |   7 +
>   8 files changed, 425 insertions(+), 7 deletions(-)
>   create mode 100644 fs/proc/ve.c
>
> diff --git a/fs/proc/Makefile b/fs/proc/Makefile
> index 7b4db9c56e6a..61a999c03663 100644
> --- a/fs/proc/Makefile
> +++ b/fs/proc/Makefile
> @@ -11,6 +11,7 @@ proc-$(CONFIG_MMU)	:= task_mmu.o
>   
>   proc-y       += inode.o root.o base.o generic.o array.o \
>   		fd.o
> +proc-$(CONFIG_VE)	+= ve.o
>   proc-$(CONFIG_TTY)      += proc_tty.o
>   proc-y	+= cmdline.o
>   proc-y	+= consoles.o
> diff --git a/fs/proc/generic.c b/fs/proc/generic.c
> index e8fd7c2d1c3a..791c38c49a86 100644
> --- a/fs/proc/generic.c
> +++ b/fs/proc/generic.c
> @@ -30,7 +30,7 @@
>   
>   #include "internal.h"
>   
> -static DEFINE_RWLOCK(proc_subdir_lock);
> +DEFINE_RWLOCK(proc_subdir_lock);
>   
>   struct kmem_cache *proc_dir_entry_cache __ro_after_init;
>   
> @@ -65,9 +65,9 @@ static struct proc_dir_entry *pde_subdir_next(struct proc_dir_entry *dir)
>   			     subdir_node);
>   }
>   
> -static struct proc_dir_entry *pde_subdir_find(struct proc_dir_entry *dir,
> -					      const char *name,
> -					      unsigned int len)
> +struct proc_dir_entry *pde_subdir_find(struct proc_dir_entry *dir,
> +				       const char *name,
> +				       unsigned int len)
>   {
>   	struct rb_node *node = dir->subdir.rb_node;
>   
> @@ -120,6 +120,31 @@ static bool proc_in_container(struct super_block *sb)
>   	return !ve_is_super(get_exec_env());
>   }
>   
> +/* Visible to the current VE: globally published (S_ISVTX) or per-VE allowed. */
> +static bool pde_visible_to_ve(struct proc_dir_entry *de)
> +{
> +	return (de->mode & S_ISVTX) || proc_d_visible(de);
> +}
> +
> +#ifdef CONFIG_VE
> +static int proc_iop_permission(struct mnt_idmap *idmap, struct inode *inode,
> +			       int mask)
> +{
> +	struct proc_dir_entry *de = PDE(inode);
> +	int ret = 0;
> +
> +	/*
> +	 * Runs safely during rcu-walk: proc_ve_permission() is a lockless rcu
> +	 * kmapset lookup and generic_permission() copes with rcu-walk on its
> +	 * own, so MAY_NOT_BLOCK needs no special handling here.
> +	 */
> +	if (proc_in_container(inode->i_sb) && !(de->mode & S_ISVTX))
> +		ret = proc_ve_permission(de, mask);
> +
> +	return ret ? ret : generic_permission(idmap, inode, mask);
> +}
> +#endif
> +
>   static int proc_notify_change(struct mnt_idmap *idmap,
>   			      struct dentry *dentry, struct iattr *iattr)
>   {
> @@ -167,6 +192,9 @@ static int proc_getattr(struct mnt_idmap *idmap,
>   
>   static const struct inode_operations proc_file_inode_operations = {
>   	.setattr	= proc_notify_change,
> +#ifdef CONFIG_VE
> +	.permission	= proc_iop_permission,
> +#endif
>   };
>   
>   /*
> @@ -264,7 +292,7 @@ struct dentry *proc_lookup_de(struct inode *dir, struct dentry *dentry,
>   	read_lock(&proc_subdir_lock);
>   	de = pde_subdir_find(de, dentry->d_name.name, dentry->d_name.len);
>   	if (de) {
> -		if (in_container && !(de->mode & S_ISVTX)) {
> +		if (in_container && !pde_visible_to_ve(de)) {
>   			read_unlock(&proc_subdir_lock);
>   			return ERR_PTR(-ENOENT);
>   		}
> @@ -317,7 +345,7 @@ int proc_readdir_de(struct file *file, struct dir_context *ctx,
>   			read_unlock(&proc_subdir_lock);
>   			return 0;
>   		}
> -		if (!in_container || (de->mode & S_ISVTX)) {
> +		if (!in_container || pde_visible_to_ve(de)) {
>   			if (!i)
>   				break;
>   			i--;
> @@ -328,7 +356,7 @@ int proc_readdir_de(struct file *file, struct dir_context *ctx,
>   	do {
>   		struct proc_dir_entry *next;
>   
> -		if (in_container && !(de->mode & S_ISVTX)) {
> +		if (in_container && !pde_visible_to_ve(de)) {
>   			de = pde_subdir_next(de);
>   			continue;
>   		}
> @@ -389,6 +417,9 @@ static const struct inode_operations proc_dir_inode_operations = {
>   	.lookup		= proc_lookup,
>   	.getattr	= proc_getattr,
>   	.setattr	= proc_notify_change,
> +#ifdef CONFIG_VE
> +	.permission	= proc_iop_permission,
> +#endif
>   };
>   
>   /* returns the registered entry, or frees dp and returns NULL on failure */
> @@ -413,6 +444,7 @@ struct proc_dir_entry *proc_register(struct proc_dir_entry *dir,
>   out_free_inum:
>   	proc_free_inum(dp->low_ino);
>   out_free_entry:
> +	proc_put_ve_perms(dp);
>   	pde_free(dp);
>   	return NULL;
>   }
> @@ -471,6 +503,7 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,
>   	ent->nlink = nlink;
>   	ent->subdir = RB_ROOT;
>   	refcount_set(&ent->refcnt, 1);
> +	proc_get_ve_perms(ent);
>   	spin_lock_init(&ent->pde_unload_lock);
>   	INIT_LIST_HEAD(&ent->pde_openers);
>   	proc_set_user(ent, (*parent)->uid, (*parent)->gid);
> @@ -498,6 +531,7 @@ struct proc_dir_entry *proc_symlink_mode(const char *name, umode_t mode,
>   			ent->proc_iops = &proc_link_inode_operations;
>   			ent = proc_register(parent, ent);
>   		} else {
> +			proc_put_ve_perms(ent);
>   			pde_free(ent);
>   			ent = NULL;
>   		}
> diff --git a/fs/proc/inode.c b/fs/proc/inode.c
> index 5d1a75408aa4..ac943a9768f4 100644
> --- a/fs/proc/inode.c
> +++ b/fs/proc/inode.c
> @@ -272,6 +272,8 @@ void proc_entry_rundown(struct proc_dir_entry *de)
>   		spin_lock(&de->pde_unload_lock);
>   	}
>   	spin_unlock(&de->pde_unload_lock);
> +
> +	proc_put_ve_perms(de);
>   }
>   
>   static loff_t proc_reg_llseek(struct file *file, loff_t offset, int whence)
> diff --git a/fs/proc/internal.h b/fs/proc/internal.h
> index 77a517f91821..4a28da7d5dee 100644
> --- a/fs/proc/internal.h
> +++ b/fs/proc/internal.h
> @@ -17,6 +17,7 @@
>   
>   struct ctl_table_header;
>   struct mempolicy;
> +struct kmapset_map;
>   
>   /*
>    * This is not completely implemented yet. The idea is to
> @@ -64,6 +65,9 @@ struct proc_dir_entry {
>   	umode_t mode;
>   	u8 flags;
>   	u8 namelen;
> +#ifdef CONFIG_VE
> +	struct kmapset_map __rcu *ve_perms_map;	/* per-VE r/w/x mask for this node */
> +#endif
>   	char inline_name[];
>   } __randomize_layout;
>   
> @@ -102,6 +106,27 @@ static inline bool pde_has_proc_compat_ioctl(const struct proc_dir_entry *pde)
>   extern struct kmem_cache *proc_dir_entry_cache;
>   void pde_free(struct proc_dir_entry *pde);
>   
> +extern rwlock_t proc_subdir_lock;
> +struct proc_dir_entry *pde_subdir_find(struct proc_dir_entry *dir,
> +				       const char *name, unsigned int len);
> +
> +#ifdef CONFIG_VE
> +void proc_init_ve_perms(void);
> +void proc_get_ve_perms(struct proc_dir_entry *de);
> +void proc_put_ve_perms(struct proc_dir_entry *de);
> +bool proc_d_visible(struct proc_dir_entry *de);
> +int proc_ve_permission(struct proc_dir_entry *de, int mask);
> +#else
> +static inline void proc_init_ve_perms(void) { }
> +static inline void proc_get_ve_perms(struct proc_dir_entry *de) { }
> +static inline void proc_put_ve_perms(struct proc_dir_entry *de) { }
> +static inline bool proc_d_visible(struct proc_dir_entry *de) { return false; }
> +static inline int proc_ve_permission(struct proc_dir_entry *de, int mask)
> +{
> +	return 0;
> +}
> +#endif
> +
>   union proc_op {
>   	int (*proc_get_link)(struct dentry *, struct path *);
>   	int (*proc_show)(struct seq_file *m,
> diff --git a/fs/proc/root.c b/fs/proc/root.c
> index 3f61de56ffff..9e0c5bf87602 100644
> --- a/fs/proc/root.c
> +++ b/fs/proc/root.c
> @@ -297,6 +297,7 @@ static struct file_system_type proc_fs_type = {
>   void __init proc_root_init(void)
>   {
>   	proc_init_kmemcache();
> +	proc_init_ve_perms();
>   	set_proc_pid_nlink();
>   	proc_self_init();
>   	proc_thread_self_init();
> diff --git a/fs/proc/ve.c b/fs/proc/ve.c
> new file mode 100644
> index 000000000000..d957510c353a
> --- /dev/null
> +++ b/fs/proc/ve.c
> @@ -0,0 +1,347 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + *  Per-VE /proc permissions (ve.proc_permissions), the procfs counterpart of
> + *  the sysfs ve.sysfs_permissions mechanism. Each proc_dir_entry carries a
> + *  kmapset map keyed by VE, so the single shared proc tree gives per-VE
> + *  answers. The filesystem agnostic leaf logic lives in fs/ve_perms.c, this
> + *  file owns the proc tree walk and the locking.
> + *
> + *  Copyright (c) 2026 Virtuozzo International GmbH. All rights reserved.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +#include <linux/string.h>
> +#include <linux/rbtree.h>
> +#include <linux/rcupdate.h>
> +#include <linux/seq_file.h>
> +#include <linux/fs.h>
> +#include <linux/cgroup.h>
> +#include <linux/ve.h>
> +#include <linux/kmapset.h>
> +#include <linux/ve-perms.h>
> +#include <linux/proc_fs.h>
> +
> +#include "internal.h"
> +
> +struct kmapset_set proc_ve_perms_set;
> +
> +static bool proc_ve_perms_inited;
> +
> +static DEFINE_MUTEX(proc_perms_mutex);
> +
> +void __init proc_init_ve_perms(void)
> +{
> +	struct kmapset_map *map;
> +
> +	kmapset_init_set(&proc_ve_perms_set);
> +	map = kmapset_new(&proc_ve_perms_set);
> +	if (map)
> +		RCU_INIT_POINTER(proc_root.ve_perms_map, kmapset_commit(map));
> +	proc_ve_perms_inited = true;
> +}
> +
> +void proc_get_ve_perms(struct proc_dir_entry *de)
> +{
> +	struct kmapset_map *map;
> +
> +	if (!proc_ve_perms_inited)
> +		return;
> +
> +	map = kmapset_new(&proc_ve_perms_set);
> +	if (map)
> +		rcu_assign_pointer(de->ve_perms_map, kmapset_commit(map));
> +	else
> +		pr_warn_once("proc: no ve_perms_map for %s, hidden from containers\n",
> +			     de->name);
> +}
> +
> +/*
> + * Drop the node's permission map. kmapset_put() can sleep (it takes the
> + * kmapset set mutex on the last reference), so every caller must be in process
> + * context. Registered entries drop the map from proc_entry_rundown() when they
> + * are removed. Entries that never reach the tree drop it on their creation error
> + * path (proc_register(), proc_symlink_mode()). pde_free() therefore never
> + * touches the map and stays safe to run from the .free_inode RCU callback, which
> + * is atomic. The mutex here serialises against a concurrent proc_perms_set() on
> + * a registered entry. The NULL fast path skips it when there is nothing to drop.
> + */
> +void proc_put_ve_perms(struct proc_dir_entry *de)
> +{
> +	struct kmapset_map *map;
> +
> +	/* Atomic-safe fast path: already dropped at rundown, or never set. */
> +	if (!rcu_access_pointer(de->ve_perms_map))
> +		return;
> +
> +	/* Serialise against a concurrent proc_perms_set() on this entry. */
> +	mutex_lock(&proc_perms_mutex);
> +	map = rcu_dereference_protected(de->ve_perms_map,
> +				       lockdep_is_held(&proc_perms_mutex));
> +	/*
> +	 * Publish NULL before dropping the map. A cached proc inode can
> +	 * outlive remove_proc_entry() and proc_ve_permission() may still
> +	 * read de->ve_perms_map through it, so leave a NULL there for that
> +	 * late reader to find instead of a pointer into the freed map.
> +	 */
> +	rcu_assign_pointer(de->ve_perms_map, NULL);
> +	mutex_unlock(&proc_perms_mutex);
> +	kmapset_put(map);
> +}
> +
> +bool proc_d_visible(struct proc_dir_entry *de)
> +{
> +	struct ve_struct *ve = get_exec_env();
> +	struct kmapset_map *map;
> +	bool visible;
> +
> +	if (ve_is_super(ve))
> +		return true;
> +
> +	/*
> +	 * proc_perms_set() can swap this map pointer concurrently and free the
> +	 * old map through kfree_rcu(). Hold rcu across both the load and the
> +	 * lookup so the map cannot be freed under us.
> +	 */
> +	rcu_read_lock();
> +	map = rcu_dereference(de->ve_perms_map);
> +	visible = map && ve_perms_visible(map, &ve->proc_perms_key);
> +	rcu_read_unlock();
> +	return visible;
> +}
> +
> +int proc_ve_permission(struct proc_dir_entry *de, int mask)
> +{
> +	struct ve_struct *ve = get_exec_env();
> +	struct kmapset_map *map;
> +	int ret;
> +
> +	if (ve_is_super(ve))
> +		return 0;
> +
> +	rcu_read_lock();
> +	map = rcu_dereference(de->ve_perms_map);
> +	ret = map ? ve_perms_check(map, &ve->proc_perms_key, mask) : -EACCES;
> +	rcu_read_unlock();
> +	return ret;
> +}
> +
> +static int proc_perms_set(char *path, struct ve_struct *ve, int mask)
> +{
> +	struct proc_dir_entry *de, *nde;
> +	char *sep = path, *dname;
> +	int ret = 0;
> +
> +	read_lock(&proc_subdir_lock);
> +	de = &proc_root;
> +	pde_get(de);
> +	do {
> +		dname = sep;
> +
> +		sep = strchr(sep, '/');
> +		if (sep)
> +			*sep++ = 0;
> +
> +		if (!*dname)
> +			break;
> +
> +		nde = pde_subdir_find(de, dname, strlen(dname));
> +		if (!nde) {
> +			read_unlock(&proc_subdir_lock);
> +			ret = -ENOENT;
> +			goto out;
> +		}
> +		pde_get(nde);
> +		pde_put(de);
> +		de = nde;
> +	} while (sep);
> +	read_unlock(&proc_subdir_lock);
> +
> +	/* empty or leading-slash path walks to nothing, reject it */
> +	if (de == &proc_root) {
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	if (!rcu_access_pointer(de->ve_perms_map)) {
> +		ret = -EPERM;
> +		goto out;
> +	}
> +
> +	ret = ve_perms_apply(&de->ve_perms_map, &ve->proc_perms_key,
> +			     ve_is_super(ve), mask);
> +out:
> +	pde_put(de);
> +	return ret;
> +}
> +
> +static int proc_perms_line(struct ve_struct *ve, char *line)
> +{
> +	int mask, ret;
> +
> +	ret = ve_perms_parse(line, &mask);
> +	if (ret)
> +		return ret;
> +	return proc_perms_set(line, ve, mask);
> +}
> +
> +static struct proc_dir_entry *proc_next_recursive(struct proc_dir_entry *de)
> +{
> +	struct rb_node *node;
> +
> +	node = rb_first(&de->subdir);
> +	if (node)
> +		return rb_entry(node, struct proc_dir_entry, subdir_node);
> +
> +	while (de->parent != de) {
> +		node = rb_next(&de->subdir_node);
> +		if (node)
> +			return rb_entry(node, struct proc_dir_entry,
> +					subdir_node);
> +		de = de->parent;
> +	}
> +	return NULL;
> +}
> +
> +static bool proc_perms_shown(struct ve_struct *ve, struct proc_dir_entry *de)
> +{
> +	bool shown;
> +
> +	if (!rcu_access_pointer(de->ve_perms_map))
> +		return false;
> +
> +	/* ve_perms_shown calls kmapset_lookup, an rcu list walk, guard it. */
> +	rcu_read_lock();
> +	shown = ve_perms_shown(rcu_dereference(de->ve_perms_map),
> +			       &ve->proc_perms_key, ve_is_super(ve));
> +	rcu_read_unlock();
> +	return shown;
> +}
> +
> +static void *proc_perms_start(struct seq_file *m, loff_t *ppos)
> +	__acquires(&proc_subdir_lock)
> +{
> +	struct ve_struct *ve = css_to_ve(seq_css(m));
> +	struct proc_dir_entry *de;
> +	loff_t pos = *ppos;
> +
> +	mutex_lock(&proc_perms_mutex);
> +	read_lock(&proc_subdir_lock);
> +	for (de = &proc_root; de; de = proc_next_recursive(de)) {
> +		if (proc_perms_shown(ve, de) && !pos--)
> +			break;
> +	}
> +	return de;
> +}
> +
> +static void *proc_perms_next(struct seq_file *m, void *v, loff_t *ppos)
> +{
> +	struct ve_struct *ve = css_to_ve(seq_css(m));
> +	struct proc_dir_entry *de = v;
> +
> +	(*ppos)++;
> +	while ((de = proc_next_recursive(de))) {
> +		if (proc_perms_shown(ve, de))
> +			break;
> +	}
> +	return de;
> +}
> +
> +static void proc_perms_stop(struct seq_file *m, void *v)
> +	__releases(&proc_subdir_lock)
> +{
> +	read_unlock(&proc_subdir_lock);
> +	mutex_unlock(&proc_perms_mutex);
> +}
> +
> +/*
> + * Emit de's path relative to the proc root, parent first, and let seq_file
> + * handle the buffer sizing. The proc tree is shallow so the recursion is
> + * bounded by its depth.
> + */
> +static void proc_perms_emit_path(struct seq_file *m, struct proc_dir_entry *de)
> +{
> +	if (de == &proc_root)
> +		return;
> +	proc_perms_emit_path(m, de->parent);
> +	seq_puts(m, de->name);
> +	if (S_ISDIR(de->mode))
> +		seq_putc(m, '/');
> +}
> +
> +static int proc_perms_show(struct seq_file *m, void *v)
> +{
> +	struct ve_struct *ve = css_to_ve(seq_css(m));
> +	struct proc_dir_entry *de = v;
> +	struct kmapset_map *map;
> +	int mask;
> +
> +	map = rcu_dereference_protected(de->ve_perms_map,
> +				       lockdep_is_held(&proc_perms_mutex));
> +	if (ve_is_super(ve))
> +		mask = map->default_value;
> +	else
> +		mask = kmapset_get_value(map, &ve->proc_perms_key);
> +
> +	proc_perms_emit_path(m, de);
> +
> +	ve_perms_emit(m, mask);
> +	return 0;
> +}
> +
> +static ssize_t proc_perms_write(struct kernfs_open_file *of, char *buf,
> +				size_t nbytes, loff_t off)
> +{
> +	struct ve_struct *ve = css_to_ve(of_css(of));
> +	char *line, *next = buf;
> +	int ret = -EINVAL;
> +
> +	mutex_lock(&proc_perms_mutex);
> +	do {
> +		line = skip_spaces(next);
> +		if (!*line)
> +			break;
> +
> +		next = strchr(line, '\n');
> +		if (next)
> +			*next++ = '\0';
> +
> +		if (*line != '#') {
> +			ret = proc_perms_line(ve, line);
> +			if (ret)
> +				break;
> +		}
> +	} while (next);
> +	mutex_unlock(&proc_perms_mutex);
> +
> +	return ret ? ret : nbytes;
> +}
> +
> +static struct cftype proc_ve_cftypes[] = {
> +	{
> +		.name		= "default_proc_permissions",
> +		.flags		= CFTYPE_ONLY_ON_ROOT,
> +		.seq_start	= proc_perms_start,
> +		.seq_next	= proc_perms_next,
> +		.seq_stop	= proc_perms_stop,
> +		.seq_show	= proc_perms_show,
> +		.write		= proc_perms_write,
> +	},
> +	{
> +		.name		= "proc_permissions",
> +		.flags		= CFTYPE_NOT_ON_ROOT,
> +		.seq_start	= proc_perms_start,
> +		.seq_next	= proc_perms_next,
> +		.seq_stop	= proc_perms_stop,
> +		.seq_show	= proc_perms_show,
> +		.write		= proc_perms_write,
> +	},
> +	{ },
> +};
> +
> +static int init_proc_ve_perms(void)
> +{
> +	return cgroup_add_cftypes(&ve_cgrp_subsys, proc_ve_cftypes);
> +}
> +module_init(init_proc_ve_perms);
> diff --git a/include/linux/ve.h b/include/linux/ve.h
> index b037f60225bb..cba827260d07 100644
> --- a/include/linux/ve.h
> +++ b/include/linux/ve.h
> @@ -69,6 +69,7 @@ struct ve_struct {
>   	int			fsync_enable;
>   
>   	struct kmapset_key	sysfs_perms_key;
> +	struct kmapset_key	proc_perms_key;
>   
>   	atomic_t		netns_avail_nr;
>   	int			netns_max_nr;
> diff --git a/kernel/ve/ve.c b/kernel/ve/ve.c
> index e58ffb22da87..d8ef28eedabd 100644
> --- a/kernel/ve/ve.c
> +++ b/kernel/ve/ve.c
> @@ -44,6 +44,9 @@
>   #include "../sched/sched.h"		/* For css_tg() */
>   
>   extern struct kmapset_set sysfs_ve_perms_set;
> +#ifdef CONFIG_PROC_FS
> +extern struct kmapset_set proc_ve_perms_set;
> +#endif
>   
>   static struct kmem_cache *ve_cachep;
>   
> @@ -771,6 +774,7 @@ static struct cgroup_subsys_state *ve_create(struct cgroup_subsys_state *parent_
>   	init_rwsem(&ve->op_sem);
>   	INIT_LIST_HEAD(&ve->ve_list);
>   	kmapset_init_key(&ve->sysfs_perms_key);
> +	kmapset_init_key(&ve->proc_perms_key);
>   
>   	atomic_set(&ve->arp_neigh_nr, 0);
>   	atomic_set(&ve->nd_neigh_nr, 0);
> @@ -866,6 +870,9 @@ static void ve_destroy(struct cgroup_subsys_state *css)
>   	free_ve_devmnts(ve);
>   
>   	kmapset_unlink(&ve->sysfs_perms_key, &sysfs_ve_perms_set);
> +#ifdef CONFIG_PROC_FS
> +	kmapset_unlink(&ve->proc_perms_key, &proc_ve_perms_set);
> +#endif
>   	ve_log_destroy(ve);
>   	ve_free_vdso(ve);
>   	mntput(ve->devtmpfs_mnt);
> -- 2.43.0 _______________________________________________ Devel 
> mailing list Devel at openvz.org 
> https://lists.openvz.org/mailman/listinfo/devel

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



More information about the Devel mailing list