mirror of
git://github.com/lxc/lxc
synced 2025-09-01 06:01:39 +00:00
Add a --thinpool argument to lxc-create, to use thin pool backed lvm when creating the container. When cloning a container backed by a thin pool, the clone will default to the same thin pool.
This commit is contained in:
committed by
Serge Hallyn
parent
e0b6898ab4
commit
f99c386b60
@@ -80,7 +80,7 @@ struct lxc_arguments {
|
|||||||
char *bdevtype, *configfile, *template;
|
char *bdevtype, *configfile, *template;
|
||||||
char *fstype;
|
char *fstype;
|
||||||
unsigned long fssize;
|
unsigned long fssize;
|
||||||
char *lvname, *vgname;
|
char *lvname, *vgname, *thinpool;
|
||||||
char *zfsroot, *lowerdir, *dir;
|
char *zfsroot, *lowerdir, *dir;
|
||||||
|
|
||||||
/* remaining arguments */
|
/* remaining arguments */
|
||||||
|
@@ -816,7 +816,7 @@ static int lvm_umount(struct bdev *bdev)
|
|||||||
* not yet exist. This function will attempt to create /dev/$vg/$lv of
|
* not yet exist. This function will attempt to create /dev/$vg/$lv of
|
||||||
* size $size.
|
* size $size.
|
||||||
*/
|
*/
|
||||||
static int do_lvm_create(const char *path, unsigned long size)
|
static int do_lvm_create(const char *path, unsigned long size, const char *thinpool)
|
||||||
{
|
{
|
||||||
int ret, pid;
|
int ret, pid;
|
||||||
char sz[24], *pathdup, *vg, *lv;
|
char sz[24], *pathdup, *vg, *lv;
|
||||||
@@ -848,11 +848,61 @@ static int do_lvm_create(const char *path, unsigned long size)
|
|||||||
if (!vg)
|
if (!vg)
|
||||||
exit(1);
|
exit(1);
|
||||||
vg++;
|
vg++;
|
||||||
execlp("lvcreate", "lvcreate", "-L", sz, vg, "-n", lv, (char *)NULL);
|
if (!thinpool) {
|
||||||
|
execlp("lvcreate", "lvcreate", "-L", sz, vg, "-n", lv, (char *)NULL);
|
||||||
|
} else {
|
||||||
|
execlp("lvcreate", "lvcreate", "--thinpool", thinpool, "-V", sz, vg, "-n", lv, (char *)NULL);
|
||||||
|
}
|
||||||
free(pathdup);
|
free(pathdup);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int lvm_is_thin_volume(const char *path)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
int ret, len, start=0;
|
||||||
|
char *cmd, output[12];
|
||||||
|
const char *lvscmd = "lvs --unbuffered --noheadings -o lv_attr %s 2>/dev/null";
|
||||||
|
|
||||||
|
len = strlen(lvscmd) + strlen(path) - 1;
|
||||||
|
cmd = malloc(len);
|
||||||
|
if (!cmd)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
ret = snprintf(cmd, len, lvscmd, path);
|
||||||
|
if (ret < 0 || ret >= len)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
process_lock();
|
||||||
|
f = popen(cmd, "r");
|
||||||
|
process_unlock();
|
||||||
|
|
||||||
|
if (f == NULL) {
|
||||||
|
SYSERROR("popen failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fgets(output, 12, f) == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
process_lock();
|
||||||
|
ret = pclose(f);
|
||||||
|
process_unlock();
|
||||||
|
|
||||||
|
if (!WIFEXITED(ret)) {
|
||||||
|
SYSERROR("error executing lvs");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = strlen(output);
|
||||||
|
while(start < len && output[start] == ' ') start++;
|
||||||
|
|
||||||
|
if (start + 6 < len && output[start + 6] == 't')
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int lvm_snapshot(const char *orig, const char *path, unsigned long size)
|
static int lvm_snapshot(const char *orig, const char *path, unsigned long size)
|
||||||
{
|
{
|
||||||
int ret, pid;
|
int ret, pid;
|
||||||
@@ -882,7 +932,18 @@ static int lvm_snapshot(const char *orig, const char *path, unsigned long size)
|
|||||||
*lv = '\0';
|
*lv = '\0';
|
||||||
lv++;
|
lv++;
|
||||||
|
|
||||||
ret = execlp("lvcreate", "lvcreate", "-s", "-L", sz, "-n", lv, orig, (char *)NULL);
|
// check if the original lv is backed by a thin pool, in which case we
|
||||||
|
// cannot specify a size that's different from the original size.
|
||||||
|
ret = lvm_is_thin_volume(orig);
|
||||||
|
if (ret == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (!ret) {
|
||||||
|
ret = execlp("lvcreate", "lvcreate", "-s", "-L", sz, "-n", lv, orig, (char *)NULL);
|
||||||
|
} else {
|
||||||
|
ret = execlp("lvcreate", "lvcreate", "-s", "-n", lv, orig, (char *)NULL);
|
||||||
|
}
|
||||||
|
|
||||||
free(pathdup);
|
free(pathdup);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@@ -965,7 +1026,7 @@ static int lvm_clonepaths(struct bdev *orig, struct bdev *new, const char *oldna
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (do_lvm_create(new->src, size) < 0) {
|
if (do_lvm_create(new->src, size, NULL) < 0) {
|
||||||
ERROR("Error creating new lvm blockdev");
|
ERROR("Error creating new lvm blockdev");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -998,7 +1059,7 @@ static int lvm_destroy(struct bdev *orig)
|
|||||||
static int lvm_create(struct bdev *bdev, const char *dest, const char *n,
|
static int lvm_create(struct bdev *bdev, const char *dest, const char *n,
|
||||||
struct bdev_specs *specs)
|
struct bdev_specs *specs)
|
||||||
{
|
{
|
||||||
const char *vg, *fstype, *lv = n;
|
const char *vg, *thinpool, *fstype, *lv = n;
|
||||||
unsigned long sz;
|
unsigned long sz;
|
||||||
int ret, len;
|
int ret, len;
|
||||||
|
|
||||||
@@ -1009,6 +1070,8 @@ static int lvm_create(struct bdev *bdev, const char *dest, const char *n,
|
|||||||
if (!vg)
|
if (!vg)
|
||||||
vg = default_lvm_vg();
|
vg = default_lvm_vg();
|
||||||
|
|
||||||
|
thinpool = specs->u.lvm.thinpool;
|
||||||
|
|
||||||
/* /dev/$vg/$lv */
|
/* /dev/$vg/$lv */
|
||||||
if (specs->u.lvm.lv)
|
if (specs->u.lvm.lv)
|
||||||
lv = specs->u.lvm.lv;
|
lv = specs->u.lvm.lv;
|
||||||
@@ -1027,7 +1090,7 @@ static int lvm_create(struct bdev *bdev, const char *dest, const char *n,
|
|||||||
sz = DEFAULT_FS_SIZE;
|
sz = DEFAULT_FS_SIZE;
|
||||||
|
|
||||||
INFO("Error creating new lvm blockdev %s size %lu", bdev->src, sz);
|
INFO("Error creating new lvm blockdev %s size %lu", bdev->src, sz);
|
||||||
if (do_lvm_create(bdev->src, sz) < 0) {
|
if (do_lvm_create(bdev->src, sz, thinpool) < 0) {
|
||||||
ERROR("Error creating new lvm blockdev %s size %lu", bdev->src, sz);
|
ERROR("Error creating new lvm blockdev %s size %lu", bdev->src, sz);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@@ -46,6 +46,7 @@ struct bdev_specs {
|
|||||||
char *lv;
|
char *lv;
|
||||||
char *fstype;
|
char *fstype;
|
||||||
unsigned long fssize; // fs size in bytes
|
unsigned long fssize; // fs size in bytes
|
||||||
|
char *thinpool; // lvm thin pool to use, if any
|
||||||
} lvm;
|
} lvm;
|
||||||
struct {
|
struct {
|
||||||
char *fstype;
|
char *fstype;
|
||||||
|
@@ -31,6 +31,7 @@ struct lxc_config_items items[] =
|
|||||||
{
|
{
|
||||||
{ .name = "lxcpath", .fn = &lxc_get_default_config_path, },
|
{ .name = "lxcpath", .fn = &lxc_get_default_config_path, },
|
||||||
{ .name = "lvm_vg", .fn = &lxc_get_default_lvm_vg, },
|
{ .name = "lvm_vg", .fn = &lxc_get_default_lvm_vg, },
|
||||||
|
{ .name = "lvm_thin_pool", .fn = &lxc_get_default_lvm_thin_pool, },
|
||||||
{ .name = "zfsroot", .fn = &lxc_get_default_zfs_root, },
|
{ .name = "zfsroot", .fn = &lxc_get_default_zfs_root, },
|
||||||
{ .name = NULL, },
|
{ .name = NULL, },
|
||||||
};
|
};
|
||||||
|
@@ -64,10 +64,11 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg)
|
|||||||
case 't': args->template = arg; break;
|
case 't': args->template = arg; break;
|
||||||
case '0': args->lvname = arg; break;
|
case '0': args->lvname = arg; break;
|
||||||
case '1': args->vgname = arg; break;
|
case '1': args->vgname = arg; break;
|
||||||
case '2': args->fstype = arg; break;
|
case '2': args->thinpool = arg; break;
|
||||||
case '3': args->fssize = get_fssize(arg); break;
|
case '3': args->fstype = arg; break;
|
||||||
case '4': args->zfsroot = arg; break;
|
case '4': args->fssize = get_fssize(arg); break;
|
||||||
case '5': args->dir = arg; break;
|
case '5': args->zfsroot = arg; break;
|
||||||
|
case '6': args->dir = arg; break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -78,10 +79,11 @@ static const struct option my_longopts[] = {
|
|||||||
{"template", required_argument, 0, 't'},
|
{"template", required_argument, 0, 't'},
|
||||||
{"lvname", required_argument, 0, '0'},
|
{"lvname", required_argument, 0, '0'},
|
||||||
{"vgname", required_argument, 0, '1'},
|
{"vgname", required_argument, 0, '1'},
|
||||||
{"fstype", required_argument, 0, '2'},
|
{"thinpool", required_argument, 0, '2'},
|
||||||
{"fssize", required_argument, 0, '3'},
|
{"fstype", required_argument, 0, '3'},
|
||||||
{"zfsroot", required_argument, 0, '4'},
|
{"fssize", required_argument, 0, '4'},
|
||||||
{"dir", required_argument, 0, '5'},
|
{"zfsroot", required_argument, 0, '5'},
|
||||||
|
{"dir", required_argument, 0, '6'},
|
||||||
LXC_COMMON_OPTIONS
|
LXC_COMMON_OPTIONS
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -129,6 +131,8 @@ Options :\n\
|
|||||||
(Default: container name)\n\
|
(Default: container name)\n\
|
||||||
--vgname=VG Use LVM vg called VG\n\
|
--vgname=VG Use LVM vg called VG\n\
|
||||||
(Default: lxc))\n\
|
(Default: lxc))\n\
|
||||||
|
--thinpool=TP Use LVM thin pool called TP\n\
|
||||||
|
(Default: none))\n\
|
||||||
--fstype=TYPE Create fstype TYPE\n\
|
--fstype=TYPE Create fstype TYPE\n\
|
||||||
(Default: ext3))\n\
|
(Default: ext3))\n\
|
||||||
--fssize=SIZE Create filesystem of size SIZE\n\
|
--fssize=SIZE Create filesystem of size SIZE\n\
|
||||||
@@ -151,8 +155,8 @@ bool validate_bdev_args(struct lxc_arguments *a)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (strcmp(a->bdevtype, "lvm") != 0) {
|
if (strcmp(a->bdevtype, "lvm") != 0) {
|
||||||
if (a->lvname || a->vgname) {
|
if (a->lvname || a->vgname || a->thinpool) {
|
||||||
fprintf(stderr, "--lvname and --vgname are only valid with -B lvm\n");
|
fprintf(stderr, "--lvname, --vgname and --thinpool are only valid with -B lvm\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -221,6 +225,8 @@ int main(int argc, char *argv[])
|
|||||||
spec.u.lvm.lv = my_args.lvname;
|
spec.u.lvm.lv = my_args.lvname;
|
||||||
if (my_args.vgname)
|
if (my_args.vgname)
|
||||||
spec.u.lvm.vg = my_args.vgname;
|
spec.u.lvm.vg = my_args.vgname;
|
||||||
|
if (my_args.thinpool)
|
||||||
|
spec.u.lvm.thinpool = my_args.thinpool;
|
||||||
if (my_args.fstype)
|
if (my_args.fstype)
|
||||||
spec.u.lvm.fstype = my_args.fstype;
|
spec.u.lvm.fstype = my_args.fstype;
|
||||||
if (my_args.fssize)
|
if (my_args.fssize)
|
||||||
|
@@ -1807,6 +1807,11 @@ const char *lxc_get_default_lvm_vg(void)
|
|||||||
return default_lvm_vg();
|
return default_lvm_vg();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *lxc_get_default_lvm_thin_pool(void)
|
||||||
|
{
|
||||||
|
return default_lvm_thin_pool();
|
||||||
|
}
|
||||||
|
|
||||||
const char *lxc_get_default_zfs_root(void)
|
const char *lxc_get_default_zfs_root(void)
|
||||||
{
|
{
|
||||||
return default_zfs_root();
|
return default_zfs_root();
|
||||||
|
@@ -245,6 +245,7 @@ int lxc_container_put(struct lxc_container *c);
|
|||||||
int lxc_get_wait_states(const char **states);
|
int lxc_get_wait_states(const char **states);
|
||||||
const char *lxc_get_default_config_path(void);
|
const char *lxc_get_default_config_path(void);
|
||||||
const char *lxc_get_default_lvm_vg(void);
|
const char *lxc_get_default_lvm_vg(void);
|
||||||
|
const char *lxc_get_default_lvm_thin_pool(void);
|
||||||
const char *lxc_get_default_zfs_root(void);
|
const char *lxc_get_default_zfs_root(void);
|
||||||
const char *lxc_get_version(void);
|
const char *lxc_get_version(void);
|
||||||
|
|
||||||
|
@@ -243,6 +243,7 @@ const char *lxc_global_config_value(const char *option_name)
|
|||||||
{
|
{
|
||||||
static const char *options[][2] = {
|
static const char *options[][2] = {
|
||||||
{ "lvm_vg", DEFAULT_VG },
|
{ "lvm_vg", DEFAULT_VG },
|
||||||
|
{ "lvm_thin_pool", NULL },
|
||||||
{ "zfsroot", DEFAULT_ZFSROOT },
|
{ "zfsroot", DEFAULT_ZFSROOT },
|
||||||
{ "lxcpath", LXCPATH },
|
{ "lxcpath", LXCPATH },
|
||||||
{ "cgroup.pattern", DEFAULT_CGROUP_PATTERN },
|
{ "cgroup.pattern", DEFAULT_CGROUP_PATTERN },
|
||||||
@@ -326,6 +327,11 @@ const char *default_lvm_vg(void)
|
|||||||
return lxc_global_config_value("lvm_vg");
|
return lxc_global_config_value("lvm_vg");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *default_lvm_thin_pool(void)
|
||||||
|
{
|
||||||
|
return lxc_global_config_value("lvm_thin_pool");
|
||||||
|
}
|
||||||
|
|
||||||
const char *default_zfs_root(void)
|
const char *default_zfs_root(void)
|
||||||
{
|
{
|
||||||
return lxc_global_config_value("zfsroot");
|
return lxc_global_config_value("zfsroot");
|
||||||
|
@@ -48,6 +48,7 @@ extern const char *lxc_global_config_value(const char *option_name);
|
|||||||
extern const char *default_lxc_path(void);
|
extern const char *default_lxc_path(void);
|
||||||
extern const char *default_zfs_root(void);
|
extern const char *default_zfs_root(void);
|
||||||
extern const char *default_lvm_vg(void);
|
extern const char *default_lvm_vg(void);
|
||||||
|
extern const char *default_lvm_thin_pool(void);
|
||||||
|
|
||||||
/* Define getline() if missing from the C library */
|
/* Define getline() if missing from the C library */
|
||||||
#ifndef HAVE_GETLINE
|
#ifndef HAVE_GETLINE
|
||||||
|
Reference in New Issue
Block a user