[lvm-devel] RFC: Command line support to create sparse devices
Alasdair G Kergon
agk at redhat.com
Thu Apr 23 21:18:41 UTC 2009
Here's a quick patch I've thrown together to make it easier to create sparse
devices.
Usage is exactly like creating a snapshot except instead of providing
an origin LV you give the size of the virtual origin you want to use
with --virtualoriginsize. The name of the VG must still be provided
of course.
E.g.
lvcreate -s vg1 -L 400M --virtualoriginsize 1T
Comments?
Alasdair
--- tools/args.h 23 Apr 2009 16:56:22 -0000 1.62
+++ tools/args.h 23 Apr 2009 21:13:13 -0000
@@ -58,6 +58,7 @@
arg(unquoted_ARG, '\0', "unquoted", NULL, 0)
arg(rows_ARG, '\0', "rows", NULL, 0)
arg(dataalignment_ARG, '\0', "dataalignment", size_kb_arg, 0)
+arg(virtualoriginsize_ARG, '\0', "virtualoriginsize", size_mb_arg, 0)
/* Allow some variations */
arg(resizable_ARG, '\0', "resizable", yes_no_arg, 0)
--- tools/commands.h 23 Apr 2009 16:56:22 -0000 1.124
+++ tools/commands.h 23 Apr 2009 21:13:13 -0000
@@ -162,6 +162,7 @@
"\t[-r|--readahead ReadAheadSectors|auto|none]\n"
"\t[-t|--test]\n"
"\t[-v|--verbose]\n"
+ "\t[--virtualoriginsize VirtualOriginSize]\n"
"\t[--version]\n"
"\tOriginalLogicalVolume[Path] [PhysicalVolumePath...]\n\n",
@@ -169,7 +170,7 @@
corelog_ARG, extents_ARG, major_ARG, minor_ARG, mirrorlog_ARG, mirrors_ARG,
name_ARG, nosync_ARG, permission_ARG, persistent_ARG, readahead_ARG,
regionsize_ARG, size_ARG, snapshot_ARG, stripes_ARG, stripesize_ARG,
- test_ARG, type_ARG, zero_ARG)
+ test_ARG, type_ARG, virtualoriginsize_ARG, zero_ARG)
xx(lvdisplay,
"Display information about a logical volume",
--- tools/lvcreate.c 21 Apr 2009 14:31:58 -0000 1.182
+++ tools/lvcreate.c 23 Apr 2009 21:13:13 -0000
@@ -43,6 +43,8 @@
/* size */
uint32_t extents;
uint64_t size;
+ uint32_t voriginextents;
+ uint64_t voriginsize;
percent_t percent;
uint32_t permission;
@@ -64,7 +66,7 @@
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,19 @@
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, size_ARG, UINT64_C(0));
+ if (!lp->voriginsize) {
+ log_error("Virtual origin size may not be zero");
+ return 0;
+ }
+ }
+
return 1;
}
@@ -390,6 +405,10 @@
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 +530,73 @@
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 +642,14 @@
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 (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->size &&
+ !(lp->extents = _extents_from_size(cmd, lp->size, vg->extent_size)))
+ return_0;
+
+ if (lp->voriginsize &&
+ !(lp->voriginextents = _extents_from_size(cmd, lp->size,
+ vg->extent_size)))
+ return_0;
/*
* Create the pv list.
@@ -645,37 +711,44 @@
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_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 +901,15 @@
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,
--- tools/toollib.c 23 Apr 2009 16:45:30 -0000 1.151
+++ tools/toollib.c 23 Apr 2009 21:13:13 -0000
@@ -1229,6 +1229,12 @@
return 0;
}
+ if (strstr(name, "_vorigin")) {
+ log_error("Names including \"_vorigin\" are reserved. "
+ "Please choose a different LV name.");
+ return 0;
+ }
+
return 1;
}
More information about the lvm-devel
mailing list