[Devel] [PATCH vz9 21/23] ve/devmnt: Introduce ve::devmnt list #PSBM-108196

Nikita Yushchenko nikita.yushchenko at virtuozzo.com
Fri Oct 1 18:53:29 MSK 2021


From: Kirill Tkhai <ktkhai at odin.com>

1)Porting patch "ve: mount option list" by Maxim Patlasov:

The patch adds new fields to ve_struct: devmnt_list and devmnt_mutex.
devmnt_list is the head of list of ve_devmnt structs. Each host block device
visible from CT can have no more than one struct ve_devmnt linked in
ve->devmnt_list. If ve_devmnt is present, it can be found by 'dev' field.

Each ve_devmnt struct may bear two strings: hidden and allowed options.
hidden_options will be automatically added to CT-user-supplied mount options
after checking allowed_options. Only options listed in allowed_options are
allowed.

devmnt_mutex is to protect operations on the list of ve_devmnt structs.

2)Porting patch "vecalls: VE_CONFIGURE_MOUNT_OPTIONS" by Maxim Patlasov.

Reworking the interface using cgroups. Each CT now has a file:

[ve_cgroup_mnt_pnt]/[CTID]/ve.mount_opts

for configuring permittions for a block device. Below is permittions line
example:

"0 major:minor;1 balloon_ino=12,pfcache_csum,pfcache=/vz/pfcache;2 barrier=1"

Here, major:minor is a device, '1' starts comma-separated list of
hidden options, and '2' is allowed ones.

https://jira.sw.ru/browse/PSBM-32273

Signed-off-by: Kirill Tkhai <ktkhai at odin.com>

Acked-by: Maxim Patlasov <mpatlasov at openvz.org>

+++
ve/cgroups: Align ve_cftypes assignments

For readability sake. We've other aligned already.

Signed-off-by: Cyrill Gorcunov <gorcunov at odin.com>

Rebase: ktkhai@: Merged "ve: increase max length of ve.mount_opts string"

ve/devmnt: Add a ability to show ve.mount_opts

A user may want to see allowed mount options.
This patch allows that.

khorenko@:
* by default ve cgroup is not visible from inside a CT

* currently it's possible to mount ve cgroup inside a CT, but this is
  temporarily, we'll disable this in the scope of
  https://jira.sw.ru/browse/PSBM-34291

* this patch allows to see mount options via ve cgroup =>
  after PSBM-34291 is fixed, mount options will be visible only from ve0 (host)

* for host it's OK to see all hidden options

Signed-off-by: Kirill Tkhai <ktkhai at odin.com>

Rebase: ktkhai@: Merged "ve: Strip unset options in ve.mount_opts"

[aryabinin: vz8 rebase]
https://jira.sw.ru/browse/PSBM-108196
Signed-off-by: Andrey Ryabinin <aryabinin at virtuozzo.com>

(cherry-picked from vz8 commit a4e36a50e65a ("ve/devmnt: Introduce
ve::devmnt list #PSBM-108196"))

Signed-off-by: Nikita Yushchenko <nikita.yushchenko at virtuozzo.com>
---
 include/linux/ve.h |  11 +++
 kernel/ve/ve.c     | 176 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 187 insertions(+)

diff --git a/include/linux/ve.h b/include/linux/ve.h
index 57e6e440bc0f..30d110cb74d6 100644
--- a/include/linux/ve.h
+++ b/include/linux/ve.h
@@ -75,6 +75,17 @@ struct ve_struct {
 
 	struct vdso_image	*vdso_64;
 	struct vdso_image	*vdso_32;
+
+	struct list_head	devmnt_list;
+	struct mutex		devmnt_mutex;
+};
+
+struct ve_devmnt {
+	struct list_head	link;
+
+	dev_t                   dev;
+	char			*allowed_options;
+	char			*hidden_options; /* balloon_ino, etc. */
 };
 
 #define VE_MEMINFO_DEFAULT	1	/* default behaviour */
diff --git a/kernel/ve/ve.c b/kernel/ve/ve.c
index 55ceb93bf9e2..9da8259fc704 100644
--- a/kernel/ve/ve.c
+++ b/kernel/ve/ve.c
@@ -11,6 +11,7 @@
  * 've.c' helper file performing VE sub-system initialization
  */
 
+#include <linux/ctype.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/ve.h>
@@ -647,6 +648,10 @@ 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);
+
+	INIT_LIST_HEAD(&ve->devmnt_list);
+	mutex_init(&ve->devmnt_mutex);
+
 	return &ve->css;
 
 err_vdso:
@@ -690,10 +695,33 @@ static void ve_offline(struct cgroup_subsys_state *css)
 	ve->ve_name = NULL;
 }
 
+static void ve_devmnt_free(struct ve_devmnt *devmnt)
+{
+	if (!devmnt)
+		return;
+
+	kfree(devmnt->allowed_options);
+	kfree(devmnt->hidden_options);
+	kfree(devmnt);
+}
+
+static void free_ve_devmnts(struct ve_struct *ve)
+{
+	while (!list_empty(&ve->devmnt_list)) {
+		struct ve_devmnt *devmnt;
+
+		devmnt = list_first_entry(&ve->devmnt_list, struct ve_devmnt, link);
+		list_del(&devmnt->link);
+		ve_devmnt_free(devmnt);
+	}
+}
+
 static void ve_destroy(struct cgroup_subsys_state *css)
 {
 	struct ve_struct *ve = css_to_ve(css);
 
+	free_ve_devmnts(ve);
+
 	kmapset_unlink(&ve->sysfs_perms_key, &sysfs_ve_perms_set);
 	ve_log_destroy(ve);
 	ve_free_vdso(ve);
@@ -1076,6 +1104,147 @@ static ssize_t ve_ts_write(struct kernfs_open_file *of, char *buf,
 	return nbytes;
 }
 
+static int ve_mount_opts_read(struct seq_file *sf, void *v)
+{
+	struct ve_struct *ve = css_to_ve(seq_css(sf));
+	struct ve_devmnt *devmnt;
+
+	if (ve_is_super(ve))
+		return -ENODEV;
+
+	mutex_lock(&ve->devmnt_mutex);
+	list_for_each_entry(devmnt, &ve->devmnt_list, link) {
+		dev_t dev = devmnt->dev;
+
+		seq_printf(sf, "0 %u:%u;", MAJOR(dev), MINOR(dev));
+		if (devmnt->hidden_options)
+			seq_printf(sf, "1 %s;", devmnt->hidden_options);
+		if (devmnt->allowed_options)
+			seq_printf(sf, "2 %s;", devmnt->allowed_options);
+		seq_putc(sf, '\n');
+	}
+	mutex_unlock(&ve->devmnt_mutex);
+	return 0;
+}
+
+/*
+ * 'data' for VE_CONFIGURE_MOUNT_OPTIONS is a zero-terminated string
+ * consisting of substrings separated by MNTOPT_DELIM.
+ */
+#define MNTOPT_DELIM ';'
+#define MNTOPT_MAXLEN 256
+
+/*
+ * Each substring has the form of "<type> <comma-separated-list-of-options>"
+ * where types are:
+ */
+enum {
+	MNTOPT_DEVICE = 0,
+	MNTOPT_HIDDEN = 1,
+	MNTOPT_ALLOWED = 2,
+};
+
+/*
+ * 'ptr' points to the first character of buffer to parse
+ * 'endp' points to the last character of buffer to parse
+ */
+static int ve_parse_mount_options(const char *ptr, const char *endp,
+				  struct ve_devmnt *devmnt)
+{
+	while (*ptr) {
+		const char *delim = strchr(ptr, MNTOPT_DELIM) ? : endp;
+		char *space = strchr(ptr, ' ');
+		int type;
+		char *options, c, s;
+		int options_size = delim - space;
+		char **opts_pp = NULL; /* where to store 'options' */
+
+		if (delim == ptr || !space || options_size <= 1 ||
+		    !isdigit(*ptr) || space > delim)
+			return -EINVAL;
+
+		if (sscanf(ptr, "%d%c", &type, &c) != 2 || c != ' ')
+			return -EINVAL;
+
+		if (type == MNTOPT_DEVICE) {
+			unsigned major, minor;
+			if (devmnt->dev)
+				return -EINVAL; /* Already set */
+			if (sscanf(space + 1, "%u%c%u%c", &major, &c,
+							  &minor, &s) != 4 ||
+			    c != ':' || s != MNTOPT_DELIM)
+				return -EINVAL;
+			devmnt->dev = MKDEV(major, minor);
+			goto next;
+		}
+
+	        options = kmalloc(options_size, GFP_KERNEL);
+		if (!options)
+			return -ENOMEM;
+
+		strncpy(options, space + 1, options_size - 1);
+		options[options_size - 1] = 0;
+
+		switch (type) {
+		case MNTOPT_ALLOWED:
+			opts_pp = &devmnt->allowed_options;
+			break;
+		case MNTOPT_HIDDEN:
+			opts_pp = &devmnt->hidden_options;
+			break;
+		};
+
+		/* wrong type or already set */
+		if (!opts_pp || *opts_pp) {
+			kfree(options);
+			return -EINVAL;
+		}
+
+		*opts_pp = options;
+next:
+		if (!*delim)
+			break;
+
+		ptr = delim + 1;
+	}
+
+	if (!devmnt->dev)
+		return -EINVAL;
+	return 0;
+}
+
+static ssize_t ve_mount_opts_write(struct kernfs_open_file *of, char *buf,
+			   size_t nbytes, loff_t off)
+{
+	struct ve_struct *ve = css_to_ve(of_css(of));
+	struct ve_devmnt *devmnt, *old;
+	int err;
+
+	devmnt = kzalloc(sizeof(*devmnt), GFP_KERNEL);
+	if (!devmnt)
+		return -ENOMEM;
+
+	err = ve_parse_mount_options(buf, buf + nbytes, devmnt);
+	if (err) {
+		ve_devmnt_free(devmnt);
+		return err;
+	}
+
+	mutex_lock(&ve->devmnt_mutex);
+	list_for_each_entry(old, &ve->devmnt_list, link) {
+		/* Delete old devmnt */
+		if (old->dev == devmnt->dev) {
+			list_del(&old->link);
+			ve_devmnt_free(old);
+			break;
+		}
+	}
+	list_add(&devmnt->link, &ve->devmnt_list);
+	mutex_unlock(&ve->devmnt_mutex);
+
+	return nbytes;
+}
+
 static struct cftype ve_cftypes[] = {
 
 	{
@@ -1133,6 +1302,13 @@ static struct cftype ve_cftypes[] = {
 		.seq_show		= ve_os_release_read,
 		.write			= ve_os_release_write,
 	},
+	{
+		.name			= "mount_opts",
+		.max_write_len		= MNTOPT_MAXLEN,
+		.flags			= CFTYPE_NOT_ON_ROOT,
+		.seq_show		= ve_mount_opts_read,
+		.write			= ve_mount_opts_write,
+	},
 	{ }
 };
 
-- 
2.30.2



More information about the Devel mailing list