The commit is pushed to "branch-rh8-4.18.0-193.6.3.vz8.4.x-ovz" and will appear 
at https://src.openvz.org/scm/ovz/vzkernel.git
after rh8-4.18.0-193.6.3.vz8.4.14
------>
commit 76979eca95b446e34bcd9c367e157287c9985e52
Author: Kirill Tkhai <ktk...@odin.com>
Date:   Thu Oct 29 15:09:39 2020 +0300

    ve/devmnt: Introduce ve::devmnt list #PSBM-108196
    
    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 <ktk...@odin.com>
    
    Acked-by: Maxim Patlasov <mpatla...@openvz.org>
    
    +++
    ve/cgroups: Align ve_cftypes assignments
    
    For readability sake. We've other aligned already.
    
    Signed-off-by: Cyrill Gorcunov <gorcu...@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 <ktk...@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 <aryabi...@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 fe14d237b37d..2f9204cbd0f4 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 ba9732d8fce1..2cacb673c0f3 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);
@@ -1087,6 +1113,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[] = {
 
        {
@@ -1152,6 +1320,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,
+       },
        { }
 };
 
_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to