]> 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 09:57:17 +0000 (10:57 +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 ccc6348c422b4f271e4dba13467dddcaabbacf3d..34b8117bb7f23de85ce7a2a7a1842e4b98744890 100644 (file)
@@ -1059,10 +1059,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 three 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 05b17a499c86133e000b5d2ddd67832e3d0d0b28..01f11422a7804ba6386e381d5ad502a3f8452bd6 100644 (file)
@@ -193,6 +193,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             },
@@ -1773,6 +1785,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')
@@ -1800,8 +1852,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, bool optional, bool dev,
-                      bool relative, const char *rootfs)
+                      unsigned long pflags, const char *data, bool optional,
+                      bool dev, bool relative, const char *rootfs)
 {
        int ret;
        char srcbuf[MAXPATHLEN];
@@ -1893,6 +1945,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
@@ -1984,7 +2053,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, relative;
        char *rootfs_path = NULL;
@@ -2006,12 +2075,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, relative, rootfs_path);
+                         pflags, mntdata, optional, dev, relative, rootfs_path);
 
        free(mntdata);
        return ret;