[lvm-devel] master - thin: lvresize supports pool metadata resize
Zdenek Kabelac
zkabelac at fedoraproject.org
Tue Jun 11 12:09:10 UTC 2013
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=87aca628d6b477ec4f0b6dac7d4895b31253a6e1
Commit: 87aca628d6b477ec4f0b6dac7d4895b31253a6e1
Parent: 72c3ae253e52b896795cc0769860c4fcd82ef244
Author: Zdenek Kabelac <zkabelac at redhat.com>
AuthorDate: Tue Jun 11 13:45:49 2013 +0200
Committer: Zdenek Kabelac <zkabelac at redhat.com>
CommitterDate: Tue Jun 11 14:05:20 2013 +0200
thin: lvresize supports pool metadata resize
Add support for lvresize of thin pool metadata device.
lvresize --poolmetadatasize +20 vgname/thinpool_lv
or
lvresize -L +20 vgname/thinpool_lv_tmeta
Where the second one allows all the args for resize (striping...)
and the first option resizes accoding to the last metadata lv segment.
---
WHATS_NEW | 1 +
man/lvcreate.8.in | 4 +-
man/lvresize.8.in | 9 +++
tools/commands.h | 10 +++-
tools/lvresize.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++------
5 files changed, 152 insertions(+), 23 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index 084738d..aecf227 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.99 -
===================================
+ Add lvresize support for online thin pool metadata volume resize.
Add helper functions find_pool_lv() and pool_can_resize_metadata().
Add detection for thin pool metadata resize kernel support.
Report lvs volume type 'e' with higher priority.
diff --git a/man/lvcreate.8.in b/man/lvcreate.8.in
index 3d675ae..ac5cf65 100644
--- a/man/lvcreate.8.in
+++ b/man/lvcreate.8.in
@@ -61,7 +61,7 @@ lvcreate \- create a logical volume in an existing volume group
.RB [ \-\-discards
.RI { ignore | nopassdown | passdown }]
.RB [ \-\-poolmetadatasize
-.IR ThinPoolMetadataSize [ bBsSkKmMgG ]]]
+.IR MetadataVolumeSize [ bBsSkKmMgG ]]]
.RB [ \-\-thinpool
.IR ThinPoolLogicalVolume { Name | Path }
.RB [ \-s | \-\-snapshot
@@ -271,7 +271,7 @@ Sets access permissions to read only (\fIr\fP) or read and write (\fIrw\fP).
.br
Default is read and write.
.TP
-.IR \fB\-\-poolmetadatasize " " ThinPoolMetadataSize [ bBsSkKmMgG ]
+.IR \fB\-\-poolmetadatasize " " MetadataVolumeSize [ bBsSkKmMgG ]
Sets the size of thin pool's metadata logical volume.
Supported values are in range between 2MiB and 16GiB.
Default value is (Pool_LV_size / Pool_LV_chunk_size * 64b).
diff --git a/man/lvresize.8.in b/man/lvresize.8.in
index 7e85993..e04869d 100644
--- a/man/lvresize.8.in
+++ b/man/lvresize.8.in
@@ -11,6 +11,8 @@ lvresize \- resize a logical volume
.RI [ + | \- ] LogicalExtentsNumber [ % { VG | LV | PVS | FREE | ORIGIN "}] |"
.RB [ \-L | \-\-size
.RI [ + | \- ] LogicalVolumeSize [ bBsSkKmMgGtTpPeE ]}
+.RB [ \-\-poolmetadatasize
+.RI [ + ] MetadataVolumeSize [ bBsSkKmMgG ]
.RB [ \-f | \-\-force ]
.RB [ \-n | \-\-nofsck ]
.RB [ \-r | \-\-resizefs ]
@@ -73,6 +75,13 @@ Defaults to whatever the last segment of the Logical Volume uses.
Not applicable to LVs using the original metadata LVM format, which must
use a single value throughout.
.TP
+.IR \fB\-\-poolmetadatasize " [" + ] MetadataVolumeSize [ bBsSkKmMgG ]
+Change or set the thin pool metadata logical volume size.
+With the \fI+\fP sign the value is added to the actual size
+of the metadata volume and rounded to the full extent size
+and without it, the value is taken as an absolute one.
+Maximal size is 16GiB. Default unit is megabytes.
+.TP
.BR \-I ", " \-\-stripesize " " \fIStripeSize
Gives the number of kilobytes for the granularity of the stripes.
Defaults to whatever the last segment of the Logical Volume uses.
diff --git a/tools/commands.h b/tools/commands.h
index 64d6d0d..2d99d5a 100644
--- a/tools/commands.h
+++ b/tools/commands.h
@@ -233,7 +233,7 @@ xx(lvcreate,
"\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
"\t{-l|--extents LogicalExtentsNumber[%{VG|FREE|ORIGIN}] |\n"
"\t -L|--size LogicalVolumeSize[bBsSkKmMgGtTpPeE]}\n"
- "\t[--poolmetadatasize Size[bBsSkKmMgG]]\n"
+ "\t[--poolmetadatasize MetadataVolumeSize[bBsSkKmMgG]]\n"
"\t[-M|--persistent {y|n}] [--major major] [--minor minor]\n"
"\t[-n|--name LogicalVolumeName]\n"
"\t[--noudevsync]\n"
@@ -308,6 +308,7 @@ xx(lvextend,
"\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
"\t{-l|--extents [+]LogicalExtentsNumber[%{VG|LV|PVS|FREE|ORIGIN}] |\n"
"\t -L|--size [+]LogicalVolumeSize[bBsSkKmMgGtTpPeE]}\n"
+ "\t --poolmetadatasize [+]MetadataVolumeSize[bBsSkKmMgG]}\n"
"\t[-m|--mirrors Mirrors]\n"
"\t[--nosync]\n"
"\t[--use-policies]\n"
@@ -321,7 +322,8 @@ xx(lvextend,
"\tLogicalVolume[Path] [ PhysicalVolumePath... ]\n",
alloc_ARG, autobackup_ARG, extents_ARG, force_ARG, mirrors_ARG,
- nofsck_ARG, nosync_ARG, noudevsync_ARG, resizefs_ARG, size_ARG, stripes_ARG,
+ nofsck_ARG, nosync_ARG, noudevsync_ARG, poolmetadatasize_ARG,
+ resizefs_ARG, size_ARG, stripes_ARG,
stripesize_ARG, test_ARG, type_ARG, use_policies_ARG)
xx(lvmchange,
@@ -437,6 +439,7 @@ xx(lvresize,
"\t[-i|--stripes Stripes [-I|--stripesize StripeSize]]\n"
"\t{-l|--extents [+|-]LogicalExtentsNumber[%{VG|LV|PVS|FREE|ORIGIN}] |\n"
"\t -L|--size [+|-]LogicalVolumeSize[bBsSkKmMgGtTpPeE]}\n"
+ "\t --poolmetadatasize [+]MetadataVolumeSize[bBsSkKmMgG]}\n"
"\t[-n|--nofsck]\n"
"\t[--noudevsync]\n"
"\t[-r|--resizefs]\n"
@@ -447,7 +450,8 @@ xx(lvresize,
"\tLogicalVolume[Path] [ PhysicalVolumePath... ]\n",
alloc_ARG, autobackup_ARG, extents_ARG, force_ARG, nofsck_ARG,
- noudevsync_ARG, resizefs_ARG, size_ARG, stripes_ARG, stripesize_ARG,
+ noudevsync_ARG, resizefs_ARG, poolmetadatasize_ARG,
+ size_ARG, stripes_ARG, stripesize_ARG,
test_ARG, type_ARG)
xx(lvs,
diff --git a/tools/lvresize.c b/tools/lvresize.c
index f552992..6de3b3b 100644
--- a/tools/lvresize.c
+++ b/tools/lvresize.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
- * Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2013 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -30,7 +30,10 @@ struct lvresize_params {
/* size */
uint32_t extents;
uint64_t size;
+ int sizeargs;
sign_t sign;
+ uint64_t poolmetadatasize;
+ sign_t poolmetadatasign;
percent_type_t percent;
enum {
@@ -192,6 +195,7 @@ static int _lvresize_params(struct cmd_context *cmd, int argc, char **argv,
int use_policy = arg_count(cmd, use_policies_ARG);
lp->sign = SIGN_NONE;
+ lp->poolmetadatasign = SIGN_NONE;
lp->resize = LV_ANY;
cmd_name = command_name(cmd);
@@ -211,13 +215,14 @@ static int _lvresize_params(struct cmd_context *cmd, int argc, char **argv,
* one or more PVs. Most likely, the intent was "resize this
* LV the best you can with these PVs"
*/
- if ((arg_count(cmd, extents_ARG) + arg_count(cmd, size_ARG) == 0) &&
- (argc >= 2)) {
+ lp->sizeargs = arg_count(cmd, extents_ARG) + arg_count(cmd, size_ARG);
+ if ((lp->sizeargs == 0) && (argc >= 2)) {
lp->extents = 100;
lp->percent = PERCENT_PVS;
lp->sign = SIGN_PLUS;
- } else if ((arg_count(cmd, extents_ARG) +
- arg_count(cmd, size_ARG) != 1)) {
+ } else if ((lp->sizeargs != 1) &&
+ ((lp->sizeargs == 2) ||
+ !arg_count(cmd, poolmetadatasize_ARG))) {
log_error("Please specify either size or extents but not "
"both.");
return 0;
@@ -235,6 +240,15 @@ static int _lvresize_params(struct cmd_context *cmd, int argc, char **argv,
lp->sign = arg_sign_value(cmd, size_ARG, SIGN_NONE);
lp->percent = PERCENT_NONE;
}
+
+ if (arg_count(cmd, poolmetadatasize_ARG)) {
+ lp->poolmetadatasize = arg_uint64_value(cmd, poolmetadatasize_ARG, 0);
+ lp->poolmetadatasign = arg_sign_value(cmd, poolmetadatasize_ARG, SIGN_NONE);
+ if (lp->poolmetadatasign == SIGN_MINUS) {
+ log_error("Can't reduce pool metadata size.");
+ return 0;
+ }
+ }
}
if (lp->resize == LV_EXTEND && lp->sign == SIGN_MINUS) {
@@ -242,7 +256,8 @@ static int _lvresize_params(struct cmd_context *cmd, int argc, char **argv,
return 0;
}
- if (lp->resize == LV_REDUCE && lp->sign == SIGN_PLUS) {
+ if (lp->resize == LV_REDUCE &&
+ ((lp->sign == SIGN_PLUS) || (lp->poolmetadatasign == SIGN_PLUS))) {
log_error("Positive sign not permitted - use lvextend");
return 0;
}
@@ -306,18 +321,23 @@ static int _adjust_policy_params(struct cmd_context *cmd,
if (lv_is_thin_pool(lv)) {
if (!lv_thin_pool_percent(lv, 1, &percent))
return_0;
- if (percent > policy_threshold) {
- /* FIXME: metadata resize support missing */
- log_error("Resize for %s/%s is not yet supported.",
- lp->vg_name, lp->lv_name);
- return ECMD_FAILED;
+ if ((PERCENT_0 < percent && percent <= PERCENT_100) &&
+ (percent > policy_threshold)) {
+ if (!pool_can_resize_metadata(lv)) {
+ log_error_once("Online metadata resize for %s/%s is not supported.",
+ lp->vg_name, lp->lv_name);
+ return 0;
+ }
+ lp->poolmetadatasize = (first_seg(lv)->metadata_lv->size *
+ policy_amount + 99) / 100;
+ lp->poolmetadatasign = SIGN_PLUS;
}
if (!lv_thin_pool_percent(lv, 0, &percent))
return_0;
if (!(PERCENT_0 < percent && percent <= PERCENT_100) ||
percent <= policy_threshold)
- return 1; /* nothing to do */
+ return 1;
} else {
if (!lv_snapshot_percent(lv, &percent))
return_0;
@@ -326,6 +346,7 @@ static int _adjust_policy_params(struct cmd_context *cmd,
}
lp->extents = policy_amount;
+ lp->sizeargs = (lp->extents) ? 1 : 0;
return 1;
}
@@ -358,6 +379,74 @@ static uint32_t lvseg_get_stripes(struct lv_segment *seg, uint32_t *stripesize)
return 0;
}
+static int _lvresize_poolmetadata(struct cmd_context *cmd, struct volume_group *vg,
+ struct lvresize_params *lp,
+ const struct logical_volume *pool_lv,
+ struct dm_list *pvh,
+ alloc_policy_t alloc)
+{
+ struct logical_volume *lv;
+ struct lv_segment *mseg;
+ uint32_t extents;
+ uint32_t seg_mirrors;
+
+ if (!pool_can_resize_metadata(pool_lv)) {
+ log_error("Support for online metadata resize not detected.");
+ return 0;
+ }
+
+ if (lp->poolmetadatasize % vg->extent_size) {
+ lp->poolmetadatasize += vg->extent_size -
+ (lp->poolmetadatasize % vg->extent_size);
+ log_print_unless_silent("Rounding pool metadata size to boundary between physical extents: %s",
+ display_size(cmd, lp->poolmetadatasize));
+ }
+
+ if (!(extents = extents_from_size(vg->cmd, lp->poolmetadatasize,
+ vg->extent_size)))
+ return_0;
+
+ lv = first_seg(pool_lv)->metadata_lv;
+ if (lp->poolmetadatasign == SIGN_PLUS) {
+ if (extents >= (MAX_EXTENT_COUNT - lv->le_count)) {
+ log_error("Unable to extend %s by %u extents, exceeds limit (%u).",
+ lv->name, lv->le_count, MAX_EXTENT_COUNT);
+ return 0;
+ }
+ extents += lv->le_count;
+ }
+
+ if (extents * vg->extent_size > DM_THIN_MAX_METADATA_SIZE) {
+ log_print_unless_silent("Rounding size to maximum supported size 16GiB "
+ "for metadata volume %s.", lv->name);
+ extents = (DM_THIN_MAX_METADATA_SIZE + vg->extent_size - 1) /
+ vg->extent_size;
+ }
+
+ if (extents == lv->le_count) {
+ log_print_unless_silent("Metadata volume %s has already %s.",
+ lv->name, display_size(cmd, lv->size));
+ return 2;
+ }
+
+ log_print_unless_silent("Extending logical volume %s to %s.",
+ lv->name,
+ display_size(cmd, (uint64_t) extents * vg->extent_size));
+ mseg = last_seg(lv);
+ seg_mirrors = lv_mirror_count(lv);
+ if (!lv_extend(lv,
+ mseg->segtype,
+ mseg->area_count / seg_mirrors,
+ mseg->stripe_size,
+ seg_mirrors,
+ mseg->region_size,
+ extents - lv->le_count, NULL,
+ pvh, alloc))
+ return_0;
+
+ return 1;
+}
+
static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
struct lvresize_params *lp)
{
@@ -485,6 +574,8 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
return ECMD_FAILED;
}
+ if (lp->sizeargs) { /* TODO: reindent or move to function */
+
switch(lp->percent) {
case PERCENT_VG:
lp->extents = percent_of_extents(lp->extents, vg->extent_count,
@@ -552,6 +643,11 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
}
if (lp->extents == lv->le_count) {
+ /* A bit of hack - but still may resize metadata */
+ if (lp->poolmetadatasize) {
+ lp->sizeargs = 0;
+ goto metadata_resize;
+ }
if (use_policy)
return ECMD_PROCESSED; /* Nothing to do. */
if (!lp->resizefs) {
@@ -778,6 +874,9 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
log_warn("Thin pool volumes do not have filesystem.");
lp->resizefs = 0;
}
+ } else if (lp->poolmetadatasize) {
+ log_error("--poolmetadatasize can be used only with thin pools.");
+ return ECMD_FAILED;
}
if ((lp->resize == LV_REDUCE) && lp->argc)
@@ -832,18 +931,34 @@ static int _lvresize(struct cmd_context *cmd, struct volume_group *vg,
return ECMD_FAILED;
}
+ /* If thin metadata, must suspend thin pool */
+ if (lv_is_thin_pool_metadata(lv)) {
+ if (!(lock_lv = find_pool_lv(lv)))
+ return_0;
+ /* If snapshot, must suspend all associated devices */
+ } else if (lv_is_cow(lv))
+ lock_lv = origin_from_cow(lv);
+ else
+ lock_lv = lv;
+
+ } /* lp->sizeargs */
+
+ if (lp->poolmetadatasize) {
+metadata_resize:
+ if (!(status = _lvresize_poolmetadata(cmd, vg, lp, lv, pvh, alloc))) {
+ stack;
+ return ECMD_FAILED;
+ } else if ((status == 2) && !lp->sizeargs)
+ return ECMD_PROCESSED;
+ lock_lv = lv;
+ }
+
/* store vg on disk(s) */
if (!vg_write(vg)) {
stack;
return ECMD_FAILED;
}
- /* If snapshot, must suspend all associated devices */
- if (lv_is_cow(lv))
- lock_lv = origin_from_cow(lv);
- else
- lock_lv = lv;
-
if (!suspend_lv(cmd, lock_lv)) {
log_error("Failed to suspend %s", lock_lv->name);
vg_revert(vg);
More information about the lvm-devel
mailing list