bdev: non-functional changes

parent b9986e43
...@@ -75,110 +75,110 @@ lxc_log_define(bdev, lxc); ...@@ -75,110 +75,110 @@ lxc_log_define(bdev, lxc);
/* aufs */ /* aufs */
static const struct bdev_ops aufs_ops = { static const struct bdev_ops aufs_ops = {
.detect = &aufs_detect, .detect = &aufs_detect,
.mount = &aufs_mount, .mount = &aufs_mount,
.umount = &aufs_umount, .umount = &aufs_umount,
.clone_paths = &aufs_clonepaths, .clone_paths = &aufs_clonepaths,
.destroy = &aufs_destroy, .destroy = &aufs_destroy,
.create = &aufs_create, .create = &aufs_create,
.can_snapshot = true, .can_snapshot = true,
.can_backup = true, .can_backup = true,
}; };
/* btrfs */ /* btrfs */
static const struct bdev_ops btrfs_ops = { static const struct bdev_ops btrfs_ops = {
.detect = &btrfs_detect, .detect = &btrfs_detect,
.mount = &btrfs_mount, .mount = &btrfs_mount,
.umount = &btrfs_umount, .umount = &btrfs_umount,
.clone_paths = &btrfs_clonepaths, .clone_paths = &btrfs_clonepaths,
.destroy = &btrfs_destroy, .destroy = &btrfs_destroy,
.create = &btrfs_create, .create = &btrfs_create,
.can_snapshot = true, .can_snapshot = true,
.can_backup = true, .can_backup = true,
}; };
/* dir */ /* dir */
static const struct bdev_ops dir_ops = { static const struct bdev_ops dir_ops = {
.detect = &dir_detect, .detect = &dir_detect,
.mount = &dir_mount, .mount = &dir_mount,
.umount = &dir_umount, .umount = &dir_umount,
.clone_paths = &dir_clonepaths, .clone_paths = &dir_clonepaths,
.destroy = &dir_destroy, .destroy = &dir_destroy,
.create = &dir_create, .create = &dir_create,
.can_snapshot = false, .can_snapshot = false,
.can_backup = true, .can_backup = true,
}; };
/* loop */ /* loop */
static const struct bdev_ops loop_ops = { static const struct bdev_ops loop_ops = {
.detect = &loop_detect, .detect = &loop_detect,
.mount = &loop_mount, .mount = &loop_mount,
.umount = &loop_umount, .umount = &loop_umount,
.clone_paths = &loop_clonepaths, .clone_paths = &loop_clonepaths,
.destroy = &loop_destroy, .destroy = &loop_destroy,
.create = &loop_create, .create = &loop_create,
.can_snapshot = false, .can_snapshot = false,
.can_backup = true, .can_backup = true,
}; };
/* lvm */ /* lvm */
static const struct bdev_ops lvm_ops = { static const struct bdev_ops lvm_ops = {
.detect = &lvm_detect, .detect = &lvm_detect,
.mount = &lvm_mount, .mount = &lvm_mount,
.umount = &lvm_umount, .umount = &lvm_umount,
.clone_paths = &lvm_clonepaths, .clone_paths = &lvm_clonepaths,
.destroy = &lvm_destroy, .destroy = &lvm_destroy,
.create = &lvm_create, .create = &lvm_create,
.can_snapshot = true, .can_snapshot = true,
.can_backup = false, .can_backup = false,
}; };
/* nbd */ /* nbd */
const struct bdev_ops nbd_ops = { const struct bdev_ops nbd_ops = {
.detect = &nbd_detect, .detect = &nbd_detect,
.mount = &nbd_mount, .mount = &nbd_mount,
.umount = &nbd_umount, .umount = &nbd_umount,
.clone_paths = &nbd_clonepaths, .clone_paths = &nbd_clonepaths,
.destroy = &nbd_destroy, .destroy = &nbd_destroy,
.create = &nbd_create, .create = &nbd_create,
.can_snapshot = true, .can_snapshot = true,
.can_backup = false, .can_backup = false,
}; };
/* overlay */ /* overlay */
static const struct bdev_ops ovl_ops = { static const struct bdev_ops ovl_ops = {
.detect = &ovl_detect, .detect = &ovl_detect,
.mount = &ovl_mount, .mount = &ovl_mount,
.umount = &ovl_umount, .umount = &ovl_umount,
.clone_paths = &ovl_clonepaths, .clone_paths = &ovl_clonepaths,
.destroy = &ovl_destroy, .destroy = &ovl_destroy,
.create = &ovl_create, .create = &ovl_create,
.can_snapshot = true, .can_snapshot = true,
.can_backup = true, .can_backup = true,
}; };
/* rbd */ /* rbd */
static const struct bdev_ops rbd_ops = { static const struct bdev_ops rbd_ops = {
.detect = &rbd_detect, .detect = &rbd_detect,
.mount = &rbd_mount, .mount = &rbd_mount,
.umount = &rbd_umount, .umount = &rbd_umount,
.clone_paths = &rbd_clonepaths, .clone_paths = &rbd_clonepaths,
.destroy = &rbd_destroy, .destroy = &rbd_destroy,
.create = &rbd_create, .create = &rbd_create,
.can_snapshot = false, .can_snapshot = false,
.can_backup = false, .can_backup = false,
}; };
/* zfs */ /* zfs */
static const struct bdev_ops zfs_ops = { static const struct bdev_ops zfs_ops = {
.detect = &zfs_detect, .detect = &zfs_detect,
.mount = &zfs_mount, .mount = &zfs_mount,
.umount = &zfs_umount, .umount = &zfs_umount,
.clone_paths = &zfs_clonepaths, .clone_paths = &zfs_clonepaths,
.destroy = &zfs_destroy, .destroy = &zfs_destroy,
.create = &zfs_create, .create = &zfs_create,
.can_snapshot = true, .can_snapshot = true,
.can_backup = true, .can_backup = true,
}; };
struct bdev_type { struct bdev_type {
...@@ -187,32 +187,33 @@ struct bdev_type { ...@@ -187,32 +187,33 @@ struct bdev_type {
}; };
static const struct bdev_type bdevs[] = { static const struct bdev_type bdevs[] = {
{.name = "zfs", .ops = &zfs_ops,}, { .name = "zfs", .ops = &zfs_ops, },
{.name = "lvm", .ops = &lvm_ops,}, { .name = "lvm", .ops = &lvm_ops, },
{.name = "rbd", .ops = &rbd_ops,}, { .name = "rbd", .ops = &rbd_ops, },
{.name = "btrfs", .ops = &btrfs_ops,}, { .name = "btrfs", .ops = &btrfs_ops, },
{.name = "dir", .ops = &dir_ops,}, { .name = "dir", .ops = &dir_ops, },
{.name = "aufs", .ops = &aufs_ops,}, { .name = "aufs", .ops = &aufs_ops, },
{.name = "overlayfs", .ops = &ovl_ops,}, { .name = "overlayfs", .ops = &ovl_ops, },
{.name = "loop", .ops = &loop_ops,}, { .name = "loop", .ops = &loop_ops, },
{.name = "nbd", .ops = &nbd_ops,}, { .name = "nbd", .ops = &nbd_ops, },
}; };
static const size_t numbdevs = sizeof(bdevs) / sizeof(struct bdev_type); static const size_t numbdevs = sizeof(bdevs) / sizeof(struct bdev_type);
/* helpers */ /* helpers */
static const struct bdev_type *bdev_query(struct lxc_conf *conf, const char *src); static const struct bdev_type *bdev_query(struct lxc_conf *conf,
const char *src);
static struct bdev *bdev_get(const char *type); static struct bdev *bdev_get(const char *type);
static struct bdev *do_bdev_create(const char *dest, const char *type, static struct bdev *do_bdev_create(const char *dest, const char *type,
const char *cname, struct bdev_specs *specs); const char *cname, struct bdev_specs *specs);
static int find_fstype_cb(char *buffer, void *data); static int find_fstype_cb(char *buffer, void *data);
static char *linkderef(char *path, char *dest); static char *linkderef(char *path, char *dest);
static bool unpriv_snap_allowed(struct bdev *b, const char *t, bool snap, static bool unpriv_snap_allowed(struct bdev *b, const char *t, bool snap,
bool maybesnap); bool maybesnap);
/* the bulk of this needs to become a common helper */ /* the bulk of this needs to become a common helper */
char *dir_new_path(char *src, const char *oldname, const char *name, char *dir_new_path(char *src, const char *oldname, const char *name,
const char *oldpath, const char *lxcpath) const char *oldpath, const char *lxcpath)
{ {
char *ret, *p, *p2; char *ret, *p, *p2;
int l1, l2, nlen; int l1, l2, nlen;
...@@ -244,11 +245,12 @@ char *dir_new_path(char *src, const char *oldname, const char *name, ...@@ -244,11 +245,12 @@ char *dir_new_path(char *src, const char *oldname, const char *name,
while ((p2 = strstr(src, oldname)) != NULL) { while ((p2 = strstr(src, oldname)) != NULL) {
strncpy(p, src, p2 - src); // copy text up to oldname strncpy(p, src, p2 - src); // copy text up to oldname
p += p2 - src; // move target pointer (p) p += p2 - src; // move target pointer (p)
p += sprintf(p, "%s", name); // print new name in place of oldname p += sprintf(p, "%s",
src = p2 + l2; // move src to end of oldname name); // print new name in place of oldname
src = p2 + l2; // move src to end of oldname
} }
sprintf(p, "%s", src); // copy the rest of src sprintf(p, "%s", src); // copy the rest of src
return ret; return ret;
} }
...@@ -264,15 +266,19 @@ bool attach_block_device(struct lxc_conf *conf) ...@@ -264,15 +266,19 @@ bool attach_block_device(struct lxc_conf *conf)
if (!conf->rootfs.path) if (!conf->rootfs.path)
return true; return true;
path = conf->rootfs.path; path = conf->rootfs.path;
if (!requires_nbd(path)) if (!requires_nbd(path))
return true; return true;
path = strchr(path, ':'); path = strchr(path, ':');
if (!path) if (!path)
return false; return false;
path++; path++;
if (!attach_nbd(path, conf)) if (!attach_nbd(path, conf))
return false; return false;
return true; return true;
} }
...@@ -283,6 +289,7 @@ bool bdev_can_backup(struct lxc_conf *conf) ...@@ -283,6 +289,7 @@ bool bdev_can_backup(struct lxc_conf *conf)
if (!bdev) if (!bdev)
return false; return false;
ret = bdev->ops->can_backup; ret = bdev->ops->can_backup;
bdev_put(bdev); bdev_put(bdev);
return ret; return ret;
...@@ -293,8 +300,8 @@ bool bdev_can_backup(struct lxc_conf *conf) ...@@ -293,8 +300,8 @@ bool bdev_can_backup(struct lxc_conf *conf)
* the original, mount the new, and rsync the contents. * the original, mount the new, and rsync the contents.
*/ */
struct bdev *bdev_copy(struct lxc_container *c0, const char *cname, struct bdev *bdev_copy(struct lxc_container *c0, const char *cname,
const char *lxcpath, const char *bdevtype, int flags, const char *lxcpath, const char *bdevtype, int flags,
const char *bdevdata, uint64_t newsize, int *needs_rdep) const char *bdevdata, uint64_t newsize, int *needs_rdep)
{ {
struct bdev *orig, *new; struct bdev *orig, *new;
pid_t pid; pid_t pid;
...@@ -311,8 +318,9 @@ struct bdev *bdev_copy(struct lxc_container *c0, const char *cname, ...@@ -311,8 +318,9 @@ struct bdev *bdev_copy(struct lxc_container *c0, const char *cname,
* we don't know how to come up with a new name * we don't know how to come up with a new name
*/ */
if (strstr(src, oldname) == NULL) { if (strstr(src, oldname) == NULL) {
ERROR("original rootfs path %s doesn't include container name %s", ERROR(
src, oldname); "original rootfs path %s doesn't include container name %s",
src, oldname);
return NULL; return NULL;
} }
...@@ -334,6 +342,7 @@ struct bdev *bdev_copy(struct lxc_container *c0, const char *cname, ...@@ -334,6 +342,7 @@ struct bdev *bdev_copy(struct lxc_container *c0, const char *cname,
bdev_put(orig); bdev_put(orig);
return NULL; return NULL;
} }
ret = snprintf(orig->dest, len, "%s/%s/rootfs", oldpath, oldname); ret = snprintf(orig->dest, len, "%s/%s/rootfs", oldpath, oldname);
if (ret < 0 || (size_t)ret >= len) { if (ret < 0 || (size_t)ret >= len) {
ERROR("rootfs path too long"); ERROR("rootfs path too long");
...@@ -341,9 +350,11 @@ struct bdev *bdev_copy(struct lxc_container *c0, const char *cname, ...@@ -341,9 +350,11 @@ struct bdev *bdev_copy(struct lxc_container *c0, const char *cname,
return NULL; return NULL;
} }
ret = stat(orig->dest, &sb); ret = stat(orig->dest, &sb);
if (ret < 0 && errno == ENOENT) if (ret < 0 && errno == ENOENT)
if (mkdir_p(orig->dest, 0755) < 0) if (mkdir_p(orig->dest, 0755) < 0)
WARN("Error creating '%s', continuing.", orig->dest); WARN("Error creating '%s', continuing.",
orig->dest);
} }
/* /*
...@@ -357,7 +368,8 @@ struct bdev *bdev_copy(struct lxc_container *c0, const char *cname, ...@@ -357,7 +368,8 @@ struct bdev *bdev_copy(struct lxc_container *c0, const char *cname,
/* /*
* If newtype is NULL and snapshot is set, then use overlayfs * If newtype is NULL and snapshot is set, then use overlayfs
*/ */
if (!bdevtype && !keepbdevtype && snap && strcmp(orig->type , "dir") == 0) if (!bdevtype && !keepbdevtype && snap &&
strcmp(orig->type, "dir") == 0)
bdevtype = "overlayfs"; bdevtype = "overlayfs";
if (am_unpriv() && !unpriv_snap_allowed(orig, bdevtype, snap, maybe_snap)) { if (am_unpriv() && !unpriv_snap_allowed(orig, bdevtype, snap, maybe_snap)) {
...@@ -368,23 +380,24 @@ struct bdev *bdev_copy(struct lxc_container *c0, const char *cname, ...@@ -368,23 +380,24 @@ struct bdev *bdev_copy(struct lxc_container *c0, const char *cname,
*needs_rdep = 0; *needs_rdep = 0;
if (bdevtype && strcmp(orig->type, "dir") == 0 && if (bdevtype && strcmp(orig->type, "dir") == 0 &&
(strcmp(bdevtype, "aufs") == 0 || (strcmp(bdevtype, "aufs") == 0 ||
strcmp(bdevtype, "overlayfs") == 0)) { strcmp(bdevtype, "overlayfs") == 0)) {
*needs_rdep = 1; *needs_rdep = 1;
} else if (snap && strcmp(orig->type, "lvm") == 0 && } else if (snap && strcmp(orig->type, "lvm") == 0 &&
!lvm_is_thin_volume(orig->src)) { !lvm_is_thin_volume(orig->src)) {
*needs_rdep = 1; *needs_rdep = 1;
} }
new = bdev_get(bdevtype ? bdevtype : orig->type); new = bdev_get(bdevtype ? bdevtype : orig->type);
if (!new) { if (!new) {
ERROR("no such block device type: %s", bdevtype ? bdevtype : orig->type); ERROR("no such block device type: %s",
bdevtype ? bdevtype : orig->type);
bdev_put(orig); bdev_put(orig);
return NULL; return NULL;
} }
if (new->ops->clone_paths(orig, new, oldname, cname, oldpath, lxcpath, if (new->ops->clone_paths(orig, new, oldname, cname, oldpath, lxcpath,
snap, newsize, c0->lxc_conf) < 0) { snap, newsize, c0->lxc_conf) < 0) {
ERROR("failed getting pathnames for cloned storage: %s", src); ERROR("failed getting pathnames for cloned storage: %s", src);
goto err; goto err;
} }
...@@ -397,11 +410,12 @@ struct bdev *bdev_copy(struct lxc_container *c0, const char *cname, ...@@ -397,11 +410,12 @@ struct bdev *bdev_copy(struct lxc_container *c0, const char *cname,
/* /*
* https://github.com/lxc/lxc/issues/131 * https://github.com/lxc/lxc/issues/131
* Use btrfs snapshot feature instead of rsync to restore if both orig and new are btrfs * Use btrfs snapshot feature instead of rsync to restore if both orig
* and new are btrfs
*/ */
if (bdevtype && if (bdevtype && strcmp(orig->type, "btrfs") == 0 &&
strcmp(orig->type, "btrfs") == 0 && strcmp(new->type, "btrfs") == 0 && strcmp(new->type, "btrfs") == 0 &&
btrfs_same_fs(orig->dest, new->dest) == 0) { btrfs_same_fs(orig->dest, new->dest) == 0) {
if (btrfs_destroy(new) < 0) { if (btrfs_destroy(new) < 0) {
ERROR("Error destroying %s subvolume", new->dest); ERROR("Error destroying %s subvolume", new->dest);
goto err; goto err;
...@@ -411,7 +425,8 @@ struct bdev *bdev_copy(struct lxc_container *c0, const char *cname, ...@@ -411,7 +425,8 @@ struct bdev *bdev_copy(struct lxc_container *c0, const char *cname,
goto err; goto err;
} }
if (btrfs_snapshot(orig->dest, new->dest) < 0) { if (btrfs_snapshot(orig->dest, new->dest) < 0) {
ERROR("Error restoring %s to %s", orig->dest, new->dest); ERROR("Error restoring %s to %s", orig->dest,
new->dest);
goto err; goto err;
} }
bdev_put(orig); bdev_put(orig);
...@@ -437,7 +452,8 @@ struct bdev *bdev_copy(struct lxc_container *c0, const char *cname, ...@@ -437,7 +452,8 @@ struct bdev *bdev_copy(struct lxc_container *c0, const char *cname,
data.orig = orig; data.orig = orig;
data.new = new; data.new = new;
if (am_unpriv()) if (am_unpriv())
ret = userns_exec_1(c0->lxc_conf, rsync_rootfs_wrapper, &data, "rsync_rootfs_wrapper"); ret = userns_exec_1(c0->lxc_conf, rsync_rootfs_wrapper, &data,
"rsync_rootfs_wrapper");
else else
ret = rsync_rootfs(&data); ret = rsync_rootfs(&data);
...@@ -461,7 +477,7 @@ err: ...@@ -461,7 +477,7 @@ err:
* @specs: details about the backing store to create, like fstype * @specs: details about the backing store to create, like fstype
*/ */
struct bdev *bdev_create(const char *dest, const char *type, const char *cname, struct bdev *bdev_create(const char *dest, const char *type, const char *cname,
struct bdev_specs *specs) struct bdev_specs *specs)
{ {
struct bdev *bdev; struct bdev *bdev;
char *best_options[] = {"btrfs", "zfs", "lvm", "dir", "rbd", NULL}; char *best_options[] = {"btrfs", "zfs", "lvm", "dir", "rbd", NULL};
...@@ -474,10 +490,13 @@ struct bdev *bdev_create(const char *dest, const char *type, const char *cname, ...@@ -474,10 +490,13 @@ struct bdev *bdev_create(const char *dest, const char *type, const char *cname,
// try for the best backing store type, according to our // try for the best backing store type, according to our
// opinionated preferences // opinionated preferences
for (i = 0; best_options[i]; i++) { for (i = 0; best_options[i]; i++) {
if ((bdev = do_bdev_create(dest, best_options[i], cname, specs))) if ((bdev = do_bdev_create(dest, best_options[i], cname,
specs)))
return bdev; return bdev;
} }
return NULL; // 'dir' should never fail, so this shouldn't happen
return NULL; // 'dir' should never fail, so this shouldn't
// happen
} }
// -B lvm,dir // -B lvm,dir
...@@ -485,7 +504,7 @@ struct bdev *bdev_create(const char *dest, const char *type, const char *cname, ...@@ -485,7 +504,7 @@ struct bdev *bdev_create(const char *dest, const char *type, const char *cname,
char *dup = alloca(strlen(type) + 1), *saveptr = NULL, *token; char *dup = alloca(strlen(type) + 1), *saveptr = NULL, *token;
strcpy(dup, type); strcpy(dup, type);
for (token = strtok_r(dup, ",", &saveptr); token; for (token = strtok_r(dup, ",", &saveptr); token;
token = strtok_r(NULL, ",", &saveptr)) { token = strtok_r(NULL, ",", &saveptr)) {
if ((bdev = do_bdev_create(dest, token, cname, specs))) if ((bdev = do_bdev_create(dest, token, cname, specs)))
return bdev; return bdev;
} }
...@@ -518,20 +537,23 @@ int bdev_destroy_wrapper(void *data) ...@@ -518,20 +537,23 @@ int bdev_destroy_wrapper(void *data)
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;
} }
if (!bdev_destroy(conf)) if (!bdev_destroy(conf))
return -1; return -1;
else
return 0; return 0;
} }
struct bdev *bdev_init(struct lxc_conf *conf, const char *src, const char *dst, struct bdev *bdev_init(struct lxc_conf *conf, const char *src, const char *dst,
const char *mntopts) const char *mntopts)
{ {
struct bdev *bdev; struct bdev *bdev;
const struct bdev_type *q; const struct bdev_type *q;
...@@ -549,6 +571,7 @@ struct bdev *bdev_init(struct lxc_conf *conf, const char *src, const char *dst, ...@@ -549,6 +571,7 @@ struct bdev *bdev_init(struct lxc_conf *conf, const char *src, const char *dst,
bdev = malloc(sizeof(struct bdev)); bdev = malloc(sizeof(struct bdev));
if (!bdev) if (!bdev)
return NULL; return NULL;
memset(bdev, 0, sizeof(struct bdev)); memset(bdev, 0, sizeof(struct bdev));
bdev->ops = q->ops; bdev->ops = q->ops;
bdev->type = q->name; bdev->type = q->name;
...@@ -620,7 +643,7 @@ void detach_block_device(struct lxc_conf *conf) ...@@ -620,7 +643,7 @@ void detach_block_device(struct lxc_conf *conf)
*/ */
int detect_fs(struct bdev *bdev, char *type, int len) int detect_fs(struct bdev *bdev, char *type, int len)
{ {
int p[2], ret; int p[2], ret;
size_t linelen; size_t linelen;
pid_t pid; pid_t pid;
FILE *f; FILE *f;
...@@ -637,8 +660,10 @@ int detect_fs(struct bdev *bdev, char *type, int len) ...@@ -637,8 +660,10 @@ int detect_fs(struct bdev *bdev, char *type, int len)
ret = pipe(p); ret = pipe(p);
if (ret < 0) if (ret < 0)
return -1; return -1;
if ((pid = fork()) < 0) if ((pid = fork()) < 0)
return -1; return -1;
if (pid > 0) { if (pid > 0) {
int status; int status;
close(p[1]); close(p[1]);
...@@ -664,7 +689,7 @@ int detect_fs(struct bdev *bdev, char *type, int len) ...@@ -664,7 +689,7 @@ int detect_fs(struct bdev *bdev, char *type, int len)
exit(1); exit(1);
if (detect_shared_rootfs()) { if (detect_shared_rootfs()) {
if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL)) { if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL)) {
SYSERROR("Failed to make / rslave"); SYSERROR("Failed to make / rslave");
ERROR("Continuing..."); ERROR("Continuing...");
} }
...@@ -672,9 +697,11 @@ int detect_fs(struct bdev *bdev, char *type, int len) ...@@ -672,9 +697,11 @@ int detect_fs(struct bdev *bdev, char *type, int len)
ret = mount_unknown_fs(srcdev, bdev->dest, bdev->mntopts); ret = mount_unknown_fs(srcdev, bdev->dest, bdev->mntopts);
if (ret < 0) { if (ret < 0) {
ERROR("failed mounting %s onto %s to detect fstype", srcdev, bdev->dest); ERROR("failed mounting %s onto %s to detect fstype", srcdev,
bdev->dest);
exit(1); exit(1);
} }
// if symlink, get the real dev name // if symlink, get the real dev name
char devpath[MAXPATHLEN]; char devpath[MAXPATHLEN];
char *l = linkderef(srcdev, devpath); char *l = linkderef(srcdev, devpath);
...@@ -683,6 +710,7 @@ int detect_fs(struct bdev *bdev, char *type, int len) ...@@ -683,6 +710,7 @@ int detect_fs(struct bdev *bdev, char *type, int len)
f = fopen("/proc/self/mounts", "r"); f = fopen("/proc/self/mounts", "r");
if (!f) if (!f)
exit(1); exit(1);
while (getline(&line, &linelen, f) != -1) { while (getline(&line, &linelen, f) != -1) {
sp1 = strchr(line, ' '); sp1 = strchr(line, ' ');
if (!sp1) if (!sp1)
...@@ -701,8 +729,10 @@ int detect_fs(struct bdev *bdev, char *type, int len) ...@@ -701,8 +729,10 @@ int detect_fs(struct bdev *bdev, char *type, int len)
sp2++; sp2++;
if (write(p[1], sp2, strlen(sp2)) != strlen(sp2)) if (write(p[1], sp2, strlen(sp2)) != strlen(sp2))
exit(1); exit(1);
exit(0); exit(0);
} }
exit(1); exit(1);
} }
...@@ -720,9 +750,10 @@ int do_mkfs(const char *path, const char *fstype) ...@@ -720,9 +750,10 @@ int do_mkfs(const char *path, const char *fstype)
// If the file is not a block device, we don't want mkfs to ask // If the file is not a block device, we don't want mkfs to ask
// us about whether to proceed. // us about whether to proceed.
if (null_stdfds() < 0) if (null_stdfds() < 0)
exit(1); exit(EXIT_FAILURE);
execlp("mkfs", "mkfs", "-t", fstype, path, (char *)NULL); execlp("mkfs", "mkfs", "-t", fstype, path, (char *)NULL);
exit(1); exit(EXIT_FAILURE);
} }
/* /*
...@@ -733,20 +764,23 @@ int is_blktype(struct bdev *b) ...@@ -733,20 +764,23 @@ int is_blktype(struct bdev *b)
{ {
if (strcmp(b->type, "lvm") == 0) if (strcmp(b->type, "lvm") == 0)
return 1; return 1;
return 0; return 0;
} }
int mount_unknown_fs(const char *rootfs, const char *target, int mount_unknown_fs(const char *rootfs, const char *target,
const char *options) const char *options)
{ {
size_t i;
int ret;
struct cbarg { struct cbarg {
const char *rootfs; const char *rootfs;
const char *target; const char *target;
const char *options; const char *options;
} cbarg = { } cbarg = {
.rootfs = rootfs, .rootfs = rootfs,
.target = target, .target = target,
.options = options, .options = options,
}; };
/* /*
...@@ -755,15 +789,11 @@ int mount_unknown_fs(const char *rootfs, const char *target, ...@@ -755,15 +789,11 @@ int mount_unknown_fs(const char *rootfs, const char *target,
* are auto-loaded and fall back to the supported kernel fs * are auto-loaded and fall back to the supported kernel fs
*/ */
char *fsfile[] = { char *fsfile[] = {
"/etc/filesystems", "/etc/filesystems",
"/proc/filesystems", "/proc/filesystems",
}; };
size_t i;
for (i = 0; i < sizeof(fsfile) / sizeof(fsfile[0]); i++) { for (i = 0; i < sizeof(fsfile) / sizeof(fsfile[0]); i++) {
int ret;
if (access(fsfile[i], F_OK)) if (access(fsfile[i], F_OK))
continue; continue;
...@@ -788,34 +818,38 @@ bool rootfs_is_blockdev(struct lxc_conf *conf) ...@@ -788,34 +818,38 @@ bool rootfs_is_blockdev(struct lxc_conf *conf)
int ret; int ret;
if (!conf->rootfs.path || strcmp(conf->rootfs.path, "/") == 0 || if (!conf->rootfs.path || strcmp(conf->rootfs.path, "/") == 0 ||
strlen(conf->rootfs.path) == 0) strlen(conf->rootfs.path) == 0)
return false; return false;
ret = stat(conf->rootfs.path, &st); ret = stat(conf->rootfs.path, &st);
if (ret == 0 && S_ISBLK(st.st_mode)) if (ret == 0 && S_ISBLK(st.st_mode))
return true; return true;
q = bdev_query(conf, conf->rootfs.path); q = bdev_query(conf, conf->rootfs.path);
if (!q) if (!q)
return false; return false;
if (strcmp(q->name, "lvm") == 0 || if (strcmp(q->name, "lvm") == 0 ||
strcmp(q->name, "loop") == 0 || strcmp(q->name, "loop") == 0 ||
strcmp(q->name, "nbd") == 0) strcmp(q->name, "nbd") == 0)
return true; return true;
return false; return false;
} }
static struct bdev *do_bdev_create(const char *dest, const char *type, static struct bdev *do_bdev_create(const char *dest, const char *type,
const char *cname, struct bdev_specs *specs) const char *cname, struct bdev_specs *specs)
{ {
struct bdev *bdev = bdev_get(type); struct bdev *bdev;
if (!bdev) {
bdev = bdev_get(type);
if (!bdev)
return NULL; return NULL;
}
if (bdev->ops->create(bdev, dest, cname, specs) < 0) { if (bdev->ops->create(bdev, dest, cname, specs) < 0) {
bdev_put(bdev); bdev_put(bdev);
return NULL; return NULL;
} }
return bdev; return bdev;
...@@ -830,14 +864,18 @@ static struct bdev *bdev_get(const char *type) ...@@ -830,14 +864,18 @@ static struct bdev *bdev_get(const char *type)
if (strcmp(bdevs[i].name, type) == 0) if (strcmp(bdevs[i].name, type) == 0)
break; break;
} }
if (i == numbdevs) if (i == numbdevs)
return NULL; return NULL;
bdev = malloc(sizeof(struct bdev)); bdev = malloc(sizeof(struct bdev));
if (!bdev) if (!bdev)
return NULL; return NULL;
memset(bdev, 0, sizeof(struct bdev)); memset(bdev, 0, sizeof(struct bdev));
bdev->ops = bdevs[i].ops; bdev->ops = bdevs[i].ops;
bdev->type = bdevs[i].name; bdev->type = bdevs[i].name;
return bdev; return bdev;
} }
...@@ -885,7 +923,7 @@ static const struct bdev_type *bdev_query(struct lxc_conf *conf, ...@@ -885,7 +923,7 @@ static const struct bdev_type *bdev_query(struct lxc_conf *conf,
* the callback system, they can be pulled from there eventually, so we * the callback system, they can be pulled from there eventually, so we
* don't need to pollute utils.c with these low level functions * don't need to pollute utils.c with these low level functions
*/ */
static int find_fstype_cb(char* buffer, void *data) static int find_fstype_cb(char *buffer, void *data)
{ {
struct cbarg { struct cbarg {
const char *rootfs; const char *rootfs;
...@@ -905,8 +943,8 @@ static int find_fstype_cb(char* buffer, void *data) ...@@ -905,8 +943,8 @@ static int find_fstype_cb(char* buffer, void *data)
fstype += lxc_char_left_gc(fstype, strlen(fstype)); fstype += lxc_char_left_gc(fstype, strlen(fstype));
fstype[lxc_char_right_gc(fstype, strlen(fstype))] = '\0'; fstype[lxc_char_right_gc(fstype, strlen(fstype))] = '\0';
DEBUG("trying to mount '%s'->'%s' with fstype '%s'", DEBUG("trying to mount '%s'->'%s' with fstype '%s'", cbarg->rootfs,
cbarg->rootfs, cbarg->target, fstype); cbarg->target, fstype);
if (parse_mntopts(cbarg->options, &mntflags, &mntdata) < 0) { if (parse_mntopts(cbarg->options, &mntflags, &mntdata) < 0) {
free(mntdata); free(mntdata);
...@@ -921,8 +959,8 @@ static int find_fstype_cb(char* buffer, void *data) ...@@ -921,8 +959,8 @@ static int find_fstype_cb(char* buffer, void *data)
free(mntdata); free(mntdata);
INFO("mounted '%s' on '%s', with fstype '%s'", INFO("mounted '%s' on '%s', with fstype '%s'", cbarg->rootfs,
cbarg->rootfs, cbarg->target, fstype); cbarg->target, fstype);
return 1; return 1;
} }
...@@ -935,8 +973,10 @@ static char *linkderef(char *path, char *dest) ...@@ -935,8 +973,10 @@ static char *linkderef(char *path, char *dest)
ret = stat(path, &sbuf); ret = stat(path, &sbuf);
if (ret < 0) if (ret < 0)
return NULL; return NULL;
if (!S_ISLNK(sbuf.st_mode)) if (!S_ISLNK(sbuf.st_mode))
return path; return path;
ret = readlink(path, dest, MAXPATHLEN); ret = readlink(path, dest, MAXPATHLEN);
if (ret < 0) { if (ret < 0) {
SYSERROR("error reading link %s", path); SYSERROR("error reading link %s", path);
...@@ -946,6 +986,7 @@ static char *linkderef(char *path, char *dest) ...@@ -946,6 +986,7 @@ static char *linkderef(char *path, char *dest)
return NULL; return NULL;
} }
dest[ret] = '\0'; dest[ret] = '\0';
return dest; return dest;
} }
...@@ -953,43 +994,46 @@ static char *linkderef(char *path, char *dest) ...@@ -953,43 +994,46 @@ static char *linkderef(char *path, char *dest)
* is an unprivileged user allowed to make this kind of snapshot * is an unprivileged user allowed to make this kind of snapshot
*/ */
static bool unpriv_snap_allowed(struct bdev *b, const char *t, bool snap, static bool unpriv_snap_allowed(struct bdev *b, const char *t, bool snap,
bool maybesnap) bool maybesnap)
{ {
if (!t) { if (!t) {
// new type will be same as original // new type will be same as original
// (unless snap && b->type == dir, in which case it will be // (unless snap && b->type == dir, in which case it will be
// 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, "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)
return true; return true;
return false; return false;
} }
// unprivileged users can copy and snapshot dir, overlayfs, // unprivileged users can copy and snapshot dir, overlayfs,
// 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, "overlayfs") == 0 || strcmp(t, "overlayfs") == 0 ||
strcmp(t, "btrfs") == 0 || strcmp(t, "btrfs") == 0 ||
strcmp(t, "loop") == 0) strcmp(t, "loop") == 0)
return true; return true;
return false; return false;
} }
bool is_valid_bdev_type(const char *type) bool is_valid_bdev_type(const char *type)
{ {
if (strcmp(type, "dir") == 0 || if (strcmp(type, "dir") == 0 ||
strcmp(type, "btrfs") == 0 || strcmp(type, "btrfs") == 0 ||
strcmp(type, "aufs") == 0 || strcmp(type, "aufs") == 0 ||
strcmp(type, "loop") == 0 || strcmp(type, "loop") == 0 ||
strcmp(type, "lvm") == 0 || strcmp(type, "lvm") == 0 ||
strcmp(type, "nbd") == 0 || strcmp(type, "nbd") == 0 ||
strcmp(type, "overlayfs") == 0 || strcmp(type, "overlayfs") == 0 ||
strcmp(type, "rbd") == 0 || strcmp(type, "rbd") == 0 ||
strcmp(type, "zfs") == 0) strcmp(type, "zfs") == 0)
return true; return true;
return false; return false;
} }
...@@ -23,17 +23,13 @@ ...@@ -23,17 +23,13 @@
#ifndef __LXC_BDEV_H #ifndef __LXC_BDEV_H
#define __LXC_BDEV_H #define __LXC_BDEV_H
/* blockdev operations for:
* aufs, dir, raw, btrfs, overlayfs, aufs, lvm, loop, zfs, nbd (qcow2, raw, vdi, qed)
*/
#include <lxc/lxccontainer.h> #include "config.h"
#include <stdint.h> #include <stdint.h>
#include <sys/mount.h> #include <sys/mount.h>
#include "config.h" #include <lxc/lxccontainer.h>
/* define constants if the kernel/glibc headers don't define them */
#ifndef MS_DIRSYNC #ifndef MS_DIRSYNC
#define MS_DIRSYNC 128 #define MS_DIRSYNC 128
#endif #endif
...@@ -71,20 +67,21 @@ struct bdev_ops { ...@@ -71,20 +67,21 @@ struct bdev_ops {
int (*umount)(struct bdev *bdev); int (*umount)(struct bdev *bdev);
int (*destroy)(struct bdev *bdev); int (*destroy)(struct bdev *bdev);
int (*create)(struct bdev *bdev, const char *dest, const char *n, int (*create)(struct bdev *bdev, const char *dest, const char *n,
struct bdev_specs *specs); struct bdev_specs *specs);
/* given original mount, rename the paths for cloned container */ /* given original mount, rename the paths for cloned container */
int (*clone_paths)(struct bdev *orig, struct bdev *new, const char *oldname, int (*clone_paths)(struct bdev *orig, struct bdev *new,
const char *cname, const char *oldpath, const char *lxcpath, const char *oldname, const char *cname,
int snap, uint64_t newsize, struct lxc_conf *conf); const char *oldpath, const char *lxcpath, int snap,
uint64_t newsize, struct lxc_conf *conf);
bool can_snapshot; bool can_snapshot;
bool can_backup; bool can_backup;
}; };
/* /*
* When lxc-start (conf.c) is mounting a rootfs, then src will be the * When lxc-start is mounting a rootfs, then src will be the "lxc.rootfs" value,
* 'lxc.rootfs' value, dest will be mount dir (i.e. $libdir/lxc) When clone * dest will be mount dir (i.e. $libdir/lxc) When clone or create is doing so,
* or create is doing so, then dest will be $lxcpath/$lxcname/rootfs, since * then dest will be $lxcpath/$lxcname/rootfs, since we may need to rsync from
* we may need to rsync from one to the other. * one to the other.
* data is so far unused. * data is so far unused.
*/ */
struct bdev { struct bdev {
...@@ -93,10 +90,10 @@ struct bdev { ...@@ -93,10 +90,10 @@ struct bdev {
char *src; char *src;
char *dest; char *dest;
char *mntopts; char *mntopts;
// turn the following into a union if need be /* Turn the following into a union if need be. */
// lofd is the open fd for the mounted loopback file /* lofd is the open fd for the mounted loopback file. */
int lofd; int lofd;
// index for the connected nbd device /* index for the connected nbd device. */
int nbd_idx; int nbd_idx;
}; };
...@@ -104,27 +101,27 @@ bool bdev_is_dir(struct lxc_conf *conf, const char *path); ...@@ -104,27 +101,27 @@ bool bdev_is_dir(struct lxc_conf *conf, const char *path);
bool bdev_can_backup(struct lxc_conf *conf); bool bdev_can_backup(struct lxc_conf *conf);
/* /*
* Instantiate a bdev object. The src is used to determine which blockdev * Instantiate a bdev object. The src is used to determine which blockdev type
* type this should be. The dst and data are optional, and will be used * this should be. The dst and data are optional, and will be used in case of
* in case of mount/umount. * mount/umount.
* *
* Optionally, src can be 'dir:/var/lib/lxc/c1' or 'lvm:/dev/lxc/c1'. For * Optionally, src can be 'dir:/var/lib/lxc/c1' or 'lvm:/dev/lxc/c1'. For
* other backing stores, this will allow additional options. In particular, * other backing stores, this will allow additional options. In particular,
* "overlayfs:/var/lib/lxc/canonical/rootfs:/var/lib/lxc/c1/delta" will mean * "overlayfs:/var/lib/lxc/canonical/rootfs:/var/lib/lxc/c1/delta" will mean
* use /var/lib/lxc/canonical/rootfs as lower dir, and /var/lib/lxc/c1/delta * use /var/lib/lxc/canonical/rootfs as lower dir, and /var/lib/lxc/c1/delta
* as the upper, writeable layer. * as the upper, writeable layer.
*/ */
struct bdev *bdev_init(struct lxc_conf *conf, const char *src, const char *dst, struct bdev *bdev_init(struct lxc_conf *conf, const char *src, const char *dst,
const char *data); const char *data);
struct bdev *bdev_copy(struct lxc_container *c0, const char *cname, struct bdev *bdev_copy(struct lxc_container *c0, const char *cname,
const char *lxcpath, const char *bdevtype, const char *lxcpath, const char *bdevtype, int flags,
int flags, const char *bdevdata, uint64_t newsize, const char *bdevdata, uint64_t newsize, int *needs_rdep);
int *needs_rdep); struct bdev *bdev_create(const char *dest, const char *type, const char *cname,
struct bdev *bdev_create(const char *dest, const char *type, struct bdev_specs *specs);
const char *cname, struct bdev_specs *specs);
void bdev_put(struct bdev *bdev); void bdev_put(struct bdev *bdev);
bool bdev_destroy(struct lxc_conf *conf); 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);
...@@ -139,6 +136,7 @@ int is_blktype(struct bdev *b); ...@@ -139,6 +136,7 @@ int is_blktype(struct bdev *b);
int mount_unknown_fs(const char *rootfs, const char *target, int mount_unknown_fs(const char *rootfs, const char *target,
const char *options); const char *options);
bool rootfs_is_blockdev(struct lxc_conf *conf); bool rootfs_is_blockdev(struct lxc_conf *conf);
/* /*
* these are really for qemu-nbd support, as container shutdown * these are really for qemu-nbd support, as container shutdown
* must explicitly request device detach. * must explicitly request device detach.
......
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