master - raid: Report supported lvconvert conversions if invalid.
by Alasdair Kergon
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=de7f1deb804990...
Commit: de7f1deb80499087662e57c4aef9e9373f15ca63
Parent: 6f236c3353cbcac799f755870251da7a5d576c41
Author: Alasdair G Kergon <agk(a)redhat.com>
AuthorDate: Sun Aug 7 00:30:26 2016 +0100
Committer: Alasdair G Kergon <agk(a)redhat.com>
CommitterDate: Sun Aug 7 00:30:26 2016 +0100
raid: Report supported lvconvert conversions if invalid.
---
WHATS_NEW | 1 +
lib/metadata/raid_manip.c | 206 ++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 204 insertions(+), 3 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index df1a434..7282081 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.163 -
=================================
+ Report supported conversions when asked for unsupported raid lvconvert.
Add "--rebuild PV" option to lvchange to allow for PV selective rebuilds.
Preserve existing mirror region size when using --repair.
Forbid stripe parameters with lvconvert --repair.
diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c
index 840c831..2e491eb 100644
--- a/lib/metadata/raid_manip.c
+++ b/lib/metadata/raid_manip.c
@@ -2061,6 +2061,7 @@ static uint32_t _min_sublv_area_at_le(struct lv_segment *seg, uint32_t area_le)
return area_len;
}
+
/*
* All areas from lv image component LV's segments are
* being split at "striped" compatible boundaries and
@@ -2200,7 +2201,6 @@ static struct lv_segment *_convert_striped_to_raid0(struct logical_volume *lv,
if (!is_power_of_2(seg->stripe_size)) {
log_error("Cannot convert striped LV %s with non-power of 2 stripe size %u",
display_lvname(lv), seg->stripe_size);
- // log_error("Please use \"lvconvert --duplicate ...\"");
return NULL;
}
@@ -2260,6 +2260,195 @@ static struct lv_segment *_convert_striped_to_raid0(struct logical_volume *lv,
/***********************************************/
+/*
+ * Takeover.
+ *
+ */
+#define ALLOW_NONE 0x0
+#define ALLOW_STRIPES 0x2
+#define ALLOW_STRIPE_SIZE 0x4
+
+struct possible_takeover_reshape_type {
+ /* First 2 have to stay... */
+ const uint64_t possible_types;
+ const uint32_t options;
+ const uint64_t current_types;
+ const uint32_t current_areas;
+};
+
+struct possible_type {
+ /* ..to be handed back via this struct */
+ const uint64_t possible_types;
+ const uint32_t options;
+};
+
+static struct possible_takeover_reshape_type _possible_takeover_reshape_types[] = {
+ /* striped -> */
+ { .current_types = SEG_STRIPED_TARGET, /* striped, i.e. seg->area_count > 1 */
+ .possible_types = SEG_RAID0|SEG_RAID0_META,
+ .current_areas = ~0U,
+ .options = ALLOW_NONE },
+ /* raid0* -> */
+ { .current_types = SEG_RAID0|SEG_RAID0_META, /* raid0 striped, i.e. seg->area_count > 0 */
+ .possible_types = SEG_STRIPED_TARGET|SEG_RAID0|SEG_RAID0_META,
+ .current_areas = ~0U,
+ .options = ALLOW_NONE },
+ /* raid1 -> */
+ { .current_types = SEG_RAID1,
+ .possible_types = SEG_RAID1,
+ .current_areas = ~0U,
+ .options = ALLOW_NONE },
+ /* mirror -> raid1 with arbitrary number of legs */
+ { .current_types = SEG_MIRROR,
+ .possible_types = SEG_MIRROR,
+ .current_areas = ~0U,
+ .options = ALLOW_NONE },
+
+ /* END */
+ { .current_types = 0 }
+};
+
+/*
+ * Return possible_type struct for current segment type.
+ */
+static struct possible_takeover_reshape_type *_get_possible_takeover_reshape_type(const struct lv_segment *seg_from,
+ const struct segment_type *segtype_to,
+ struct possible_type *last_pt)
+{
+ struct possible_takeover_reshape_type *lpt = (struct possible_takeover_reshape_type *) last_pt;
+ struct possible_takeover_reshape_type *pt = lpt ? lpt + 1 : _possible_takeover_reshape_types;
+
+ for ( ; pt->current_types; pt++)
+ if ((seg_from->segtype->flags & pt->current_types) &&
+ (segtype_to ? (segtype_to->flags & pt->possible_types) : 1))
+ if (seg_from->area_count <= pt->current_areas)
+ return pt;
+
+ return NULL;
+}
+
+static struct possible_type *_get_possible_type(const struct lv_segment *seg_from,
+ const struct segment_type *segtype_to,
+ uint32_t new_image_count,
+ struct possible_type *last_pt)
+{
+ return (struct possible_type *) _get_possible_takeover_reshape_type(seg_from, segtype_to, last_pt);
+}
+
+/*
+ * Log any possible conversions for @lv
+ */
+typedef int (*type_flag_fn_t)(uint64_t *processed_segtypes, void *data);
+
+/* Loop through pt->flags calling tfn with argument @data */
+static int _process_type_flags(const struct logical_volume *lv, struct possible_type *pt, uint64_t *processed_segtypes, type_flag_fn_t tfn, void *data)
+{
+ unsigned i;
+ uint64_t t;
+ const struct lv_segment *seg = first_seg(lv);
+ const struct segment_type *segtype;
+
+ for (i = 0; i < 64; i++) {
+ t = 1ULL << i;
+ if ((t & pt->possible_types) &&
+ !(t & seg->segtype->flags) &&
+ ((segtype = get_segtype_from_flag(lv->vg->cmd, t))))
+ if (!tfn(processed_segtypes, data ? : (void *) segtype))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Callback to increment unsigned possible conversion types in *data */
+static int _count_possible_conversions(uint64_t *processed_segtypes, void *data)
+{
+ unsigned *possible_conversions = data;
+
+ (*possible_conversions)++;
+
+ return 1;
+}
+
+/* Callback to log possible conversion to segment type in *data */
+static int _log_possible_conversion(uint64_t *processed_segtypes, void *data)
+{
+ struct segment_type *segtype = data;
+
+ /* Already processed? */
+ if (!(~*processed_segtypes & segtype->flags))
+ return 1;
+
+ log_error(" %s", segtype->name);
+
+ *processed_segtypes |= segtype->flags;
+
+ return 1;
+}
+
+static const char *_get_segtype_alias(const struct segment_type *segtype)
+{
+ if (!strcmp(segtype->name, SEG_TYPE_NAME_RAID5))
+ return SEG_TYPE_NAME_RAID5_LS;
+
+ if (!strcmp(segtype->name, SEG_TYPE_NAME_RAID6))
+ return SEG_TYPE_NAME_RAID6_ZR;
+
+ if (!strcmp(segtype->name, SEG_TYPE_NAME_RAID5_LS))
+ return SEG_TYPE_NAME_RAID5;
+
+ if (!strcmp(segtype->name, SEG_TYPE_NAME_RAID6_ZR))
+ return SEG_TYPE_NAME_RAID6;
+
+ return "";
+}
+
+/* Return "linear" for striped segtype with 1 area instead of "striped" */
+static const char *_get_segtype_name(const struct segment_type *segtype, unsigned new_image_count)
+{
+ if (!segtype || (segtype_is_striped(segtype) && new_image_count == 1))
+ return "linear";
+
+ return segtype->name;
+}
+
+static int _log_possible_conversion_types(const struct logical_volume *lv, const struct segment_type *new_segtype)
+{
+ unsigned possible_conversions = 0;
+ const struct lv_segment *seg = first_seg(lv);
+ struct possible_type *pt = NULL;
+ const char *alias;
+ uint64_t processed_segtypes = UINT64_C(0);
+
+ /* Count any possible segment types @seg an be directly converted to */
+ while ((pt = _get_possible_type(seg, NULL, 0, pt)))
+ if (!_process_type_flags(lv, pt, &processed_segtypes, _count_possible_conversions, &possible_conversions))
+ return_0;
+
+ if (!possible_conversions)
+ log_error("Direct conversion of %s LV %s is not possible.", lvseg_name(seg), display_lvname(lv));
+ else {
+ alias = _get_segtype_alias(seg->segtype);
+
+ log_error("Converting %s from %s%s%s%s is "
+ "directly possible to the following layout%s:",
+ display_lvname(lv), _get_segtype_name(seg->segtype, seg->area_count),
+ *alias ? " (same as " : "", alias, *alias ? ")" : "",
+ possible_conversions > 1 ? "s" : "");
+
+ pt = NULL;
+
+ /* Print any possible segment types @seg can be directly converted to */
+ while ((pt = _get_possible_type(seg, NULL, 0, pt)))
+ if (!_process_type_flags(lv, pt, &processed_segtypes, _log_possible_conversion, NULL))
+ return_0;
+ }
+
+ return 0;
+}
+
+/***********************************************/
+
#define TAKEOVER_FN_ARGS \
struct logical_volume *lv, \
const struct segment_type *new_segtype, \
@@ -2293,6 +2482,9 @@ static int _takeover_unsupported(TAKEOVER_FN_ARGS)
(segtype_is_striped_target(new_segtype) &&
(new_stripes == 1)) ? SEG_TYPE_NAME_LINEAR : new_segtype->name);
+ if (!_log_possible_conversion_types(lv, new_segtype))
+ stack;
+
return 0;
}
@@ -2303,6 +2495,9 @@ static int _takeover_unsupported_yet(const struct logical_volume *lv, const unsi
(segtype_is_striped_target(new_segtype) &&
(new_stripes == 1)) ? SEG_TYPE_NAME_LINEAR : new_segtype->name);
+ if (!_log_possible_conversion_types(lv, new_segtype))
+ stack;
+
return 0;
}
@@ -2453,6 +2648,7 @@ static int _takeover_from_raid0_to_mirrored(TAKEOVER_FN_ARGS)
{
return _takeover_unsupported_yet(lv, new_stripes, new_segtype);
}
+
static int _takeover_from_raid0_to_raid0_meta(TAKEOVER_FN_ARGS)
{
if (!_raid0_meta_change_wrapper(lv, new_segtype, new_stripes, yes, force, 1, allocate_pvs))
@@ -2766,9 +2962,13 @@ static uint32_t _data_rimages_count(const struct lv_segment *seg, const uint32_t
/*
* lv_raid_convert
*
- * Convert an LV from one RAID type (or 'mirror' segtype) to another.
+ * Convert lv from one RAID type (or striped/mirror segtype) to new_segtype,
+ * or add/remove LVs to/from a RAID LV.
*
- * Returns: 1 on success, 0 on failure
+ * Non dm-raid changes e.g. mirror/striped functions are also called from here.
+ *
+ * Takeover is defined as a switch from one raid level to another, potentially
+ * involving the addition of one or more image component pairs and rebuild.
*/
int lv_raid_convert(struct logical_volume *lv,
const struct segment_type *new_segtype,
7 years, 9 months
master - raid: Add workaround to prepare for raid4 conversions.
by Alasdair Kergon
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=6f236c3353cbca...
Commit: 6f236c3353cbcac799f755870251da7a5d576c41
Parent: ba0c26a078119f5a7d551e047189f23bdd76e2be
Author: Alasdair G Kergon <agk(a)redhat.com>
AuthorDate: Sun Aug 7 00:07:06 2016 +0100
Committer: Alasdair G Kergon <agk(a)redhat.com>
CommitterDate: Sun Aug 7 00:07:06 2016 +0100
raid: Add workaround to prepare for raid4 conversions.
---
lib/metadata/raid_manip.c | 27 ++++++++++++++++-----------
1 files changed, 16 insertions(+), 11 deletions(-)
diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c
index f5a800b..840c831 100644
--- a/lib/metadata/raid_manip.c
+++ b/lib/metadata/raid_manip.c
@@ -571,7 +571,7 @@ static struct logical_volume *_alloc_image_component(struct logical_volume *lv,
static int _alloc_image_components(struct logical_volume *lv,
struct dm_list *pvs, uint32_t count,
struct dm_list *new_meta_lvs,
- struct dm_list *new_data_lvs)
+ struct dm_list *new_data_lvs, int use_existing_area_len)
{
uint32_t s;
uint32_t region_size;
@@ -607,7 +607,11 @@ static int _alloc_image_components(struct logical_volume *lv,
* individual devies, we must specify how large the individual device
* is along with the number we want ('count').
*/
- if (segtype_is_raid10(segtype)) {
+ if (use_existing_area_len)
+ /* FIXME Workaround for segment type changes where new segtype is unknown here */
+ /* Only for raid0* to raid4 */
+ extents = (lv->le_count / seg->area_count) * count;
+ else if (segtype_is_raid10(segtype)) {
if (seg->area_count < 2) {
log_error(INTERNAL_ERROR "LV %s needs at least 2 areas.",
display_lvname(lv));
@@ -715,7 +719,8 @@ static int _alloc_rmeta_for_lv(struct logical_volume *data_lv,
}
static int _raid_add_images_without_commit(struct logical_volume *lv,
- uint32_t new_count, struct dm_list *pvs)
+ uint32_t new_count, struct dm_list *pvs,
+ int use_existing_area_len)
{
uint32_t s;
uint32_t old_count = lv_raid_image_count(lv);
@@ -767,7 +772,7 @@ static int _raid_add_images_without_commit(struct logical_volume *lv,
return 0;
}
- if (!_alloc_image_components(lv, pvs, count, &meta_lvs, &data_lvs))
+ if (!_alloc_image_components(lv, pvs, count, &meta_lvs, &data_lvs, use_existing_area_len))
return_0;
/*
@@ -910,13 +915,13 @@ fail:
static int _raid_add_images(struct logical_volume *lv,
uint32_t new_count, struct dm_list *pvs,
- int commit)
+ int commit, int use_existing_area_len)
{
int rebuild_flag_cleared = 0;
struct lv_segment *seg = first_seg(lv);
uint32_t s;
- if (!_raid_add_images_without_commit(lv, new_count, pvs))
+ if (!_raid_add_images_without_commit(lv, new_count, pvs, use_existing_area_len))
return_0;
if (!commit)
@@ -1235,7 +1240,7 @@ static int _raid_remove_images(struct logical_volume *lv,
*/
static int _lv_raid_change_image_count(struct logical_volume *lv, uint32_t new_count,
struct dm_list *allocate_pvs, struct dm_list *removal_lvs,
- int commit)
+ int commit, int use_existing_area_len)
{
uint32_t old_count = lv_raid_image_count(lv);
@@ -1258,13 +1263,13 @@ static int _lv_raid_change_image_count(struct logical_volume *lv, uint32_t new_c
if (old_count > new_count)
return _raid_remove_images(lv, new_count, allocate_pvs, removal_lvs, commit);
- return _raid_add_images(lv, new_count, allocate_pvs, commit);
+ return _raid_add_images(lv, new_count, allocate_pvs, commit, use_existing_area_len);
}
int lv_raid_change_image_count(struct logical_volume *lv, uint32_t new_count,
struct dm_list *allocate_pvs)
{
- return _lv_raid_change_image_count(lv, new_count, allocate_pvs, NULL, 1);
+ return _lv_raid_change_image_count(lv, new_count, allocate_pvs, NULL, 1, 0);
}
int lv_raid_split(struct logical_volume *lv, const char *split_name,
@@ -2204,7 +2209,7 @@ static struct lv_segment *_convert_striped_to_raid0(struct logical_volume *lv,
/* Allocate empty rimage components */
dm_list_init(&data_lvs);
- if (!_alloc_image_components(lv, NULL, area_count, NULL, &data_lvs)) {
+ if (!_alloc_image_components(lv, NULL, area_count, NULL, &data_lvs, 0)) {
log_error("Failed to allocate empty image components for raid0 LV %s.",
display_lvname(lv));
return NULL;
@@ -3050,7 +3055,7 @@ static int _lv_raid_rebuild_or_replace(struct logical_volume *lv,
*/
try_again:
if (!_alloc_image_components(lv, allocate_pvs, match_count,
- &new_meta_lvs, &new_data_lvs)) {
+ &new_meta_lvs, &new_data_lvs, 0)) {
if (!lv_is_partial(lv)) {
log_error("LV %s in not partial.", display_lvname(lv));
return 0;
7 years, 9 months
master - raid: Pass list of LVs to remove into more fns.
by Alasdair Kergon
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=ba0c26a078119f...
Commit: ba0c26a078119f5a7d551e047189f23bdd76e2be
Parent: 30884208d47f9b26543134ef3d87e51422a66a85
Author: Alasdair G Kergon <agk(a)redhat.com>
AuthorDate: Sat Aug 6 23:46:45 2016 +0100
Committer: Alasdair G Kergon <agk(a)redhat.com>
CommitterDate: Sat Aug 6 23:46:45 2016 +0100
raid: Pass list of LVs to remove into more fns.
---
lib/metadata/raid_manip.c | 108 +++++++++++++++++++++++++++-----------------
1 files changed, 66 insertions(+), 42 deletions(-)
diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c
index c46802a..f5a800b 100644
--- a/lib/metadata/raid_manip.c
+++ b/lib/metadata/raid_manip.c
@@ -678,8 +678,15 @@ static int _alloc_rmeta_for_lv(struct logical_volume *data_lv,
dm_list_init(&allocatable_pvs);
- if (!allocate_pvs)
+ if (!allocate_pvs) {
allocate_pvs = &allocatable_pvs;
+ if (!get_pv_list_for_lv(data_lv->vg->cmd->mem,
+ data_lv, &allocatable_pvs)) {
+ log_error("Failed to build list of PVs for %s/%s",
+ data_lv->vg->name, data_lv->name);
+ return 0;
+ }
+ }
if (!seg_is_linear(seg)) {
log_error(INTERNAL_ERROR "Unable to allocate RAID metadata "
@@ -691,17 +698,10 @@ static int _alloc_rmeta_for_lv(struct logical_volume *data_lv,
if ((p = strstr(base_name, "_mimage_")))
*p = '\0';
- if (!get_pv_list_for_lv(data_lv->vg->cmd->mem,
- data_lv, &allocatable_pvs)) {
- log_error("Failed to build list of PVs for %s/%s",
- data_lv->vg->name, data_lv->name);
- return 0;
- }
-
if (!(ah = allocate_extents(data_lv->vg, NULL, seg->segtype, 0, 1, 0,
seg->region_size,
1 /*RAID_METADATA_AREA_LEN*/,
- &allocatable_pvs, data_lv->alloc, 0, NULL)))
+ allocate_pvs, data_lv->alloc, 0, NULL)))
return_0;
if (!(*meta_lv = _alloc_image_component(data_lv, base_name, ah, 0, RAID_META))) {
@@ -714,10 +714,9 @@ static int _alloc_rmeta_for_lv(struct logical_volume *data_lv,
return 1;
}
-static int _raid_add_images(struct logical_volume *lv,
- uint32_t new_count, struct dm_list *pvs)
+static int _raid_add_images_without_commit(struct logical_volume *lv,
+ uint32_t new_count, struct dm_list *pvs)
{
- int rebuild_flag_cleared = 0;
uint32_t s;
uint32_t old_count = lv_raid_image_count(lv);
uint32_t count = new_count - old_count;
@@ -894,6 +893,35 @@ to be left for these sub-lvs.
dm_list_iterate_items(lvl, &data_lvs)
lv_set_hidden(lvl->lv);
+ return 1;
+
+fail:
+ /* Cleanly remove newly-allocated LVs that failed insertion attempt */
+ dm_list_iterate_items(lvl, &meta_lvs)
+ if (!lv_remove(lvl->lv))
+ return_0;
+
+ dm_list_iterate_items(lvl, &data_lvs)
+ if (!lv_remove(lvl->lv))
+ return_0;
+
+ return 0;
+}
+
+static int _raid_add_images(struct logical_volume *lv,
+ uint32_t new_count, struct dm_list *pvs,
+ int commit)
+{
+ int rebuild_flag_cleared = 0;
+ struct lv_segment *seg = first_seg(lv);
+ uint32_t s;
+
+ if (!_raid_add_images_without_commit(lv, new_count, pvs))
+ return_0;
+
+ if (!commit)
+ return 1;
+
if (!lv_update_and_reload_origin(lv))
return_0;
@@ -921,18 +949,6 @@ to be left for these sub-lvs.
}
return 1;
-
-fail:
- /* Cleanly remove newly-allocated LVs that failed insertion attempt */
- dm_list_iterate_items(lvl, &meta_lvs)
- if (!lv_remove(lvl->lv))
- return_0;
-
- dm_list_iterate_items(lvl, &data_lvs)
- if (!lv_remove(lvl->lv))
- return_0;
-
- return 0;
}
/*
@@ -979,6 +995,7 @@ static int _extract_image_components(struct lv_segment *seg, uint32_t idx,
seg_type(seg, idx) = AREA_UNASSIGNED;
seg_metatype(seg, idx) = AREA_UNASSIGNED;
+ /* FIXME Remove duplicated prefix? */
if (!(data_lv->name = _generate_raid_name(data_lv, "_extracted", -1)))
return_0;
@@ -1111,18 +1128,22 @@ static int _raid_extract_images(struct logical_volume *lv, uint32_t new_count,
}
static int _raid_remove_images(struct logical_volume *lv,
- uint32_t new_count, struct dm_list *pvs)
+ uint32_t new_count, struct dm_list *allocate_pvs,
+ struct dm_list *removal_lvs, int commit)
{
- struct dm_list removal_lvs;
+ struct dm_list removed_lvs;
struct lv_list *lvl;
+ dm_list_init(&removed_lvs);
+
if (!archive(lv->vg))
return_0;
- dm_list_init(&removal_lvs);
+ if (!removal_lvs)
+ removal_lvs = &removed_lvs;
- if (!_raid_extract_images(lv, new_count, pvs, 1,
- &removal_lvs, &removal_lvs)) {
+ if (!_raid_extract_images(lv, new_count, allocate_pvs, 1,
+ removal_lvs, removal_lvs)) {
log_error("Failed to extract images from %s/%s",
lv->vg->name, lv->name);
return 0;
@@ -1130,7 +1151,7 @@ static int _raid_remove_images(struct logical_volume *lv,
/* Convert to linear? */
if (new_count == 1) {
- if (!_raid_remove_top_layer(lv, &removal_lvs)) {
+ if (!_raid_remove_top_layer(lv, removal_lvs)) {
log_error("Failed to remove RAID layer"
" after linear conversion");
return 0;
@@ -1139,6 +1160,9 @@ static int _raid_remove_images(struct logical_volume *lv,
first_seg(lv)->writebehind = 0;
}
+ if (!commit)
+ return 1;
+
if (!vg_write(lv->vg)) {
log_error("Failed to write changes to %s in %s",
lv->name, lv->vg->name);
@@ -1163,7 +1187,7 @@ static int _raid_remove_images(struct logical_volume *lv,
* and won't conflict with the remaining (possibly shifted)
* sub-LVs.
*/
- dm_list_iterate_items(lvl, &removal_lvs) {
+ dm_list_iterate_items(lvl, removal_lvs) {
if (!activate_lv_excl_local(lv->vg->cmd, lvl->lv)) {
log_error("Failed to resume extracted LVs");
return 0;
@@ -1185,13 +1209,9 @@ static int _raid_remove_images(struct logical_volume *lv,
/*
* Eliminate the extracted LVs
*/
- if (!dm_list_empty(&removal_lvs)) {
- dm_list_iterate_items(lvl, &removal_lvs) {
- if (!deactivate_lv(lv->vg->cmd, lvl->lv))
- return_0;
- if (!lv_remove(lvl->lv))
- return_0;
- }
+ if (!dm_list_empty(removal_lvs)) {
+ if (!_deactivate_and_remove_lvs(lv->vg, removal_lvs))
+ return_0;
if (!vg_write(lv->vg) || !vg_commit(lv->vg))
return_0;
@@ -1214,7 +1234,8 @@ static int _raid_remove_images(struct logical_volume *lv,
* the results.
*/
static int _lv_raid_change_image_count(struct logical_volume *lv, uint32_t new_count,
- struct dm_list *allocate_pvs, struct dm_list *removal_lvs)
+ struct dm_list *allocate_pvs, struct dm_list *removal_lvs,
+ int commit)
{
uint32_t old_count = lv_raid_image_count(lv);
@@ -1235,15 +1256,15 @@ static int _lv_raid_change_image_count(struct logical_volume *lv, uint32_t new_c
}
if (old_count > new_count)
- return _raid_remove_images(lv, new_count, allocate_pvs);
+ return _raid_remove_images(lv, new_count, allocate_pvs, removal_lvs, commit);
- return _raid_add_images(lv, new_count, allocate_pvs);
+ return _raid_add_images(lv, new_count, allocate_pvs, commit);
}
int lv_raid_change_image_count(struct logical_volume *lv, uint32_t new_count,
struct dm_list *allocate_pvs)
{
- return _lv_raid_change_image_count(lv, new_count, allocate_pvs, NULL);
+ return _lv_raid_change_image_count(lv, new_count, allocate_pvs, NULL, 1);
}
int lv_raid_split(struct logical_volume *lv, const char *split_name,
@@ -2105,6 +2126,9 @@ static int _raid0_to_striped_retrieve_segments_and_lvs(struct logical_volume *lv
return 1;
}
+/*
+ * Convert a RAID0 set to striped
+ */
static int _convert_raid0_to_striped(struct logical_volume *lv,
int update_and_reload,
struct dm_list *removal_lvs)
7 years, 9 months
master - raid: Move two functions.
by Alasdair Kergon
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=30884208d47f9b...
Commit: 30884208d47f9b26543134ef3d87e51422a66a85
Parent: 802bd34562f810b9f183c5b20cd24fc5675e2f98
Author: Alasdair G Kergon <agk(a)redhat.com>
AuthorDate: Sat Aug 6 23:29:27 2016 +0100
Committer: Alasdair G Kergon <agk(a)redhat.com>
CommitterDate: Sat Aug 6 23:29:27 2016 +0100
raid: Move two functions.
---
lib/metadata/lv_manip.c | 2 +-
lib/metadata/raid_manip.c | 63 +++++++++++++++++++++++----------------------
2 files changed, 33 insertions(+), 32 deletions(-)
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index d74c571..cb7e6b7 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -3281,7 +3281,7 @@ static struct alloc_handle *_alloc_init(struct cmd_context *cmd,
log_debug("Adjusted allocation request to %" PRIu32 " logical extents. Existing size %" PRIu32 ". New size %" PRIu32 ".",
total_extents, existing_extents, total_extents + existing_extents);
if (ah->log_len)
- log_debug("Mirror log of %" PRIu32 " extents of size %" PRIu32 "sectors needed for region size %" PRIu32 ".",
+ log_debug("Mirror log of %" PRIu32 " extents of size %" PRIu32 " sectors needed for region size %" PRIu32 ".",
ah->log_len, extent_size, ah->region_size);
if (mirrors || stripes)
diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c
index 4498f2f..c46802a 100644
--- a/lib/metadata/raid_manip.c
+++ b/lib/metadata/raid_manip.c
@@ -190,6 +190,38 @@ static void _clear_allocation_prohibited(struct dm_list *pvs)
pvl->pv->status &= ~PV_ALLOCATION_PROHIBITED;
}
+/* FIXME Move this out */
+/* Write, commit and optionally backup metadata of vg */
+static int _vg_write_commit_backup(struct volume_group *vg)
+{
+ if (!vg_write(vg) || !vg_commit(vg)) {
+ log_error("Failed to commit VG %s metadata.", vg->name);
+ return 0;
+ }
+
+ if (!backup(vg))
+ log_warn("WARNING: Backup of VG %s metadata failed. Continuing.", vg->name);
+
+ return 1;
+}
+
+/*
+ * Deactivate and remove the LVs on removal_lvs list from vg.
+ */
+static int _deactivate_and_remove_lvs(struct volume_group *vg, struct dm_list *removal_lvs)
+{
+ struct lv_list *lvl;
+
+ dm_list_iterate_items(lvl, removal_lvs) {
+ if (!deactivate_lv(vg->cmd, lvl->lv))
+ return_0;
+ if (!lv_remove(lvl->lv))
+ return_0;
+ }
+
+ return 1;
+}
+
/*
* _raid_in_sync
* @lv
@@ -1495,21 +1527,6 @@ int lv_raid_merge(struct logical_volume *image_lv)
}
/*
- * Deactivate and remove the LVs on removal_lvs list from vg.
- */
-static int _deactivate_and_remove_lvs(struct volume_group *vg, struct dm_list *removal_lvs)
-{
- struct lv_list *lvl;
-
- dm_list_iterate_items(lvl, removal_lvs)
- if (!deactivate_lv(vg->cmd, lvl->lv) ||
- !lv_remove(lvl->lv))
- return_0;
-
- return 1;
-}
-
-/*
* Allocate metadata devs for all @new_data_devs and link them to list @new_meta_lvs
*/
static int _alloc_rmeta_devs_for_rimage_devs(struct logical_volume *lv,
@@ -1769,22 +1786,6 @@ static int _alloc_and_add_rmeta_devs_for_lv(struct logical_volume *lv, struct dm
return 1;
}
-
-/* FIXME Move this out */
-/* Write, commit and optionally backup metadata of vg */
-static int _vg_write_commit_backup(struct volume_group *vg)
-{
- if (!vg_write(vg) || !vg_commit(vg)) {
- log_error("Failed to commit VG %s metadata.", vg->name);
- return 0;
- }
-
- if (!backup(vg))
- log_warn("WARNING: Backup of VG %s metadata failed. Continuing.", vg->name);
-
- return 1;
-}
-
/*
* Eliminate the extracted LVs on @removal_lvs from @vg incl. vg write, commit and backup
*/
7 years, 9 months
master - WHATS_NEW: fixup order
by Heinz Mauelshagen
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=802bd34562f810...
Commit: 802bd34562f810b9f183c5b20cd24fc5675e2f98
Parent: 8f25ad6416ee6edb2648ddd207a39819a6f99c1e
Author: Heinz Mauelshagen <heinzm(a)redhat.com>
AuthorDate: Fri Aug 5 16:31:46 2016 +0200
Committer: Heinz Mauelshagen <heinzm(a)redhat.com>
CommitterDate: Fri Aug 5 16:31:46 2016 +0200
WHATS_NEW: fixup order
---
WHATS_NEW | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index dce14a9..df1a434 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,10 +1,10 @@
Version 2.02.163 -
=================================
+ Add "--rebuild PV" option to lvchange to allow for PV selective rebuilds.
Preserve existing mirror region size when using --repair.
Forbid stripe parameters with lvconvert --repair.
Unify stripe size validation into get_stripe_params to catch missing cases.
Further lvconvert validation logic refactoring.
- Add "--rebuild PV" option to lvchange to allow for PV selective rebuilds.
Version 2.02.162 - 28th July 2016
=================================
7 years, 9 months
master - raid_manip: fix log print format from commit d2c3b23e6dc3
by Heinz Mauelshagen
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=8f25ad6416ee6e...
Commit: 8f25ad6416ee6edb2648ddd207a39819a6f99c1e
Parent: 9aefe9aa7ace98fa2e1cb2867a8f895e9caf380d
Author: Heinz Mauelshagen <heinzm(a)redhat.com>
AuthorDate: Fri Aug 5 16:29:56 2016 +0200
Committer: Heinz Mauelshagen <heinzm(a)redhat.com>
CommitterDate: Fri Aug 5 16:29:56 2016 +0200
raid_manip: fix log print format from commit d2c3b23e6dc3
---
lib/metadata/raid_manip.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c
index 1e2f018..4498f2f 100644
--- a/lib/metadata/raid_manip.c
+++ b/lib/metadata/raid_manip.c
@@ -2970,7 +2970,7 @@ static int _lv_raid_rebuild_or_replace(struct logical_volume *lv,
}
if (!match_count) {
- log_print_unless_silent("%s/%s does not contain devices specified"
+ log_print_unless_silent("%s does not contain devices specified"
" to %s", display_lvname(lv), action_str);
return 1;
} else if (match_count == raid_seg->area_count) {
7 years, 9 months
master - WHATS_NEW: add '--rebuild PV' option to lvchange to allow for PV selective rebuilds
by Heinz Mauelshagen
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=9aefe9aa7ace98...
Commit: 9aefe9aa7ace98fa2e1cb2867a8f895e9caf380d
Parent: d2c3b23e6dc39565093256c97ff66984e8648bda
Author: Heinz Mauelshagen <heinzm(a)redhat.com>
AuthorDate: Fri Aug 5 16:07:14 2016 +0200
Committer: Heinz Mauelshagen <heinzm(a)redhat.com>
CommitterDate: Fri Aug 5 16:07:14 2016 +0200
WHATS_NEW: add '--rebuild PV' option to lvchange to allow for PV selective rebuilds
---
WHATS_NEW | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index 3a64bbd..dce14a9 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -4,6 +4,7 @@ Version 2.02.163 -
Forbid stripe parameters with lvconvert --repair.
Unify stripe size validation into get_stripe_params to catch missing cases.
Further lvconvert validation logic refactoring.
+ Add "--rebuild PV" option to lvchange to allow for PV selective rebuilds.
Version 2.02.162 - 28th July 2016
=================================
7 years, 9 months
master - lvchange: Allow device specification when requesting a repair
by Heinz Mauelshagen
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=d2c3b23e6dc395...
Commit: d2c3b23e6dc39565093256c97ff66984e8648bda
Parent: 91f866f7866eed6eb8ead5a876efcac5a58511da
Author: Heinz Mauelshagen <heinzm(a)redhat.com>
AuthorDate: Fri Aug 5 15:54:49 2016 +0200
Committer: Heinz Mauelshagen <heinzm(a)redhat.com>
CommitterDate: Fri Aug 5 16:01:46 2016 +0200
lvchange: Allow device specification when requesting a repair
'lvchange --resync LV' or 'lvchange --syncaction repair LV' request the
RAID layout specific parity blocks in raid4/5/6 to be recreated or the
mirrored blocks to be copied again from the master leg/copy for raid1/10,
thus not allowing a rebuild of a particular PV.
Introduce repeatable option '--[raid]rebuild PV' to allow to request
rebuilds of specific PVs in a RaidLV which are known to contain corrupt
data (e.g. rebuild a raid1 master leg).
Add test lvchange-rebuild-raid.sh to test/shell doing rebuild
variations on raid1/10 and 5; add aux function check_status_chars
to support the new test.
- Resolves rhbz1064592
---
lib/metadata/metadata-exported.h | 1 +
lib/metadata/raid_manip.c | 99 +++++++++++++++++++++++++++++---------
man/lvchange.8.in | 27 ++++++++++
test/lib/aux.sh | 6 ++
tools/args.h | 2 +
tools/commands.h | 10 ++--
tools/lvchange.c | 63 ++++++++++++++++++++++++
tools/lvmcmdline.c | 1 +
8 files changed, 182 insertions(+), 27 deletions(-)
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index e1a3538..3329535 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -1204,6 +1204,7 @@ int lv_raid_convert(struct logical_volume *lv,
const unsigned new_stripe_size,
const uint32_t new_region_size,
struct dm_list *allocate_pvs);
+int lv_raid_rebuild(struct logical_volume *lv, struct dm_list *rebuild_pvs);
int lv_raid_replace(struct logical_volume *lv, struct dm_list *remove_pvs,
struct dm_list *allocate_pvs);
int lv_raid_remove_missing(struct logical_volume *lv);
diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c
index a2bf832..1e2f018 100644
--- a/lib/metadata/raid_manip.c
+++ b/lib/metadata/raid_manip.c
@@ -2889,16 +2889,24 @@ has_enough_space:
}
/*
- * lv_raid_replace
+ * Helper:
+ *
+ * _lv_raid_rebuild_or_replace
* @lv
* @remove_pvs
* @allocate_pvs
+ * @rebuild
+ *
+ * Rebuild the specified PVs on @remove_pvs if rebuild != 0;
+ * @allocate_pvs not accessed for rebuild.
*
- * Replace the specified PVs.
+ * Replace the specified PVs on @remove_pvs if rebuild == 0;
+ * new SubLVS are allocated on PVs on list @allocate_pvs.
*/
-int lv_raid_replace(struct logical_volume *lv,
- struct dm_list *remove_pvs,
- struct dm_list *allocate_pvs)
+static int _lv_raid_rebuild_or_replace(struct logical_volume *lv,
+ struct dm_list *remove_pvs,
+ struct dm_list *allocate_pvs,
+ int rebuild)
{
int partial_segment_removed = 0;
uint32_t s, sd, match_count = 0;
@@ -2907,6 +2915,7 @@ int lv_raid_replace(struct logical_volume *lv,
struct lv_segment *raid_seg = first_seg(lv);
struct lv_list *lvl;
char *tmp_names[raid_seg->area_count * 2];
+ const char *action_str = rebuild ? "rebuild" : "replace";
if (seg_is_any_raid0(raid_seg)) {
log_error("Can't replace any devices in %s LV %s",
@@ -2951,28 +2960,33 @@ int lv_raid_replace(struct logical_volume *lv,
if (lv_is_virtual(seg_lv(raid_seg, s)) ||
lv_is_virtual(seg_metalv(raid_seg, s)) ||
lv_is_on_pvs(seg_lv(raid_seg, s), remove_pvs) ||
- lv_is_on_pvs(seg_metalv(raid_seg, s), remove_pvs))
+ lv_is_on_pvs(seg_metalv(raid_seg, s), remove_pvs)) {
match_count++;
+ if (rebuild) {
+ seg_lv(raid_seg, s)->status |= LV_REBUILD;
+ seg_metalv(raid_seg, s)->status |= LV_REBUILD;
+ }
+ }
}
if (!match_count) {
- log_verbose("%s/%s does not contain devices specified"
- " for replacement", lv->vg->name, lv->name);
+ log_print_unless_silent("%s/%s does not contain devices specified"
+ " to %s", display_lvname(lv), action_str);
return 1;
} else if (match_count == raid_seg->area_count) {
- log_error("Unable to remove all PVs from %s/%s at once.",
- lv->vg->name, lv->name);
+ log_error("Unable to %s all PVs from %s/%s at once.",
+ action_str, lv->vg->name, lv->name);
return 0;
} else if (raid_seg->segtype->parity_devs &&
(match_count > raid_seg->segtype->parity_devs)) {
- log_error("Unable to replace more than %u PVs from (%s) %s/%s",
- raid_seg->segtype->parity_devs,
+ log_error("Unable to %s more than %u PVs from (%s) %s/%s",
+ action_str, raid_seg->segtype->parity_devs,
lvseg_name(raid_seg),
lv->vg->name, lv->name);
return 0;
} else if (seg_is_raid10(raid_seg)) {
uint32_t i, rebuilds_per_group = 0;
- /* FIXME: We only support 2-way mirrors in RAID10 currently */
+ /* FIXME: We only support 2-way mirrors (i.e. 2 data copies) in RAID10 currently */
uint32_t copies = 2;
for (i = 0; i < raid_seg->area_count * copies; i++) {
@@ -2985,13 +2999,16 @@ int lv_raid_replace(struct logical_volume *lv,
lv_is_virtual(seg_metalv(raid_seg, s)))
rebuilds_per_group++;
if (rebuilds_per_group >= copies) {
- log_error("Unable to replace all the devices "
- "in a RAID10 mirror group.");
+ log_error("Unable to %s all the devices "
+ "in a RAID10 mirror group.", action_str);
return 0;
}
}
}
+ if (rebuild)
+ goto skip_alloc;
+
/* Prevent any PVs holding image components from being used for allocation */
if (!_avoid_pvs_with_other_images_of_lv(lv, allocate_pvs)) {
log_error("Failed to prevent PVs holding image components "
@@ -3122,9 +3139,11 @@ try_again:
tmp_names[s] = tmp_names[sd] = NULL;
}
+skip_alloc:
if (!lv_update_and_reload_origin(lv))
return_0;
+ /* @old_lvs is empty in case of a rebuild */
dm_list_iterate_items(lvl, &old_lvs) {
if (!deactivate_lv(lv->vg->cmd, lvl->lv))
return_0;
@@ -3132,23 +3151,57 @@ try_again:
return_0;
}
- /* Update new sub-LVs to correct name and clear REBUILD flag */
+ /* Clear REBUILD flag */
for (s = 0; s < raid_seg->area_count; s++) {
- sd = s + raid_seg->area_count;
- if (tmp_names[s] && tmp_names[sd]) {
- seg_metalv(raid_seg, s)->name = tmp_names[s];
- seg_lv(raid_seg, s)->name = tmp_names[sd];
- seg_metalv(raid_seg, s)->status &= ~LV_REBUILD;
- seg_lv(raid_seg, s)->status &= ~LV_REBUILD;
- }
+ seg_lv(raid_seg, s)->status &= ~LV_REBUILD;
+ seg_metalv(raid_seg, s)->status &= ~LV_REBUILD;
}
+ /* If replace, correct name(s) */
+ if (!rebuild)
+ for (s = 0; s < raid_seg->area_count; s++) {
+ sd = s + raid_seg->area_count;
+ if (tmp_names[s] && tmp_names[sd]) {
+ seg_metalv(raid_seg, s)->name = tmp_names[s];
+ seg_lv(raid_seg, s)->name = tmp_names[sd];
+ }
+ }
+
if (!lv_update_and_reload_origin(lv))
return_0;
return 1;
}
+/*
+ * lv_raid_rebuild
+ * @lv
+ * @remove_pvs
+ *
+ * Rebuild the specified PVs of @lv on @remove_pvs.
+ */
+int lv_raid_rebuild(struct logical_volume *lv,
+ struct dm_list *rebuild_pvs)
+{
+ return _lv_raid_rebuild_or_replace(lv, rebuild_pvs, NULL, 1);
+}
+
+/*
+ * lv_raid_replace
+ * @lv
+ * @remove_pvs
+ * @allocate_pvs
+ *
+ * Replace the specified PVs on @remove_pvs of @lv
+ * allocating new SubLVs from PVs on list @allocate_pvs.
+ */
+int lv_raid_replace(struct logical_volume *lv,
+ struct dm_list *remove_pvs,
+ struct dm_list *allocate_pvs)
+{
+ return _lv_raid_rebuild_or_replace(lv, remove_pvs, allocate_pvs, 0);
+}
+
int lv_raid_remove_missing(struct logical_volume *lv)
{
uint32_t s;
diff --git a/man/lvchange.8.in b/man/lvchange.8.in
index 3800369..8da9f2d 100644
--- a/man/lvchange.8.in
+++ b/man/lvchange.8.in
@@ -25,6 +25,8 @@ lvchange \(em change attributes of a logical volume
.IR AllocationPolicy ]
.RB [ \-A | \-\-autobackup
.RB { y | n }]
+.RB [ \-\-rebuild
+.IR PhysicalVolume ]
.RB [ \-\-cachemode
.RB { passthrough | writeback | writethrough }]
.RB [ \-\-cachepolicy
@@ -326,6 +328,31 @@ immediately poll a logical volume when it is activated, use
\fB\-\-poll n\fP to defer and then \fB\-\-poll y\fP to restart the process.
.
.HP
+.BR \-\- [ raid ] rebuild
+.BR \fIPhysicalVolume
+.br
+Option can be repeated multiple times.
+Selects PhysicalVolume(s) to be rebuild in a RaidLV.
+Use this option instead of
+.BR \-\-resync
+or
+.BR \-\- [ raid ] syncaction
+\fBrepair\fP in case the PVs with corrupted data are known and their data
+should be reconstructed rather than reconstructing default (rotating) data.
+.br
+E.g. in a raid1 mirror, the master leg on /dev/sda may hold corrupt data due
+to a known transient disk error, thus
+.br
+\fBlvchange --rebuild /dev/sda LV\fP
+.br
+will request the master leg to be rebuild rather than rebuilding
+all other legs from the master.
+On a raid5 with rotating data and parity
+.br
+\fBlvchange --rebuild /dev/sda LV\fP
+.br
+will rebuild all data and parity blocks in the stripe on /dev/sda.
+.HP
.BR \-\- [ raid ] maxrecoveryrate
.BR \fIRate [ b | B | s | S | k | K | m | M | g | G ]
.br
diff --git a/test/lib/aux.sh b/test/lib/aux.sh
index 90f2ab1..726cfe3 100644
--- a/test/lib/aux.sh
+++ b/test/lib/aux.sh
@@ -1265,6 +1265,12 @@ wait_for_sync() {
return 1
}
+# aux check_status_chars $vg $lv "Aaaaa"
+check_status_chars() {
+ [ `dmsetup status $1-$2|awk '{print $6}'` = $3 ] && return
+ return 1
+}
+
# Check if tests are running on 64bit architecture
can_use_16T() {
test "$(getconf LONG_BIT)" -eq 64
diff --git a/tools/args.h b/tools/args.h
index 5902513..a04d81d 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -88,6 +88,7 @@ arg(poolmetadatasize_ARG, '\0', "poolmetadatasize", size_mb_arg, 0, 0)
arg(poolmetadataspare_ARG, '\0', "poolmetadataspare", yes_no_arg, 0, 0)
arg(profile_ARG, '\0', "profile", string_arg, 0, 0)
arg(pvmetadatacopies_ARG, '\0', "pvmetadatacopies", int_arg, 0, 0)
+arg(raidrebuild_ARG, '\0', "raidrebuild", string_arg, ARG_GROUPABLE, 0)
arg(raidmaxrecoveryrate_ARG, '\0', "raidmaxrecoveryrate", size_kb_arg, 0, 0)
arg(raidminrecoveryrate_ARG, '\0', "raidminrecoveryrate", size_kb_arg, 0, 0)
arg(raidsyncaction_ARG, '\0', "raidsyncaction", string_arg, 0, 0)
@@ -96,6 +97,7 @@ arg(raidwritemostly_ARG, '\0', "raidwritemostly", string_arg, ARG_GROUPABLE, 0)
arg(readonly_ARG, '\0', "readonly", NULL, 0, 0)
arg(refresh_ARG, '\0', "refresh", NULL, 0, 0)
arg(removemissing_ARG, '\0', "removemissing", NULL, 0, 0)
+arg(rebuild_ARG, '\0', "rebuild", string_arg, ARG_GROUPABLE, 0)
arg(repair_ARG, '\0', "repair", NULL, 0, 0)
arg(replace_ARG, '\0', "replace", string_arg, ARG_GROUPABLE, 0)
arg(reportformat_ARG, '\0', "reportformat", string_arg, 0, 0)
diff --git a/tools/commands.h b/tools/commands.h
index c348753..baf89b1 100644
--- a/tools/commands.h
+++ b/tools/commands.h
@@ -195,6 +195,7 @@ xx(lvchange,
"\t[--activationmode {complete|degraded|partial}"
"\t[--addtag <Tag>]\n"
"\t[--alloc <AllocationPolicy>]\n"
+ "\t[--rebuild PhysicalVolume]\n"
"\t[-C|--contiguous {y|n}]\n"
"\t[--cachemode <CacheMode>]\n"
"\t[--cachepolicy <policyname>] [--cachesettings <parameter=value>]\n"
@@ -244,10 +245,10 @@ xx(lvchange,
ignoreskippedcluster_ARG, major_ARG, metadataprofile_ARG, minor_ARG,
monitor_ARG, minrecoveryrate_ARG, maxrecoveryrate_ARG, noudevsync_ARG,
partial_ARG, permission_ARG, persistent_ARG, poll_ARG,
- raidminrecoveryrate_ARG, raidmaxrecoveryrate_ARG, raidsyncaction_ARG,
- raidwritebehind_ARG, raidwritemostly_ARG, readahead_ARG, reportformat_ARG,
- resync_ARG, refresh_ARG, select_ARG, setactivationskip_ARG, syncaction_ARG,
- sysinit_ARG, test_ARG, writebehind_ARG, writemostly_ARG, zero_ARG)
+ raidrebuild_ARG, raidminrecoveryrate_ARG, raidmaxrecoveryrate_ARG,
+ raidsyncaction_ARG, raidwritebehind_ARG, raidwritemostly_ARG, readahead_ARG,
+ reportformat_ARG, rebuild_ARG, resync_ARG, refresh_ARG, select_ARG, setactivationskip_ARG,
+ syncaction_ARG, sysinit_ARG, test_ARG, writebehind_ARG, writemostly_ARG, zero_ARG)
#define COMMON_OPTS \
"\t[--commandprofile <ProfileName>] [-d|--debug] [-h|-?|--help]\n" \
@@ -259,6 +260,7 @@ xx(lvconvert,
"lvconvert "
"[-m|--mirrors <Mirrors> [--mirrorlog {disk|core|mirrored}|--corelog]]\n"
"\t[--type <SegmentType>]\n"
+ "\t[--rebuild PhysicalVolume]\n"
"\t[--repair [--use-policies]]\n"
"\t[--replace PhysicalVolume]\n"
"\t[-R|--regionsize <MirrorLogRegionSize>]\n"
diff --git a/tools/lvchange.c b/tools/lvchange.c
index 9194cd6..e0d91fc 100644
--- a/tools/lvchange.c
+++ b/tools/lvchange.c
@@ -750,6 +750,60 @@ static int _lvchange_tag(struct cmd_context *cmd, struct logical_volume *lv, int
return 1;
}
+static int _lvchange_rebuild(struct logical_volume *lv)
+{
+ int pv_count, i = 0;
+ char **rebuild_pvs;
+ const char *tmp_str;
+ struct dm_list *rebuild_pvh = NULL;
+ struct arg_value_group_list *group;
+ struct volume_group *vg = lv->vg;
+ struct cmd_context *cmd = vg->cmd;
+ struct lv_segment *raid_seg = first_seg(lv);
+
+ if (!seg_is_raid(raid_seg) || seg_is_any_raid0(raid_seg)) {
+ log_error("--rebuild can only be used with 'raid4/5/6/10' segment types.");
+ return 0;
+ }
+
+ if (!(pv_count = arg_count(cmd, rebuild_ARG))) {
+ log_error("No --rebuild found!");
+ return 0;
+ }
+
+ if (!arg_is_set(cmd, yes_ARG) &&
+ yes_no_prompt("Do you really want to rebuild %u PVs "
+ "of logical volume %s [y/n]: ",
+ pv_count, display_lvname(lv)) == 'n') {
+ log_error("Logical volume %s not rebuild.",
+ display_lvname(lv));
+ return 0;
+ }
+
+ /* rebuild can be specified more than once */
+ if (!(rebuild_pvs = dm_pool_alloc(vg->vgmem, sizeof(char *) * pv_count)))
+ return_0;
+
+ dm_list_iterate_items(group, &cmd->arg_value_groups) {
+ if (!grouped_arg_is_set(group->arg_values, rebuild_ARG))
+ continue;
+
+ if (!(tmp_str = grouped_arg_str_value(group->arg_values,
+ rebuild_ARG, NULL)))
+ return_0;
+
+ if (!(rebuild_pvs[i++] = dm_pool_strdup(cmd->mem, tmp_str)))
+ return_0;
+ }
+
+ if (!(rebuild_pvh = create_pv_list(cmd->mem, vg,
+ pv_count, rebuild_pvs, 0)))
+ return_ECMD_FAILED;
+
+ /* Rebuild PVs listed on @rebuild_pvh */
+ return lv_raid_rebuild(lv, rebuild_pvh);
+}
+
static int _lvchange_writemostly(struct logical_volume *lv)
{
int s, pv_count, i = 0;
@@ -1132,6 +1186,14 @@ static int _lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
docmds++;
}
+ /* rebuild selected PVs */
+ if (arg_is_set(cmd, rebuild_ARG)) {
+ if (!archive(lv->vg))
+ return_ECMD_FAILED;
+ doit += _lvchange_rebuild(lv);
+ docmds++;
+ }
+
/* change writemostly/writebehind */
if (arg_is_set(cmd, writemostly_ARG) || arg_is_set(cmd, writebehind_ARG)) {
if (!archive(lv->vg))
@@ -1245,6 +1307,7 @@ int lvchange(struct cmd_context *cmd, int argc, char **argv)
errorwhenfull_ARG,
maxrecoveryrate_ARG,
minrecoveryrate_ARG,
+ rebuild_ARG,
resync_ARG,
syncaction_ARG,
writebehind_ARG,
diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
index fd00ce6..4ad2ea6 100644
--- a/tools/lvmcmdline.c
+++ b/tools/lvmcmdline.c
@@ -1167,6 +1167,7 @@ static int _get_settings(struct cmd_context *cmd)
!_merge_synonym(cmd, allocation_ARG, resizeable_ARG) ||
!_merge_synonym(cmd, virtualoriginsize_ARG, virtualsize_ARG) ||
!_merge_synonym(cmd, available_ARG, activate_ARG) ||
+ !_merge_synonym(cmd, raidrebuild_ARG, rebuild_ARG) ||
!_merge_synonym(cmd, raidsyncaction_ARG, syncaction_ARG) ||
!_merge_synonym(cmd, raidwritemostly_ARG, writemostly_ARG) ||
!_merge_synonym(cmd, raidminrecoveryrate_ARG, minrecoveryrate_ARG) ||
7 years, 9 months
master - raid: Tell lib whether stripesize was specified
by Alasdair Kergon
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=91f866f7866eed...
Commit: 91f866f7866eed6eb8ead5a876efcac5a58511da
Parent: 7482ff93b8316767ad128b43fcf5fae8725f8057
Author: Alasdair G Kergon <agk(a)redhat.com>
AuthorDate: Fri Aug 5 14:28:14 2016 +0100
Committer: Alasdair G Kergon <agk(a)redhat.com>
CommitterDate: Fri Aug 5 14:28:14 2016 +0100
raid: Tell lib whether stripesize was specified
---
lib/metadata/metadata-exported.h | 1 +
lib/metadata/raid_manip.c | 11 ++++++-----
tools/lvconvert.c | 5 ++++-
3 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index e61802d..e1a3538 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -1200,6 +1200,7 @@ int lv_raid_convert(struct logical_volume *lv,
const struct segment_type *new_segtype,
int yes, int force,
const unsigned stripes,
+ const unsigned new_stripe_size_supplied,
const unsigned new_stripe_size,
const uint32_t new_region_size,
struct dm_list *allocate_pvs);
diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c
index 2cc48e1..a2bf832 100644
--- a/lib/metadata/raid_manip.c
+++ b/lib/metadata/raid_manip.c
@@ -2744,6 +2744,7 @@ int lv_raid_convert(struct logical_volume *lv,
const struct segment_type *new_segtype,
int yes, int force,
const unsigned new_stripes,
+ const unsigned new_stripe_size_supplied,
const unsigned new_stripe_size,
const uint32_t new_region_size,
struct dm_list *allocate_pvs)
@@ -2758,7 +2759,11 @@ int lv_raid_convert(struct logical_volume *lv,
return 0;
}
- stripes = new_stripes ?: _data_rimages_count(seg, seg->area_count);
+ stripes = new_stripes ? : _data_rimages_count(seg, seg->area_count);
+
+ /* FIXME Ensure caller does *not* set wrong default value! */
+ /* Define new stripe size if not passed in */
+ stripe_size = new_stripe_size ? : seg->stripe_size;
if (segtype_is_striped(new_segtype))
new_image_count = stripes;
@@ -2766,10 +2771,6 @@ int lv_raid_convert(struct logical_volume *lv,
if (segtype_is_raid(new_segtype) && !_check_max_raid_devices(new_image_count))
return_0;
- /* FIXME Ensure caller does *not* set wrong default value! */
- /* Define new stripe size if not passed in */
- stripe_size = new_stripe_size ?: seg->stripe_size;
-
takeover_fn = _get_takeover_fn(first_seg(lv), new_segtype, new_image_count);
/* Exit without doing activation checks if the combination isn't possible */
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 5731558..8c3bf05 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -86,6 +86,7 @@ struct lvconvert_params {
sign_t mirrors_sign;
uint32_t stripes;
uint32_t stripe_size;
+ uint32_t stripe_size_supplied;
uint32_t read_ahead;
cache_mode_t cache_mode; /* cache */
const char *policy_name; /* cache */
@@ -1905,7 +1906,7 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
log_error("RAID module does not support RAID0.");
return 0;
}
- if (!lv_raid_convert(lv, lp->segtype, lp->yes, lp->force, lp->stripes, lp->stripe_size,
+ if (!lv_raid_convert(lv, lp->segtype, lp->yes, lp->force, lp->stripes, lp->stripe_size_supplied, lp->stripe_size,
lp->region_size, lp->pvh))
return_0;
log_print_unless_silent("Logical volume %s successfully converted.",
@@ -4405,6 +4406,8 @@ static int _lvconvert(struct cmd_context *cmd, struct logical_volume *lv,
_striped_type_requested(lp->type_str) || lp->repair || lp->mirrorlog || lp->corelog) {
if (!get_stripe_params(cmd, lp->segtype, &lp->stripes, &lp->stripe_size))
return_0;
+ /* FIXME Move this into the get function */
+ lp->stripe_size_supplied = arg_is_set(cmd, stripesize_ARG);
if (_raid0_type_requested(lp->type_str) || _striped_type_requested(lp->type_str))
/* FIXME Shouldn't need to override get_stripe_params which defaults to 1 stripe (i.e. linear)! */
7 years, 9 months
master - raid: Turn lv_raid_change_image_count into wrapper
by Alasdair Kergon
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=7482ff93b83167...
Commit: 7482ff93b8316767ad128b43fcf5fae8725f8057
Parent: b66fa91c46f88029eb730f07524d2c09a4ded559
Author: Alasdair G Kergon <agk(a)redhat.com>
AuthorDate: Fri Aug 5 14:10:41 2016 +0100
Committer: Alasdair G Kergon <agk(a)redhat.com>
CommitterDate: Fri Aug 5 14:17:54 2016 +0100
raid: Turn lv_raid_change_image_count into wrapper
Eventually the separate entry point will disappear.
---
lib/metadata/metadata-exported.h | 2 +-
lib/metadata/raid_manip.c | 24 ++++++++++++++----------
2 files changed, 15 insertions(+), 11 deletions(-)
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 531fa03..e61802d 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -1190,7 +1190,7 @@ struct logical_volume *first_replicator_dev(const struct logical_volume *lv);
int lv_is_raid_with_tracking(const struct logical_volume *lv);
uint32_t lv_raid_image_count(const struct logical_volume *lv);
int lv_raid_change_image_count(struct logical_volume *lv,
- uint32_t new_count, struct dm_list *pvs);
+ uint32_t new_count, struct dm_list *allocate_pvs);
int lv_raid_split(struct logical_volume *lv, const char *split_name,
uint32_t new_count, struct dm_list *splittable_pvs);
int lv_raid_split_and_track(struct logical_volume *lv,
diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c
index 109cb2e..2cc48e1 100644
--- a/lib/metadata/raid_manip.c
+++ b/lib/metadata/raid_manip.c
@@ -1171,21 +1171,18 @@ static int _raid_remove_images(struct logical_volume *lv,
}
/*
- * lv_raid_change_image_count
- * @lv
- * @new_count: The absolute count of images (e.g. '2' for a 2-way mirror)
- * @pvs: The list of PVs that are candidates for removal (or empty list)
+ * _lv_raid_change_image_count
+ * new_count: The absolute count of images (e.g. '2' for a 2-way mirror)
+ * allocate_pvs: The list of PVs that are candidates for removal (or empty list)
*
* RAID arrays have 'images' which are composed of two parts, they are:
* - 'rimage': The data/parity holding portion
* - 'rmeta' : The metadata holding portion (i.e. superblock/bitmap area)
* This function adds or removes _both_ portions of the image and commits
* the results.
- *
- * Returns: 1 on success, 0 on failure
*/
-int lv_raid_change_image_count(struct logical_volume *lv,
- uint32_t new_count, struct dm_list *pvs)
+static int _lv_raid_change_image_count(struct logical_volume *lv, uint32_t new_count,
+ struct dm_list *allocate_pvs, struct dm_list *removal_lvs)
{
uint32_t old_count = lv_raid_image_count(lv);
@@ -1206,9 +1203,15 @@ int lv_raid_change_image_count(struct logical_volume *lv,
}
if (old_count > new_count)
- return _raid_remove_images(lv, new_count, pvs);
+ return _raid_remove_images(lv, new_count, allocate_pvs);
- return _raid_add_images(lv, new_count, pvs);
+ return _raid_add_images(lv, new_count, allocate_pvs);
+}
+
+int lv_raid_change_image_count(struct logical_volume *lv, uint32_t new_count,
+ struct dm_list *allocate_pvs)
+{
+ return _lv_raid_change_image_count(lv, new_count, allocate_pvs, NULL);
}
int lv_raid_split(struct logical_volume *lv, const char *split_name,
@@ -1543,6 +1546,7 @@ static int _alloc_rmeta_devs_for_rimage_devs(struct logical_volume *lv,
return 1;
}
+
/* Add new @lvs to @lv at @area_offset */
static int _add_image_component_list(struct lv_segment *seg, int delete_from_list,
uint64_t lv_flags, struct dm_list *lvs, uint32_t area_offset)
7 years, 9 months