Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for using thin provisioned lvm volumes when creating a container. #67

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/lxc/arguments.h
Expand Up @@ -80,7 +80,7 @@ struct lxc_arguments {
char *bdevtype, *configfile, *template;
char *fstype;
unsigned long fssize;
char *lvname, *vgname;
char *lvname, *vgname, *thinpool;
char *zfsroot, *lowerdir, *dir;

/* remaining arguments */
Expand Down
75 changes: 69 additions & 6 deletions src/lxc/bdev.c
Expand Up @@ -816,7 +816,7 @@ static int lvm_umount(struct bdev *bdev)
* not yet exist. This function will attempt to create /dev/$vg/$lv of
* 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;
char sz[24], *pathdup, *vg, *lv;
Expand Down Expand Up @@ -848,11 +848,61 @@ static int do_lvm_create(const char *path, unsigned long size)
if (!vg)
exit(1);
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);
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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why -1 here? The strlen() returns length not including final \0. So I think you actually want a +1 for a final \0. Am I thinking wrong?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'%s' is 2 chars long and gets replaced by path, so if I'm doing the math right then -1 is correct.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha!

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)
{
int ret, pid;
Expand Down Expand Up @@ -882,7 +932,18 @@ static int lvm_snapshot(const char *orig, const char *path, unsigned long size)
*lv = '\0';
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);
exit(1);
}
Expand Down Expand Up @@ -965,7 +1026,7 @@ static int lvm_clonepaths(struct bdev *orig, struct bdev *new, const char *oldna
return -1;
}
} else {
if (do_lvm_create(new->src, size) < 0) {
if (do_lvm_create(new->src, size, NULL) < 0) {
ERROR("Error creating new lvm blockdev");
return -1;
}
Expand Down Expand Up @@ -998,7 +1059,7 @@ static int lvm_destroy(struct bdev *orig)
static int lvm_create(struct bdev *bdev, const char *dest, const char *n,
struct bdev_specs *specs)
{
const char *vg, *fstype, *lv = n;
const char *vg, *thinpool, *fstype, *lv = n;
unsigned long sz;
int ret, len;

Expand All @@ -1009,6 +1070,8 @@ static int lvm_create(struct bdev *bdev, const char *dest, const char *n,
if (!vg)
vg = default_lvm_vg();

thinpool = specs->u.lvm.thinpool;

/* /dev/$vg/$lv */
if (specs->u.lvm.lv)
lv = specs->u.lvm.lv;
Expand All @@ -1027,7 +1090,7 @@ static int lvm_create(struct bdev *bdev, const char *dest, const char *n,
sz = DEFAULT_FS_SIZE;

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);
return -1;
}
Expand Down
1 change: 1 addition & 0 deletions src/lxc/bdev.h
Expand Up @@ -46,6 +46,7 @@ struct bdev_specs {
char *lv;
char *fstype;
unsigned long fssize; // fs size in bytes
char *thinpool; // lvm thin pool to use, if any
} lvm;
struct {
char *fstype;
Expand Down
1 change: 1 addition & 0 deletions src/lxc/lxc_config.c
Expand Up @@ -31,6 +31,7 @@ struct lxc_config_items items[] =
{
{ .name = "lxcpath", .fn = &lxc_get_default_config_path, },
{ .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 = NULL, },
};
Expand Down
26 changes: 16 additions & 10 deletions src/lxc/lxc_create.c
Expand Up @@ -64,10 +64,11 @@ static int my_parser(struct lxc_arguments* args, int c, char* arg)
case 't': args->template = arg; break;
case '0': args->lvname = arg; break;
case '1': args->vgname = arg; break;
case '2': args->fstype = arg; break;
case '3': args->fssize = get_fssize(arg); break;
case '4': args->zfsroot = arg; break;
case '5': args->dir = arg; break;
case '2': args->thinpool = arg; break;
case '3': args->fstype = arg; break;
case '4': args->fssize = get_fssize(arg); break;
case '5': args->zfsroot = arg; break;
case '6': args->dir = arg; break;
}
return 0;
}
Expand All @@ -78,10 +79,11 @@ static const struct option my_longopts[] = {
{"template", required_argument, 0, 't'},
{"lvname", required_argument, 0, '0'},
{"vgname", required_argument, 0, '1'},
{"fstype", required_argument, 0, '2'},
{"fssize", required_argument, 0, '3'},
{"zfsroot", required_argument, 0, '4'},
{"dir", required_argument, 0, '5'},
{"thinpool", required_argument, 0, '2'},
{"fstype", required_argument, 0, '3'},
{"fssize", required_argument, 0, '4'},
{"zfsroot", required_argument, 0, '5'},
{"dir", required_argument, 0, '6'},
LXC_COMMON_OPTIONS
};

Expand Down Expand Up @@ -129,6 +131,8 @@ Options :\n\
(Default: container name)\n\
--vgname=VG Use LVM vg called VG\n\
(Default: lxc))\n\
--thinpool=TP Use LVM thin pool called TP\n\
(Default: none))\n\
--fstype=TYPE Create fstype TYPE\n\
(Default: ext3))\n\
--fssize=SIZE Create filesystem of size SIZE\n\
Expand All @@ -151,8 +155,8 @@ bool validate_bdev_args(struct lxc_arguments *a)
}
}
if (strcmp(a->bdevtype, "lvm") != 0) {
if (a->lvname || a->vgname) {
fprintf(stderr, "--lvname and --vgname are only valid with -B lvm\n");
if (a->lvname || a->vgname || a->thinpool) {
fprintf(stderr, "--lvname, --vgname and --thinpool are only valid with -B lvm\n");
return false;
}
}
Expand Down Expand Up @@ -221,6 +225,8 @@ int main(int argc, char *argv[])
spec.u.lvm.lv = my_args.lvname;
if (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)
spec.u.lvm.fstype = my_args.fstype;
if (my_args.fssize)
Expand Down
5 changes: 5 additions & 0 deletions src/lxc/lxccontainer.c
Expand Up @@ -1807,6 +1807,11 @@ const char *lxc_get_default_lvm_vg(void)
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)
{
return default_zfs_root();
Expand Down
1 change: 1 addition & 0 deletions src/lxc/lxccontainer.h
Expand Up @@ -245,6 +245,7 @@ int lxc_container_put(struct lxc_container *c);
int lxc_get_wait_states(const char **states);
const char *lxc_get_default_config_path(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_version(void);

Expand Down
6 changes: 6 additions & 0 deletions src/lxc/utils.c
Expand Up @@ -243,6 +243,7 @@ const char *lxc_global_config_value(const char *option_name)
{
static const char *options[][2] = {
{ "lvm_vg", DEFAULT_VG },
{ "lvm_thin_pool", NULL },
{ "zfsroot", DEFAULT_ZFSROOT },
{ "lxcpath", LXCPATH },
{ "cgroup.pattern", DEFAULT_CGROUP_PATTERN },
Expand Down Expand Up @@ -326,6 +327,11 @@ const char *default_lvm_vg(void)
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)
{
return lxc_global_config_value("zfsroot");
Expand Down
1 change: 1 addition & 0 deletions src/lxc/utils.h
Expand Up @@ -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_zfs_root(void);
extern const char *default_lvm_vg(void);
extern const char *default_lvm_thin_pool(void);

/* Define getline() if missing from the C library */
#ifndef HAVE_GETLINE
Expand Down