From 5748a52d562b6a72f958a632a8ab8bd9b0157e11 Mon Sep 17 00:00:00 2001 From: tanyifeng Date: Mon, 14 Jan 2019 17:02:02 +0800 Subject: [PATCH 022/138] support rootfs mount propagation Signed-off-by: LiFeng --- src/lxc/conf.c | 230 ++++++++++++++++++++++++++-------------- src/lxc/conf.h | 2 +- src/lxc/confile.c | 8 +- src/lxc/criu.c | 4 +- src/lxc/storage/btrfs.c | 4 +- src/lxc/storage/dir.c | 9 +- src/lxc/storage/overlay.c | 4 +- src/lxc/storage/storage_utils.c | 4 +- src/lxc/storage/zfs.c | 4 +- 9 files changed, 165 insertions(+), 104 deletions(-) diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 8d8230f..55d1e45 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -1296,11 +1296,102 @@ static int lxc_fill_autodev(const struct lxc_rootfs *rootfs) return 0; } +static void null_endofword(char *word) +{ + while (*word && *word != ' ' && *word != '\t') + word++; + *word = '\0'; +} + +/* skip @nfields spaces in @src */ +static char *get_field(char *src, int nfields) +{ + int i; + char *p = src; + + for (i = 0; i < nfields; i++) { + while (*p && *p != ' ' && *p != '\t') + p++; + + if (!*p) + break; + + p++; + } + + return p; +} + +static int rootfs_parent_mount_private(char *rootfs) +{ + /* walk /proc/self/mountinfo and change parent of rootfs to private */ + FILE *f = fopen("/proc/self/mountinfo", "r"); + char *line = NULL; + char *parent = NULL, *options = NULL; + size_t len = 0; + int ret = 0; + + if (!f) { + SYSERROR("Failed to open /proc/self/mountinfo to make parent of rootfs to private"); + return -1; + } + + while (getline(&line, &len, f) != -1) { + char *target, *opts, *tmptarget; + target = get_field(line, 4); + if (!target) + continue; + tmptarget = strdup(target); + if (!tmptarget) + continue; + null_endofword(tmptarget); + if (!strstr(rootfs, tmptarget)) { + free(tmptarget); + continue; + } + if (!parent || strlen(tmptarget) > strlen(parent)) { + free(parent); + parent = tmptarget; + } else { + free(tmptarget); + continue; + } + opts = get_field(target, 2); + if (!opts) + continue; + null_endofword(opts); + free(options); + options = strdup(opts); + if (!options) + continue; + } + + if (!parent || !options) { + ERROR("Could not find parent mount of %s", rootfs); + ret = -1; + } else { + if (strstr(options, "shared")) { + if (mount(NULL, parent, NULL, MS_PRIVATE, NULL)) { + SYSERROR("Failed to make %s private", parent); + ret = -1; + } + DEBUG("Mounted parent %s of rootfs %s to private", parent, rootfs); + } + } + free(parent); + free(options); + fclose(f); + free(line); + return ret; +} + static int lxc_mount_rootfs(struct lxc_conf *conf) { int ret; struct lxc_storage *bdev; const struct lxc_rootfs *rootfs = &conf->rootfs; + unsigned long flags, mntflags, pflags; + char *mntdata; if (!rootfs->path) { ret = mount("", "/", NULL, MS_SLAVE | MS_REC, 0); @@ -1319,6 +1410,44 @@ static int lxc_mount_rootfs(struct lxc_conf *conf) return -1; } + // isulad-start: support mount propagations of rootfs + //Get rootfs mnt propagation options, such as slave or shared + if (parse_mntopts(conf->rootfs.options, &mntflags, &pflags, &mntdata) < 0) { + free(mntdata); + return -1; + } + free(mntdata); + + flags = MS_SLAVE | MS_REC; + if (pflags) + flags = pflags; + + /* Mount propagation inside container can not greater than host. + * So we must change propagation of root according to flags, default is rslave. + * That means shared propagation inside container is disabled by default. + */ + ret = mount("", "/", NULL, flags, NULL); + if (ret < 0) { + SYSERROR("Failed to make / to propagation flags %lu.", flags); + return -1; + } + + /* Make parent mount private to make sure following bind mount does + * not propagate in other namespaces. Also it will help with kernel + * check pass in pivot_root. (IS_SHARED(new_mnt->mnt_parent)) + */ + ret = rootfs_parent_mount_private(conf->rootfs.mount); + if (ret != 0) { + ERROR("Failed to make parent of rootfs %s to private.", conf->rootfs.mount); + return -1; + } + + ret = mount(conf->rootfs.mount, conf->rootfs.mount, "bind", MS_BIND | MS_REC, NULL); + if (ret < 0) { + SYSERROR("Failed to mount rootfs %s", conf->rootfs.mount); + return -1; + }// isulad-end: support mount propagations of rootfs + bdev = storage_init(conf); if (!bdev) { ERROR("Failed to mount rootfs \"%s\" onto \"%s\" with options \"%s\"", @@ -1960,7 +2089,7 @@ static int lxc_setup_console(const struct lxc_rootfs *rootfs, return lxc_setup_ttydir_console(rootfs, console, ttydir); } -static void parse_mntopt(char *opt, unsigned long *flags, char **data, size_t size) +static void parse_mntopt(char *opt, unsigned long *mflags, unsigned long *pflags, char **data, size_t size) { struct mount_opt *mo; @@ -1970,26 +2099,40 @@ static void parse_mntopt(char *opt, unsigned long *flags, char **data, size_t si for (mo = &mount_opt[0]; mo->name != NULL; mo++) { if (strncmp(opt, mo->name, strlen(mo->name)) == 0) { if (mo->clear) - *flags &= ~mo->flag; + *mflags &= ~mo->flag; else - *flags |= mo->flag; + *mflags |= mo->flag; return; } } + /* 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) + continue; + + if (mo->clear) + *pflags &= ~mo->flag; + else + *pflags |= mo->flag; + + return; + } + if (strlen(*data)) (void)strlcat(*data, ",", size); (void)strlcat(*data, opt, size); } -int parse_mntopts(const char *mntopts, unsigned long *mntflags, char **mntdata) +int parse_mntopts(const char *mntopts, unsigned long *mntflags, unsigned long *pflags, char **mntdata) { char *data, *p, *s; size_t size; *mntdata = NULL; *mntflags = 0L; + *pflags = 0L; if (!mntopts) return 0; @@ -2007,7 +2150,7 @@ int parse_mntopts(const char *mntopts, unsigned long *mntflags, char **mntdata) *data = 0; lxc_iterate_parts(p, s, ",") - parse_mntopt(p, mntflags, &data, size); + parse_mntopt(p, mntflags, pflags, &data, size); if (*data) *mntdata = data; @@ -2018,71 +2161,6 @@ int parse_mntopts(const char *mntopts, unsigned long *mntflags, char **mntdata) 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) - continue; - - if (mo->clear) - *flags &= ~mo->flag; - else - *flags |= mo->flag; - - return; - } -} - -int parse_propagationopts(const char *mntopts, unsigned long *pflags) -{ - char *p, *s; - - if (!mntopts) - return 0; - - s = strdup(mntopts); - if (!s) { - SYSERROR("Failed to allocate memory"); - return -ENOMEM; - } - - *pflags = 0L; - lxc_iterate_parts(p, s, ",") - parse_propagationopt(p, pflags); - free(s); - - return 0; -} - -static void null_endofword(char *word) -{ - while (*word && *word != ' ' && *word != '\t') - word++; - *word = '\0'; -} - -/* skip @nfields spaces in @src */ -static char *get_field(char *src, int nfields) -{ - int i; - char *p = src; - - for (i = 0; i < nfields; i++) { - while (*p && *p != ' ' && *p != '\t') - p++; - - if (!*p) - break; - - p++; - } - - return p; -} - static int mount_entry(const char *fsname, const char *target, const char *fstype, unsigned long mountflags, unsigned long pflags, const char *data, bool optional, @@ -2289,10 +2367,9 @@ 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; - unsigned long pflags = 0; char *rootfs_path = NULL; optional = hasmntopt(mntent, "optional") != NULL; @@ -2312,11 +2389,7 @@ 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); + ret = parse_mntopts(mntent->mnt_opts, &mntflags, &pflags, &mntdata); if (ret < 0) return -1; @@ -3544,7 +3617,8 @@ int lxc_setup_rootfs_prepare_root(struct lxc_conf *conf, const char *name, return 0; } - remount_all_slave(); + if (!conf->rootfs.options) + remount_all_slave(); ret = run_lxc_hooks(name, "pre-mount", conf, NULL); if (ret < 0) { diff --git a/src/lxc/conf.h b/src/lxc/conf.h index db474e1..7393dbf 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -463,7 +463,7 @@ extern int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data, extern int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data, const char *fn_name); extern int parse_mntopts(const char *mntopts, unsigned long *mntflags, - char **mntdata); + unsigned long *pflags, char **mntdata); extern int parse_propagationopts(const char *mntopts, unsigned long *pflags); extern void tmp_proc_unmount(struct lxc_conf *lxc_conf); extern void remount_all_slave(void); diff --git a/src/lxc/confile.c b/src/lxc/confile.c index e199965..db63b55 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -2065,16 +2065,10 @@ static int set_config_rootfs_options(const char *key, const char *value, char *mdata = NULL, *opts = NULL; struct lxc_rootfs *rootfs = &lxc_conf->rootfs; - ret = parse_mntopts(value, &mflags, &mdata); + ret = parse_mntopts(value, &mflags, &pflags, &mdata); if (ret < 0) return -EINVAL; - ret = parse_propagationopts(value, &pflags); - if (ret < 0) { - free(mdata); - return -EINVAL; - } - ret = set_config_string_item(&opts, value); if (ret < 0) { free(mdata); diff --git a/src/lxc/criu.c b/src/lxc/criu.c index 31c1940..bb97859 100644 --- a/src/lxc/criu.c +++ b/src/lxc/criu.c @@ -389,9 +389,9 @@ static void exec_criu(struct cgroup_ops *cgroup_ops, struct lxc_conf *conf, while (getmntent_r(mnts, &mntent, buf, sizeof(buf))) { char *fmt, *key, *val, *mntdata; char arg[2 * PATH_MAX + 2]; - unsigned long flags; + unsigned long flags, pflags; - if (parse_mntopts(mntent.mnt_opts, &flags, &mntdata) < 0) + if (parse_mntopts(mntent.mnt_opts, &flags, &pflags, &mntdata) < 0) goto err; free(mntdata); diff --git a/src/lxc/storage/btrfs.c b/src/lxc/storage/btrfs.c index bbfce61..a02c215 100644 --- a/src/lxc/storage/btrfs.c +++ b/src/lxc/storage/btrfs.c @@ -212,7 +212,7 @@ bool btrfs_detect(const char *path) int btrfs_mount(struct lxc_storage *bdev) { - unsigned long mntflags; + unsigned long mntflags, pflags; char *mntdata; const char *src; int ret; @@ -223,7 +223,7 @@ int btrfs_mount(struct lxc_storage *bdev) if (!bdev->src || !bdev->dest) return -22; - if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) { + if (parse_mntopts(bdev->mntopts, &mntflags, &pflags, &mntdata) < 0) { free(mntdata); return -22; } diff --git a/src/lxc/storage/dir.c b/src/lxc/storage/dir.c index 79b6469..c7b5ee2 100644 --- a/src/lxc/storage/dir.c +++ b/src/lxc/storage/dir.c @@ -170,20 +170,13 @@ int dir_mount(struct lxc_storage *bdev) if (!bdev->src || !bdev->dest) return -22; - ret = parse_mntopts(bdev->mntopts, &mntflags, &mntdata); + ret = parse_mntopts(bdev->mntopts, &mntflags, &pflags, &mntdata); if (ret < 0) { ERROR("Failed to parse mount options \"%s\"", bdev->mntopts); free(mntdata); return -EINVAL; } - ret = parse_propagationopts(bdev->mntopts, &pflags); - if (ret < 0) { - ERROR("Failed to parse propagation options \"%s\"", bdev->mntopts); - free(mntdata); - return -EINVAL; - } - src = lxc_storage_get_path(bdev->src, bdev->type); ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags | pflags, mntdata); diff --git a/src/lxc/storage/overlay.c b/src/lxc/storage/overlay.c index 01546b1..90408a3 100644 --- a/src/lxc/storage/overlay.c +++ b/src/lxc/storage/overlay.c @@ -495,7 +495,7 @@ int ovl_mount(struct lxc_storage *bdev) char *options_work, *work, *lastslash; int lastslashidx; size_t len, len2; - unsigned long mntflags; + unsigned long mntflags, pflags; char *mntdata; int ret, ret2; @@ -575,7 +575,7 @@ int ovl_mount(struct lxc_storage *bdev) memcpy(work + lastslashidx, "olwork", STRLITERALLEN("olwork")); work[lastslashidx + STRLITERALLEN("olwork")] = '\0'; - ret = parse_mntopts(bdev->mntopts, &mntflags, &mntdata); + ret = parse_mntopts(bdev->mntopts, &mntflags, &pflags, &mntdata); if (ret < 0) { ERROR("Failed to parse mount options"); free(mntdata); diff --git a/src/lxc/storage/storage_utils.c b/src/lxc/storage/storage_utils.c index fa4e727..46e08a3 100644 --- a/src/lxc/storage/storage_utils.c +++ b/src/lxc/storage/storage_utils.c @@ -396,7 +396,7 @@ int find_fstype_cb(char *buffer, void *data) const char *options; } *cbarg = data; - unsigned long mntflags; + unsigned long mntflags, pflags; char *mntdata; char *fstype; @@ -411,7 +411,7 @@ int find_fstype_cb(char *buffer, void *data) DEBUG("Trying to mount \"%s\"->\"%s\" with FSType \"%s\"", cbarg->rootfs, cbarg->target, fstype); - if (parse_mntopts(cbarg->options, &mntflags, &mntdata) < 0) { + if (parse_mntopts(cbarg->options, &mntflags, &pflags, &mntdata) < 0) { free(mntdata); return 0; } diff --git a/src/lxc/storage/zfs.c b/src/lxc/storage/zfs.c index ba104da..752b0c5 100644 --- a/src/lxc/storage/zfs.c +++ b/src/lxc/storage/zfs.c @@ -184,7 +184,7 @@ int zfs_mount(struct lxc_storage *bdev) size_t oldlen, newlen, totallen; char *mntdata, *tmp; const char *src; - unsigned long mntflags; + unsigned long mntflags, pflags; char cmd_output[PATH_MAX] = {0}; if (strcmp(bdev->type, "zfs")) @@ -193,7 +193,7 @@ int zfs_mount(struct lxc_storage *bdev) if (!bdev->src || !bdev->dest) return -22; - ret = parse_mntopts(bdev->mntopts, &mntflags, &mntdata); + ret = parse_mntopts(bdev->mntopts, &mntflags, &pflags, &mntdata); if (ret < 0) { ERROR("Failed to parse mount options"); free(mntdata); -- 1.8.3.1