From: Stéphane Graber Date: Sun, 26 Jan 2014 05:08:49 +0000 (-0500) Subject: Implement lxc.rootfs.options X-Git-Tag: lxc-1.0.0.beta4~32 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a17b1e65faaffe34c83860e599be21ad8e59b338;p=thirdparty%2Flxc.git Implement lxc.rootfs.options This introduces a new lxc.rootfs.options which lets you pass new mountflags/mountdata when mounting the root filesystem. Signed-off-by: Stéphane Graber Acked-by: Serge E. Hallyn --- diff --git a/doc/lxc.container.conf.sgml.in b/doc/lxc.container.conf.sgml.in index aee5451e8..5313b972a 100644 --- a/doc/lxc.container.conf.sgml.in +++ b/doc/lxc.container.conf.sgml.in @@ -862,6 +862,17 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + + + + + + extra mount options to use when mounting the rootfs. + + + + diff --git a/src/lxc/bdev.c b/src/lxc/bdev.c index c4e51214c..39e677fa8 100644 --- a/src/lxc/bdev.c +++ b/src/lxc/bdev.c @@ -121,9 +121,11 @@ static int find_fstype_cb(char* buffer, void *data) struct cbarg { const char *rootfs; const char *target; - int mntopt; + const char *options; } *cbarg = data; + unsigned long mntflags; + char *mntdata; char *fstype; /* we don't try 'nodev' entries */ @@ -137,29 +139,38 @@ static int find_fstype_cb(char* buffer, void *data) DEBUG("trying to mount '%s'->'%s' with fstype '%s'", cbarg->rootfs, cbarg->target, fstype); - if (mount(cbarg->rootfs, cbarg->target, fstype, cbarg->mntopt, NULL)) { + if (parse_mntopts(cbarg->options, &mntflags, &mntdata) < 0) { + free(mntdata); + return 0; + } + + if (mount(cbarg->rootfs, cbarg->target, fstype, mntflags, mntdata)) { DEBUG("mount failed with error: %s", strerror(errno)); + free(mntdata); return 0; } + free(mntdata); + INFO("mounted '%s' on '%s', with fstype '%s'", cbarg->rootfs, cbarg->target, fstype); return 1; } -static int mount_unknown_fs(const char *rootfs, const char *target, int mntopt) +static int mount_unknown_fs(const char *rootfs, const char *target, + const char *options) { int i; struct cbarg { const char *rootfs; const char *target; - int mntopt; + const char *options; } cbarg = { .rootfs = rootfs, .target = target, - .mntopt = mntopt, + .options = options, }; /* @@ -291,7 +302,7 @@ static int detect_fs(struct bdev *bdev, char *type, int len) if (unshare(CLONE_NEWNS) < 0) exit(1); - ret = mount_unknown_fs(srcdev, bdev->dest, 0); + ret = mount_unknown_fs(srcdev, bdev->dest, bdev->mntopts); if (ret < 0) { ERROR("failed mounting %s onto %s to detect fstype", srcdev, bdev->dest); exit(1); @@ -355,11 +366,23 @@ static int dir_detect(const char *path) // static int dir_mount(struct bdev *bdev) { + unsigned long mntflags; + char *mntdata; + int ret; + if (strcmp(bdev->type, "dir")) return -22; if (!bdev->src || !bdev->dest) return -22; - return mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC, NULL); + + if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) { + free(mntdata); + return -22; + } + + ret = mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata); + free(mntdata); + return ret; } static int dir_umount(struct bdev *bdev) @@ -532,11 +555,23 @@ static int zfs_detect(const char *path) static int zfs_mount(struct bdev *bdev) { + unsigned long mntflags; + char *mntdata; + int ret; + if (strcmp(bdev->type, "zfs")) return -22; if (!bdev->src || !bdev->dest) return -22; - return mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC, NULL); + + if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) { + free(mntdata); + return -22; + } + + ret = mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata); + free(mntdata); + return ret; } static int zfs_umount(struct bdev *bdev) @@ -783,7 +818,7 @@ static int lvm_mount(struct bdev *bdev) return -22; /* if we might pass in data sometime, then we'll have to enrich * mount_unknown_fs */ - return mount_unknown_fs(bdev->src, bdev->dest, 0); + return mount_unknown_fs(bdev->src, bdev->dest, bdev->mntopts); } static int lvm_umount(struct bdev *bdev) @@ -996,9 +1031,9 @@ static int lvm_clonepaths(struct bdev *orig, struct bdev *new, const char *oldna return -1; } - if (orig->data) { - new->data = strdup(orig->data); - if (!new->data) + if (orig->mntopts) { + new->mntopts = strdup(orig->mntopts); + if (!new->mntopts) return -1; } @@ -1191,11 +1226,23 @@ static int btrfs_detect(const char *path) static int btrfs_mount(struct bdev *bdev) { + unsigned long mntflags; + char *mntdata; + int ret; + if (strcmp(bdev->type, "btrfs")) return -22; if (!bdev->src || !bdev->dest) return -22; - return mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC, NULL); + + if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) { + free(mntdata); + return -22; + } + + ret = mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata); + free(mntdata); + return ret; } static int btrfs_umount(struct bdev *bdev) @@ -1356,7 +1403,7 @@ static int btrfs_clonepaths(struct bdev *orig, struct bdev *new, const char *old if ((new->dest = strdup(new->src)) == NULL) return -1; - if (orig->data && (new->data = strdup(orig->data)) == NULL) + if (orig->mntopts && (new->mntopts = strdup(orig->mntopts)) == NULL) return -1; if (snap) @@ -1508,7 +1555,7 @@ static int loop_mount(struct bdev *bdev) goto out; } - ret = mount_unknown_fs(loname, bdev->dest, 0); + ret = mount_unknown_fs(loname, bdev->dest, bdev->mntopts); if (ret < 0) ERROR("Error mounting %s\n", bdev->src); else @@ -1717,6 +1764,8 @@ static int overlayfs_mount(struct bdev *bdev) { char *options, *dup, *lower, *upper; int len; + unsigned long mntflags; + char *mntdata; int ret; if (strcmp(bdev->type, "overlayfs")) @@ -1735,15 +1784,30 @@ static int overlayfs_mount(struct bdev *bdev) *upper = '\0'; upper++; + if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) { + free(mntdata); + return -22; + } + // TODO We should check whether bdev->src is a blockdev, and if so // but for now, only support overlays of a basic directory - len = strlen(lower) + strlen(upper) + strlen("upperdir=,lowerdir=") + 1; - options = alloca(len); - ret = snprintf(options, len, "upperdir=%s,lowerdir=%s", upper, lower); - if (ret < 0 || ret >= len) + if (mntdata) { + len = strlen(lower) + strlen(upper) + strlen("upperdir=,lowerdir=,") + strlen(mntdata) + 1; + options = alloca(len); + ret = snprintf(options, len, "upperdir=%s,lowerdir=%s,%s", upper, lower, mntdata); + } + else { + len = strlen(lower) + strlen(upper) + strlen("upperdir=,lowerdir=") + 1; + options = alloca(len); + ret = snprintf(options, len, "upperdir=%s,lowerdir=%s", upper, lower); + } + if (ret < 0 || ret >= len) { + free(mntdata); return -1; - ret = mount(lower, bdev->dest, "overlayfs", MS_MGC_VAL, options); + } + + ret = mount(lower, bdev->dest, "overlayfs", MS_MGC_VAL | mntflags, options); if (ret < 0) SYSERROR("overlayfs: error mounting %s onto %s options %s", lower, bdev->dest, options); @@ -1946,8 +2010,8 @@ static const size_t numbdevs = sizeof(bdevs) / sizeof(struct bdev_type); void bdev_put(struct bdev *bdev) { - if (bdev->data) - free(bdev->data); + if (bdev->mntopts) + free(bdev->mntopts); if (bdev->src) free(bdev->src); if (bdev->dest) @@ -1975,7 +2039,7 @@ struct bdev *bdev_get(const char *type) return bdev; } -struct bdev *bdev_init(const char *src, const char *dst, const char *data) +struct bdev *bdev_init(const char *src, const char *dst, const char *mntopts) { int i; struct bdev *bdev; @@ -1995,8 +2059,8 @@ struct bdev *bdev_init(const char *src, const char *dst, const char *data) memset(bdev, 0, sizeof(struct bdev)); bdev->ops = bdevs[i].ops; bdev->type = bdevs[i].name; - if (data) - bdev->data = strdup(data); + if (mntopts) + bdev->mntopts = strdup(mntopts); if (src) bdev->src = strdup(src); if (dst) diff --git a/src/lxc/bdev.h b/src/lxc/bdev.h index cc7b59e84..f2d6dc08d 100644 --- a/src/lxc/bdev.h +++ b/src/lxc/bdev.h @@ -78,7 +78,7 @@ struct bdev { const char *type; char *src; char *dest; - char *data; + char *mntopts; // turn the following into a union if need be // lofd is the open fd for the mounted loopback file int lofd; diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 8b790a2fc..d4578f349 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -424,9 +424,11 @@ static int find_fstype_cb(char* buffer, void *data) struct cbarg { const char *rootfs; const char *target; - int mntopt; + const char *options; } *cbarg = data; + unsigned long mntflags; + char *mntdata; char *fstype; /* we don't try 'nodev' entries */ @@ -440,10 +442,17 @@ static int find_fstype_cb(char* buffer, void *data) DEBUG("trying to mount '%s'->'%s' with fstype '%s'", cbarg->rootfs, cbarg->target, fstype); - if (mount(cbarg->rootfs, cbarg->target, fstype, cbarg->mntopt, NULL)) { + if (parse_mntopts(cbarg->options, &mntflags, &mntdata) < 0) { + free(mntdata); + return -1; + } + + if (mount(cbarg->rootfs, cbarg->target, fstype, mntflags, mntdata)) { DEBUG("mount failed with error: %s", strerror(errno)); + free(mntdata); return 0; } + free(mntdata); INFO("mounted '%s' on '%s', with fstype '%s'", cbarg->rootfs, cbarg->target, fstype); @@ -451,18 +460,19 @@ static int find_fstype_cb(char* buffer, void *data) return 1; } -static int mount_unknown_fs(const char *rootfs, const char *target, int mntopt) +static int mount_unknown_fs(const char *rootfs, const char *target, + const char *options) { int i; struct cbarg { const char *rootfs; const char *target; - int mntopt; + const char *options; } cbarg = { .rootfs = rootfs, .target = target, - .mntopt = mntopt, + .options = options, }; /* @@ -496,9 +506,22 @@ static int mount_unknown_fs(const char *rootfs, const char *target, int mntopt) return -1; } -static int mount_rootfs_dir(const char *rootfs, const char *target) +static int mount_rootfs_dir(const char *rootfs, const char *target, + const char *options) { - return mount(rootfs, target, "none", MS_BIND | MS_REC, NULL); + unsigned long mntflags; + char *mntdata; + int ret; + + if (parse_mntopts(options, &mntflags, &mntdata) < 0) { + free(mntdata); + return -1; + } + + ret = mount(rootfs, target, "none", MS_BIND | MS_REC | mntflags, mntdata); + free(mntdata); + + return ret; } static int setup_lodev(const char *rootfs, int fd, struct loop_info64 *loinfo) @@ -533,7 +556,8 @@ out: return ret; } -static int mount_rootfs_file(const char *rootfs, const char *target) +static int mount_rootfs_file(const char *rootfs, const char *target, + const char *options) { struct dirent dirent, *direntp; struct loop_info64 loinfo; @@ -585,7 +609,7 @@ static int mount_rootfs_file(const char *rootfs, const char *target) ret = setup_lodev(rootfs, fd, &loinfo); if (!ret) - ret = mount_unknown_fs(path, target, 0); + ret = mount_unknown_fs(path, target, options); close(fd); break; @@ -597,9 +621,10 @@ static int mount_rootfs_file(const char *rootfs, const char *target) return ret; } -static int mount_rootfs_block(const char *rootfs, const char *target) +static int mount_rootfs_block(const char *rootfs, const char *target, + const char *options) { - return mount_unknown_fs(rootfs, target, 0); + return mount_unknown_fs(rootfs, target, options); } /* @@ -729,13 +754,13 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_cg return 0; } -static int mount_rootfs(const char *rootfs, const char *target) +static int mount_rootfs(const char *rootfs, const char *target, const char *options) { char absrootfs[MAXPATHLEN]; struct stat s; int i; - typedef int (*rootfs_cb)(const char *, const char *); + typedef int (*rootfs_cb)(const char *, const char *, const char *); struct rootfs_type { int type; @@ -766,7 +791,7 @@ static int mount_rootfs(const char *rootfs, const char *target) if (!__S_ISTYPE(s.st_mode, rtfs_type[i].type)) continue; - return rtfs_type[i].cb(absrootfs, target); + return rtfs_type[i].cb(absrootfs, target, options); } ERROR("unsupported rootfs type for '%s'", absrootfs); @@ -1530,7 +1555,7 @@ static int setup_rootfs(struct lxc_conf *conf) } // First try mounting rootfs using a bdev - struct bdev *bdev = bdev_init(rootfs->path, rootfs->mount, NULL); + struct bdev *bdev = bdev_init(rootfs->path, rootfs->mount, rootfs->options); if (bdev && bdev->ops->mount(bdev) == 0) { bdev_put(bdev); DEBUG("mounted '%s' on '%s'", rootfs->path, rootfs->mount); @@ -1538,7 +1563,7 @@ static int setup_rootfs(struct lxc_conf *conf) } if (bdev) bdev_put(bdev); - if (mount_rootfs(rootfs->path, rootfs->mount)) { + if (mount_rootfs(rootfs->path, rootfs->mount, rootfs->options)) { ERROR("failed to mount rootfs"); return -1; } @@ -1791,7 +1816,7 @@ static void parse_mntopt(char *opt, unsigned long *flags, char **data) strcat(*data, opt); } -static int parse_mntopts(const char *mntopts, unsigned long *mntflags, +int parse_mntopts(const char *mntopts, unsigned long *mntflags, char **mntdata) { char *s, *data; @@ -1865,11 +1890,6 @@ static inline int mount_entry_on_systemfs(const struct mntent *mntent) FILE *pathfile = NULL; char* pathdirname = NULL; - if (parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata) < 0) { - ERROR("failed to parse mount option '%s'", mntent->mnt_opts); - return -1; - } - if (hasmntopt(mntent, "create=dir")) { if (!mkdir_p(mntent->mnt_dir, 0755)) { WARN("Failed to create mount target '%s'", mntent->mnt_dir); @@ -1890,6 +1910,11 @@ static inline int mount_entry_on_systemfs(const struct mntent *mntent) fclose(pathfile); } + if (parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata) < 0) { + free(mntdata); + return -1; + } + ret = mount_entry(mntent->mnt_fsname, mntent->mnt_dir, mntent->mnt_type, mntflags, mntdata); @@ -1915,11 +1940,6 @@ static int mount_entry_on_absolute_rootfs(const struct mntent *mntent, FILE *pathfile = NULL; char *pathdirname = NULL; - if (parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata) < 0) { - ERROR("failed to parse mount option '%s'", mntent->mnt_opts); - return -1; - } - lxcpath = lxc_global_config_value("lxc.lxcpath"); if (!lxcpath) { ERROR("Out of memory"); @@ -1976,15 +1996,21 @@ skipabs: fclose(pathfile); } + if (parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata) < 0) { + free(mntdata); + return -1; + } + ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type, mntflags, mntdata); + free(mntdata); + if (hasmntopt(mntent, "optional") != NULL) ret = 0; out: free(pathdirname); - free(mntdata); return ret; } @@ -1998,11 +2024,6 @@ static int mount_entry_on_relative_rootfs(const struct mntent *mntent, FILE *pathfile = NULL; char *pathdirname = NULL; - if (parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata) < 0) { - ERROR("failed to parse mount option '%s'", mntent->mnt_opts); - return -1; - } - /* relative to root mount point */ ret = snprintf(path, sizeof(path), "%s/%s", rootfs, mntent->mnt_dir); if (ret >= sizeof(path)) { @@ -2030,6 +2051,11 @@ static int mount_entry_on_relative_rootfs(const struct mntent *mntent, fclose(pathfile); } + if (parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata) < 0) { + free(mntdata); + return -1; + } + ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type, mntflags, mntdata); @@ -3906,6 +3932,8 @@ void lxc_conf_free(struct lxc_conf *conf) free(conf->console.path); if (conf->rootfs.mount) free(conf->rootfs.mount); + if (conf->rootfs.options) + free(conf->rootfs.options); if (conf->rootfs.path) free(conf->rootfs.path); if (conf->rootfs.pivot) diff --git a/src/lxc/conf.h b/src/lxc/conf.h index cd4b115bd..e5a23ec44 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -219,6 +219,7 @@ struct lxc_rootfs { char *path; char *mount; char *pivot; + char *options; }; /* @@ -375,4 +376,6 @@ extern int mapped_hostid(int id, struct lxc_conf *conf); extern int chown_mapped_root(char *path, struct lxc_conf *conf); extern int ttys_shift_ids(struct lxc_conf *c); extern int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data); +extern int parse_mntopts(const char *mntopts, unsigned long *mntflags, + char **mntdata); #endif diff --git a/src/lxc/confile.c b/src/lxc/confile.c index 8a027cc30..03a42c5b3 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -65,6 +65,7 @@ static int config_logfile(const char *, const char *, struct lxc_conf *); static int config_mount(const char *, const char *, struct lxc_conf *); static int config_rootfs(const char *, const char *, struct lxc_conf *); static int config_rootfs_mount(const char *, const char *, struct lxc_conf *); +static int config_rootfs_options(const char *, const char *, struct lxc_conf *); static int config_pivotdir(const char *, const char *, struct lxc_conf *); static int config_utsname(const char *, const char *, struct lxc_conf *); static int config_hook(const char *, const char *, struct lxc_conf *lxc_conf); @@ -110,6 +111,7 @@ static struct lxc_config_t config[] = { { "lxc.logfile", config_logfile }, { "lxc.mount", config_mount }, { "lxc.rootfs.mount", config_rootfs_mount }, + { "lxc.rootfs.options", config_rootfs_options }, { "lxc.rootfs", config_rootfs }, { "lxc.pivotdir", config_pivotdir }, { "lxc.utsname", config_utsname }, @@ -1566,6 +1568,12 @@ static int config_rootfs_mount(const char *key, const char *value, return config_path_item(&lxc_conf->rootfs.mount, value); } +static int config_rootfs_options(const char *key, const char *value, + struct lxc_conf *lxc_conf) +{ + return config_string_item(&lxc_conf->rootfs.options, value); +} + static int config_pivotdir(const char *key, const char *value, struct lxc_conf *lxc_conf) { @@ -2096,6 +2104,8 @@ int lxc_get_config_item(struct lxc_conf *c, const char *key, char *retv, v = c->console.path; else if (strcmp(key, "lxc.rootfs.mount") == 0) v = c->rootfs.mount; + else if (strcmp(key, "lxc.rootfs.options") == 0) + v = c->rootfs.options; else if (strcmp(key, "lxc.rootfs") == 0) v = c->rootfs.path; else if (strcmp(key, "lxc.pivotdir") == 0) @@ -2313,6 +2323,8 @@ void write_config(FILE *fout, struct lxc_conf *c) fprintf(fout, "lxc.rootfs = %s\n", c->rootfs.path); if (c->rootfs.mount && strcmp(c->rootfs.mount, LXCROOTFSMOUNT) != 0) fprintf(fout, "lxc.rootfs.mount = %s\n", c->rootfs.mount); + if (c->rootfs.options) + fprintf(fout, "lxc.rootfs.options = %s\n", c->rootfs.options); if (c->rootfs.pivot) fprintf(fout, "lxc.pivotdir = %s\n", c->rootfs.pivot); if (c->start_auto)