From: Christian Brauner Date: Fri, 28 Jul 2017 13:21:44 +0000 (+0200) Subject: overlay: rework overlay storage driver X-Git-Tag: lxc-2.1.0~32^2~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=241978fac5fcb8ed330f8cc90cf896943ac21536;p=thirdparty%2Flxc.git overlay: rework overlay storage driver Signed-off-by: Christian Brauner --- diff --git a/src/lxc/bdev/lxcoverlay.c b/src/lxc/bdev/lxcoverlay.c index 5e4fde5e7..02868c88f 100644 --- a/src/lxc/bdev/lxcoverlay.c +++ b/src/lxc/bdev/lxcoverlay.c @@ -45,8 +45,6 @@ static char *ovl_version[] = {"overlay", "overlayfs"}; static char *ovl_detect_name(void); static int ovl_do_rsync(struct bdev *orig, struct bdev *new, struct lxc_conf *conf); -static int ovl_rsync(struct rsync_data *data); -static int ovl_rsync_wrapper(void *data); static int ovl_remount_on_enodev(const char *lower, const char *target, const char *name, unsigned long mountflags, const void *options); @@ -55,61 +53,80 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, const char *cname, const char *oldpath, const char *lxcpath, int snap, uint64_t newsize, struct lxc_conf *conf) { - char *src; + int ret; + char *src; if (!snap) { - ERROR("overlay is only for snapshot clones"); + ERROR("The overlay storage driver can only be used for " + "snapshots"); return -22; } if (!orig->src || !orig->dest) return -1; - new->dest = lxc_string_join( - "/", (const char *[]){lxcpath, cname, "rootfs", NULL}, false); - if (!new->dest) - return -1; + new->dest = must_make_path(lxcpath, cname, "rootfs", NULL); - if (mkdir_p(new->dest, 0755) < 0) + ret = mkdir_p(new->dest, 0755); + if (ret < 0 && errno != EEXIST) { + SYSERROR("Failed to create directory \"%s\"", new->dest); return -1; + } - if (am_unpriv() && chown_mapped_root(new->dest, conf) < 0) - WARN("Failed to update ownership of %s", new->dest); + if (am_unpriv()) { + ret = chown_mapped_root(new->dest, conf); + if (ret < 0) + WARN("Failed to update ownership of %s", new->dest); + } if (strcmp(orig->type, "dir") == 0) { char *delta, *lastslash; char *work; int ret, len, lastslashidx; - /* - * if we have - * /var/lib/lxc/c2/rootfs - * then delta will be - * /var/lib/lxc/c2/delta0 + /* If we have "/var/lib/lxc/c2/rootfs" then delta will be + * "/var/lib/lxc/c2/delta0". */ lastslash = strrchr(new->dest, '/'); - if (!lastslash) + if (!lastslash) { + ERROR("Failed to detect \"/\" in string \"%s\"", + new->dest); return -22; - if (strlen(lastslash) < 7) + } + + if (strlen(lastslash) < (sizeof("/rootfs") - 1)) { + ERROR("Failed to detect \"/rootfs\" in string \"%s\"", + new->dest); return -22; + } + lastslash++; lastslashidx = lastslash - new->dest; delta = malloc(lastslashidx + 7); - if (!delta) + if (!delta) { + ERROR("Failed to allocate memory"); return -1; + } + strncpy(delta, new->dest, lastslashidx + 1); - strcpy(delta + lastslashidx, "delta0"); - if ((ret = mkdir(delta, 0755)) < 0) { - SYSERROR("error: mkdir %s", delta); + strncpy(delta + lastslashidx, "delta0", sizeof("delta0") - 1); + delta[lastslashidx + sizeof("delta0")] = '\0'; + + ret = mkdir(delta, 0755); + if (ret < 0 && errno != EEXIST) { + SYSERROR("Failed to create directory \"%s\"", delta); free(delta); return -1; } - if (am_unpriv() && chown_mapped_root(delta, conf) < 0) - WARN("Failed to update ownership of %s", delta); - /* - * Make workdir for overlayfs.v22 or higher: + if (am_unpriv()) { + ret = chown_mapped_root(delta, conf); + if (ret < 0) + WARN("Failed to update ownership of %s", delta); + } + + /* Make workdir for overlayfs.v22 or higher: * The workdir will be * /var/lib/lxc/c2/olwork * and is used to prepare files before they are atomically @@ -119,86 +136,103 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, */ work = malloc(lastslashidx + 7); if (!work) { + ERROR("Failed to allocate memory"); free(delta); return -1; } + strncpy(work, new->dest, lastslashidx + 1); - strcpy(work + lastslashidx, "olwork"); + strncpy(work + lastslashidx, "olwork", sizeof("olwork") - 1); + work[lastslashidx + sizeof("olwork")] = '\0'; + if (mkdir(work, 0755) < 0) { SYSERROR("error: mkdir %s", work); free(delta); free(work); return -1; } - if (am_unpriv() && chown_mapped_root(work, conf) < 0) - WARN("Failed to update ownership of %s", work); + + if (am_unpriv()) { + ret = chown_mapped_root(work, conf); + if (ret < 0) + WARN("Failed to update ownership of %s", work); + } free(work); + /* strlen("overlay:") = 8 + * + + * strlen(delta) + * + + * : + * + + * strlen(src) + * + + * \0 + */ src = lxc_storage_get_path(orig->src, orig->type); - // the src will be 'overlayfs:lowerdir:upperdir' - len = strlen(delta) + strlen(src) + 12; + len = 8 + strlen(delta) + 1 + strlen(src) + 1; new->src = malloc(len); if (!new->src) { + ERROR("Failed to allocate memory"); free(delta); return -ENOMEM; } + ret = snprintf(new->src, len, "overlay:%s:%s", src, delta); free(delta); - if (ret < 0 || ret >= len) + if (ret < 0 || (size_t)ret >= len) { + ERROR("Failed to create string"); return -1; - } else if (!strcmp(orig->type, "overlayfs") || !strcmp(orig->type, "overlay")) { - /* - * What exactly do we want to do here? I think we want to use - * the original lowerdir, with a private delta which is - * originally rsynced from the original delta - */ + } + } else if (!strcmp(orig->type, "overlayfs") || + !strcmp(orig->type, "overlay")) { char *osrc, *odelta, *nsrc, *ndelta, *work; char *lastslash; - int len, ret, lastslashidx; + int ret, lastslashidx; + size_t len; osrc = strdup(orig->src); if (!osrc) { - SYSERROR("Failed to duplicate \"%s\"", orig->src); + ERROR("Failed to duplicate string \"%s\"", orig->src); return -22; - } + } nsrc = strchr(osrc, ':') + 1; if ((nsrc != osrc + 8) && (nsrc != osrc + 10)) { free(osrc); - ERROR("Detected \":\" in \"%s\" at wrong position", osrc); + ERROR("Detected \":\" in \"%s\" at wrong position", + osrc); return -22; - } + } odelta = strchr(nsrc, ':'); if (!odelta) { free(osrc); - ERROR("Failed to find \":\" in \"%s\"", nsrc); + ERROR("Failed to find \":\" in \"%s\"", nsrc); return -22; } *odelta = '\0'; odelta++; - ndelta = lxc_string_join("/", (const char *[]){lxcpath, cname, "rootfs", NULL}, false); - if (!ndelta) { - free(osrc); - ERROR("Failed to create new path"); - return -ENOMEM; - } + ndelta = must_make_path(lxcpath, cname, "delta0", NULL); ret = mkdir(ndelta, 0755); if (ret < 0 && errno != EEXIST) { free(osrc); free(ndelta); - SYSERROR("Failed to create \"%s\"", ndelta); + SYSERROR("Failed to create directory \"%s\"", ndelta); return -1; } - if (am_unpriv() && chown_mapped_root(ndelta, conf) < 0) - WARN("Failed to update ownership of %s", ndelta); + if (am_unpriv()) { + ret = chown_mapped_root(ndelta, conf); + if (ret < 0) + WARN("Failed to update ownership of %s", + ndelta); + } - /* - * make workdir for overlayfs.v22 or higher (see comment further - * up) + /* Make workdir for overlayfs.v22 or higher (See the comment + * further up.). */ lastslash = strrchr(ndelta, '/'); if (!lastslash) { @@ -217,22 +251,38 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, ERROR("Failed to allocate memory"); return -1; } + strncpy(work, ndelta, lastslashidx + 1); - strcpy(work + lastslashidx, "olwork"); + strncpy(work + lastslashidx, "olwork", sizeof("olwork") - 1); + work[lastslashidx + sizeof("olwork")] = '\0'; + ret = mkdir(work, 0755); if (ret < 0 && errno != EEXIST) { free(osrc); free(ndelta); free(work); - SYSERROR("Failed to create \"%s\"", ndelta); + SYSERROR("Failed to create directory \"%s\"", ndelta); return -1; } - if (am_unpriv() && chown_mapped_root(work, conf) < 0) - WARN("Failed to update ownership of %s", work); + if (am_unpriv()) { + ret = chown_mapped_root(work, conf); + if (ret < 0) + WARN("Failed to update ownership of %s", work); + } free(work); - len = strlen(nsrc) + strlen(ndelta) + 10; + /* strlen("overlay:") = 8 + * + + * strlen(delta) + * + + * : + * + + * strlen(src) + * + + * \0 + */ + len = 8 + strlen(ndelta) + 1 + strlen(nsrc) + 1; new->src = malloc(len); if (!new->src) { free(osrc); @@ -243,17 +293,16 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, ret = snprintf(new->src, len, "overlay:%s:%s", nsrc, ndelta); free(osrc); free(ndelta); - if (ret < 0 || ret >= len) { + if (ret < 0 || (size_t)ret >= len) { ERROR("Failed to create string"); return -1; - } + } return ovl_do_rsync(orig, new, conf); } else { ERROR("overlay clone of %s container is not yet supported", orig->type); - /* - * Note, supporting this will require ovl_mount supporting + /* Note, supporting this will require ovl_mount supporting * mounting of the underlay. No big deal, just needs to be done. */ return -1; @@ -262,67 +311,86 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, return 0; } -/* - * to say 'lxc-create -t ubuntu -n o1 -B overlay' means you want - * $lxcpath/$lxcname/rootfs to have the created container, while all - * changes after starting the container are written to - * $lxcpath/$lxcname/delta0 +/* To say "lxc-create -t ubuntu -n o1 -B overlay" means you want + * "//rootfs" to have the created container, while all changes + * after starting the container are written to "//delta0". */ int ovl_create(struct bdev *bdev, const char *dest, const char *n, - struct bdev_specs *specs) + struct bdev_specs *specs) { char *delta; - int ret, len = strlen(dest), newlen; + int ret; + size_t len, newlen; - if (len < 8 || strcmp(dest + len - 7, "/rootfs") != 0) + len = strlen(dest); + if (len < 8 || strcmp(dest + len - 7, "/rootfs")) { + ERROR("Failed to detect \"/rootfs\" in \"%s\"", dest); return -1; + } - if (!(bdev->dest = strdup(dest))) { - ERROR("Out of memory"); + bdev->dest = strdup(dest); + if (!bdev->dest) { + ERROR("Failed to duplicate string \"%s\"", dest); return -1; } - delta = alloca(strlen(dest) + 1); - strcpy(delta, dest); - strcpy(delta + len - 6, "delta0"); + delta = malloc(len + 1); + if (!delta) { + ERROR("Failed to allocate memory"); + return -1; + } + + strncpy(delta, dest, len); + strncpy(delta + len - 6, "delta0", sizeof("delta0") - 1); + delta[len + sizeof("delta0")] = '\0'; - if (mkdir_p(delta, 0755) < 0) { - ERROR("Error creating %s", delta); + ret = mkdir_p(delta, 0755); + if (ret < 0) { + SYSERROR("Failed to create directory \"%s\"", delta); + free(delta); return -1; } - // overlay:lower:upper + /* overlay:lower:upper */ newlen = (2 * len) + strlen("overlay:") + 2; bdev->src = malloc(newlen); if (!bdev->src) { - ERROR("Out of memory"); + ERROR("Failed to allocate memory"); + free(delta); return -1; } + ret = snprintf(bdev->src, newlen, "overlay:%s:%s", dest, delta); - if (ret < 0 || ret >= newlen) + if (ret < 0 || (size_t)ret >= newlen) { + ERROR("Failed to create string"); + free(delta); return -1; + } - if (mkdir_p(bdev->dest, 0755) < 0) { - ERROR("Error creating %s", bdev->dest); + ret = mkdir_p(bdev->dest, 0755); + if (ret < 0) { + SYSERROR("Failed to create directory \"%s\"", bdev->dest); + free(delta); return -1; } + free(delta); return 0; } int ovl_destroy(struct bdev *orig) { - bool ovl; + bool ovl; char *upper = orig->src; - ovl = !strncmp(upper, "overlay:", 8); + ovl = !strncmp(upper, "overlay:", 8); if (!ovl && strncmp(upper, "overlayfs:", 10)) return -22; - if (ovl) - upper += 8; - else - upper += 10; + if (ovl) + upper += 8; + else + upper += 10; upper = strchr(upper, ':'); if (!upper) @@ -348,7 +416,7 @@ int ovl_mount(struct bdev *bdev) char *tmp, *options, *dup, *lower, *upper; char *options_work, *work, *lastslash; int lastslashidx; - int len, len2; + size_t len, len2; unsigned long mntflags; char *mntdata; int ret, ret2; @@ -362,53 +430,87 @@ int ovl_mount(struct bdev *bdev) if (!ovl_name) ovl_name = ovl_detect_name(); - /* - * separately mount it first: - * mount -t overlayfs * -oupperdir=${upper},lowerdir=${lower} lower dest + /* Separately mount it first: + * mount -t overlay * -o upperdir=${upper},lowerdir=${lower} lower dest */ - dup = alloca(strlen(bdev->src) + 1); - strcpy(dup, bdev->src); + dup = strdup(bdev->src); + if (!dup) { + ERROR("Failed to allocate memory"); + return -1; + } + /* support multiple lower layers */ - if (!(lower = strstr(dup, ":/"))) - return -22; + lower = strstr(dup, ":/"); + if (!lower) { + ERROR("Failed to detect \":/\" in string \"%s\"", dup); + free(dup); + return -22; + } + lower++; upper = lower; while ((tmp = strstr(++upper, ":/"))) { upper = tmp; } - if (--upper == lower) + + upper--; + if (upper == lower) { + free(dup); return -22; + } *upper = '\0'; upper++; - // if delta doesn't yet exist, create it - if (mkdir_p(upper, 0755) < 0 && errno != EEXIST) + /* if delta doesn't yet exist, create it */ + ret = mkdir_p(upper, 0755) < 0; + if (ret < 0 && errno != EEXIST) { + SYSERROR("Failed to create directory \"%s\"", upper); + free(dup); return -22; + } - /* - * overlayfs.v22 or higher needs workdir option: + /* overlayfs.v22 or higher needs workdir option: * if upper is * /var/lib/lxc/c2/delta0 * then workdir is * /var/lib/lxc/c2/olwork */ lastslash = strrchr(upper, '/'); - if (!lastslash) + if (!lastslash) { + ERROR("Failed to detect \"/\" in string \"%s\"", upper); + free(dup); return -22; + } + lastslash++; lastslashidx = lastslash - upper; - work = alloca(lastslashidx + 7); - strncpy(work, upper, lastslashidx + 7); - strcpy(work + lastslashidx, "olwork"); + work = malloc(lastslashidx + 7); + if (!work) { + ERROR("Failed to allocate memory"); + free(dup); + return -22; + } - if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) { + strncpy(work, upper, lastslashidx + 1); + strncpy(work + lastslashidx, "olwork", sizeof("olwork") - 1); + work[lastslashidx + sizeof("olwork")] = '\0'; + + ret = parse_mntopts(bdev->mntopts, &mntflags, &mntdata); + if (ret < 0) { + ERROR("Failed to parse mount options"); free(mntdata); + free(dup); + free(work); return -22; } - if (mkdir_p(work, 0755) < 0 && errno != EEXIST) { + ret = mkdir_p(work, 0755); + if (ret < 0 && errno != EEXIST) { + SYSERROR("Failed to create directory \"%s\"", work); free(mntdata); + free(dup); + free(work); return -22; } @@ -419,72 +521,94 @@ int ovl_mount(struct bdev *bdev) */ if (mntdata) { - len = strlen(lower) + strlen(upper) + strlen("upperdir=,lowerdir=,") + strlen(mntdata) + 1; + 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); + ret = snprintf(options, len, "upperdir=%s,lowerdir=%s,%s", + upper, lower, mntdata); - len2 = strlen(lower) + strlen(upper) + strlen(work) - + strlen("upperdir=,lowerdir=,workdir=") + strlen(mntdata) + 1; + len2 = strlen(lower) + strlen(upper) + strlen(work) + + strlen("upperdir=,lowerdir=,workdir=") + + strlen(mntdata) + 1; options_work = alloca(len2); - ret2 = snprintf(options, len2, "upperdir=%s,lowerdir=%s,workdir=%s,%s", - upper, lower, work, mntdata); + ret2 = snprintf(options, len2, + "upperdir=%s,lowerdir=%s,workdir=%s,%s", upper, + lower, work, mntdata); } else { - len = strlen(lower) + strlen(upper) + strlen("upperdir=,lowerdir=") + 1; + len = strlen(lower) + strlen(upper) + + strlen("upperdir=,lowerdir=") + 1; options = alloca(len); - ret = snprintf(options, len, "upperdir=%s,lowerdir=%s", upper, lower); + ret = snprintf(options, len, "upperdir=%s,lowerdir=%s", upper, + lower); - len2 = strlen(lower) + strlen(upper) + strlen(work) - + strlen("upperdir=,lowerdir=,workdir=") + 1; + len2 = strlen(lower) + strlen(upper) + strlen(work) + + strlen("upperdir=,lowerdir=,workdir=") + 1; options_work = alloca(len2); - ret2 = snprintf(options_work, len2, "upperdir=%s,lowerdir=%s,workdir=%s", - upper, lower, work); + ret2 = snprintf(options_work, len2, + "upperdir=%s,lowerdir=%s,workdir=%s", upper, + lower, work); } if (ret < 0 || ret >= len || ret2 < 0 || ret2 >= len2) { + ERROR("Failed to create string"); free(mntdata); + free(dup); + free(work); return -1; } - /* Assume we need a workdir as we are on a overlay version >= v22. */ + /* Assume we need a workdir as we are on a overlay version >= v22. */ ret = ovl_remount_on_enodev(lower, bdev->dest, ovl_name, MS_MGC_VAL | mntflags, options_work); if (ret < 0) { - INFO("Overlay: Error mounting %s onto %s with options %s. " - "Retrying without workdir: %s.", + INFO("Failed to mount \"%s\" on \"%s\" with options \"%s\". " + "Retrying without workdir: %s", lower, bdev->dest, options_work, strerror(errno)); - /* Assume we cannot use a workdir as we are on a version <= v21. */ + /* Assume we cannot use a workdir as we are on a version <= v21. + */ ret = ovl_remount_on_enodev(lower, bdev->dest, ovl_name, - MS_MGC_VAL | mntflags, options); + MS_MGC_VAL | mntflags, options); if (ret < 0) - SYSERROR("Overlay: Error mounting %s onto %s with " - "options %s: %s.", - lower, bdev->dest, options, - strerror(errno)); + SYSERROR("Failed to mount \"%s\" on \"%s\" with " + "options \"%s\": %s", + lower, bdev->dest, options, strerror(errno)); else - INFO("Overlay: Mounted %s onto %s with options %s.", + INFO("Mounted \"%s\" on \"%s\" with options \"%s\"", lower, bdev->dest, options); } else { - INFO("Overlay: Mounted %s onto %s with options %s.", lower, + INFO("Mounted \"%s\" on \"%s\" with options \"%s\"", lower, bdev->dest, options_work); } + + free(dup); + free(work); return ret; } int ovl_umount(struct bdev *bdev) { + int ret; + if (strcmp(bdev->type, "overlay") && strcmp(bdev->type, "overlayfs")) return -22; if (!bdev->src || !bdev->dest) return -22; - return umount(bdev->dest); + ret = umount(bdev->dest); + if (ret < 0) + SYSERROR("Failed to unmount \"%s\"", bdev->dest); + else + TRACE("Unmounted \"%s\"", bdev->dest); + + return ret; } char *ovl_get_lower(const char *rootfs_path) { char *s1; + s1 = strstr(rootfs_path, ":/"); if (!s1) return NULL; @@ -512,7 +636,8 @@ char *ovl_get_rootfs(const char *rootfs_path, size_t *rootfslen) if (!s1) return NULL; - if ((s2 = strstr(s1, ":/"))) { + s2 = strstr(s1, ":/"); + if (s2) { s2 = s2 + 1; if ((s3 = strstr(s2, ":/"))) *s3 = '\0'; @@ -537,18 +662,12 @@ int ovl_mkdir(const struct mntent *mntent, const struct lxc_rootfs *rootfs, const char *lxc_name, const char *lxc_path) { char lxcpath[MAXPATHLEN]; - char *rootfs_path = NULL; - char *rootfsdir = NULL; - char *upperdir = NULL; - char *workdir = NULL; - char **opts = NULL; + char **opts; + int ret; + size_t arrlen, dirlen, i, len, rootfslen; int fret = -1; - int ret = 0; - size_t arrlen = 0; - size_t dirlen = 0; - size_t i; - size_t len = 0; - size_t rootfslen = 0; + char *rootfs_dir = NULL, *rootfs_path = NULL, *upperdir = NULL, + *workdir = NULL; /* When rootfs == NULL we have a container without a rootfs. */ if (rootfs && rootfs->path) @@ -561,19 +680,22 @@ int ovl_mkdir(const struct mntent *mntent, const struct lxc_rootfs *rootfs, goto err; for (i = 0; i < arrlen; i++) { - if (strstr(opts[i], "upperdir=") && (strlen(opts[i]) > (len = strlen("upperdir=")))) + if (strstr(opts[i], "upperdir=") && + (strlen(opts[i]) > (len = strlen("upperdir=")))) upperdir = opts[i] + len; - else if (strstr(opts[i], "workdir=") && (strlen(opts[i]) > (len = strlen("workdir=")))) + else if (strstr(opts[i], "workdir=") && + (strlen(opts[i]) > (len = strlen("workdir=")))) workdir = opts[i] + len; } if (rootfs_path) { - ret = snprintf(lxcpath, MAXPATHLEN, "%s/%s", lxc_path, lxc_name); + ret = + snprintf(lxcpath, MAXPATHLEN, "%s/%s", lxc_path, lxc_name); if (ret < 0 || ret >= MAXPATHLEN) goto err; - rootfsdir = ovl_get_rootfs(rootfs_path, &rootfslen); - if (!rootfsdir) + rootfs_dir = ovl_get_rootfs(rootfs_path, &rootfslen); + if (!rootfs_dir) goto err; dirlen = strlen(lxcpath); @@ -588,51 +710,52 @@ int ovl_mkdir(const struct mntent *mntent, const struct lxc_rootfs *rootfs, if (upperdir) { if (!rootfs_path) ret = mkdir_p(upperdir, 0755); - else if ((strncmp(upperdir, lxcpath, dirlen) == 0) && (strncmp(upperdir, rootfsdir, rootfslen) != 0)) + else if (!strncmp(upperdir, lxcpath, dirlen) && + strncmp(upperdir, rootfs_dir, rootfslen)) ret = mkdir_p(upperdir, 0755); if (ret < 0) - WARN("Failed to create upperdir"); + WARN("Failed to create directory \"%s\": %s", upperdir, + strerror(errno)); } ret = 0; if (workdir) { if (!rootfs_path) ret = mkdir_p(workdir, 0755); - else if ((strncmp(workdir, lxcpath, dirlen) == 0) && (strncmp(workdir, rootfsdir, rootfslen) != 0)) + else if (!strncmp(workdir, lxcpath, dirlen) && + strncmp(workdir, rootfs_dir, rootfslen)) ret = mkdir_p(workdir, 0755); if (ret < 0) - WARN("Failed to create workdir"); + WARN("Failed to create directory \"%s\": %s", workdir, + strerror(errno)); } fret = 0; err: - free(rootfsdir); + free(rootfs_dir); lxc_free_array((void **)opts, free); return fret; } -/* - * To be called from lxcapi_clone() in lxccontainer.c: When we clone a container +/* To be called from lxcapi_clone() in lxccontainer.c: When we clone a container * with overlay lxc.mount.entry entries we need to update absolute paths for * upper- and workdir. This update is done in two locations: * lxc_conf->unexpanded_config and lxc_conf->mount_list. Both updates are done - * independent of each other since lxc_conf->mountlist may container more mount - * entries (e.g. from other included files) than lxc_conf->unexpanded_config . + * independent of each other since lxc_conf->mountlist may contain more mount + * entries (e.g. from other included files) than lxc_conf->unexpanded_config. */ int ovl_update_abs_paths(struct lxc_conf *lxc_conf, const char *lxc_path, const char *lxc_name, const char *newpath, const char *newname) { - char new_upper[MAXPATHLEN]; - char new_work[MAXPATHLEN]; - char old_upper[MAXPATHLEN]; - char old_work[MAXPATHLEN]; - char *cleanpath = NULL; + char new_upper[MAXPATHLEN], new_work[MAXPATHLEN], old_upper[MAXPATHLEN], + old_work[MAXPATHLEN]; size_t i; + struct lxc_list *iterator; + char *cleanpath = NULL; int fret = -1; int ret = 0; - struct lxc_list *iterator; const char *ovl_dirs[] = {"br", "upperdir", "workdir"}; cleanpath = strdup(newpath); @@ -652,19 +775,20 @@ int ovl_update_abs_paths(struct lxc_conf *lxc_conf, const char *lxc_path, goto err; } - ret = snprintf(old_work, MAXPATHLEN, "workdir=%s/%s", lxc_path, lxc_name); + ret = + snprintf(old_work, MAXPATHLEN, "workdir=%s/%s", lxc_path, lxc_name); if (ret < 0 || ret >= MAXPATHLEN) goto err; - ret = snprintf(new_work, MAXPATHLEN, "workdir=%s/%s", cleanpath, newname); + ret = + snprintf(new_work, MAXPATHLEN, "workdir=%s/%s", cleanpath, newname); if (ret < 0 || ret >= MAXPATHLEN) goto err; lxc_list_for_each(iterator, &lxc_conf->mount_list) { - char *mnt_entry = NULL; - char *new_mnt_entry = NULL; - char *tmp = NULL; - char *tmp_mnt_entry = NULL; + char *mnt_entry = NULL, *new_mnt_entry = NULL, *tmp = NULL, + *tmp_mnt_entry = NULL; + mnt_entry = iterator->elem; if (strstr(mnt_entry, "overlay")) @@ -675,23 +799,28 @@ int ovl_update_abs_paths(struct lxc_conf *lxc_conf, const char *lxc_path, if (!tmp) continue; - ret = snprintf(old_upper, MAXPATHLEN, "%s=%s/%s", tmp, lxc_path, lxc_name); + ret = snprintf(old_upper, MAXPATHLEN, "%s=%s/%s", tmp, lxc_path, + lxc_name); if (ret < 0 || ret >= MAXPATHLEN) goto err; - ret = snprintf(new_upper, MAXPATHLEN, "%s=%s/%s", tmp, cleanpath, newname); + ret = snprintf(new_upper, MAXPATHLEN, "%s=%s/%s", tmp, + cleanpath, newname); if (ret < 0 || ret >= MAXPATHLEN) goto err; if (strstr(mnt_entry, old_upper)) { - tmp_mnt_entry = lxc_string_replace(old_upper, new_upper, mnt_entry); + tmp_mnt_entry = + lxc_string_replace(old_upper, new_upper, mnt_entry); } if (strstr(mnt_entry, old_work)) { if (tmp_mnt_entry) - new_mnt_entry = lxc_string_replace(old_work, new_work, tmp_mnt_entry); + new_mnt_entry = lxc_string_replace( + old_work, new_work, tmp_mnt_entry); else - new_mnt_entry = lxc_string_replace(old_work, new_work, mnt_entry); + new_mnt_entry = lxc_string_replace( + old_work, new_work, mnt_entry); } if (new_mnt_entry) { @@ -716,68 +845,24 @@ static int ovl_remount_on_enodev(const char *lower, const char *target, const char *name, unsigned long mountflags, const void *options) { - int ret; - ret = mount(lower, target, ovl_name, MS_MGC_VAL | mountflags, options); - if (ret < 0 && errno == ENODEV) /* Try other module name. */ + int ret; + ret = mount(lower, target, ovl_name, MS_MGC_VAL | mountflags, options); + if (ret < 0 && errno == ENODEV) /* Try other module name. */ ret = mount(lower, target, ovl_name == ovl_version[0] ? ovl_version[1] : ovl_version[0], MS_MGC_VAL | mountflags, options); - return ret; -} - -static int ovl_rsync(struct rsync_data *data) -{ - int ret; - - if (setgid(0) < 0) { - ERROR("Failed to setgid to 0"); - return -1; - } - if (setgroups(0, NULL) < 0) - WARN("Failed to clear groups"); - if (setuid(0) < 0) { - ERROR("Failed to setuid to 0"); - return -1; - } - - if (unshare(CLONE_NEWNS) < 0) { - SYSERROR("Unable to unshare mounts ns"); - return -1; - } - if (detect_shared_rootfs()) { - if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL)) { - SYSERROR("Failed to make / rslave"); - ERROR("Continuing..."); - } - } - if (ovl_mount(data->orig) < 0) { - ERROR("Failed mounting original container fs"); - return -1; - } - if (ovl_mount(data->new) < 0) { - ERROR("Failed mounting new container fs"); - return -1; - } - ret = do_rsync(data->orig->dest, data->new->dest); - - ovl_umount(data->new); - ovl_umount(data->orig); - - if (ret < 0) { - ERROR("rsyncing %s to %s", data->orig->dest, data->new->dest); - return -1; - } - - return 0; + return ret; } static char *ovl_detect_name(void) { + FILE *f; char *v = ovl_version[0]; char *line = NULL; size_t len = 0; - FILE *f = fopen("/proc/filesystems", "r"); + + f = fopen("/proc/filesystems", "r"); if (!f) return v; @@ -793,27 +878,28 @@ static char *ovl_detect_name(void) return v; } -static int ovl_do_rsync(struct bdev *orig, struct bdev *new, struct lxc_conf *conf) +static int ovl_do_rsync(struct bdev *orig, struct bdev *new, + struct lxc_conf *conf) { int ret = -1; - struct rsync_data rdata; + struct rsync_data rdata = {0, 0}; + char cmd_output[MAXPATHLEN] = {0}; rdata.orig = orig; rdata.new = new; - if (am_unpriv()) - ret = userns_exec_1(conf, ovl_rsync_wrapper, &rdata, - "ovl_rsync_wrapper"); - else - ret = ovl_rsync(&rdata); - if (ret) - ERROR("copying overlay delta"); + if (am_unpriv()) { + ret = userns_exec_1(conf, lxc_rsync_exec_wrapper, &rdata, + "lxc_rsync_exec_wrapper"); + if (ret < 0) + ERROR("Failed to rsync from \"%s\" into \"%s\"", + orig->dest, new->dest); + } else { + ret = run_command(cmd_output, sizeof(cmd_output), + lxc_rsync_exec_wrapper, (void *)&rdata); + if (ret < 0) + ERROR("Failed to rsync from \"%s\" into \"%s\": %s", + orig->dest, new->dest, cmd_output); + } return ret; } - -static int ovl_rsync_wrapper(void *data) -{ - struct rsync_data *arg = data; - return ovl_rsync(arg); -} - diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index 4818eb644..4c00187f4 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -1263,11 +1263,45 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_ if (strcmp(bdev->type, "dir") && strcmp(bdev->type, "btrfs")) { if (geteuid() != 0) { ERROR("non-root users can only create btrfs and directory-backed containers"); - exit(1); + exit(EXIT_FAILURE); } - if (bdev->ops->mount(bdev) < 0) { - ERROR("Error mounting rootfs"); - exit(1); + + if (!strcmp(bdev->type, "overlay") || !strcmp(bdev->type, "overlayfs")) { + /* If we create an overlay container we need to + * rsync the contents into + * //rootfs. + * However, the overlay mount function will + * mount will mount + * //delta0 + * over + * //rootfs + * which means we would rsync the rootfs into + * the delta directory. That doesn't make sense + * since the delta directory only exists to + * record the differences to + * //rootfs. So + * let's simply bind-mount here and then rsync + * directly into + * //rootfs. + */ + char *src; + + src = ovl_get_rootfs(bdev->src, &(size_t){0}); + if (!src) { + ERROR("Failed to get rootfs"); + exit(EXIT_FAILURE); + } + + ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC, NULL); + if (ret < 0) { + ERROR("Failed to mount rootfs"); + return -1; + } + } else { + if (bdev->ops->mount(bdev) < 0) { + ERROR("Failed to mount rootfs"); + exit(EXIT_FAILURE); + } } } else { // TODO come up with a better way here! char *src;