1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

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.
This commit is contained in:
Zdenek Kabelac 2013-06-11 13:45:49 +02:00
parent 72c3ae253e
commit 87aca628d6
5 changed files with 152 additions and 23 deletions

View File

@ -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.

View File

@ -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).

View File

@ -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.

View File

@ -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,

View File

@ -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);