The commit is pushed to "branch-rh9-5.14.vz9.1.x-ovz" and will appear at 
https://src.openvz.org/scm/ovz/vzkernel.git
after ark-5.14
------>
commit 127cb0644fa9c33926b6ae8a0f8d9d3907a793e7
Author: Kirill Tkhai <ktk...@odin.com>
Date:   Fri Oct 1 19:38:49 2021 +0300

    ve/fs/devmnt: process mount options
    
    Port patch diff-ve-fs-process-mount-options-check-and-insert by Maxim 
Patlasov:
    
    The patch implements two kinds of processing mount options: check and 
insert.
    Check is OK if and only if each option supplied by CT-user is present
    among options listed in allowed_options.
    
    Insert transforms mount options supplied by CT-user like this:
    
    <mount_options> = <hidden_options> + <user_supplied_mount_options>
    
    Check is performed both for mount and remount. Insert - only for mount. All
    this happens only for mount/remount inside CT and if proper ve_devmnt struct
    is found in ve->devmnt_list (searched by 'dev').
    
    https://jira.sw.ru/browse/PSBM-32273
    
    Signed-off-by: Kirill Tkhai <ktk...@odin.com>
    
    Acked-by: Maxim Patlasov <mpatla...@openvz.org>
    
    +++
    ve/fs/devmnt: allow more than one mount option inside a CT
    
    strsep() changes provided string: puts '\0' instead of separators,
    thus after successful call to ve_devmnt_check() we insert
    only first provided mount options, ignoring others.
    
    mFixes: bc4143b ("ve/fs/devmnt: process mount options")
    
    Found during implementation of
    https://jira.sw.ru/browse/PSBM-40075
    
    Signed-off-by: Konstantin Khorenko <khore...@virtuozzo.com>
    
    Reviewed-by: Kirill Tkhai <ktk...@virtuozzo.com>
    
    https://jira.sw.ru/browse/PSBM-108196
    Signed-off-by: Andrey Ryabinin <aryabi...@virtuozzo.com>
    
    +++
    ve/devmnt: initialize s_mode before deactivate_locked_super to suppress 
warning
    
    WARNING: CPU: 12 PID: 898592 at fs/super.c:1120 kill_block_super+0x63/0x70
    Call Trace:
    [<ffffffff816a02f8>] dump_stack+0x19/0x1b
    [<ffffffff81088be8>] __warn+0xd8/0x100
    [<ffffffff81088d2d>] warn_slowpath_null+0x1d/0x20
    [<ffffffff8121dfa3>] kill_block_super+0x63/0x70
    [<ffffffffc04891ec>] ext4_kill_sb+0x4c/0x60 [ext4]
    [<ffffffff8121e499>] deactivate_locked_super+0x49/0x80
    [<ffffffff8121efd7>] mount_bdev+0x227/0x240
    [<ffffffffc048f330>] ? ext4_calculate_overhead+0x430/0x430 [ext4]
    [<ffffffffc0489f34>] ext4_mount+0x44/0x60 [ext4]
    [<ffffffff8121fb35>] mount_fs+0x15/0xc0
    [<ffffffff8123c757>] vfs_kern_mount+0x67/0x110
    [<ffffffff8123efb9>] do_mount+0x219/0xae0
    [<ffffffff8123fbc6>] SyS_mount+0x96/0xf0
    [<ffffffff816b1649>] system_call_fastpath+0x16/0x1b
    
    On 3.10.0-693.1.1.vz7.37.30 kernel.
    
    We warn on no FMODE_EXCL on super block at kill_block_super. We get
    there from ve_devmnt_process's error path in mount_bdev, here we have
    yet uninitialized sb, thus it's s_mode has no FMODE_EXCL. So lets move
    s_mode initialization before these error path.
    
    mFixes: vz7 commit 0759581712eb ("ve/fs/devmnt: process mount options")
    
    https://jira.sw.ru/browse/PSBM-80743
    
    Signed-off-by: Pavel Tikhomirov <ptikhomi...@virtuozzo.com>
    
    Reviewed-by: Kirill Tkhai <ktk...@virtuozzo.com>
    
    (cherry picked from vz7 commit 3543274fc3f1 ("ve/devmnt: initialize s_mode
    before deactivate_locked_super to suppress warning"))
    
    mFixes: vz8 commit b7285b56b1a9 ("ve/fs/devmnt: process mount options")
    
    VZ 8 rebase part https://jira.sw.ru/browse/PSBM-127837
    
    Signed-off-by: Alexander Mikhalitsyn <alexander.mikhalit...@virtuozzo.com>
    
    (cherry-picked from vz8 commit 511fc2b59027 ("ve/fs/devmnt: process mount
    options"))
    
    Signed-off-by: Nikita Yushchenko <nikita.yushche...@virtuozzo.com>
---
 fs/namespace.c     | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/super.c         |  18 +++++++
 include/linux/fs.h |   2 +
 3 files changed, 168 insertions(+)

diff --git a/fs/namespace.c b/fs/namespace.c
index 954238cab6ec..bc2819c49315 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -2625,6 +2625,149 @@ static int do_reconfigure_mnt(struct path *path, 
unsigned int mnt_flags)
        return ret;
 }
 
+#ifdef CONFIG_VE
+/*
+ * Returns first occurrence of needle in haystack separated by sep,
+ * or NULL if not found
+ */
+static char *strstr_separated(char *haystack, char *needle, char sep)
+{
+       int needle_len = strlen(needle);
+
+       while (haystack) {
+               if (!strncmp(haystack, needle, needle_len) &&
+                   (haystack[needle_len] == 0 || /* end-of-line or */
+                    haystack[needle_len] == sep)) /* separator */
+                       return haystack;
+
+               haystack = strchr(haystack, sep);
+               if (haystack)
+                       haystack++;
+       }
+
+       return NULL;
+}
+
+static int ve_devmnt_check(char *options, char *allowed)
+{
+       char *p;
+       char *tmp_options;
+
+       if (!options || !*options)
+               return 0;
+
+       if (!allowed)
+               return -EPERM;
+
+       /* strsep() changes provided string: puts '\0' instead of separators */
+       tmp_options = kstrdup(options, GFP_KERNEL);
+       if (!tmp_options)
+               return -ENOMEM;
+
+       while ((p = strsep(&tmp_options, ",")) != NULL) {
+               if (!*p)
+                       continue;
+
+               if (!strstr_separated(allowed, p, ',')) {
+                       kfree(tmp_options);
+                       return -EPERM;
+               }
+       }
+
+       kfree(tmp_options);
+       return 0;
+}
+
+static int ve_devmnt_insert(char *options, char *hidden)
+{
+       int options_len;
+       int hidden_len;
+
+       if (!hidden)
+               return 0;
+
+       if (!options)
+               return -EAGAIN;
+
+       options_len = strlen(options);
+       hidden_len = strlen(hidden);
+
+       if (hidden_len + options_len + 2 > PAGE_SIZE)
+               return -EPERM;
+
+       memmove(options + hidden_len + 1, options, options_len);
+       memcpy(options, hidden, hidden_len);
+
+       options[hidden_len] = ',';
+       options[hidden_len + options_len + 1] = 0;
+
+       return 0;
+}
+
+int ve_devmnt_process(struct ve_struct *ve, dev_t dev, void **data_pp, int 
remount)
+{
+       void *data = *data_pp;
+       struct ve_devmnt *devmnt;
+       int err;
+again:
+       err = 1;
+       mutex_lock(&ve->devmnt_mutex);
+       list_for_each_entry(devmnt, &ve->devmnt_list, link) {
+               if (devmnt->dev == dev) {
+                       err = ve_devmnt_check(data, devmnt->allowed_options);
+
+                       if (!err && !remount)
+                               err = ve_devmnt_insert(data, 
devmnt->hidden_options);
+
+                       break;
+               }
+       }
+       mutex_unlock(&ve->devmnt_mutex);
+
+       switch (err) {
+       case -EAGAIN:
+               if (!(data = (void *)__get_free_page(GFP_KERNEL)))
+                       return -ENOMEM;
+               *(char *)data = 0; /* the string must be zero-terminated */
+               goto again;
+       case 1:
+               if (*data_pp) {
+                       ve_printk(VE_LOG_BOTH, KERN_WARNING "VE%s: no allowed "
+                                 "mount options found for device %u:%u\n",
+                                 ve->ve_name, MAJOR(dev), MINOR(dev));
+                       err = -EPERM;
+               } else
+                       err = 0;
+               break;
+       case 0:
+               *data_pp = data;
+               break;
+       }
+
+       if (data && data != *data_pp)
+               free_page((unsigned long)data);
+
+       return err;
+}
+#endif
+
+static int ve_prepare_mount_options(struct fs_context *fc, void *data)
+{
+#ifdef CONFIG_VE
+       struct super_block *sb = fc->root->d_sb;
+       struct ve_struct *ve = get_exec_env();
+
+       if (sb->s_bdev && data && !ve_is_super(ve)) {
+               int err;
+
+               err = ve_devmnt_process(ve, sb->s_bdev->bd_dev, &data, 1);
+               if (err)
+                       return err;
+       }
+#endif
+       return 0;
+}
+
 /*
  * change filesystem flags. dir should be a physical root of filesystem.
  * If you've mounted a non-root directory somewhere and want to do remount
@@ -2652,6 +2795,11 @@ static int do_remount(struct path *path, int ms_flags, 
int sb_flags,
                return PTR_ERR(fc);
 
        fc->oldapi = true;
+       err = ve_prepare_mount_options(fc, data);
+       if (err) {
+               put_fs_context(fc);
+               return err;
+       }
        err = parse_monolithic_mount_data(fc, data);
        if (!err) {
                down_write(&sb->s_umount);
diff --git a/fs/super.c b/fs/super.c
index f40b431420f7..9fbb8d6f0628 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -1390,10 +1390,28 @@ struct dentry *mount_bdev(struct file_system_type 
*fs_type,
                blkdev_put(bdev, mode);
                down_write(&s->s_umount);
        } else {
+#ifdef CONFIG_VE
+               void *data_orig = data;
+               struct ve_struct *ve = get_exec_env();
+#endif
+
                s->s_mode = mode;
+#ifdef CONFIG_VE
+               if (!ve_is_super(ve)) {
+                       error = ve_devmnt_process(ve, bdev->bd_dev, &data, 0);
+                       if (error) {
+                               deactivate_locked_super(s);
+                               goto error;
+                       }
+               }
+#endif
                snprintf(s->s_id, sizeof(s->s_id), "%pg", bdev);
                sb_set_blocksize(s, block_size(bdev));
                error = fill_super(s, data, flags & SB_SILENT ? 1 : 0);
+#ifdef CONFIG_VE
+               if (data_orig != data)
+                       free_page((unsigned long)data);
+#endif
                if (error) {
                        deactivate_locked_super(s);
                        goto error;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 8d86a85187ae..f4f31c29259f 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2569,6 +2569,8 @@ extern int super_setup_bdi(struct super_block *sb);
 
 extern int current_umask(void);
 
+extern int ve_devmnt_process(struct ve_struct *, dev_t, void **, int);
+
 extern void ihold(struct inode * inode);
 extern void iput(struct inode *);
 extern int generic_update_time(struct inode *, struct timespec64 *, int);
_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to