diff options
author | Alasdair G Kergon <agk@redhat.com> | 2017-05-12 02:04:05 +0100 |
---|---|---|
committer | Alasdair G Kergon <agk@redhat.com> | 2017-05-12 02:31:35 +0100 |
commit | cf73f6cf61793e9d71391bb7a8f35162509898a4 (patch) | |
tree | bed6d0cd0f353024ec0926732a998d5727af1d4b | |
parent | d49a20b7bdc9b741def219be897c5057db5e05ff (diff) | |
download | lvm2-cf73f6cf61793e9d71391bb7a8f35162509898a4.tar.gz |
lvcreate: Fix mirror percentage size calculations.
Trap cases where the percentage calculation currently leads to an empty
LV and the message:
Internal error: Unable to create new logical volume with no extents
Additionally convert the calculated number of extents from physical to
logical when creating a mirror using a percentage that is based on
Physical Extents. Otherwise a command like 'lvcreate -m3 -l80%FREE'
can never leave any free space.
This brings the behaviour closer to that of lvresize.
(A further patch is needed to cover all the raid types.)
-rw-r--r-- | WHATS_NEW | 1 | ||||
-rw-r--r-- | tools/lvcreate.c | 37 |
2 files changed, 31 insertions, 7 deletions
@@ -1,5 +1,6 @@ Version 2.02.172 - =============================== + Fix lvcreate extent percentage calculation for mirrors. Don't reinstate still-missing devices when correcting inconsistent metadata. Properly handle subshell return codes in fsadm. Disallow cachepool creation with policy cleaner and mode writeback. diff --git a/tools/lvcreate.c b/tools/lvcreate.c index f77529078..dddf8ad3b 100644 --- a/tools/lvcreate.c +++ b/tools/lvcreate.c @@ -251,6 +251,7 @@ static int _update_extents_params(struct volume_group *vg, uint32_t size_rest; uint32_t stripesize_extents; uint32_t extents; + uint32_t base_calc_extents; if (lcp->size && !(lp->extents = extents_from_size(vg->cmd, lcp->size, @@ -275,17 +276,17 @@ static int _update_extents_params(struct volume_group *vg, switch (lcp->percent) { case PERCENT_VG: - extents = percent_of_extents(lp->extents, vg->extent_count, 0); + extents = percent_of_extents(lp->extents, base_calc_extents = vg->extent_count, 0); break; case PERCENT_FREE: - extents = percent_of_extents(lp->extents, vg->free_count, 0); + extents = percent_of_extents(lp->extents, base_calc_extents = vg->free_count, 0); break; case PERCENT_PVS: if (lcp->pv_count) { pv_extent_count = pv_list_extents_free(lp->pvh); - extents = percent_of_extents(lp->extents, pv_extent_count, 0); + extents = percent_of_extents(lp->extents, base_calc_extents = pv_extent_count, 0); } else - extents = percent_of_extents(lp->extents, vg->extent_count, 0); + extents = percent_of_extents(lp->extents, base_calc_extents = vg->extent_count, 0); break; case PERCENT_LV: log_error("Please express size as %%FREE%s, %%PVS or %%VG.", @@ -304,7 +305,7 @@ static int _update_extents_params(struct volume_group *vg, } /* Add whole metadata size estimation */ extents = cow_max_extents(origin_lv, lp->chunk_size) - origin_lv->le_count + - percent_of_extents(lp->extents, origin_lv->le_count, 1); + percent_of_extents(lp->extents, base_calc_extents = origin_lv->le_count, 1); break; case PERCENT_NONE: extents = lp->extents; @@ -314,10 +315,27 @@ static int _update_extents_params(struct volume_group *vg, return 0; } - if (lcp->percent) { + if (lcp->percent != PERCENT_NONE) { /* FIXME Don't do the adjustment for parallel allocation with PERCENT_ORIGIN! */ lp->approx_alloc = 1; - log_verbose("Converted %" PRIu32 "%%%s into %" PRIu32 " extents.", lp->extents, get_percent_string(lcp->percent), extents); + if (!extents) { + log_error("Calculated size of logical volume is 0 extents. Needs to be larger."); + return 0; + } + + /* For mirrors and raid with percentages based on physical extents, convert the total number of PEs + * into the number of logical extents per image (minimum 1) */ + /* FIXME Handle all the supported raid layouts here based on already-known segtype. */ + if ((lcp->percent != PERCENT_ORIGIN) && lp->mirrors) { + extents /= lp->mirrors; + if (!extents) + extents = 1; + } + + log_verbose("Converted %" PRIu32 "%% of %s (%" PRIu32 ") extents into %" PRIu32 " (with mimages %" PRIu32 " and stripes %" PRIu32 + " for segtype %s).", lp->extents, get_percent_string(lcp->percent), base_calc_extents, + extents, lp->mirrors, lp->stripes, lp->segtype->name); + lp->extents = extents; } @@ -389,6 +407,11 @@ static int _update_extents_params(struct volume_group *vg, } } + if (!lp->extents) { + log_error("Adjusted size of logical volume is 0 extents. Needs to be larger."); + return 0; + } + return 1; } |