summaryrefslogtreecommitdiffstats
path: root/tools/lvcreate.c
diff options
context:
space:
mode:
authorAlasdair Kergon <agk@redhat.com>2009-04-25 01:17:59 +0000
committerAlasdair Kergon <agk@redhat.com>2009-04-25 01:17:59 +0000
commit87f42fda5eddb8c8fed00bb51ac4ec6619232b3e (patch)
tree0f84ddfef8da35a7c317b9197145fcb39ac2e990 /tools/lvcreate.c
parent7f54ef36dcd495ffd87690a3240d9987e7a04ca7 (diff)
downloadlvm2-87f42fda5eddb8c8fed00bb51ac4ec6619232b3e.tar.gz
lvm2-87f42fda5eddb8c8fed00bb51ac4ec6619232b3e.tar.xz
lvm2-87f42fda5eddb8c8fed00bb51ac4ec6619232b3e.zip
Add sparse devices: lvcreate -s --virtualoriginsize (hidden zero origin).
Add lvs origin_size field. Fix linux configure --enable-debug to exclude -O2. Still a few rough edges, but hopefully usable now: lvcreate -s vg1 -L 100M --virtualoriginsize 1T
Diffstat (limited to 'tools/lvcreate.c')
-rw-r--r--tools/lvcreate.c186
1 files changed, 137 insertions, 49 deletions
diff --git a/tools/lvcreate.c b/tools/lvcreate.c
index 78dc6b3a..8975470a 100644
--- a/tools/lvcreate.c
+++ b/tools/lvcreate.c
@@ -43,6 +43,8 @@ struct lvcreate_params {
/* size */
uint32_t extents;
uint64_t size;
+ uint32_t voriginextents;
+ uint64_t voriginsize;
percent_t percent;
uint32_t permission;
@@ -64,7 +66,7 @@ static int _lvcreate_name_params(struct lvcreate_params *lp,
if (arg_count(cmd, name_ARG))
lp->lv_name = arg_value(cmd, name_ARG);
- if (lp->snapshot) {
+ if (lp->snapshot && !arg_count(cmd, virtualoriginsize_ARG)) {
if (!argc) {
log_err("Please specify a logical volume to act as "
"the snapshot origin.");
@@ -175,6 +177,20 @@ static int _read_size_params(struct lvcreate_params *lp,
lp->percent = PERCENT_NONE;
}
+ /* Size returned in kilobyte units; held in sectors */
+ if (arg_count(cmd, virtualoriginsize_ARG)) {
+ if (arg_sign_value(cmd, virtualoriginsize_ARG, 0) == SIGN_MINUS) {
+ log_error("Negative virtual origin size is invalid");
+ return 0;
+ }
+ lp->voriginsize = arg_uint64_value(cmd, virtualoriginsize_ARG,
+ UINT64_C(0));
+ if (!lp->voriginsize) {
+ log_error("Virtual origin size may not be zero");
+ return 0;
+ }
+ }
+
return 1;
}
@@ -390,6 +406,10 @@ static int _lvcreate_params(struct lvcreate_params *lp, struct cmd_context *cmd,
log_error("-c is only available with snapshots");
return 0;
}
+ if (arg_count(cmd, virtualoriginsize_ARG)) {
+ log_error("--virtualoriginsize is only available with snapshots");
+ return 0;
+ }
}
if (lp->mirrors > 1) {
@@ -511,12 +531,73 @@ static int _lvcreate_params(struct lvcreate_params *lp, struct cmd_context *cmd,
return 1;
}
+static uint64_t _extents_from_size(struct cmd_context *cmd, uint64_t size,
+ uint32_t extent_size)
+{
+ if (size % extent_size) {
+ size += extent_size - size % extent_size;
+ log_print("Rounding up size to full physical extent %s",
+ display_size(cmd, size));
+ }
+
+ if (size > (uint64_t) UINT32_MAX * extent_size) {
+ log_error("Volume too large (%s) for extent size %s. "
+ "Upper limit is %s.",
+ display_size(cmd, size),
+ display_size(cmd, (uint64_t) extent_size),
+ display_size(cmd, (uint64_t) UINT32_MAX *
+ extent_size));
+ return 0;
+ }
+
+ return (uint64_t) size / extent_size;
+}
+
+static struct logical_volume *_create_virtual_origin(struct cmd_context *cmd,
+ struct volume_group *vg,
+ const char *lv_name,
+ uint32_t permission,
+ uint64_t voriginextents)
+{
+ const struct segment_type *segtype;
+ size_t len;
+ char *vorigin_name;
+ struct logical_volume *lv;
+
+ if (!(segtype = get_segtype_from_string(cmd, "zero"))) {
+ log_error("Zero segment type for virtual origin not found");
+ return 0;
+ }
+
+ len = strlen(lv_name) + 32;
+ if (!(vorigin_name = alloca(len)) ||
+ dm_snprintf(vorigin_name, len, "%s_vorigin", lv_name) < 0) {
+ log_error("Virtual origin name allocation failed.");
+ return 0;
+ }
+
+ if (!(lv = lv_create_empty(vorigin_name, NULL, permission,
+ ALLOC_INHERIT, 0, vg)))
+ return_0;
+
+ if (!lv_extend(lv, segtype, 1, 0, 1, voriginextents, NULL, 0u, 0u,
+ NULL, ALLOC_INHERIT))
+ return_0;
+
+ /* store vg on disk(s) */
+ if (!vg_write(vg) || !vg_commit(vg))
+ return_0;
+
+ backup(vg);
+
+ return lv;
+}
+
static int _lvcreate(struct cmd_context *cmd, struct volume_group *vg,
struct lvcreate_params *lp)
{
uint32_t size_rest;
uint32_t status = 0;
- uint64_t tmp_size;
struct logical_volume *lv, *org = NULL;
struct dm_list *pvh;
const char *tag = NULL;
@@ -562,28 +643,14 @@ static int _lvcreate(struct cmd_context *cmd, struct volume_group *vg,
return 0;
}
- if (lp->size) {
- /* No of 512-byte sectors */
- tmp_size = lp->size;
-
- if (tmp_size % vg->extent_size) {
- tmp_size += vg->extent_size - tmp_size %
- vg->extent_size;
- log_print("Rounding up size to full physical extent %s",
- display_size(cmd, tmp_size));
- }
+ if (lp->size &&
+ !(lp->extents = _extents_from_size(cmd, lp->size, vg->extent_size)))
+ return_0;
- if (tmp_size > (uint64_t) UINT32_MAX * vg->extent_size) {
- log_error("Volume too large (%s) for extent size %s. "
- "Upper limit is %s.",
- display_size(cmd, tmp_size),
- display_size(cmd, (uint64_t) vg->extent_size),
- display_size(cmd, (uint64_t) UINT32_MAX *
- vg->extent_size));
- return 0;
- }
- lp->extents = (uint64_t) tmp_size / vg->extent_size;
- }
+ if (lp->voriginsize &&
+ !(lp->voriginextents = _extents_from_size(cmd, lp->voriginsize,
+ vg->extent_size)))
+ return_0;
/*
* Create the pv list.
@@ -645,37 +712,49 @@ static int _lvcreate(struct cmd_context *cmd, struct volume_group *vg,
log_error("Clustered snapshots are not yet supported.");
return 0;
}
- if (!(org = find_lv(vg, lp->origin))) {
- log_err("Couldn't find origin volume '%s'.",
- lp->origin);
- return 0;
- }
- if (lv_is_cow(org)) {
- log_error("Snapshots of snapshots are not supported "
- "yet.");
- return 0;
- }
- if (org->status & LOCKED) {
- log_error("Snapshots of locked devices are not "
- "supported yet");
- return 0;
- }
- if (org->status & MIRROR_IMAGE ||
- org->status & MIRROR_LOG ||
- org->status & MIRRORED) {
- log_error("Snapshots and mirrors may not yet be mixed.");
- return 0;
- }
/* Must zero cow */
status |= LVM_WRITE;
- if (!lv_info(cmd, org, &info, 0, 0)) {
- log_error("Check for existence of snapshot origin "
- "'%s' failed.", org->name);
- return 0;
+ if (arg_count(cmd, virtualoriginsize_ARG))
+ origin_active = 1;
+ else {
+
+ if (!(org = find_lv(vg, lp->origin))) {
+ log_error("Couldn't find origin volume '%s'.",
+ lp->origin);
+ return 0;
+ }
+ if (lv_is_virtual_origin(lv)) {
+ log_error("Can't share virtual origins. "
+ "Use --virtualoriginsize.");
+ return 0;
+ }
+ if (lv_is_cow(org)) {
+ log_error("Snapshots of snapshots are not "
+ "supported yet.");
+ return 0;
+ }
+ if (org->status & LOCKED) {
+ log_error("Snapshots of locked devices are not "
+ "supported yet");
+ return 0;
+ }
+ if (org->status & MIRROR_IMAGE ||
+ org->status & MIRROR_LOG ||
+ org->status & MIRRORED) {
+ log_error("Snapshots and mirrors may not yet "
+ "be mixed.");
+ return 0;
+ }
+
+ if (!lv_info(cmd, org, &info, 0, 0)) {
+ log_error("Check for existence of snapshot "
+ "origin '%s' failed.", org->name);
+ return 0;
+ }
+ origin_active = info.exists;
}
- origin_active = info.exists;
}
if (!lp->extents) {
@@ -828,6 +907,15 @@ static int _lvcreate(struct cmd_context *cmd, struct volume_group *vg,
return 0;
}
+ if (lp->voriginsize &&
+ !(org = _create_virtual_origin(cmd, vg, lv->name,
+ lp->permission,
+ lp->voriginextents))) {
+ log_error("Couldn't create virtual origin for LV %s",
+ lv->name);
+ goto deactivate_and_revert_new_lv;
+ }
+
/* cow LV remains active and becomes snapshot LV */
if (!vg_add_snapshot(NULL, org, lv, NULL,