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

lvresize: support more resized LVs

Add code to support more LVs to be resized through a same code path
using a single lvresize_params struct.
(Now it's used for thin-pool metadata resize,
next user will be snapshot virtual resize).

Update code to adjust percent amount resize for use_policies.

Properly activate inactive thin-pool in case of any pool resize
as the command should not 'deffer' this operation to next activation.
This commit is contained in:
Zdenek Kabelac 2016-06-22 23:32:35 +02:00
parent d44e653fe1
commit 7092c6ba10
2 changed files with 125 additions and 107 deletions

View File

@ -1,5 +1,6 @@
Version 2.02.158 -
=================================
Pool metadata lvresize uses now same code as resize of normal volume.
Log system error when locking dir cannot be accessed.
Preserve monitoring status when updating thin-pool metadata.
Rerurn 0 (inactive) when status cannot be queried in _lv_active().

View File

@ -4439,7 +4439,7 @@ static int _fsadm_cmd(enum fsadm_cmd_e fcmd,
return exec_cmd(cmd, argv, status, 1);
}
static int _adjust_amount(dm_percent_t percent, int policy_threshold, int *policy_amount)
static uint32_t _adjust_amount(dm_percent_t percent, int policy_threshold, int policy_amount)
{
if (!(DM_PERCENT_0 < percent && percent <= DM_PERCENT_100) ||
percent <= (policy_threshold * DM_PERCENT_1))
@ -4452,18 +4452,18 @@ static int _adjust_amount(dm_percent_t percent, int policy_threshold, int *polic
percent = (percent / policy_threshold + (DM_PERCENT_1 - 1) / 100) / (DM_PERCENT_1 / 100) - 100;
/* Use it if current policy amount is smaller */
if (*policy_amount < percent)
*policy_amount = percent;
return 1;
return (policy_amount < percent) ? (uint32_t) policy_amount : (uint32_t) percent;
}
static int _adjust_policy_params(struct logical_volume *lv, struct lvresize_params *lp)
static int _lvresize_adjust_policy(const struct logical_volume *lv,
uint32_t *amount, uint32_t *meta_amount)
{
struct cmd_context *cmd = lv->vg->cmd;
dm_percent_t percent;
int policy_threshold, policy_amount;
*amount = *meta_amount = 0;
if (lv_is_thin_pool(lv)) {
policy_threshold =
find_config_tree_int(cmd, activation_thin_pool_autoextend_threshold_CFG,
@ -4488,11 +4488,8 @@ static int _adjust_policy_params(struct logical_volume *lv, struct lvresize_para
}
}
if (policy_threshold >= 100) {
lp->extents = lp->poolmetadata_size = 0;
lp->sizeargs = 0;
if (policy_threshold >= 100)
return 1; /* nothing to do */
}
if (!policy_amount) {
log_error("Can't extend %s with %s autoextend percent set to 0%%.",
@ -4509,16 +4506,9 @@ static int _adjust_policy_params(struct logical_volume *lv, struct lvresize_para
if (lv_is_thin_pool(lv)) {
if (!lv_thin_pool_percent(lv, 1, &percent))
return_0;
if (_adjust_amount(percent, policy_threshold, &policy_amount)) {
if (!thin_pool_feature_supported(lv, THIN_FEATURE_METADATA_RESIZE)) {
log_error_once("Online metadata resize for %s is not supported.",
display_lvname(lv));
return 0;
}
lp->poolmetadata_size = (first_seg(lv)->metadata_lv->size *
policy_amount + 99) / 100;
lp->poolmetadata_sign = SIGN_PLUS;
}
*meta_amount = _adjust_amount(percent, policy_threshold, policy_amount);
if (!lv_thin_pool_percent(lv, 0, &percent))
return_0;
} else {
@ -4526,11 +4516,7 @@ static int _adjust_policy_params(struct logical_volume *lv, struct lvresize_para
return_0;
}
if (!_adjust_amount(percent, policy_threshold, &policy_amount))
return 1; /* nothing to do */
lp->extents = policy_amount;
lp->sizeargs = (lp->extents) ? 1 : 0;
*amount = _adjust_amount(percent, policy_threshold, policy_amount);
return 1;
}
@ -4646,8 +4632,8 @@ static int _lvresize_poolmetadata(struct logical_volume *pool_lv,
return 1;
}
static int _lvresize_check_lv(struct logical_volume *lv,
struct lvresize_params *lp)
static int _lvresize_check(struct logical_volume *lv,
struct lvresize_params *lp)
{
struct volume_group *vg = lv->vg;
@ -4884,10 +4870,6 @@ static int _lvresize_adjust_extents(struct logical_volume *lv,
uint32_t new_extents;
int reducing = 0;
if (lv_is_thin_pool(lv))
/* Manipulate the thin data layer underneath */
lv = seg_lv(first_seg(lv), 0);
seg_last = last_seg(lv);
/* FIXME Support LVs with mixed segment types */
@ -5086,12 +5068,6 @@ static int _lvresize_adjust_extents(struct logical_volume *lv,
}
if (lp->extents == existing_logical_extents) {
if (lp->poolmetadata_size || lp->use_policies) {
/* Signal that normal resizing is not required */
lp->sizeargs = 0;
return 1;
}
if (!lp->resizefs) {
log_error("New size (%d extents) matches existing size "
"(%d extents)", lp->extents, existing_logical_extents);
@ -5192,8 +5168,9 @@ static int _lvresize_check_type(const struct logical_volume *lv,
}
if (lp->resize == LV_REDUCE) {
if (lv_is_thin_pool(lv)) {
log_error("Thin pool volumes cannot be reduced in size yet.");
if (lv_is_thin_pool_data(lv)) {
log_error("Thin pool volumes %s cannot be reduced in size yet.",
display_lvname(lv));
return 0;
}
if (lv_is_thin_pool_metadata(lv)) {
@ -5201,6 +5178,13 @@ static int _lvresize_check_type(const struct logical_volume *lv,
return 0;
}
} else if (lp->resize == LV_EXTEND) {
if (lv_is_thin_pool_metadata(lv) &&
!thin_pool_feature_supported(find_pool_seg(first_seg(lv))->lv, THIN_FEATURE_METADATA_RESIZE)) {
log_error("Support for online metadata resize of %s not detected.",
display_lvname(lv));
return 0;
}
/* Validate thin target supports bigger size of thin volume then external origin */
if (lv_is_thin_volume(lv) && first_seg(lv)->external_lv &&
(lv->size > first_seg(lv)->external_lv->size) &&
@ -5220,18 +5204,9 @@ static struct logical_volume *_lvresize_volume(struct logical_volume *lv,
struct volume_group *vg = lv->vg;
struct cmd_context *cmd = vg->cmd;
struct logical_volume *lock_lv = NULL;
struct lv_segment *seg = NULL;
uint32_t old_extents;
int status;
alloc_policy_t alloc;
if (lv_is_thin_pool(lv)) {
lock_lv = lv;
seg = first_seg(lv);
/* Switch to layered LV resizing */
lv = seg_lv(seg, 0);
}
alloc = lp->alloc ? : lv->alloc;
alloc_policy_t alloc = lp->alloc ? : lv->alloc;
if ((lp->resize == LV_REDUCE) && (pvh != &vg->pvs))
log_print_unless_silent("Ignoring PVs on command line when reducing.");
@ -5307,81 +5282,106 @@ static struct logical_volume *_lvresize_volume(struct logical_volume *lv,
return lock_lv;
}
static int _lvresize_prepare(struct logical_volume *lv,
static int _lvresize_prepare(struct logical_volume **lv,
struct lvresize_params *lp,
struct dm_list *pvh)
{
if (!_lvresize_check_lv(lv, lp))
struct volume_group *vg = (*lv)->vg;
if (lv_is_thin_pool(*lv))
*lv = seg_lv(first_seg(*lv), 0); /* switch to data LV */
/* Resolve extents from size */
if (lp->size && !_lvresize_adjust_size(vg, lp->size, lp->sign, &lp->extents))
return_0;
else if (lp->extents && !_lvresize_extents_from_percent(*lv, lp, pvh))
return_0;
if (lp->use_policies && !_adjust_policy_params(lv, lp))
if (lp->extents && !_lvresize_adjust_extents(*lv, lp, pvh))
return_0;
if (lp->size && !_lvresize_adjust_size(lv->vg, lp->size, lp->sign,
&lp->extents))
return_0;
else if (lp->extents && !_lvresize_extents_from_percent(lv, lp, pvh))
return_0;
if (lp->extents && !_lvresize_adjust_extents(lv, lp, pvh))
return_0;
if ((lp->extents == lv->le_count) && lp->use_policies) {
/* Nothing to do. */
lp->sizeargs = 0;
lp->poolmetadata_size = 0;
}
if (lp->extents && !_lvresize_check_type(lv, lp))
return_0;
if (lp->poolmetadata_size &&
!_lvresize_poolmetadata_prepare(lv, lp))
if (lp->extents && !_lvresize_check_type(*lv, lp))
return_0;
return 1;
}
/* Set aux LV properties, we can't use those from command line */
static struct logical_volume *_lvresize_setup_aux(struct logical_volume *lv,
struct lvresize_params *lp)
{
struct lv_segment *mseg = last_seg(lv);
lp->alloc = lv->alloc;
lp->mirrors = seg_is_mirrored(mseg) ? lv_mirror_count(lv) : 0;
lp->resizefs = 0;
lp->stripes = lp->mirrors ? mseg->area_count / lp->mirrors : 0;
lp->stripe_size = mseg->stripe_size;
return lv;
}
int lv_resize(struct logical_volume *lv,
struct lvresize_params *lp,
struct dm_list *pvh)
{
struct volume_group *vg = lv->vg;
struct cmd_context *cmd = vg->cmd;
struct logical_volume *lock_lv = NULL;
int inactive = 0;
struct logical_volume *lock_lv = (struct logical_volume*) lv_lock_holder(lv);
struct logical_volume *aux_lv = NULL; /* Note: aux_lv never resizes fs */
struct lvresize_params aux_lp;
int activated = 0;
int ret = 0;
if (!_lvresize_prepare(lv, lp, pvh))
if (!_lvresize_check(lv, lp))
return_0;
if (lv_is_cache_type(lv)) {
log_error("Unable to resize logical volumes of cache type.");
return 0;
}
/*
* If the LV is locked from activation, this lock call is a no-op.
* Otherwise, this acquires a transient lock on the lv (not PERSISTENT).
*/
if (!lockd_lv(cmd, lv, "ex", 0))
return_0;
if (lp->extents &&
!(lock_lv = _lvresize_volume(lv, lp, pvh)))
return_0;
if (lp->poolmetadataextents) {
if (!_lvresize_poolmetadata(lv, lp, pvh))
if (lp->use_policies) {
lp->percent = SIGN_PLUS;
aux_lp = *lp;
if (!_lvresize_adjust_policy(lv, &lp->extents, &aux_lp.extents))
return_0;
lock_lv = lv;
if (!lp->extents) {
if (!aux_lp.extents)
return 1; /* Nothing to do */
/* Resize thin-pool metadata as mainlv */
lv = first_seg(lv)->metadata_lv; /* metadata LV */
lp->extents = aux_lp.extents;
} else if (aux_lp.extents) {
/* Also resize thin-pool metadata */
aux_lv = _lvresize_setup_aux(first_seg(lv)->metadata_lv, &aux_lp);
}
} else if (lp->poolmetadata_size) {
if (!lp->extents && !lp->size) {
/* When only --poolmetadatasize give and not --size
* swith directly to resize metadata LV */
lv = first_seg(lv)->metadata_lv;
lp->size = lp->poolmetadata_size;
lp->sign = lp->poolmetadata_sign;
} else {
aux_lp = *lp;
aux_lv = _lvresize_setup_aux(first_seg(lv)->metadata_lv, &aux_lp);
aux_lp.size = lp->poolmetadata_size;
aux_lp.sign = lp->poolmetadata_sign;
}
}
if (!lock_lv)
return 1; /* Nothing to do */
if (aux_lv && !_lvresize_prepare(&aux_lv, &aux_lp, pvh))
return_0;
if (lv_is_thin_pool(lock_lv) &&
pool_is_active(lock_lv) &&
if (!_lvresize_prepare(&lv, lp, pvh))
return_0;
if (lv_is_thin_pool(lock_lv) && /* Lock holder is thin-pool */
!lv_is_active(lock_lv)) {
if (!activation()) {
log_error("Cannot resize %s without using "
"device-mapper kernel driver.",
display_lvname(lock_lv));
return 0;
}
/*
* Active 'hidden' -tpool can be waiting for resize, but the
* pool LV itself might be inactive.
@ -5390,13 +5390,33 @@ int lv_resize(struct logical_volume *lv,
* then use suspend and resume and deactivate pool LV,
* instead of searching for an active thin volume.
*/
inactive = 1;
if (!activate_lv_excl(cmd, lock_lv)) {
log_error("Failed to activate %s.", display_lvname(lock_lv));
return 0;
}
activated = 1;
}
/*
* If the LV is locked from activation, this lock call is a no-op.
* Otherwise, this acquires a transient lock on the lv (not PERSISTENT).
*/
if (!lockd_lv(cmd, lock_lv, "ex", 0))
return_0;
if (aux_lv) {
if (!_lvresize_volume(aux_lv, &aux_lp, pvh))
goto_bad;
/* store vg on disk(s) */
if (!lv_update_and_reload(lock_lv))
goto_bad;
}
if (!_lvresize_volume(lv, lp, pvh))
goto_bad;
/* store vg on disk(s) */
if (!lv_update_and_reload(lock_lv))
goto_bad;
@ -5411,11 +5431,6 @@ int lv_resize(struct logical_volume *lv,
goto_bad;
backup(vg);
if (inactive && !deactivate_lv(cmd, lock_lv)) {
log_error("Problem deactivating %s.", display_lvname(lock_lv));
return 0;
}
}
log_print_unless_silent("Logical volume %s successfully resized.",
@ -5425,12 +5440,14 @@ int lv_resize(struct logical_volume *lv,
!_fsadm_cmd(FSADM_CMD_RESIZE, lv, lp->extents, lp->force, NULL))
return_0;
return 1;
ret = 1;
bad:
if (inactive && !deactivate_lv(cmd, lock_lv))
if (activated && !deactivate_lv(cmd, lock_lv)) {
log_error("Problem deactivating %s.", display_lvname(lock_lv));
ret = 0;
}
return 0;
return ret;
}
char *generate_lv_name(struct volume_group *vg, const char *format,