From: Sidnei da Silva Date: Mon, 19 Aug 2013 22:34:19 +0000 (-0300) Subject: Add a --thinpool argument to lxc-create, to use thin pool backed lvm when creating... X-Git-Tag: lxc-1.0.0.alpha2~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f99c386b60e7f635c2f95a2e3256f21e751fb50b;p=thirdparty%2Flxc.git 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. --- diff --git a/src/lxc/arguments.h b/src/lxc/arguments.h index 7da7d5fdc..dc2d117eb 100644 --- a/src/lxc/arguments.h +++ b/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 */ diff --git a/src/lxc/bdev.c b/src/lxc/bdev.c index b643bb7b5..bc8ec61a4 100644 --- a/src/lxc/bdev.c +++ b/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,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; + 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; @@ -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); } @@ -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; } @@ -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; @@ -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; @@ -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; } diff --git a/src/lxc/bdev.h b/src/lxc/bdev.h index a603d9e95..e10ea8e1c 100644 --- a/src/lxc/bdev.h +++ b/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; diff --git a/src/lxc/lxc_config.c b/src/lxc/lxc_config.c index c90be7dca..21bde6456 100644 --- a/src/lxc/lxc_config.c +++ b/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, }, }; diff --git a/src/lxc/lxc_create.c b/src/lxc/lxc_create.c index 98cca325b..15b104dda 100644 --- a/src/lxc/lxc_create.c +++ b/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) diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index 6f9787911..616c92d50 100644 --- a/src/lxc/lxccontainer.c +++ b/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(); diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h index 5901066a5..b7dc1a47f 100644 --- a/src/lxc/lxccontainer.h +++ b/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); diff --git a/src/lxc/utils.c b/src/lxc/utils.c index 12ed454af..11f5fb7b8 100644 --- a/src/lxc/utils.c +++ b/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"); diff --git a/src/lxc/utils.h b/src/lxc/utils.h index 87a914b9b..fc4676096 100644 --- a/src/lxc/utils.h +++ b/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