[Devel] [PATCH vz8 1/2] ve/devmnt: Introduce ve::devmnt list #PSBM-108196
Andrey Ryabinin
aryabinin at virtuozzo.com
Mon Oct 26 20:53:44 MSK 2020
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>
---
include/linux/ve.h | 11 +++
kernel/ve/ve.c | 175 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 186 insertions(+)
diff --git a/include/linux/ve.h b/include/linux/ve.h
index 5b1962ff4c66..1b6317275ca2 100644
--- a/include/linux/ve.h
+++ b/include/linux/ve.h
@@ -96,6 +96,17 @@ struct ve_struct {
#endif
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 ac3dda55e9ae..935e13340051 100644
--- a/kernel/ve/ve.c
+++ b/kernel/ve/ve.c
@@ -9,6 +9,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>
@@ -643,6 +644,8 @@ static struct cgroup_subsys_state *ve_create(struct cgroup_subsys_state *parent_
#ifdef CONFIG_COREDUMP
strcpy(ve->core_pattern, "core");
#endif
+ INIT_LIST_HEAD(&ve->devmnt_list);
+ mutex_init(&ve->devmnt_mutex);
return &ve->css;
@@ -687,10 +690,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);
@@ -1085,6 +1111,148 @@ static u64 ve_netns_avail_nr_read(struct cgroup_subsys_state *css, struct cftype
return atomic_read(&css_to_ve(css)->netns_avail_nr);
}
+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[] = {
{
@@ -1150,6 +1318,13 @@ static struct cftype ve_cftypes[] = {
.name = "netns_avail_nr",
.read_u64 = ve_netns_avail_nr_read,
},
+ {
+ .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.26.2
More information about the Devel
mailing list