diff options
author | Alasdair Kergon <agk@redhat.com> | 2009-04-25 01:17:59 +0000 |
---|---|---|
committer | Alasdair Kergon <agk@redhat.com> | 2009-04-25 01:17:59 +0000 |
commit | 87f42fda5eddb8c8fed00bb51ac4ec6619232b3e (patch) | |
tree | 0f84ddfef8da35a7c317b9197145fcb39ac2e990 /tools/lvcreate.c | |
parent | 7f54ef36dcd495ffd87690a3240d9987e7a04ca7 (diff) | |
download | lvm2-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.c | 186 |
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, |