Skip to content

Loading…

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

Closed
wants to merge 3 commits into from

2 participants

@sidnei

Per issue #32, 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.

Sidnei da Silva 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.
8767fcb
@hallyn hallyn commented on the diff
src/lxc/bdev.c
((10 lines not shown))
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;
@hallyn LXC - Linux Containers member
hallyn added a note

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?

@sidnei
sidnei added a note

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

@hallyn LXC - Linux Containers member
hallyn added a note

Gotcha!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Sidnei da Silva added some commits
@sidnei sidnei closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Oct 18, 2013
  1. Add a --thinpool argument to lxc-create, to use thin pool backed lvm …

    Sidnei da Silva committed
    …when creating
    
    the container. When cloning a container backed by a thin pool, the clone will default
    to the same thin pool.
  2. Document the new --thinpool option

    Sidnei da Silva committed
  3. Allocate cmd string with alloca instead of malloc, close popen handle…

    Sidnei da Silva committed
    … if fgets fails.
Showing with 106 additions and 17 deletions.
  1. +3 −0 doc/lxc-create.sgml.in
  2. +1 −1 src/lxc/arguments.h
  3. +71 −6 src/lxc/bdev.c
  4. +1 −0 src/lxc/bdev.h
  5. +1 −0 src/lxc/lxc_config.c
  6. +16 −10 src/lxc/lxc_create.c
  7. +5 −0 src/lxc/lxccontainer.c
  8. +1 −0 src/lxc/lxccontainer.h
  9. +6 −0 src/lxc/utils.c
  10. +1 −0 src/lxc/utils.h
View
3 doc/lxc-create.sgml.in
@@ -143,6 +143,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
is the container name. <replaceable>--vgname vgname1</replaceable>
will create the LV in volume group <filename>vgname1</filename>
rather than the default, <filename>lxc</filename>.
+ <replaceable>--thinpool thinpool1</replaceable> will create the
+ LV as a thin-provisioned volume in the pool named
+ <filename>thinpool1</filename>.
<replaceable>--fstype FSTYPE</replaceable> will create an FSTYPE
filesystem on the LV, rather than the default, which is ext4.
<replaceable>--fssize SIZE</replaceable> will create a LV (and
View
2 src/lxc/arguments.h
@@ -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 */
View
77 src/lxc/bdev.c
@@ -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;
@@ -848,11 +848,63 @@ 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;
@hallyn LXC - Linux Containers member
hallyn added a note

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?

@sidnei
sidnei added a note

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

@hallyn LXC - Linux Containers member
hallyn added a note

Gotcha!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ cmd = alloca(len);
+
+ 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) {
+ process_lock();
+ (void) pclose(f);
+ process_unlock();
+ 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;
@@ -882,7 +934,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);
}
@@ -965,7 +1028,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;
}
@@ -998,7 +1061,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;
@@ -1009,6 +1072,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;
@@ -1027,7 +1092,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;
}
View
1 src/lxc/bdev.h
@@ -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;
View
1 src/lxc/lxc_config.c
@@ -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, },
};
View
26 src/lxc/lxc_create.c
@@ -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;
}
@@ -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
};
@@ -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\
@@ -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;
}
}
@@ -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)
View
5 src/lxc/lxccontainer.c
@@ -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();
View
1 src/lxc/lxccontainer.h
@@ -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);
View
6 src/lxc/utils.c
@@ -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 },
@@ -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");
View
1 src/lxc/utils.h
@@ -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
Something went wrong with that request. Please try again.