mirror of
https://git.proxmox.com/git/mirror_lxc
synced 2025-08-07 22:35:31 +00:00
implement zfs bdev and clone
Signed-off-by: Serge Hallyn <serge.hallyn@ubuntu.com>
This commit is contained in:
parent
9be5377379
commit
3baa76fe36
177
src/lxc/bdev.c
177
src/lxc/bdev.c
@ -427,6 +427,182 @@ struct bdev_ops dir_ops = {
|
|||||||
.clone_paths = &dir_clonepaths,
|
.clone_paths = &dir_clonepaths,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// XXXXXXX zfs ops
|
||||||
|
// There are two ways we could do this. We could always specify the
|
||||||
|
// 'zfs device' (i.e. tank/lxc lxc/container) as rootfs. But instead
|
||||||
|
// (at least right now) we have lxc-create specify $lxcpath/$lxcname/rootfs
|
||||||
|
// as the mountpoint, so that it is always mounted.
|
||||||
|
//
|
||||||
|
// That means 'mount' is really never needed and could be noop, but for the
|
||||||
|
// sake of flexibility let's always bind-mount.
|
||||||
|
//
|
||||||
|
|
||||||
|
static int zfs_list_entry(const char *path, char *output)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
int found=0;
|
||||||
|
|
||||||
|
if ((f = popen("zfs list", "r")) == NULL) {
|
||||||
|
SYSERROR("popen failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
while (fgets(output, LXC_LOG_BUFFER_SIZE, f)) {
|
||||||
|
if (strstr(output, path)) {
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(void) pclose(f);
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int zfs_detect(const char *path)
|
||||||
|
{
|
||||||
|
char *output = malloc(LXC_LOG_BUFFER_SIZE);
|
||||||
|
int found;
|
||||||
|
|
||||||
|
if (!output) {
|
||||||
|
ERROR("out of memory");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
found = zfs_list_entry(path, output);
|
||||||
|
free(output);
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zfs_mount(struct bdev *bdev)
|
||||||
|
{
|
||||||
|
if (strcmp(bdev->type, "zfs"))
|
||||||
|
return -22;
|
||||||
|
if (!bdev->src || !bdev->dest)
|
||||||
|
return -22;
|
||||||
|
return mount(bdev->src, bdev->dest, "bind", MS_BIND | MS_REC, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int zfs_umount(struct bdev *bdev)
|
||||||
|
{
|
||||||
|
if (strcmp(bdev->type, "zfs"))
|
||||||
|
return -22;
|
||||||
|
if (!bdev->src || !bdev->dest)
|
||||||
|
return -22;
|
||||||
|
return umount(bdev->dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int zfs_clone(const char *opath, const char *npath, const char *oname,
|
||||||
|
const char *nname, const char *lxcpath, int snapshot)
|
||||||
|
{
|
||||||
|
// use the 'zfs list | grep opath' entry to get the zfsroot
|
||||||
|
char output[MAXPATHLEN], option[MAXPATHLEN], *p;
|
||||||
|
int ret;
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
if (zfs_list_entry(opath, output) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((p = index(output, ' ')) == NULL)
|
||||||
|
return -1;
|
||||||
|
*p = '\0';
|
||||||
|
if ((p = rindex(output, '/')) == NULL)
|
||||||
|
return -1;
|
||||||
|
*p = '\0';
|
||||||
|
|
||||||
|
ret = snprintf(option, MAXPATHLEN, "-omountpoint=%s/%s/rootfs",
|
||||||
|
lxcpath, nname);
|
||||||
|
if (ret < 0 || ret >= MAXPATHLEN)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// zfsroot is output up to ' '
|
||||||
|
// zfs create -omountpoint=$lxcpath/$lxcname $zfsroot/$nname
|
||||||
|
if (!snapshot) {
|
||||||
|
if ((pid = fork()) < 0)
|
||||||
|
return -1;
|
||||||
|
if (!pid) {
|
||||||
|
char dev[MAXPATHLEN];
|
||||||
|
ret = snprintf(dev, MAXPATHLEN, "%s/%s", output, nname);
|
||||||
|
if (ret < 0 || ret >= MAXPATHLEN)
|
||||||
|
exit(1);
|
||||||
|
return execlp("zfs", "zfs", "create", option, dev, NULL);
|
||||||
|
}
|
||||||
|
return wait_for_pid(pid);
|
||||||
|
} else {
|
||||||
|
// if snapshot, do
|
||||||
|
// 'zfs snapshot zfsroot/oname@nname
|
||||||
|
// zfs clone zfsroot/oname@nname zfsroot/nname
|
||||||
|
char path1[MAXPATHLEN], path2[MAXPATHLEN];
|
||||||
|
|
||||||
|
ret = snprintf(path1, MAXPATHLEN, "%s/%s@%s", output,
|
||||||
|
oname, nname);
|
||||||
|
if (ret < 0 || ret >= MAXPATHLEN)
|
||||||
|
return -1;
|
||||||
|
(void) snprintf(path2, MAXPATHLEN, "%s/%s", output, nname);
|
||||||
|
|
||||||
|
// if the snapshot exists, delete it
|
||||||
|
if ((pid = fork()) < 0)
|
||||||
|
return -1;
|
||||||
|
if (!pid) {
|
||||||
|
return execlp("zfs", "zfs", "destroy", path1, NULL);
|
||||||
|
}
|
||||||
|
// it probably doesn't exist so destroy probably will fail.
|
||||||
|
(void) wait_for_pid(pid);
|
||||||
|
|
||||||
|
// run first (snapshot) command
|
||||||
|
if ((pid = fork()) < 0)
|
||||||
|
return -1;
|
||||||
|
if (!pid) {
|
||||||
|
return execlp("zfs", "zfs", "snapshot", path1, NULL);
|
||||||
|
}
|
||||||
|
if (wait_for_pid(pid) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// run second (clone) command
|
||||||
|
if ((pid = fork()) < 0)
|
||||||
|
return -1;
|
||||||
|
if (!pid) {
|
||||||
|
return execlp("zfs", "zfs", "clone", option, path1, path2, NULL);
|
||||||
|
}
|
||||||
|
return wait_for_pid(pid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int zfs_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
|
||||||
|
const char *cname, const char *oldpath, const char *lxcpath, int snap,
|
||||||
|
unsigned long newsize)
|
||||||
|
{
|
||||||
|
if (!orig->src || !orig->dest)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (strcmp(orig->type, "zfs")) {
|
||||||
|
ERROR("zfs clone from %s backing store is not supported",
|
||||||
|
orig->type);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (orig->data) {
|
||||||
|
new->data = strdup(orig->data);
|
||||||
|
if (!new->data)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
new->dest = dir_new_path(orig->dest, oldname, cname, oldpath, lxcpath);
|
||||||
|
if (!new->dest)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
new->src = dir_new_path(orig->src, oldname, cname, oldpath, lxcpath);
|
||||||
|
if (!new->src)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return zfs_clone(orig->src, new->src, oldname, cname, lxcpath, snap);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct bdev_ops zfs_ops = {
|
||||||
|
.detect = &zfs_detect,
|
||||||
|
.mount = &zfs_mount,
|
||||||
|
.umount = &zfs_umount,
|
||||||
|
.clone_paths = &zfs_clonepaths,
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// LVM ops
|
// LVM ops
|
||||||
//
|
//
|
||||||
@ -1021,6 +1197,7 @@ struct bdev_ops overlayfs_ops = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct bdev_type bdevs[] = {
|
struct bdev_type bdevs[] = {
|
||||||
|
{.name = "zfs", .ops = &zfs_ops,},
|
||||||
{.name = "lvm", .ops = &lvm_ops,},
|
{.name = "lvm", .ops = &lvm_ops,},
|
||||||
{.name = "btrfs", .ops = &btrfs_ops,},
|
{.name = "btrfs", .ops = &btrfs_ops,},
|
||||||
{.name = "dir", .ops = &dir_ops,},
|
{.name = "dir", .ops = &dir_ops,},
|
||||||
|
Loading…
Reference in New Issue
Block a user