Commit 789edffe by Stéphane Graber Committed by GitHub

Merge pull request #1747 from brauner/2017-08-15/stable_2_0_cherry_picks

stable 2.0: revert a bunch of cherry picks
parents 93b8f59a 7d3391cb
...@@ -73,10 +73,6 @@ struct bdev_ops { ...@@ -73,10 +73,6 @@ struct bdev_ops {
const char *oldname, const char *cname, const char *oldname, const char *cname,
const char *oldpath, const char *lxcpath, int snap, const char *oldpath, const char *lxcpath, int snap,
uint64_t newsize, struct lxc_conf *conf); uint64_t newsize, struct lxc_conf *conf);
bool (*create_clone)(struct lxc_conf *conf, struct bdev *orig,
struct bdev *new, uint64_t newsize);
bool (*create_snapshot)(struct lxc_conf *conf, struct bdev *orig,
struct bdev *new, uint64_t newsize);
bool can_snapshot; bool can_snapshot;
bool can_backup; bool can_backup;
}; };
...@@ -129,6 +125,5 @@ bool bdev_destroy(struct lxc_conf *conf); ...@@ -129,6 +125,5 @@ bool bdev_destroy(struct lxc_conf *conf);
/* callback function to be used with userns_exec_1() */ /* callback function to be used with userns_exec_1() */
int bdev_destroy_wrapper(void *data); int bdev_destroy_wrapper(void *data);
extern bool rootfs_is_blockdev(struct lxc_conf *conf); extern bool rootfs_is_blockdev(struct lxc_conf *conf);
extern char *lxc_storage_get_path(char *src, const char *prefix);
#endif // __LXC_BDEV_H #endif // __LXC_BDEV_H
...@@ -32,7 +32,6 @@ ...@@ -32,7 +32,6 @@
#include <unistd.h> #include <unistd.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/vfs.h> #include <sys/vfs.h>
...@@ -40,10 +39,14 @@ ...@@ -40,10 +39,14 @@
#include "log.h" #include "log.h"
#include "lxcbtrfs.h" #include "lxcbtrfs.h"
#include "lxcrsync.h" #include "lxcrsync.h"
#include "../utils.h" #include "utils.h"
lxc_log_define(lxcbtrfs, lxc); lxc_log_define(lxcbtrfs, lxc);
/* defined in lxccontainer.c: needs to become common helper */
extern char *dir_new_path(char *src, const char *oldname, const char *name,
const char *oldpath, const char *lxcpath);
/* /*
* Return the full path of objid under dirid. Let's say dirid is * Return the full path of objid under dirid. Let's say dirid is
* /lxc/c1/rootfs, and objid is /lxc/c1/rootfs/a/b/c. Then we will * /lxc/c1/rootfs, and objid is /lxc/c1/rootfs/a/b/c. Then we will
...@@ -188,12 +191,11 @@ int btrfs_detect(const char *path) ...@@ -188,12 +191,11 @@ int btrfs_detect(const char *path)
int btrfs_mount(struct bdev *bdev) int btrfs_mount(struct bdev *bdev)
{ {
unsigned long mntflags; unsigned long mntflags;
char *mntdata, *src; char *mntdata;
int ret; int ret;
if (strcmp(bdev->type, "btrfs")) if (strcmp(bdev->type, "btrfs"))
return -22; return -22;
if (!bdev->src || !bdev->dest) if (!bdev->src || !bdev->dest)
return -22; return -22;
...@@ -202,9 +204,7 @@ int btrfs_mount(struct bdev *bdev) ...@@ -202,9 +204,7 @@ int btrfs_mount(struct bdev *bdev)
return -22; return -22;
} }
src = lxc_storage_get_path(bdev->src, "btrfs"); ret = mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata);
ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata);
free(mntdata); free(mntdata);
return ret; return ret;
} }
...@@ -213,50 +213,45 @@ int btrfs_umount(struct bdev *bdev) ...@@ -213,50 +213,45 @@ int btrfs_umount(struct bdev *bdev)
{ {
if (strcmp(bdev->type, "btrfs")) if (strcmp(bdev->type, "btrfs"))
return -22; return -22;
if (!bdev->src || !bdev->dest) if (!bdev->src || !bdev->dest)
return -22; return -22;
return umount(bdev->dest); return umount(bdev->dest);
} }
static int btrfs_subvolume_create(const char *path) static int btrfs_subvolume_create(const char *path)
{ {
int ret, saved_errno; int ret, fd = -1;
struct btrfs_ioctl_vol_args args; struct btrfs_ioctl_vol_args args;
char *p, *newfull; char *p, *newfull = strdup(path);
int fd = -1;
newfull = strdup(path);
if (!newfull) { if (!newfull) {
errno = ENOMEM; ERROR("Error: out of memory");
return -ENOMEM; return -1;
} }
p = strrchr(newfull, '/'); p = strrchr(newfull, '/');
if (!p) { if (!p) {
ERROR("bad path: %s", path);
free(newfull); free(newfull);
errno = EINVAL; return -1;
return -EINVAL;
} }
*p = '\0'; *p = '\0';
fd = open(newfull, O_RDONLY); fd = open(newfull, O_RDONLY);
if (fd < 0) { if (fd < 0) {
ERROR("Error opening %s", newfull);
free(newfull); free(newfull);
return -errno; return -1;
} }
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
strncpy(args.name, p + 1, BTRFS_SUBVOL_NAME_MAX); strncpy(args.name, p+1, BTRFS_SUBVOL_NAME_MAX);
args.name[BTRFS_SUBVOL_NAME_MAX - 1] = 0; args.name[BTRFS_SUBVOL_NAME_MAX-1] = 0;
ret = ioctl(fd, BTRFS_IOC_SUBVOL_CREATE, &args); ret = ioctl(fd, BTRFS_IOC_SUBVOL_CREATE, &args);
saved_errno = errno; INFO("btrfs: snapshot create ioctl returned %d", ret);
close(fd);
free(newfull); free(newfull);
errno = saved_errno; close(fd);
return ret; return ret;
} }
...@@ -303,37 +298,39 @@ out: ...@@ -303,37 +298,39 @@ out:
int btrfs_snapshot(const char *orig, const char *new) int btrfs_snapshot(const char *orig, const char *new)
{ {
struct btrfs_ioctl_vol_args_v2 args;
char *newdir, *newname;
char *newfull = NULL;
int saved_errno = -1;
int fd = -1, fddst = -1, ret = -1; int fd = -1, fddst = -1, ret = -1;
struct btrfs_ioctl_vol_args_v2 args;
char *newdir, *newname, *newfull = NULL;
newfull = strdup(new); newfull = strdup(new);
if (!newfull) if (!newfull) {
ERROR("Error: out of memory");
goto out; goto out;
}
ret = rmdir(newfull); // make sure the directory doesn't already exist
if (ret < 0 && errno != ENOENT) if (rmdir(newfull) < 0 && errno != ENOENT) {
SYSERROR("Error removing empty new rootfs");
goto out; goto out;
}
newname = basename(newfull); newname = basename(newfull);
newdir = dirname(newfull);
fd = open(orig, O_RDONLY); fd = open(orig, O_RDONLY);
if (fd < 0) if (fd < 0) {
SYSERROR("Error opening original rootfs %s", orig);
goto out; goto out;
}
newdir = dirname(newfull);
fddst = open(newdir, O_RDONLY); fddst = open(newdir, O_RDONLY);
if (fddst < 0) if (fddst < 0) {
SYSERROR("Error opening new container dir %s", newdir);
goto out; goto out;
}
memset(&args, 0, sizeof(args)); memset(&args, 0, sizeof(args));
args.fd = fd; args.fd = fd;
strncpy(args.name, newname, BTRFS_SUBVOL_NAME_MAX); strncpy(args.name, newname, BTRFS_SUBVOL_NAME_MAX);
args.name[BTRFS_SUBVOL_NAME_MAX - 1] = 0; args.name[BTRFS_SUBVOL_NAME_MAX-1] = 0;
ret = ioctl(fddst, BTRFS_IOC_SNAP_CREATE_V2, &args); ret = ioctl(fddst, BTRFS_IOC_SNAP_CREATE_V2, &args);
saved_errno = errno; INFO("btrfs: snapshot create ioctl returned %d", ret);
out: out:
if (fddst != -1) if (fddst != -1)
...@@ -341,31 +338,23 @@ out: ...@@ -341,31 +338,23 @@ out:
if (fd != -1) if (fd != -1)
close(fd); close(fd);
free(newfull); free(newfull);
if (saved_errno >= 0)
errno = saved_errno;
return ret; return ret;
} }
int btrfs_snapshot_wrapper(void *data) static int btrfs_snapshot_wrapper(void *data)
{ {
char *src;
struct rsync_data_char *arg = data; struct rsync_data_char *arg = data;
if (setgid(0) < 0) { if (setgid(0) < 0) {
ERROR("Failed to setgid to 0"); ERROR("Failed to setgid to 0");
return -1; return -1;
} }
if (setgroups(0, NULL) < 0) if (setgroups(0, NULL) < 0)
WARN("Failed to clear groups"); WARN("Failed to clear groups");
if (setuid(0) < 0) { if (setuid(0) < 0) {
ERROR("Failed to setuid to 0"); ERROR("Failed to setuid to 0");
return -1; return -1;
} }
return btrfs_snapshot(arg->src, arg->dest);
src = lxc_storage_get_path(arg->src, "btrfs");
return btrfs_snapshot(src, arg->dest);
} }
int btrfs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, int btrfs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
...@@ -373,126 +362,52 @@ int btrfs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, ...@@ -373,126 +362,52 @@ int btrfs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
const char *lxcpath, int snap, uint64_t newsize, const char *lxcpath, int snap, uint64_t newsize,
struct lxc_conf *conf) struct lxc_conf *conf)
{ {
char *src;
if (!orig->dest || !orig->src) if (!orig->dest || !orig->src)
return -1; return -1;
if (strcmp(orig->type, "btrfs") && snap) { if (strcmp(orig->type, "btrfs")) {
ERROR("btrfs snapshot from %s backing store is not supported", int len, ret;
orig->type); if (snap) {
return -1; ERROR("btrfs snapshot from %s backing store is not supported",
} orig->type);
new->src = lxc_string_join(
"/",
(const char *[]){"btrfs:", *lxcpath != '/' ? lxcpath : ++lxcpath,
cname, "rootfs", NULL},
false);
if (!new->src) {
ERROR("Failed to create new rootfs path");
return -1;
}
TRACE("Constructed new rootfs path \"%s\"", new->src);
src = lxc_storage_get_path(new->src, "btrfs");
new->dest = strdup(src);
if (!new->dest) {
ERROR("Failed to duplicate string \"%s\"", src);
return -1;
}
if (orig->mntopts) {
new->mntopts = strdup(orig->mntopts);
if (!new->mntopts) {
ERROR("Failed to duplicate string \"%s\"",
orig->mntopts);
return -1; return -1;
} }
} len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 3;
new->src = malloc(len);
return 0; if (!new->src)
} return -1;
ret = snprintf(new->src, len, "%s/%s/rootfs", lxcpath, cname);
bool btrfs_create_clone(struct lxc_conf *conf, struct bdev *orig, if (ret < 0 || ret >= len)
struct bdev *new, uint64_t newsize) return -1;
{ } else {
int ret; // in case rootfs is in custom path, reuse it
struct rsync_data data = {0, 0}; if ((new->src = dir_new_path(orig->src, oldname, cname, oldpath, lxcpath)) == NULL)
char cmd_output[MAXPATHLEN] = {0}; return -1;
ret = rmdir(new->dest);
if (ret < 0 && errno != ENOENT)
return false;
ret = btrfs_subvolume_create(new->dest);
if (ret < 0) {
SYSERROR("Failed to create btrfs subvolume \"%s\"", new->dest);
return false;
}
/* rsync the contents from source to target */
data.orig = orig;
data.new = new;
if (am_unpriv()) {
ret = userns_exec_1(conf, lxc_rsync_exec_wrapper, &data,
"lxc_rsync_exec_wrapper");
if (ret < 0) {
ERROR("Failed to rsync from \"%s\" into \"%s\"",
orig->dest, new->dest);
return false;
}
return true;
}
ret = run_command(cmd_output, sizeof(cmd_output),
lxc_rsync_exec_wrapper, (void *)&data);
if (ret < 0) {
ERROR("Failed to rsync from \"%s\" into \"%s\": %s", orig->dest,
new->dest, cmd_output);
return false;
} }
return true; if ((new->dest = strdup(new->src)) == NULL)
} return -1;
bool btrfs_create_snapshot(struct lxc_conf *conf, struct bdev *orig,
struct bdev *new, uint64_t newsize)
{
int ret;
ret = rmdir(new->dest);
if (ret < 0 && errno != ENOENT)
return false;
if (am_unpriv()) {
struct rsync_data_char args;
args.src = orig->dest;
args.dest = new->dest;
ret = userns_exec_1(conf, btrfs_snapshot_wrapper, &args, if (orig->mntopts && (new->mntopts = strdup(orig->mntopts)) == NULL)
"btrfs_snapshot_wrapper"); return -1;
if (ret < 0) {
ERROR("Failed to run \"btrfs_snapshot_wrapper\"");
return false;
}
TRACE("Created btrfs snapshot \"%s\" from \"%s\"", new->dest, if (snap) {
orig->dest); struct rsync_data_char sdata;
return true; if (!am_unpriv())
return btrfs_snapshot(orig->dest, new->dest);
sdata.dest = new->dest;
sdata.src = orig->dest;
return userns_exec_1(conf, btrfs_snapshot_wrapper, &sdata,
"btrfs_snapshot_wrapper");
} }
ret = btrfs_snapshot(orig->dest, new->dest); if (rmdir(new->dest) < 0 && errno != ENOENT) {
if (ret < 0) { SYSERROR("removing %s", new->dest);
SYSERROR("Failed to create btrfs snapshot \"%s\" from \"%s\"", return -1;
new->dest, orig->dest);
return false;
} }
TRACE("Created btrfs snapshot \"%s\" from \"%s\"", new->dest, orig->dest); return btrfs_subvolume_create(new->dest);
return true;
} }
static int btrfs_do_destroy_subvol(const char *path) static int btrfs_do_destroy_subvol(const char *path)
...@@ -816,50 +731,21 @@ bool btrfs_try_remove_subvol(const char *path) ...@@ -816,50 +731,21 @@ bool btrfs_try_remove_subvol(const char *path)
{ {
if (!btrfs_detect(path)) if (!btrfs_detect(path))
return false; return false;
return btrfs_recursive_destroy(path) == 0; return btrfs_recursive_destroy(path) == 0;
} }
int btrfs_destroy(struct bdev *orig) int btrfs_destroy(struct bdev *orig)
{ {
char *src; return btrfs_recursive_destroy(orig->src);
src = lxc_storage_get_path(orig->src, "btrfs");
return btrfs_recursive_destroy(src);
} }
int btrfs_create(struct bdev *bdev, const char *dest, const char *n, int btrfs_create(struct bdev *bdev, const char *dest, const char *n,
struct bdev_specs *specs) struct bdev_specs *specs)
{ {
int ret; bdev->src = strdup(dest);
size_t len;
len = strlen(dest) + 1;
/* strlen("btrfs:") */
len += 6;
bdev->src = malloc(len);
if (!bdev->src) {
ERROR("Failed to allocate memory");
return -1;
}
ret = snprintf(bdev->src, len, "btrfs:%s", dest);
if (ret < 0 || (size_t)ret >= len) {
ERROR("Failed to create string");
return -1;
}
bdev->dest = strdup(dest); bdev->dest = strdup(dest);
if (!bdev->dest) { if (!bdev->src || !bdev->dest)
ERROR("Failed to duplicate string \"%s\"", dest);
return -1; return -1;
} return btrfs_subvolume_create(bdev->dest);
ret = btrfs_subvolume_create(bdev->dest);
if (ret < 0) {
SYSERROR("Failed to create btrfs subvolume \"%s\"", bdev->dest);
}
return ret;
} }
...@@ -412,10 +412,5 @@ int is_btrfs_subvol(const char *path); ...@@ -412,10 +412,5 @@ int is_btrfs_subvol(const char *path);
bool btrfs_try_remove_subvol(const char *path); bool btrfs_try_remove_subvol(const char *path);
int btrfs_same_fs(const char *orig, const char *new); int btrfs_same_fs(const char *orig, const char *new);
int btrfs_snapshot(const char *orig, const char *new); int btrfs_snapshot(const char *orig, const char *new);
int btrfs_snapshot_wrapper(void *data);
bool btrfs_create_clone(struct lxc_conf *conf, struct bdev *orig,
struct bdev *new, uint64_t newsize);
bool btrfs_create_snapshot(struct lxc_conf *conf, struct bdev *orig,
struct bdev *new, uint64_t newsize);
#endif // __LXC_BTRFS_H #endif // __LXC_BTRFS_H
...@@ -36,101 +36,61 @@ lxc_log_define(lxcdir, lxc); ...@@ -36,101 +36,61 @@ lxc_log_define(lxcdir, lxc);
* name and paths for the new * name and paths for the new
*/ */
int dir_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, int dir_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
const char *cname, const char *oldpath, const char *lxcpath, const char *cname, const char *oldpath, const char *lxcpath,
int snap, uint64_t newsize, struct lxc_conf *conf) int snap, uint64_t newsize, struct lxc_conf *conf)
{ {
char *src_no_prefix; int len, ret;
int ret;
size_t len;
if (snap) { if (snap) {
ERROR("Directories cannot be snapshotted"); ERROR("directories cannot be snapshotted. Try aufs or overlayfs.");
return -1; return -1;
} }
if (!orig->dest || !orig->src) if (!orig->dest || !orig->src)
return -1; return -1;
len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 4 + 3; len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 3;
new->src = malloc(len); new->src = malloc(len);
if (!new->src) { if (!new->src)
ERROR("Failed to allocate memory");
return -1; return -1;
} ret = snprintf(new->src, len, "%s/%s/rootfs", lxcpath, cname);
if (ret < 0 || ret >= len)
ret = snprintf(new->src, len, "dir:%s/%s/rootfs", lxcpath, cname);
if (ret < 0 || (size_t)ret >= len) {
ERROR("Failed to create string");
return -1; return -1;
} if ((new->dest = strdup(new->src)) == NULL)
src_no_prefix = lxc_storage_get_path(new->src, new->type);
new->dest = strdup(src_no_prefix);
if (!new->dest) {
ERROR("Failed to duplicate string \"%s\"", new->src);
return -1; return -1;
}
TRACE("Created new path \"%s\" for dir storage driver", new->dest);
return 0; return 0;
} }
int dir_create(struct bdev *bdev, const char *dest, const char *n, int dir_create(struct bdev *bdev, const char *dest, const char *n,
struct bdev_specs *specs) struct bdev_specs *specs)
{ {
int ret;
const char *src;
size_t len;
/* strlen("dir:") */
len = 4;
if (specs && specs->dir) if (specs && specs->dir)
src = specs->dir; bdev->src = strdup(specs->dir);
else else
src = dest; bdev->src = strdup(dest);
bdev->dest = strdup(dest);
len += strlen(src) + 1; if (!bdev->src || !bdev->dest) {
bdev->src = malloc(len); ERROR("Out of memory");
if (!bdev->src) {
ERROR("Failed to allocate memory");
return -1;
}
ret = snprintf(bdev->src, len, "dir:%s", src);
if (ret < 0 || (size_t)ret >= len) {
ERROR("Failed to create string");
return -1; return -1;
} }
bdev->dest = strdup(dest); if (mkdir_p(bdev->src, 0755) < 0) {
if (!bdev->dest) { ERROR("Error creating %s", bdev->src);
ERROR("Failed to duplicate string \"%s\"", dest);
return -1; return -1;
} }
if (mkdir_p(bdev->dest, 0755) < 0) {
ret = mkdir_p(dest, 0755); ERROR("Error creating %s", bdev->dest);
if (ret < 0) {
ERROR("Failed to create directory \"%s\"", dest);
return -1; return -1;
} }
TRACE("Created directory \"%s\"", dest);
return 0; return 0;
} }
int dir_destroy(struct bdev *orig) int dir_destroy(struct bdev *orig)
{ {
int ret; if (lxc_rmdir_onedev(orig->src, NULL) < 0)
char *src;
src = lxc_storage_get_path(orig->src, orig->src);
ret = lxc_rmdir_onedev(src, NULL);
if (ret < 0) {
ERROR("Failed to delete \"%s\"", src);
return -1; return -1;
}
return 0; return 0;
} }
...@@ -140,47 +100,34 @@ int dir_detect(const char *path) ...@@ -140,47 +100,34 @@ int dir_detect(const char *path)
return 1; // take their word for it return 1; // take their word for it
if (is_dir(path)) if (is_dir(path))
return 1; return 1;
return 0; return 0;
} }
int dir_mount(struct bdev *bdev) int dir_mount(struct bdev *bdev)
{ {
unsigned long mntflags;
char *mntdata;
int ret; int ret;
unsigned long mflags, mntflags; unsigned long mflags;
char *src, *mntdata;
if (strcmp(bdev->type, "dir")) if (strcmp(bdev->type, "dir"))
return -22; return -22;
if (!bdev->src || !bdev->dest) if (!bdev->src || !bdev->dest)
return -22; return -22;
ret = parse_mntopts(bdev->mntopts, &mntflags, &mntdata); if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) {
if (ret < 0) {
ERROR("Failed to parse mount options \"%s\"", bdev->mntopts);
free(mntdata); free(mntdata);
return -22; return -22;
} }
src = lxc_storage_get_path(bdev->src, bdev->type); ret = mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata);
ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags,
mntdata);
if ((0 == ret) && (mntflags & MS_RDONLY)) { if ((0 == ret) && (mntflags & MS_RDONLY)) {
DEBUG("Remounting \"%s\" on \"%s\" readonly", DEBUG("remounting %s on %s with readonly options",
src ? src : "(none)", bdev->dest ? bdev->dest : "(none)"); bdev->src ? bdev->src : "(none)", bdev->dest ? bdev->dest : "(none)");
mflags = add_required_remount_flags(src, bdev->dest, MS_BIND | MS_REC | mntflags | MS_REMOUNT); mflags = add_required_remount_flags(bdev->src, bdev->dest, MS_BIND | MS_REC | mntflags | MS_REMOUNT);
ret = mount(src, bdev->dest, "bind", mflags, mntdata); ret = mount(bdev->src, bdev->dest, "bind", mflags, mntdata);
} }
if (ret < 0) {
SYSERROR("Failed to mount \"%s\" on \"%s\"", src, bdev->dest);
free(mntdata);
return -1;
}
TRACE("Mounted \"%s\" on \"%s\"", src, bdev->dest);
free(mntdata); free(mntdata);
return ret; return ret;
} }
...@@ -189,9 +136,7 @@ int dir_umount(struct bdev *bdev) ...@@ -189,9 +136,7 @@ int dir_umount(struct bdev *bdev)
{ {
if (strcmp(bdev->type, "dir")) if (strcmp(bdev->type, "dir"))
return -22; return -22;
if (!bdev->src || !bdev->dest) if (!bdev->src || !bdev->dest)
return -22; return -22;
return umount(bdev->dest); return umount(bdev->dest);
} }
...@@ -22,15 +22,12 @@ ...@@ -22,15 +22,12 @@
*/ */
#define _GNU_SOURCE #define _GNU_SOURCE
#define __STDC_FORMAT_MACROS
#include <dirent.h> #include <dirent.h>
#include <errno.h>
#include <inttypes.h>
#include <linux/loop.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <linux/loop.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
...@@ -49,16 +46,16 @@ static int do_loop_create(const char *path, uint64_t size, const char *fstype); ...@@ -49,16 +46,16 @@ static int do_loop_create(const char *path, uint64_t size, const char *fstype);
* called $lxcpath/$lxcname/rootdev * called $lxcpath/$lxcname/rootdev
*/ */
int loop_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, int loop_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
const char *cname, const char *oldpath, const char *lxcpath, const char *cname, const char *oldpath, const char *lxcpath,
int snap, uint64_t newsize, struct lxc_conf *conf) int snap, uint64_t newsize, struct lxc_conf *conf)
{ {
char fstype[100];
uint64_t size = newsize; uint64_t size = newsize;
int len, ret; int len, ret;
char *srcdev; char *srcdev;
char fstype[100] = "ext4";
if (snap) { if (snap) {
ERROR("The loop storage driver does not support snapshots"); ERROR("loop devices cannot be snapshotted.");
return -1; return -1;
} }
...@@ -68,65 +65,43 @@ int loop_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, ...@@ -68,65 +65,43 @@ int loop_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
len = strlen(lxcpath) + strlen(cname) + strlen("rootdev") + 3; len = strlen(lxcpath) + strlen(cname) + strlen("rootdev") + 3;
srcdev = alloca(len); srcdev = alloca(len);
ret = snprintf(srcdev, len, "%s/%s/rootdev", lxcpath, cname); ret = snprintf(srcdev, len, "%s/%s/rootdev", lxcpath, cname);
if (ret < 0 || ret >= len) { if (ret < 0 || ret >= len)
ERROR("Failed to create string");
return -1; return -1;
}
new->src = malloc(len + 5); new->src = malloc(len + 5);
if (!new->src) { if (!new->src)
ERROR("Failed to allocate memory");
return -1; return -1;
} ret = snprintf(new->src, len + 5, "loop:%s", srcdev);
if (ret < 0 || ret >= len + 5)
ret = snprintf(new->src, (len + 5), "loop:%s", srcdev);
if (ret < 0 || ret >= (len + 5)) {
ERROR("Failed to create string");
return -1; return -1;
}
new->dest = malloc(len); new->dest = malloc(len);
if (!new->dest) { if (!new->dest)
ERROR("Failed to allocate memory");
return -1; return -1;
}
ret = snprintf(new->dest, len, "%s/%s/rootfs", lxcpath, cname); ret = snprintf(new->dest, len, "%s/%s/rootfs", lxcpath, cname);
if (ret < 0 || ret >= len) { if (ret < 0 || ret >= len)
ERROR("Failed to create string");
return -1; return -1;
}
/* It's tempting to say: if orig->src == loopback and !newsize, then // it's tempting to say: if orig->src == loopback and !newsize, then
* copy the loopback file. However, we'd have to make sure to correctly // copy the loopback file. However, we'd have to make sure to
* keep holes! So punt for now. // correctly keep holes! So punt for now.
*/
if (is_blktype(orig)) { if (is_blktype(orig)) {
/* detect size */
if (!newsize && blk_getsize(orig, &size) < 0) { if (!newsize && blk_getsize(orig, &size) < 0) {
ERROR("Failed to detect size of loop file \"%s\"", ERROR("Error getting size of %s", orig->src);
orig->src);
return -1; return -1;
} }
/* detect filesystem */
if (detect_fs(orig, fstype, 100) < 0) { if (detect_fs(orig, fstype, 100) < 0) {
INFO("Failed to detect filesystem type for \"%s\"", orig->src); INFO("could not find fstype for %s, using %s", orig->src,
DEFAULT_FSTYPE);
return -1; return -1;
} }
} else if (!newsize) { } else {
sprintf(fstype, "%s", DEFAULT_FSTYPE);
if (!newsize)
size = DEFAULT_FS_SIZE; size = DEFAULT_FS_SIZE;
} }
return do_loop_create(srcdev, size, fstype);
ret = do_loop_create(srcdev, size, fstype);
if (ret < 0) {
ERROR("Failed to create loop storage volume \"%s\" with "
"filesystem \"%s\" and size \"%" PRIu64 "\"",
srcdev, fstype, size);
return -1;
}
return 0;
} }
int loop_create(struct bdev *bdev, const char *dest, const char *n, int loop_create(struct bdev *bdev, const char *dest, const char *n,
...@@ -140,35 +115,23 @@ int loop_create(struct bdev *bdev, const char *dest, const char *n, ...@@ -140,35 +115,23 @@ int loop_create(struct bdev *bdev, const char *dest, const char *n,
if (!specs) if (!specs)
return -1; return -1;
/* <dest> is passed in as <lxcpath>/<lxcname>/rootfs, <srcdev> will // dest is passed in as $lxcpath / $lxcname / rootfs
* be <lxcpath>/<lxcname>/rootdev, and <src> will be "loop:<srcdev>". // srcdev will be: $lxcpath / $lxcname / rootdev
*/ // src will be 'loop:$srcdev'
len = strlen(dest) + 2; len = strlen(dest) + 2;
srcdev = alloca(len); srcdev = alloca(len);
ret = snprintf(srcdev, len, "%s", dest); ret = snprintf(srcdev, len, "%s", dest);
if (ret < 0 || ret >= len) { if (ret < 0 || ret >= len)
ERROR("Failed to create string");
return -1;
}
ret = sprintf(srcdev + len - 4, "dev");
if (ret < 0) {
ERROR("Failed to create string");
return -1; return -1;
} sprintf(srcdev + len - 4, "dev");
bdev->src = malloc(len + 5); bdev->src = malloc(len + 5);
if (!bdev->src) { if (!bdev->src)
ERROR("Failed to allocate memory");
return -1; return -1;
}
ret = snprintf(bdev->src, len + 5, "loop:%s", srcdev); ret = snprintf(bdev->src, len + 5, "loop:%s", srcdev);
if (ret < 0 || ret >= len + 5) { if (ret < 0 || ret >= len + 5)
ERROR("Failed to create string");
return -1; return -1;
}
sz = specs->fssize; sz = specs->fssize;
if (!sz) if (!sz)
...@@ -178,31 +141,19 @@ int loop_create(struct bdev *bdev, const char *dest, const char *n, ...@@ -178,31 +141,19 @@ int loop_create(struct bdev *bdev, const char *dest, const char *n,
if (!fstype) if (!fstype)
fstype = DEFAULT_FSTYPE; fstype = DEFAULT_FSTYPE;
bdev->dest = strdup(dest); if (!(bdev->dest = strdup(dest)))
if (!bdev->dest) {
ERROR("Failed to duplicate string \"%s\"", dest);
return -1; return -1;
}
ret = mkdir_p(bdev->dest, 0755); if (mkdir_p(bdev->dest, 0755) < 0) {
if (ret < 0) { ERROR("Error creating %s", bdev->dest);
ERROR("Failed creating directory \"%s\"", bdev->dest);
return -1; return -1;
} }
return do_loop_create(srcdev, sz, fstype);
ret = do_loop_create(srcdev, sz, fstype);
if (ret < 0) {
ERROR("Failed to create loop storage volume \"%s\" with "
"filesystem \"%s\" and size \"%" PRIu64 "\"",
srcdev, fstype, sz);
return -1;
}
return 0;
} }
int loop_destroy(struct bdev *orig) { int loop_destroy(struct bdev *orig)
{
return unlink(orig->src + 5); return unlink(orig->src + 5);
} }
...@@ -228,7 +179,7 @@ int loop_mount(struct bdev *bdev) ...@@ -228,7 +179,7 @@ int loop_mount(struct bdev *bdev)
{ {
int ret, loopfd; int ret, loopfd;
char loname[MAXPATHLEN]; char loname[MAXPATHLEN];
char *src; char *src = bdev->src;
if (strcmp(bdev->type, "loop")) if (strcmp(bdev->type, "loop"))
return -22; return -22;
...@@ -237,98 +188,73 @@ int loop_mount(struct bdev *bdev) ...@@ -237,98 +188,73 @@ int loop_mount(struct bdev *bdev)
return -22; return -22;
/* skip prefix */ /* skip prefix */
src = lxc_storage_get_path(bdev->src, bdev->type); if (!strncmp(bdev->src, "loop:", 5))
src += 5;
loopfd = lxc_prepare_loop_dev(src, loname, LO_FLAGS_AUTOCLEAR); loopfd = lxc_prepare_loop_dev(src, loname, LO_FLAGS_AUTOCLEAR);
if (loopfd < 0) { if (loopfd < 0) {
ERROR("Failed to prepare loop device for loop file \"%s\"", src); ERROR("failed to prepare loop device for loop file \"%s\"", src);
return -1; return -1;
} }
DEBUG("Prepared loop device \"%s\"", loname); DEBUG("prepared loop device \"%s\"", loname);
ret = mount_unknown_fs(loname, bdev->dest, bdev->mntopts); ret = mount_unknown_fs(loname, bdev->dest, bdev->mntopts);
if (ret < 0) { if (ret < 0)
ERROR("Failed to mount rootfs \"%s\" on \"%s\" via loop device \"%s\"", ERROR("failed to mount rootfs \"%s\" onto \"%s\" via loop device \"%s\"", bdev->src, bdev->dest, loname);
bdev->src, bdev->dest, loname); else
close(loopfd); bdev->lofd = loopfd;
return -1; DEBUG("mounted rootfs \"%s\" onto \"%s\" via loop device \"%s\"", bdev->src, bdev->dest, loname);
}
bdev->lofd = loopfd;
DEBUG("Mounted rootfs \"%s\" on \"%s\" via loop device \"%s\"",
bdev->src, bdev->dest, loname);
return 0; return ret;
} }
int loop_umount(struct bdev *bdev) int loop_umount(struct bdev *bdev)
{ {
int ret, saved_errno; int ret;
if (strcmp(bdev->type, "loop")) if (strcmp(bdev->type, "loop"))
return -22; return -22;
if (!bdev->src || !bdev->dest) if (!bdev->src || !bdev->dest)
return -22; return -22;
ret = umount(bdev->dest); ret = umount(bdev->dest);
saved_errno = errno;
if (bdev->lofd >= 0) { if (bdev->lofd >= 0) {
close(bdev->lofd); close(bdev->lofd);
bdev->lofd = -1; bdev->lofd = -1;
} }
errno = saved_errno; return ret;
if (ret < 0) {
SYSERROR("Failed to umount \"%s\"", bdev->dest);
return -1;
}
return 0;
} }
static int do_loop_create(const char *path, uint64_t size, const char *fstype) static int do_loop_create(const char *path, uint64_t size, const char *fstype)
{ {
int fd, ret; int fd, ret;
char cmd_output[MAXPATHLEN];
const char *cmd_args[2] = {fstype, path}; const char *cmd_args[2] = {fstype, path};
char cmd_output[MAXPATHLEN];
/* create the new loopback file */ // create the new loopback file.
fd = creat(path, S_IRUSR | S_IWUSR); fd = creat(path, S_IRUSR|S_IWUSR);
if (fd < 0) { if (fd < 0)
SYSERROR("Failed to create new loop file \"%s\"", path);
return -1; return -1;
} if (lseek(fd, size, SEEK_SET) < 0) {
SYSERROR("Error seeking to set new loop file size");
ret = lseek(fd, size, SEEK_SET);
if (ret < 0) {
SYSERROR("Failed to seek to set new loop file size for loop "
"file \"%s\"", path);
close(fd); close(fd);
return -1; return -1;
} }
if (write(fd, "1", 1) != 1) {
ret = write(fd, "1", 1); SYSERROR("Error creating new loop file");
if (ret != 1) {
SYSERROR("Failed creating new loop file \"%s\"", path);
close(fd); close(fd);
return -1; return -1;
} }
ret = close(fd); ret = close(fd);
if (ret < 0) { if (ret < 0) {
SYSERROR("Failed to create new loop file \"%s\"", path); SYSERROR("Error closing new loop file");
return -1; return -1;
} }
// create an fs in the loopback file // create an fs in the loopback file
ret = run_command(cmd_output, sizeof(cmd_output), do_mkfs_exec_wrapper, ret = run_command(cmd_output, sizeof(cmd_output), do_mkfs_exec_wrapper,
(void *)cmd_args); (void *)cmd_args);
if (ret < 0) { if (ret < 0)
ERROR("Failed to create new filesystem \"%s\" for loop file "
"\"%s\": %s", fstype, path, cmd_output);
return -1; return -1;
}
return 0; return 0;
} }
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#define __LXC_LVM_H #define __LXC_LVM_H
#define _GNU_SOURCE #define _GNU_SOURCE
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
/* defined in bdev.h */ /* defined in bdev.h */
...@@ -53,9 +52,5 @@ int lvm_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, ...@@ -53,9 +52,5 @@ int lvm_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
int lvm_destroy(struct bdev *orig); int lvm_destroy(struct bdev *orig);
int lvm_create(struct bdev *bdev, const char *dest, const char *n, int lvm_create(struct bdev *bdev, const char *dest, const char *n,
struct bdev_specs *specs); struct bdev_specs *specs);
bool lvm_create_clone(struct lxc_conf *conf, struct bdev *orig,
struct bdev *new, uint64_t newsize);
bool lvm_create_snapshot(struct lxc_conf *conf, struct bdev *orig,
struct bdev *new, uint64_t newsize);
#endif /* __LXC_LVM_H */ #endif /* __LXC_LVM_H */
...@@ -116,21 +116,17 @@ int nbd_detect(const char *path) ...@@ -116,21 +116,17 @@ int nbd_detect(const char *path)
int nbd_mount(struct bdev *bdev) int nbd_mount(struct bdev *bdev)
{ {
int ret = -1, partition; int ret = -1, partition;
char *src;
char path[50]; char path[50];
if (strcmp(bdev->type, "nbd")) if (strcmp(bdev->type, "nbd"))
return -22; return -22;
if (!bdev->src || !bdev->dest) if (!bdev->src || !bdev->dest)
return -22; return -22;
/* nbd_idx should have been copied by bdev_init from the lxc_conf */ /* nbd_idx should have been copied by bdev_init from the lxc_conf */
if (bdev->nbd_idx < 0) if (bdev->nbd_idx < 0)
return -22; return -22;
partition = nbd_get_partition(bdev->src);
src = lxc_storage_get_path(bdev->src, bdev->type);
partition = nbd_get_partition(src);
if (partition) if (partition)
ret = snprintf(path, 50, "/dev/nbd%dp%d", bdev->nbd_idx, ret = snprintf(path, 50, "/dev/nbd%dp%d", bdev->nbd_idx,
partition); partition);
...@@ -155,13 +151,14 @@ int nbd_mount(struct bdev *bdev) ...@@ -155,13 +151,14 @@ int nbd_mount(struct bdev *bdev)
int nbd_umount(struct bdev *bdev) int nbd_umount(struct bdev *bdev)
{ {
int ret;
if (strcmp(bdev->type, "nbd")) if (strcmp(bdev->type, "nbd"))
return -22; return -22;
if (!bdev->src || !bdev->dest) if (!bdev->src || !bdev->dest)
return -22; return -22;
ret = umount(bdev->dest);
return umount(bdev->dest); return ret;
} }
bool requires_nbd(const char *path) bool requires_nbd(const char *path)
......
...@@ -34,7 +34,6 @@ ...@@ -34,7 +34,6 @@
#include "lxccontainer.h" #include "lxccontainer.h"
#include "lxcoverlay.h" #include "lxcoverlay.h"
#include "lxcrsync.h" #include "lxcrsync.h"
#include "storage_utils.h"
#include "utils.h" #include "utils.h"
lxc_log_define(lxcoverlay, lxc); lxc_log_define(lxcoverlay, lxc);
...@@ -42,6 +41,10 @@ lxc_log_define(lxcoverlay, lxc); ...@@ -42,6 +41,10 @@ lxc_log_define(lxcoverlay, lxc);
static char *ovl_name; static char *ovl_name;
static char *ovl_version[] = {"overlay", "overlayfs"}; static char *ovl_version[] = {"overlay", "overlayfs"};
/* defined in lxccontainer.c: needs to become common helper */
extern char *dir_new_path(char *src, const char *oldname, const char *name,
const char *oldpath, const char *lxcpath);
static char *ovl_detect_name(void); static char *ovl_detect_name(void);
static int ovl_do_rsync(struct bdev *orig, struct bdev *new, static int ovl_do_rsync(struct bdev *orig, struct bdev *new,
struct lxc_conf *conf); struct lxc_conf *conf);
...@@ -55,21 +58,17 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, ...@@ -55,21 +58,17 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
const char *cname, const char *oldpath, const char *lxcpath, const char *cname, const char *oldpath, const char *lxcpath,
int snap, uint64_t newsize, struct lxc_conf *conf) int snap, uint64_t newsize, struct lxc_conf *conf)
{ {
char *src;
if (!snap) { if (!snap) {
ERROR("overlay is only for snapshot clones"); ERROR("overlayfs is only for snapshot clones");
return -22; return -22;
} }
if (!orig->src || !orig->dest) if (!orig->src || !orig->dest)
return -1; return -1;
new->dest = lxc_string_join( new->dest = dir_new_path(orig->dest, oldname, cname, oldpath, lxcpath);
"/", (const char *[]){lxcpath, cname, "rootfs", NULL}, false);
if (!new->dest) if (!new->dest)
return -1; return -1;
if (mkdir_p(new->dest, 0755) < 0) if (mkdir_p(new->dest, 0755) < 0)
return -1; return -1;
...@@ -134,19 +133,18 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, ...@@ -134,19 +133,18 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
WARN("Failed to update ownership of %s", work); WARN("Failed to update ownership of %s", work);
free(work); free(work);
src = lxc_storage_get_path(orig->src, orig->type);
// the src will be 'overlayfs:lowerdir:upperdir' // the src will be 'overlayfs:lowerdir:upperdir'
len = strlen(delta) + strlen(src) + 12; len = strlen(delta) + strlen(orig->src) + 12;
new->src = malloc(len); new->src = malloc(len);
if (!new->src) { if (!new->src) {
free(delta); free(delta);
return -ENOMEM; return -ENOMEM;
} }
ret = snprintf(new->src, len, "overlay:%s:%s", src, delta); ret = snprintf(new->src, len, "overlayfs:%s:%s", orig->src, delta);
free(delta); free(delta);
if (ret < 0 || ret >= len) if (ret < 0 || ret >= len)
return -1; return -ENOMEM;
} else if (!strcmp(orig->type, "overlayfs") || !strcmp(orig->type, "overlay")) { } else if (strcmp(orig->type, "overlayfs") == 0) {
/* /*
* What exactly do we want to do here? I think we want to use * What exactly do we want to do here? I think we want to use
* the original lowerdir, with a private delta which is * the original lowerdir, with a private delta which is
...@@ -155,44 +153,26 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, ...@@ -155,44 +153,26 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
char *osrc, *odelta, *nsrc, *ndelta, *work; char *osrc, *odelta, *nsrc, *ndelta, *work;
char *lastslash; char *lastslash;
int len, ret, lastslashidx; int len, ret, lastslashidx;
if (!(osrc = strdup(orig->src)))
osrc = strdup(orig->src);
if (!osrc) {
SYSERROR("Failed to duplicate \"%s\"", orig->src);
return -22; return -22;
}
nsrc = strchr(osrc, ':') + 1; nsrc = strchr(osrc, ':') + 1;
if ((nsrc != osrc + 8) && (nsrc != osrc + 10)) { if (nsrc != osrc + 10 || (odelta = strchr(nsrc, ':')) == NULL) {
free(osrc);
ERROR("Detected \":\" in \"%s\" at wrong position", osrc);
return -22;
}
odelta = strchr(nsrc, ':');
if (!odelta) {
free(osrc); free(osrc);
ERROR("Failed to find \":\" in \"%s\"", nsrc);
return -22; return -22;
} }
*odelta = '\0'; *odelta = '\0';
odelta++; odelta++;
ndelta = lxc_string_join("/", (const char *[]){lxcpath, cname, "rootfs", NULL}, false); ndelta = dir_new_path(odelta, oldname, cname, oldpath, lxcpath);
if (!ndelta) { if (!ndelta) {
free(osrc); free(osrc);
ERROR("Failed to create new path");
return -ENOMEM; return -ENOMEM;
} }
if ((ret = mkdir(ndelta, 0755)) < 0 && errno != EEXIST) {
ret = mkdir(ndelta, 0755); SYSERROR("error: mkdir %s", ndelta);
if (ret < 0 && errno != EEXIST) {
free(osrc); free(osrc);
free(ndelta); free(ndelta);
SYSERROR("Failed to create \"%s\"", ndelta);
return -1; return -1;
} }
if (am_unpriv() && chown_mapped_root(ndelta, conf) < 0) if (am_unpriv() && chown_mapped_root(ndelta, conf) < 0)
WARN("Failed to update ownership of %s", ndelta); WARN("Failed to update ownership of %s", ndelta);
...@@ -204,7 +184,6 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, ...@@ -204,7 +184,6 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
if (!lastslash) { if (!lastslash) {
free(osrc); free(osrc);
free(ndelta); free(ndelta);
ERROR("Failed to detect \"/\" in \"%s\"", ndelta);
return -1; return -1;
} }
lastslash++; lastslash++;
...@@ -214,43 +193,37 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, ...@@ -214,43 +193,37 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
if (!work) { if (!work) {
free(osrc); free(osrc);
free(ndelta); free(ndelta);
ERROR("Failed to allocate memory");
return -1; return -1;
} }
strncpy(work, ndelta, lastslashidx + 1); strncpy(work, ndelta, lastslashidx + 1);
strcpy(work + lastslashidx, "olwork"); strcpy(work + lastslashidx, "olwork");
ret = mkdir(work, 0755); if ((mkdir(work, 0755) < 0) && errno != EEXIST) {
if (ret < 0 && errno != EEXIST) { SYSERROR("error: mkdir %s", work);
free(osrc); free(osrc);
free(ndelta); free(ndelta);
free(work); free(work);
SYSERROR("Failed to create \"%s\"", ndelta);
return -1; return -1;
} }
if (am_unpriv() && chown_mapped_root(work, conf) < 0) if (am_unpriv() && chown_mapped_root(work, conf) < 0)
WARN("Failed to update ownership of %s", work); WARN("Failed to update ownership of %s", work);
free(work); free(work);
len = strlen(nsrc) + strlen(ndelta) + 10; len = strlen(nsrc) + strlen(ndelta) + 12;
new->src = malloc(len); new->src = malloc(len);
if (!new->src) { if (!new->src) {
free(osrc); free(osrc);
free(ndelta); free(ndelta);
ERROR("Failed to allocate memory");
return -ENOMEM; return -ENOMEM;
} }
ret = snprintf(new->src, len, "overlay:%s:%s", nsrc, ndelta); ret = snprintf(new->src, len, "overlayfs:%s:%s", nsrc, ndelta);
free(osrc); free(osrc);
free(ndelta); free(ndelta);
if (ret < 0 || ret >= len) { if (ret < 0 || ret >= len)
ERROR("Failed to create string"); return -ENOMEM;
return -1;
}
return ovl_do_rsync(orig, new, conf); return ovl_do_rsync(orig, new, conf);
} else { } else {
ERROR("overlay clone of %s container is not yet supported", ERROR("overlayfs clone of %s container is not yet supported",
orig->type); orig->type);
/* /*
* Note, supporting this will require ovl_mount supporting * Note, supporting this will require ovl_mount supporting
...@@ -263,7 +236,7 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, ...@@ -263,7 +236,7 @@ int ovl_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
} }
/* /*
* to say 'lxc-create -t ubuntu -n o1 -B overlay' means you want * to say 'lxc-create -t ubuntu -n o1 -B overlayfs' means you want
* $lxcpath/$lxcname/rootfs to have the created container, while all * $lxcpath/$lxcname/rootfs to have the created container, while all
* changes after starting the container are written to * changes after starting the container are written to
* $lxcpath/$lxcname/delta0 * $lxcpath/$lxcname/delta0
...@@ -291,14 +264,14 @@ int ovl_create(struct bdev *bdev, const char *dest, const char *n, ...@@ -291,14 +264,14 @@ int ovl_create(struct bdev *bdev, const char *dest, const char *n,
return -1; return -1;
} }
// overlay:lower:upper // overlayfs:lower:upper
newlen = (2 * len) + strlen("overlay:") + 2; newlen = (2 * len) + strlen("overlayfs:") + 2;
bdev->src = malloc(newlen); bdev->src = malloc(newlen);
if (!bdev->src) { if (!bdev->src) {
ERROR("Out of memory"); ERROR("Out of memory");
return -1; return -1;
} }
ret = snprintf(bdev->src, newlen, "overlay:%s:%s", dest, delta); ret = snprintf(bdev->src, newlen, "overlayfs:%s:%s", dest, delta);
if (ret < 0 || ret >= newlen) if (ret < 0 || ret >= newlen)
return -1; return -1;
...@@ -312,23 +285,14 @@ int ovl_create(struct bdev *bdev, const char *dest, const char *n, ...@@ -312,23 +285,14 @@ int ovl_create(struct bdev *bdev, const char *dest, const char *n,
int ovl_destroy(struct bdev *orig) int ovl_destroy(struct bdev *orig)
{ {
bool ovl; char *upper;
char *upper = orig->src;
ovl = !strncmp(upper, "overlay:", 8); if (strncmp(orig->src, "overlayfs:", 10) != 0)
if (!ovl && strncmp(upper, "overlayfs:", 10))
return -22; return -22;
upper = strchr(orig->src + 10, ':');
if (ovl)
upper += 8;
else
upper += 10;
upper = strchr(upper, ':');
if (!upper) if (!upper)
return -22; return -22;
upper++; upper++;
return lxc_rmdir_onedev(upper, NULL); return lxc_rmdir_onedev(upper, NULL);
} }
...@@ -339,6 +303,14 @@ int ovl_detect(const char *path) ...@@ -339,6 +303,14 @@ int ovl_detect(const char *path)
return 0; return 0;
} }
char *ovl_getlower(char *p)
{
char *p1 = strchr(p, ':');
if (p1)
*p1 = '\0';
return p;
}
int ovl_mount(struct bdev *bdev) int ovl_mount(struct bdev *bdev)
{ {
char *tmp, *options, *dup, *lower, *upper; char *tmp, *options, *dup, *lower, *upper;
...@@ -349,9 +321,8 @@ int ovl_mount(struct bdev *bdev) ...@@ -349,9 +321,8 @@ int ovl_mount(struct bdev *bdev)
char *mntdata; char *mntdata;
int ret, ret2; int ret, ret2;
if (strcmp(bdev->type, "overlay") && strcmp(bdev->type, "overlayfs")) if (strcmp(bdev->type, "overlayfs"))
return -22; return -22;
if (!bdev->src || !bdev->dest) if (!bdev->src || !bdev->dest)
return -22; return -22;
...@@ -445,7 +416,7 @@ int ovl_mount(struct bdev *bdev) ...@@ -445,7 +416,7 @@ int ovl_mount(struct bdev *bdev)
ret = ovl_remount_on_enodev(lower, bdev->dest, ovl_name, ret = ovl_remount_on_enodev(lower, bdev->dest, ovl_name,
MS_MGC_VAL | mntflags, options_work); MS_MGC_VAL | mntflags, options_work);
if (ret < 0) { if (ret < 0) {
INFO("Overlay: Error mounting %s onto %s with options %s. " INFO("Overlayfs: Error mounting %s onto %s with options %s. "
"Retrying without workdir: %s.", "Retrying without workdir: %s.",
lower, bdev->dest, options_work, strerror(errno)); lower, bdev->dest, options_work, strerror(errno));
...@@ -453,15 +424,15 @@ int ovl_mount(struct bdev *bdev) ...@@ -453,15 +424,15 @@ int ovl_mount(struct bdev *bdev)
ret = ovl_remount_on_enodev(lower, bdev->dest, ovl_name, ret = ovl_remount_on_enodev(lower, bdev->dest, ovl_name,
MS_MGC_VAL | mntflags, options); MS_MGC_VAL | mntflags, options);
if (ret < 0) if (ret < 0)
SYSERROR("Overlay: Error mounting %s onto %s with " SYSERROR("Overlayfs: Error mounting %s onto %s with "
"options %s: %s.", "options %s: %s.",
lower, bdev->dest, options, lower, bdev->dest, options,
strerror(errno)); strerror(errno));
else else
INFO("Overlay: Mounted %s onto %s with options %s.", INFO("Overlayfs: Mounted %s onto %s with options %s.",
lower, bdev->dest, options); lower, bdev->dest, options);
} else { } else {
INFO("Overlay: Mounted %s onto %s with options %s.", lower, INFO("Overlayfs: Mounted %s onto %s with options %s.", lower,
bdev->dest, options_work); bdev->dest, options_work);
} }
return ret; return ret;
...@@ -469,31 +440,13 @@ int ovl_mount(struct bdev *bdev) ...@@ -469,31 +440,13 @@ int ovl_mount(struct bdev *bdev)
int ovl_umount(struct bdev *bdev) int ovl_umount(struct bdev *bdev)
{ {
if (strcmp(bdev->type, "overlay") && strcmp(bdev->type, "overlayfs")) if (strcmp(bdev->type, "overlayfs"))
return -22; return -22;
if (!bdev->src || !bdev->dest) if (!bdev->src || !bdev->dest)
return -22; return -22;
return umount(bdev->dest); return umount(bdev->dest);
} }
char *ovl_get_lower(const char *rootfs_path)
{
char *s1;
s1 = strstr(rootfs_path, ":/");
if (!s1)
return NULL;
s1++;
s1 = strstr(s1, ":/");
if (!s1)
return NULL;
s1++;
return s1;
}
char *ovl_get_rootfs(const char *rootfs_path, size_t *rootfslen) char *ovl_get_rootfs(const char *rootfs_path, size_t *rootfslen)
{ {
char *rootfsdir = NULL; char *rootfsdir = NULL;
...@@ -802,7 +755,7 @@ static int ovl_do_rsync(struct bdev *orig, struct bdev *new, struct lxc_conf *co ...@@ -802,7 +755,7 @@ static int ovl_do_rsync(struct bdev *orig, struct bdev *new, struct lxc_conf *co
else else
ret = ovl_rsync(&rdata); ret = ovl_rsync(&rdata);
if (ret) if (ret)
ERROR("copying overlay delta"); ERROR("copying overlayfs delta");
return ret; return ret;
} }
......
...@@ -76,7 +76,7 @@ int ovl_update_abs_paths(struct lxc_conf *lxc_conf, const char *lxc_path, ...@@ -76,7 +76,7 @@ int ovl_update_abs_paths(struct lxc_conf *lxc_conf, const char *lxc_path,
* To be called from functions in lxccontainer.c: Get lower directory for * To be called from functions in lxccontainer.c: Get lower directory for
* overlay rootfs. * overlay rootfs.
*/ */
char *ovl_get_lower(const char *rootfs_path); char *ovl_getlower(char *p);
/* /*
* Get rootfs path for overlay backed containers. Allocated memory must be freed * Get rootfs path for overlay backed containers. Allocated memory must be freed
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#define _GNU_SOURCE #define _GNU_SOURCE
#define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */ #define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */
#include <inttypes.h> /* Required for PRIu64 to work. */ #include <inttypes.h> /* Required for PRIu64 to work. */
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
...@@ -36,69 +36,24 @@ ...@@ -36,69 +36,24 @@
lxc_log_define(lxcrbd, lxc); lxc_log_define(lxcrbd, lxc);
struct rbd_args {
const char *osd_pool_name;
const char *rbd_name;
const char *size;
};
int rbd_create_wrapper(void *data)
{
struct rbd_args *args = data;
execlp("rbd", "rbd", "create", "--pool", args->osd_pool_name,
args->rbd_name, "--size", args->size, (char *)NULL);
return -1;
}
int rbd_map_wrapper(void *data)
{
struct rbd_args *args = data;
execlp("rbd", "rbd", "map", "--pool", args->osd_pool_name,
args->rbd_name, (char *)NULL);
return -1;
}
int rbd_unmap_wrapper(void *data)
{
struct rbd_args *args = data;
execlp("rbd", "rbd", "unmap", args->rbd_name, (char *)NULL);
return -1;
}
int rbd_delete_wrapper(void *data)
{
struct rbd_args *args = data;
execlp("rbd", "rbd", "rm", args->rbd_name, (char *)NULL);
return -1;
}
int rbd_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, int rbd_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
const char *cname, const char *oldpath, const char *lxcpath, const char *cname, const char *oldpath, const char *lxcpath,
int snap, uint64_t newsize, struct lxc_conf *conf) int snap, uint64_t newsize, struct lxc_conf *conf)
{ {
ERROR("rbd clonepaths not implemented"); ERROR("rbd clonepaths not implemented");
return -1; return -1;
} }
int rbd_create(struct bdev *bdev, const char *dest, const char *n, int rbd_create(struct bdev *bdev, const char *dest, const char *n,
struct bdev_specs *specs) struct bdev_specs *specs)
{ {
const char *rbdpool, *fstype; const char *rbdpool, *rbdname = n, *fstype;
uint64_t size; uint64_t size;
int ret, len; int ret, len;
char sz[24]; char sz[24];
pid_t pid;
const char *cmd_args[2]; const char *cmd_args[2];
char cmd_output[MAXPATHLEN]; char cmd_output[MAXPATHLEN];
const char *rbdname = n;
struct rbd_args args = {0};
if (!specs) if (!specs)
return -1; return -1;
...@@ -111,112 +66,91 @@ int rbd_create(struct bdev *bdev, const char *dest, const char *n, ...@@ -111,112 +66,91 @@ int rbd_create(struct bdev *bdev, const char *dest, const char *n,
rbdname = specs->rbd.rbdname; rbdname = specs->rbd.rbdname;
/* source device /dev/rbd/lxc/ctn */ /* source device /dev/rbd/lxc/ctn */
len = strlen(rbdpool) + strlen(rbdname) + 4 + 11; len = strlen(rbdpool) + strlen(rbdname) + 11;
bdev->src = malloc(len); bdev->src = malloc(len);
if (!bdev->src) { if (!bdev->src)
ERROR("Failed to allocate memory");
return -1; return -1;
}
ret = snprintf(bdev->src, len, "rbd:/dev/rbd/%s/%s", rbdpool, rbdname); ret = snprintf(bdev->src, len, "/dev/rbd/%s/%s", rbdpool, rbdname);
if (ret < 0 || ret >= len) { if (ret < 0 || ret >= len)
ERROR("Failed to create string");
return -1; return -1;
}
/* fssize is in bytes */ // fssize is in bytes.
size = specs->fssize; size = specs->fssize;
if (!size) if (!size)
size = DEFAULT_FS_SIZE; size = DEFAULT_FS_SIZE;
/* in megabytes for rbd tool */ // in megabytes for rbd tool
ret = snprintf(sz, 24, "%" PRIu64, size / 1024 / 1024); ret = snprintf(sz, 24, "%"PRIu64, size / 1024 / 1024 );
if (ret < 0 || ret >= 24) { if (ret < 0 || ret >= 24)
ERROR("Failed to create string"); exit(1);
return -1;
}
args.osd_pool_name = rbdpool; if ((pid = fork()) < 0)
args.rbd_name = rbdname;
args.size = sz;
ret = run_command(cmd_output, sizeof(cmd_output), rbd_create_wrapper,
(void *)&args);
if (ret < 0) {
ERROR("Failed to create rbd storage volume \"%s\": %s", rbdname,
cmd_output);
return -1; return -1;
if (!pid) {
execlp("rbd", "rbd", "create" , "--pool", rbdpool, rbdname, "--size", sz, (char *)NULL);
exit(1);
} }
if (wait_for_pid(pid) < 0)
return -1;
ret = run_command(cmd_output, sizeof(cmd_output), rbd_map_wrapper, if ((pid = fork()) < 0)
(void *)&args);
if (ret < 0) {
ERROR("Failed to map rbd storage volume \"%s\": %s", rbdname,
cmd_output);
return -1; return -1;
if (!pid) {
execlp("rbd", "rbd", "map", "--pool", rbdpool, rbdname, (char *)NULL);
exit(1);
} }
if (wait_for_pid(pid) < 0)
return -1;
fstype = specs->fstype; fstype = specs->fstype;
if (!fstype) if (!fstype)
fstype = DEFAULT_FSTYPE; fstype = DEFAULT_FSTYPE;
cmd_args[0] = fstype; cmd_args[0] = fstype;
cmd_args[1] = lxc_storage_get_path(bdev->src, bdev->type); cmd_args[1] = bdev->src;
ret = run_command(cmd_output, sizeof(cmd_output), do_mkfs_exec_wrapper, ret = run_command(cmd_output, sizeof(cmd_output), do_mkfs_exec_wrapper,
(void *)cmd_args); (void *)cmd_args);
if (ret < 0) { if (ret < 0)
ERROR("Failed to map rbd storage volume \"%s\": %s", rbdname,
cmd_output);
return -1; return -1;
}
bdev->dest = strdup(dest); if (!(bdev->dest = strdup(dest)))
if (!bdev->dest) {
ERROR("Failed to duplicate string \"%s\"", dest);
return -1; return -1;
}
ret = mkdir_p(bdev->dest, 0755); if (mkdir_p(bdev->dest, 0755) < 0 && errno != EEXIST) {
if (ret < 0 && errno != EEXIST) { ERROR("Error creating %s", bdev->dest);
ERROR("Failed to create directory \"%s\"", bdev->dest);
return -1; return -1;
} }
TRACE("Created rbd storage volume \"%s\"", bdev->dest);
return 0; return 0;
} }
int rbd_destroy(struct bdev *orig) int rbd_destroy(struct bdev *orig)
{ {
int ret; pid_t pid;
char *src;
char *rbdfullname; char *rbdfullname;
char cmd_output[MAXPATHLEN];
struct rbd_args args = {0};
src = lxc_storage_get_path(orig->src, orig->type); if ( file_exists(orig->src) ) {
if (file_exists(src)) { if ((pid = fork()) < 0)
args.rbd_name = src;
ret = run_command(cmd_output, sizeof(cmd_output),
rbd_unmap_wrapper, (void *)&args);
if (ret < 0) {
ERROR("Failed to map rbd storage volume \"%s\": %s",
src, cmd_output);
return -1; return -1;
if (!pid) {
execlp("rbd", "rbd", "unmap" , orig->src, (char *)NULL);
exit(1);
} }
if (wait_for_pid(pid) < 0)
return -1;
} }
rbdfullname = alloca(strlen(src) - 8); if ((pid = fork()) < 0)
strcpy(rbdfullname, &src[9]);
args.rbd_name = rbdfullname;
ret = run_command(cmd_output, sizeof(cmd_output),
rbd_delete_wrapper, (void *)&args);
if (ret < 0) {
ERROR("Failed to delete rbd storage volume \"%s\": %s",
rbdfullname, cmd_output);
return -1; return -1;
if (!pid) {
rbdfullname = alloca(strlen(orig->src) - 8);
strcpy( rbdfullname, &orig->src[9] );
execlp("rbd", "rbd", "rm" , rbdfullname, (char *)NULL);
exit(1);
} }
return wait_for_pid(pid);
return 0;
} }
int rbd_detect(const char *path) int rbd_detect(const char *path)
...@@ -228,33 +162,25 @@ int rbd_detect(const char *path) ...@@ -228,33 +162,25 @@ int rbd_detect(const char *path)
int rbd_mount(struct bdev *bdev) int rbd_mount(struct bdev *bdev)
{ {
char *src;
if (strcmp(bdev->type, "rbd")) if (strcmp(bdev->type, "rbd"))
return -22; return -22;
if (!bdev->src || !bdev->dest) if (!bdev->src || !bdev->dest)
return -22; return -22;
src = lxc_storage_get_path(bdev->src, bdev->type); if ( !file_exists(bdev->src) ) {
if (!file_exists(src)) { // if blkdev does not exist it should be mapped, because it is not persistent on reboot
/* If blkdev does not exist it should be mapped, because it is
* not persistent on reboot.
*/
ERROR("Block device %s is not mapped.", bdev->src); ERROR("Block device %s is not mapped.", bdev->src);
return -1; return -1;
} }
return mount_unknown_fs(src, bdev->dest, bdev->mntopts); return mount_unknown_fs(bdev->src, bdev->dest, bdev->mntopts);
} }
int rbd_umount(struct bdev *bdev) int rbd_umount(struct bdev *bdev)
{ {
if (strcmp(bdev->type, "rbd")) if (strcmp(bdev->type, "rbd"))
return -22; return -22;
if (!bdev->src || !bdev->dest) if (!bdev->src || !bdev->dest)
return -22; return -22;
return umount(bdev->dest); return umount(bdev->dest);
} }
...@@ -140,81 +140,3 @@ int rsync_rootfs_wrapper(void *data) ...@@ -140,81 +140,3 @@ int rsync_rootfs_wrapper(void *data)
return rsync_rootfs(arg); return rsync_rootfs(arg);
} }
/* new helpers */
int lxc_rsync_exec_wrapper(void *data)
{
struct rsync_data *arg = data;
return lxc_rsync(arg);
}
int lxc_rsync_exec(const char *src, const char *dest)
{
int ret;
size_t l;
char *s;
l = strlen(src) + 2;
s = malloc(l);
if (!s)
return -1;
ret = snprintf(s, l, "%s", src);
if (ret < 0 || (size_t)ret >= l)
return -1;
s[l - 2] = '/';
s[l - 1] = '\0';
execlp("rsync", "rsync", "-aHXS", "--delete", s, dest, (char *)NULL);
return -1;
}
int lxc_rsync(struct rsync_data *data)
{
int ret;
struct bdev *orig = data->orig, *new = data->new;
char *dest, *src;
ret = unshare(CLONE_NEWNS);
if (ret < 0) {
SYSERROR("Failed to unshare CLONE_NEWNS");
return -1;
}
ret = detect_shared_rootfs();
if (ret) {
ret = mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL);
if (ret < 0)
SYSERROR("Failed to make \"/\" a slave mount");
}
ret = orig->ops->mount(orig);
if (ret < 0) {
ERROR("Failed mounting \"%s\" on \"%s\"", orig->src, orig->dest);
return -1;
}
ret = new->ops->mount(new);
if (ret < 0) {
ERROR("Failed mounting \"%s\" onto \"%s\"", new->src, new->dest);
return -1;
}
ret = lxc_switch_uid_gid(0, 0);
if (ret < 0)
return -1;
ret = lxc_setgroups(0, NULL);
if (ret < 0)
return -1;
src = lxc_storage_get_path(orig->dest, orig->type);
dest = lxc_storage_get_path(new->dest, new->type);
ret = lxc_rsync_exec(src, dest);
if (ret < 0) {
ERROR("Failed to rsync from \"%s\" into \"%s\"", src, dest);
return -1;
}
return 0;
}
...@@ -43,9 +43,4 @@ int rsync_delta(struct rsync_data_char *data); ...@@ -43,9 +43,4 @@ int rsync_delta(struct rsync_data_char *data);
int rsync_rootfs(struct rsync_data *data); int rsync_rootfs(struct rsync_data *data);
int rsync_rootfs_wrapper(void *data); int rsync_rootfs_wrapper(void *data);
/* new helpers */
extern int lxc_rsync_exec_wrapper(void *data);
extern int lxc_rsync_exec(const char *src, const char *dest);
extern int lxc_rsync(struct rsync_data *data);
#endif // __LXC_RSYNC_H #endif // __LXC_RSYNC_H
...@@ -85,23 +85,20 @@ int zfs_detect(const char *path) ...@@ -85,23 +85,20 @@ int zfs_detect(const char *path)
int zfs_mount(struct bdev *bdev) int zfs_mount(struct bdev *bdev)
{ {
int ret;
char *mntdata, *src;
unsigned long mntflags;
if (strcmp(bdev->type, "zfs")) if (strcmp(bdev->type, "zfs"))
return -22; return -22;
if (!bdev->src || !bdev->dest) if (!bdev->src || !bdev->dest)
return -22; return -22;
char *mntdata;
unsigned long mntflags;
if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) { if (parse_mntopts(bdev->mntopts, &mntflags, &mntdata) < 0) {
free(mntdata); free(mntdata);
return -22; return -22;
} }
src = lxc_storage_get_path(bdev->src, bdev->type); int ret = mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata);
ret = mount(src, bdev->dest, "bind", MS_BIND | MS_REC | mntflags, mntdata);
free(mntdata); free(mntdata);
return ret; return ret;
...@@ -208,7 +205,6 @@ int zfs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, ...@@ -208,7 +205,6 @@ int zfs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
const char *cname, const char *oldpath, const char *lxcpath, int snap, const char *cname, const char *oldpath, const char *lxcpath, int snap,
uint64_t newsize, struct lxc_conf *conf) uint64_t newsize, struct lxc_conf *conf)
{ {
char *origsrc, *newsrc;
int len, ret; int len, ret;
if (!orig->src || !orig->dest) if (!orig->src || !orig->dest)
...@@ -219,22 +215,19 @@ int zfs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, ...@@ -219,22 +215,19 @@ int zfs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
return -1; return -1;
} }
len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 4 + 3; len = strlen(lxcpath) + strlen(cname) + strlen("rootfs") + 3;
new->src = malloc(len); new->src = malloc(len);
if (!new->src) if (!new->src)
return -1; return -1;
ret = snprintf(new->src, len, "zfs:%s/%s/rootfs", lxcpath, cname); ret = snprintf(new->src, len, "%s/%s/rootfs", lxcpath, cname);
if (ret < 0 || ret >= len) if (ret < 0 || ret >= len)
return -1; return -1;
newsrc = lxc_storage_get_path(new->src, new->type); if ((new->dest = strdup(new->src)) == NULL)
new->dest = strdup(newsrc);
if (!new->dest)
return -1; return -1;
origsrc = lxc_storage_get_path(orig->src, orig->type); return zfs_clone(orig->src, new->src, oldname, cname, lxcpath, snap);
return zfs_clone(origsrc, newsrc, oldname, cname, lxcpath, snap);
} }
/* /*
...@@ -246,15 +239,14 @@ int zfs_destroy(struct bdev *orig) ...@@ -246,15 +239,14 @@ int zfs_destroy(struct bdev *orig)
{ {
pid_t pid; pid_t pid;
char output[MAXPATHLEN]; char output[MAXPATHLEN];
char *p, *src; char *p;
if ((pid = fork()) < 0) if ((pid = fork()) < 0)
return -1; return -1;
if (pid) if (pid)
return wait_for_pid(pid); return wait_for_pid(pid);
src = lxc_storage_get_path(orig->src, orig->type); if (!zfs_list_entry(orig->src, output, MAXPATHLEN)) {
if (!zfs_list_entry(src, output, MAXPATHLEN)) {
ERROR("Error: zfs entry for %s not found", orig->src); ERROR("Error: zfs entry for %s not found", orig->src);
return -1; return -1;
} }
...@@ -268,64 +260,41 @@ int zfs_destroy(struct bdev *orig) ...@@ -268,64 +260,41 @@ int zfs_destroy(struct bdev *orig)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
struct zfs_exec_args {
char *dataset;
char *options;
};
int zfs_create_exec_wrapper(void *args)
{
struct zfs_exec_args *zfs_args = args;
execlp("zfs", "zfs", "create", zfs_args->options, zfs_args->dataset,
(char *)NULL);
return -1;
}
int zfs_create(struct bdev *bdev, const char *dest, const char *n, int zfs_create(struct bdev *bdev, const char *dest, const char *n,
struct bdev_specs *specs) struct bdev_specs *specs)
{ {
const char *zfsroot; const char *zfsroot;
char cmd_output[MAXPATHLEN], dev[MAXPATHLEN], option[MAXPATHLEN]; char option[MAXPATHLEN];
int ret; int ret;
size_t len; pid_t pid;
struct zfs_exec_args cmd_args;
if (!specs || !specs->zfs.zfsroot) if (!specs || !specs->zfs.zfsroot)
zfsroot = lxc_global_config_value("lxc.bdev.zfs.root"); zfsroot = lxc_global_config_value("lxc.bdev.zfs.root");
else else
zfsroot = specs->zfs.zfsroot; zfsroot = specs->zfs.zfsroot;
bdev->dest = strdup(dest); if (!(bdev->dest = strdup(dest))) {
if (!bdev->dest) {
ERROR("No mount target specified or out of memory"); ERROR("No mount target specified or out of memory");
return -1; return -1;
} }
if (!(bdev->src = strdup(bdev->dest))) {
len = strlen(bdev->dest) + 1; ERROR("out of memory");
/* strlen("zfs:") */
len += 4;
bdev->src = malloc(len);
if (!bdev->src)
return -1;
ret = snprintf(bdev->src, len, "zfs:%s", bdev->dest);
if (ret < 0 || (size_t)ret >= len)
return -1; return -1;
}
ret = snprintf(option, MAXPATHLEN, "-omountpoint=%s", bdev->dest); ret = snprintf(option, MAXPATHLEN, "-omountpoint=%s", bdev->dest);
if (ret < 0 || ret >= MAXPATHLEN) if (ret < 0 || ret >= MAXPATHLEN)
return -1; return -1;
if ((pid = fork()) < 0)
return -1;
if (pid)
return wait_for_pid(pid);
char dev[MAXPATHLEN];
ret = snprintf(dev, MAXPATHLEN, "%s/%s", zfsroot, n); ret = snprintf(dev, MAXPATHLEN, "%s/%s", zfsroot, n);
if (ret < 0 || ret >= MAXPATHLEN) if (ret < 0 || ret >= MAXPATHLEN)
return -1; exit(EXIT_FAILURE);
cmd_args.options = option; execlp("zfs", "zfs", "create", option, dev, (char *)NULL);
cmd_args.dataset = dev; exit(EXIT_FAILURE);
ret = run_command(cmd_output, sizeof(cmd_output),
zfs_create_exec_wrapper, (void *)&cmd_args);
if (ret < 0)
ERROR("Failed to create zfs dataset \"%s\": %s", dev, cmd_output);
return ret;
} }
...@@ -129,10 +129,12 @@ bool attach_block_device(struct lxc_conf *conf) ...@@ -129,10 +129,12 @@ bool attach_block_device(struct lxc_conf *conf)
int blk_getsize(struct bdev *bdev, uint64_t *size) int blk_getsize(struct bdev *bdev, uint64_t *size)
{ {
int fd, ret; int fd, ret;
char *src; char *path = bdev->src;
src = lxc_storage_get_path(bdev->src, bdev->type); if (strcmp(bdev->type, "loop") == 0)
fd = open(src, O_RDONLY); path = bdev->src + 5;
fd = open(path, O_RDONLY);
if (fd < 0) if (fd < 0)
return -1; return -1;
...@@ -161,12 +163,15 @@ int detect_fs(struct bdev *bdev, char *type, int len) ...@@ -161,12 +163,15 @@ int detect_fs(struct bdev *bdev, char *type, int len)
size_t linelen; size_t linelen;
pid_t pid; pid_t pid;
FILE *f; FILE *f;
char *sp1, *sp2, *sp3, *srcdev, *line = NULL; char *sp1, *sp2, *sp3, *line = NULL;
char *srcdev;
if (!bdev || !bdev->src || !bdev->dest) if (!bdev || !bdev->src || !bdev->dest)
return -1; return -1;
srcdev = lxc_storage_get_path(bdev->src, bdev->type); srcdev = bdev->src;
if (strcmp(bdev->type, "loop") == 0)
srcdev = bdev->src + 5;
ret = pipe(p); ret = pipe(p);
if (ret < 0) if (ret < 0)
...@@ -415,7 +420,6 @@ bool unpriv_snap_allowed(struct bdev *b, const char *t, bool snap, ...@@ -415,7 +420,6 @@ bool unpriv_snap_allowed(struct bdev *b, const char *t, bool snap,
// overlayfs -- which is also allowed) // overlayfs -- which is also allowed)
if (strcmp(b->type, "dir") == 0 || if (strcmp(b->type, "dir") == 0 ||
strcmp(b->type, "aufs") == 0 || strcmp(b->type, "aufs") == 0 ||
strcmp(b->type, "overlay") == 0 ||
strcmp(b->type, "overlayfs") == 0 || strcmp(b->type, "overlayfs") == 0 ||
strcmp(b->type, "btrfs") == 0 || strcmp(b->type, "btrfs") == 0 ||
strcmp(b->type, "loop") == 0) strcmp(b->type, "loop") == 0)
...@@ -428,7 +432,6 @@ bool unpriv_snap_allowed(struct bdev *b, const char *t, bool snap, ...@@ -428,7 +432,6 @@ bool unpriv_snap_allowed(struct bdev *b, const char *t, bool snap,
// and loop. In particular, not zfs, btrfs, or lvm. // and loop. In particular, not zfs, btrfs, or lvm.
if (strcmp(t, "dir") == 0 || if (strcmp(t, "dir") == 0 ||
strcmp(t, "aufs") == 0 || strcmp(t, "aufs") == 0 ||
strcmp(t, "overlay") == 0 ||
strcmp(t, "overlayfs") == 0 || strcmp(t, "overlayfs") == 0 ||
strcmp(t, "btrfs") == 0 || strcmp(t, "btrfs") == 0 ||
strcmp(t, "loop") == 0) strcmp(t, "loop") == 0)
......
...@@ -3623,6 +3623,7 @@ int chown_mapped_root(char *path, struct lxc_conf *conf) ...@@ -3623,6 +3623,7 @@ int chown_mapped_root(char *path, struct lxc_conf *conf)
{ {
uid_t rootuid, rootgid; uid_t rootuid, rootgid;
unsigned long val; unsigned long val;
char *chownpath = path;
int hostuid, hostgid, ret; int hostuid, hostgid, ret;
struct stat sb; struct stat sb;
char map1[100], map2[100], map3[100], map4[100], map5[100]; char map1[100], map2[100], map3[100], map4[100], map5[100];
...@@ -3658,6 +3659,23 @@ int chown_mapped_root(char *path, struct lxc_conf *conf) ...@@ -3658,6 +3659,23 @@ int chown_mapped_root(char *path, struct lxc_conf *conf)
} }
rootgid = (gid_t)val; rootgid = (gid_t)val;
/*
* In case of overlay, we want only the writeable layer to be chowned
*/
if (strncmp(path, "overlayfs:", 10) == 0 || strncmp(path, "aufs:", 5) == 0) {
chownpath = strchr(path, ':');
if (!chownpath) {
ERROR("Bad overlay path: %s", path);
return -1;
}
chownpath = strchr(chownpath + 1, ':');
if (!chownpath) {
ERROR("Bad overlay path: %s", path);
return -1;
}
chownpath++;
}
path = chownpath;
if (hostuid == 0) { if (hostuid == 0) {
if (chown(path, rootuid, rootgid) < 0) { if (chown(path, rootuid, rootgid) < 0) {
ERROR("Error chowning %s", path); ERROR("Error chowning %s", path);
......
...@@ -1265,10 +1265,8 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_ ...@@ -1265,10 +1265,8 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_
exit(1); exit(1);
} }
} else { // TODO come up with a better way here! } else { // TODO come up with a better way here!
char *src;
free(bdev->dest); free(bdev->dest);
src = lxc_storage_get_path(bdev->src, bdev->type); bdev->dest = strdup(bdev->src);
bdev->dest = strdup(src);
} }
/* /*
...@@ -1433,7 +1431,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_ ...@@ -1433,7 +1431,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool need_
} }
/* execute */ /* execute */
execvp(tpath, newargv); execvp(tpath, newargv);
SYSERROR("Failed to execute template %s", tpath); SYSERROR("failed to execute template %s", tpath);
exit(1); exit(1);
} }
...@@ -3225,8 +3223,8 @@ static int clone_update_rootfs_wrapper(void *data) ...@@ -3225,8 +3223,8 @@ static int clone_update_rootfs_wrapper(void *data)
sudo lxc-clone -o o1 -n n1 -s -L|-fssize fssize -v|--vgname vgname \ sudo lxc-clone -o o1 -n n1 -s -L|-fssize fssize -v|--vgname vgname \
-p|--lvprefix lvprefix -t|--fstype fstype -B backingstore -p|--lvprefix lvprefix -t|--fstype fstype -B backingstore
-s [ implies overlay] -s [ implies overlayfs]
-s -B overlay -s -B overlayfs
-s -B aufs -s -B aufs
only rootfs gets converted (copied/snapshotted) on clone. only rootfs gets converted (copied/snapshotted) on clone.
...@@ -3600,7 +3598,7 @@ static int do_lxcapi_snapshot(struct lxc_container *c, const char *commentfile) ...@@ -3600,7 +3598,7 @@ static int do_lxcapi_snapshot(struct lxc_container *c, const char *commentfile)
if (bdev_is_dir(c->lxc_conf, c->lxc_conf->rootfs.path)) { if (bdev_is_dir(c->lxc_conf, c->lxc_conf->rootfs.path)) {
ERROR("Snapshot of directory-backed container requested."); ERROR("Snapshot of directory-backed container requested.");
ERROR("Making a copy-clone. If you do want snapshots, then"); ERROR("Making a copy-clone. If you do want snapshots, then");
ERROR("please create an aufs or overlay clone first, snapshot that"); ERROR("please create an aufs or overlayfs clone first, snapshot that");
ERROR("and keep the original container pristine."); ERROR("and keep the original container pristine.");
flags &= ~LXC_CLONE_SNAPSHOT | LXC_CLONE_MAYBE_SNAPSHOT; flags &= ~LXC_CLONE_SNAPSHOT | LXC_CLONE_MAYBE_SNAPSHOT;
} }
......
...@@ -171,7 +171,7 @@ static bool do_destroy(struct lxc_container *c) ...@@ -171,7 +171,7 @@ static bool do_destroy(struct lxc_container *c)
if (ret < 0 || ret >= MAXPATHLEN) if (ret < 0 || ret >= MAXPATHLEN)
return false; return false;
if (rmdir(path) < 0 && errno != ENOENT) { if (dir_exists(path)) {
if (!quiet) if (!quiet)
fprintf(stdout, "Destroying %s failed: %s has snapshots.\n", c->name, c->name); fprintf(stdout, "Destroying %s failed: %s has snapshots.\n", c->name, c->name);
return false; return false;
...@@ -271,7 +271,7 @@ static bool do_destroy_with_snapshots(struct lxc_container *c) ...@@ -271,7 +271,7 @@ static bool do_destroy_with_snapshots(struct lxc_container *c)
if (ret < 0 || ret >= MAXPATHLEN) if (ret < 0 || ret >= MAXPATHLEN)
return false; return false;
if (rmdir(path) < 0 && errno != ENOENT) if (dir_exists(path))
bret = c->destroy_with_snapshots(c); bret = c->destroy_with_snapshots(c);
else else
bret = do_destroy(c); bret = do_destroy(c);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment