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 - 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. Log system error when locking dir cannot be accessed.
Preserve monitoring status when updating thin-pool metadata. Preserve monitoring status when updating thin-pool metadata.
Rerurn 0 (inactive) when status cannot be queried in _lv_active(). 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); 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) || if (!(DM_PERCENT_0 < percent && percent <= DM_PERCENT_100) ||
percent <= (policy_threshold * DM_PERCENT_1)) 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; percent = (percent / policy_threshold + (DM_PERCENT_1 - 1) / 100) / (DM_PERCENT_1 / 100) - 100;
/* Use it if current policy amount is smaller */ /* Use it if current policy amount is smaller */
if (*policy_amount < percent) return (policy_amount < percent) ? (uint32_t) policy_amount : (uint32_t) percent;
*policy_amount = percent;
return 1;
} }
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; struct cmd_context *cmd = lv->vg->cmd;
dm_percent_t percent; dm_percent_t percent;
int policy_threshold, policy_amount; int policy_threshold, policy_amount;
*amount = *meta_amount = 0;
if (lv_is_thin_pool(lv)) { if (lv_is_thin_pool(lv)) {
policy_threshold = policy_threshold =
find_config_tree_int(cmd, activation_thin_pool_autoextend_threshold_CFG, 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) { if (policy_threshold >= 100)
lp->extents = lp->poolmetadata_size = 0;
lp->sizeargs = 0;
return 1; /* nothing to do */ return 1; /* nothing to do */
}
if (!policy_amount) { if (!policy_amount) {
log_error("Can't extend %s with %s autoextend percent set to 0%%.", 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_is_thin_pool(lv)) {
if (!lv_thin_pool_percent(lv, 1, &percent)) if (!lv_thin_pool_percent(lv, 1, &percent))
return_0; return_0;
if (_adjust_amount(percent, policy_threshold, &policy_amount)) {
if (!thin_pool_feature_supported(lv, THIN_FEATURE_METADATA_RESIZE)) { *meta_amount = _adjust_amount(percent, policy_threshold, policy_amount);
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;
}
if (!lv_thin_pool_percent(lv, 0, &percent)) if (!lv_thin_pool_percent(lv, 0, &percent))
return_0; return_0;
} else { } else {
@ -4526,11 +4516,7 @@ static int _adjust_policy_params(struct logical_volume *lv, struct lvresize_para
return_0; return_0;
} }
if (!_adjust_amount(percent, policy_threshold, &policy_amount)) *amount = _adjust_amount(percent, policy_threshold, policy_amount);
return 1; /* nothing to do */
lp->extents = policy_amount;
lp->sizeargs = (lp->extents) ? 1 : 0;
return 1; return 1;
} }
@ -4646,7 +4632,7 @@ static int _lvresize_poolmetadata(struct logical_volume *pool_lv,
return 1; return 1;
} }
static int _lvresize_check_lv(struct logical_volume *lv, static int _lvresize_check(struct logical_volume *lv,
struct lvresize_params *lp) struct lvresize_params *lp)
{ {
struct volume_group *vg = lv->vg; struct volume_group *vg = lv->vg;
@ -4884,10 +4870,6 @@ static int _lvresize_adjust_extents(struct logical_volume *lv,
uint32_t new_extents; uint32_t new_extents;
int reducing = 0; 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); seg_last = last_seg(lv);
/* FIXME Support LVs with mixed segment types */ /* 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->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) { if (!lp->resizefs) {
log_error("New size (%d extents) matches existing size " log_error("New size (%d extents) matches existing size "
"(%d extents)", lp->extents, existing_logical_extents); "(%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 (lp->resize == LV_REDUCE) {
if (lv_is_thin_pool(lv)) { if (lv_is_thin_pool_data(lv)) {
log_error("Thin pool volumes cannot be reduced in size yet."); log_error("Thin pool volumes %s cannot be reduced in size yet.",
display_lvname(lv));
return 0; return 0;
} }
if (lv_is_thin_pool_metadata(lv)) { if (lv_is_thin_pool_metadata(lv)) {
@ -5201,6 +5178,13 @@ static int _lvresize_check_type(const struct logical_volume *lv,
return 0; return 0;
} }
} else if (lp->resize == LV_EXTEND) { } 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 */ /* Validate thin target supports bigger size of thin volume then external origin */
if (lv_is_thin_volume(lv) && first_seg(lv)->external_lv && if (lv_is_thin_volume(lv) && first_seg(lv)->external_lv &&
(lv->size > first_seg(lv)->external_lv->size) && (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 volume_group *vg = lv->vg;
struct cmd_context *cmd = vg->cmd; struct cmd_context *cmd = vg->cmd;
struct logical_volume *lock_lv = NULL; struct logical_volume *lock_lv = NULL;
struct lv_segment *seg = NULL;
uint32_t old_extents; uint32_t old_extents;
int status; int status;
alloc_policy_t alloc; alloc_policy_t alloc = lp->alloc ? : lv->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;
if ((lp->resize == LV_REDUCE) && (pvh != &vg->pvs)) if ((lp->resize == LV_REDUCE) && (pvh != &vg->pvs))
log_print_unless_silent("Ignoring PVs on command line when reducing."); 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; return lock_lv;
} }
static int _lvresize_prepare(struct logical_volume *lv, static int _lvresize_prepare(struct logical_volume **lv,
struct lvresize_params *lp, struct lvresize_params *lp,
struct dm_list *pvh) 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; return_0;
if (lp->use_policies && !_adjust_policy_params(lv, lp)) if (lp->extents && !_lvresize_adjust_extents(*lv, lp, pvh))
return_0; return_0;
if (lp->size && !_lvresize_adjust_size(lv->vg, lp->size, lp->sign, if (lp->extents && !_lvresize_check_type(*lv, lp))
&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))
return_0; return_0;
return 1; 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, int lv_resize(struct logical_volume *lv,
struct lvresize_params *lp, struct lvresize_params *lp,
struct dm_list *pvh) struct dm_list *pvh)
{ {
struct volume_group *vg = lv->vg; struct volume_group *vg = lv->vg;
struct cmd_context *cmd = vg->cmd; struct cmd_context *cmd = vg->cmd;
struct logical_volume *lock_lv = NULL; struct logical_volume *lock_lv = (struct logical_volume*) lv_lock_holder(lv);
int inactive = 0; 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; return_0;
if (lv_is_cache_type(lv)) { if (lp->use_policies) {
log_error("Unable to resize logical volumes of cache type."); lp->percent = SIGN_PLUS;
aux_lp = *lp;
if (!_lvresize_adjust_policy(lv, &lp->extents, &aux_lp.extents))
return_0;
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 (aux_lv && !_lvresize_prepare(&aux_lv, &aux_lp, pvh))
return_0;
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; 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))
return_0;
lock_lv = lv;
}
if (!lock_lv)
return 1; /* Nothing to do */
if (lv_is_thin_pool(lock_lv) &&
pool_is_active(lock_lv) &&
!lv_is_active(lock_lv)) {
/* /*
* Active 'hidden' -tpool can be waiting for resize, but the * Active 'hidden' -tpool can be waiting for resize, but the
* pool LV itself might be inactive. * 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, * then use suspend and resume and deactivate pool LV,
* instead of searching for an active thin volume. * instead of searching for an active thin volume.
*/ */
inactive = 1;
if (!activate_lv_excl(cmd, lock_lv)) { if (!activate_lv_excl(cmd, lock_lv)) {
log_error("Failed to activate %s.", display_lvname(lock_lv)); log_error("Failed to activate %s.", display_lvname(lock_lv));
return 0; 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) */ /* store vg on disk(s) */
if (!lv_update_and_reload(lock_lv)) if (!lv_update_and_reload(lock_lv))
goto_bad; goto_bad;
@ -5411,11 +5431,6 @@ int lv_resize(struct logical_volume *lv,
goto_bad; goto_bad;
backup(vg); 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.", 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)) !_fsadm_cmd(FSADM_CMD_RESIZE, lv, lp->extents, lp->force, NULL))
return_0; return_0;
return 1; ret = 1;
bad: bad:
if (inactive && !deactivate_lv(cmd, lock_lv)) if (activated && !deactivate_lv(cmd, lock_lv)) {
log_error("Problem deactivating %s.", display_lvname(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, char *generate_lv_name(struct volume_group *vg, const char *format,