]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
conf: support mount propagation
authorYifeng Tan <tanyifeng1@huawei.com>
Mon, 12 Feb 2018 12:01:32 +0000 (20:01 +0800)
committerChristian Brauner <christian.brauner@ubuntu.com>
Mon, 12 Feb 2018 16:27:34 +0000 (17:27 +0100)
Closes #810.

Signed-off-by: Yifeng Tan <tanyifeng1@huawei.com>
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
doc/lxc.container.conf.sgml.in
src/lxc/conf.c

index 84375b13ec3dc6a46abca752c7e63f0a0e9c291d..bbf0c681cd4a516b4978c7043084d26aa8718b16 100644 (file)
@@ -872,10 +872,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
           </term>
           <listitem>
             <para>
-              specify a mount point corresponding to a line in the
+              Specify a mount point corresponding to a line in the
               fstab format.
 
-              Moreover lxc add two options to mount.
+              Moreover lxc supports mount propagation, such as rslave or
+              rprivate, and adds two additional mount options.
               <option>optional</option> don't fail if mount does not work.
               <option>create=dir</option> or <option>create=file</option>
               to create dir (or file) when the point will be mounted.
index 2e66b019a639286d5948d7f6a9617adcf93166ae..f2f326c46ef3a390984a0a0f8ab9b5e6efee9078 100644 (file)
@@ -182,6 +182,18 @@ static struct mount_opt mount_opt[] = {
        { NULL,            0, 0              },
 };
 
+static struct mount_opt propagation_opt[] = {
+       { "private",       0, MS_PRIVATE           },
+       { "shared",        0, MS_SHARED            },
+       { "slave",         0, MS_SLAVE             },
+       { "unbindable",    0, MS_UNBINDABLE        },
+       { "rprivate",      0, MS_PRIVATE|MS_REC    },
+       { "rshared",       0, MS_SHARED|MS_REC     },
+       { "rslave",        0, MS_SLAVE|MS_REC      },
+       { "runbindable",   0, MS_UNBINDABLE|MS_REC },
+       { NULL,            0, 0                    },
+};
+
 #if HAVE_LIBCAP
 static struct caps_opt caps_opt[] = {
        { "chown",             CAP_CHOWN             },
@@ -1703,6 +1715,46 @@ int parse_mntopts(const char *mntopts, unsigned long *mntflags,
        return 0;
 }
 
+static void parse_propagationopt(char *opt, unsigned long *flags)
+{
+       struct mount_opt *mo;
+
+       /* If opt is found in propagation_opt, set or clear flags. */
+
+       for (mo = &propagation_opt[0]; mo->name != NULL; mo++) {
+               if (strncmp(opt, mo->name, strlen(mo->name)) == 0) {
+                       if (mo->clear)
+                               *flags &= ~mo->flag;
+                       else
+                               *flags |= mo->flag;
+                       return;
+               }
+       }
+}
+
+static int parse_propagationopts(const char *mntopts, unsigned long *pflags)
+{
+       char *s;
+       char *p, *saveptr = NULL;
+       *pflags = 0L;
+
+       if (!mntopts)
+               return 0;
+
+       s = strdup(mntopts);
+       if (!s) {
+               SYSERROR("Failed to allocate memory");
+               return -ENOMEM;
+       }
+
+       for (p = strtok_r(s, ",", &saveptr); p != NULL;
+            p = strtok_r(NULL, ",", &saveptr))
+               parse_propagationopt(p, pflags);
+
+       free(s);
+       return 0;
+}
+
 static void null_endofword(char *word)
 {
        while (*word && *word != ' ' && *word != '\t')
@@ -1730,8 +1782,8 @@ static char *get_field(char *src, int nfields)
 
 static int mount_entry(const char *fsname, const char *target,
                       const char *fstype, unsigned long mountflags,
-                      const char *data, int optional, int dev,
-                      const char *rootfs)
+                      unsigned long pflags, const char *data, bool optional,
+                      bool dev, const char *rootfs)
 {
        int ret;
 #ifdef HAVE_STATVFS
@@ -1812,6 +1864,23 @@ static int mount_entry(const char *fsname, const char *target,
                }
        }
 
+       if (pflags) {
+               ret = mount(NULL, target, NULL, pflags, NULL);
+               if (ret < 0) {
+                       if (optional) {
+                               INFO("%s - Failed to change mount propagation "
+                                    "for \"%s\" (optional)", strerror(errno), target);
+                               return 0;
+                       } else {
+                               SYSERROR("Failed to change mount propagation "
+                                        "for \"%s\" (optional)", target);
+                               return -1;
+                       }
+               }
+               DEBUG("Changed mount propagation for \"%s\"", target);
+       }
+
+
 #ifdef HAVE_STATVFS
 skipremount:
 #endif
@@ -1903,7 +1972,7 @@ static inline int mount_entry_on_generic(struct mntent *mntent,
                                         const char *lxc_path)
 {
        int ret;
-       unsigned long mntflags;
+       unsigned long mntflags, pflags;
        char *mntdata;
        bool dev, optional;
        char *rootfs_path = NULL;
@@ -1924,12 +1993,16 @@ static inline int mount_entry_on_generic(struct mntent *mntent,
        }
        cull_mntent_opt(mntent);
 
+       ret = parse_propagationopts(mntent->mnt_opts, &pflags);
+       if (ret < 0)
+               return -1;
+
        ret = parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata);
        if (ret < 0)
                return -1;
 
        ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type, mntflags,
-                         mntdata, optional, dev, rootfs_path);
+                         pflags, mntdata, optional, dev, rootfs_path);
 
        free(mntdata);
        return ret;