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

lvconvert: prevent non-synced raid1 primary leg repair

(Automatic) repair may not be allowed during the initial sync of an upconverted
linear LV, because the data on the failing, primary leg hasn't been completely
synchronized to the N-1 other legs of the raid1 LV (replacing failed legs during
repair involves discontinuing access to any replaced legs data, thus preventing
data recovery on the primary leg e.g. via dd_rescue).

Even though repair would not cause data loss when adding legs to a fully synced
raid1 LV, we don't have information yet defining this state yet (e.g. a raid1
LV flag telling the fully synchronized status before any legs were added),
hence can't automatically decide to allow to repair.

If nonetheless a repair on a non-synced raid1 LVs is intended, the "--force"
option has to be provided.

Resolves: rhbz1311765
This commit is contained in:
Heinz Mauelshagen 2016-10-28 15:54:27 +02:00
parent e118b65d65
commit 8270ff5702
4 changed files with 47 additions and 22 deletions

View File

@ -1,5 +1,6 @@
Version 2.02.167 -
======================================
Prevent non-synced raid1 repair unless --force
Prevent raid4 creation/conversion on non-supporting kernels
Add direct striped -> raid4 conversion
Fix raid4 parity image pair position on conversions from striped/raid0*

View File

@ -1208,8 +1208,8 @@ int lv_raid_convert(struct logical_volume *lv,
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_replace(struct logical_volume *lv, int force,
struct dm_list *remove_pvs, struct dm_list *allocate_pvs);
int lv_raid_remove_missing(struct logical_volume *lv);
int partial_raid_lv_supports_degraded_activation(const struct logical_volume *lv);
/* -- metadata/raid_manip.c */

View File

@ -266,19 +266,16 @@ static int _deactivate_and_remove_lvs(struct volume_group *vg, struct dm_list *r
*
* Returns: 1 if in-sync, 0 otherwise.
*/
#define _RAID_IN_SYNC_RETRIES 6
static int _raid_in_sync(struct logical_volume *lv)
{
int retries = _RAID_IN_SYNC_RETRIES;
dm_percent_t sync_percent;
if (seg_is_striped(first_seg(lv)))
return 1;
if (!lv_raid_percent(lv, &sync_percent)) {
log_error("Unable to determine sync status of %s/%s.",
lv->vg->name, lv->name);
return 0;
}
if (sync_percent == DM_PERCENT_0) {
do {
/*
* FIXME We repeat the status read here to workaround an
* unresolved kernel bug when we see 0 even though the
@ -290,14 +287,31 @@ static int _raid_in_sync(struct logical_volume *lv)
lv->vg->name, lv->name);
return 0;
}
if (sync_percent == DM_PERCENT_100)
if (sync_percent > DM_PERCENT_0)
break;
if (retries == _RAID_IN_SYNC_RETRIES)
log_warn("WARNING: Sync status for %s is inconsistent.",
display_lvname(lv));
}
usleep(500000);
} while (--retries);
return (sync_percent == DM_PERCENT_100) ? 1 : 0;
}
/* Check if RaidLV @lv is synced or any raid legs of @lv are not synced */
static int _raid_devs_sync_healthy(struct logical_volume *lv)
{
char *raid_health;
if (!_raid_in_sync(lv))
return 0;
if (!lv_raid_dev_health(lv, &raid_health))
return_0;
return (strchr(raid_health, 'a') || strchr(raid_health, 'D')) ? 0 : 1;
}
/*
* _raid_remove_top_layer
* @lv
@ -1054,6 +1068,7 @@ static int _extract_image_components(struct lv_segment *seg, uint32_t idx,
/*
* _raid_extract_images
* @lv
* @force: force a replacement in case of primary mirror leg
* @new_count: The absolute count of images (e.g. '2' for a 2-way mirror)
* @target_pvs: The list of PVs that are candidates for removal
* @shift: If set, use _shift_and_rename_image_components().
@ -1068,7 +1083,8 @@ static int _extract_image_components(struct lv_segment *seg, uint32_t idx,
*
* Returns: 1 on success, 0 on failure
*/
static int _raid_extract_images(struct logical_volume *lv, uint32_t new_count,
static int _raid_extract_images(struct logical_volume *lv,
int force, uint32_t new_count,
struct dm_list *target_pvs, int shift,
struct dm_list *extracted_meta_lvs,
struct dm_list *extracted_data_lvs)
@ -1136,11 +1152,16 @@ static int _raid_extract_images(struct logical_volume *lv, uint32_t new_count,
!lv_is_on_pvs(seg_metalv(seg, s), target_pvs))
continue;
if (!_raid_in_sync(lv) &&
(!seg_is_mirrored(seg) || (s == 0))) {
/*
* Kernel may report raid LV in-sync but still
* image devices may not be in-sync or faulty.
*/
if (!_raid_devs_sync_healthy(lv) &&
(!seg_is_mirrored(seg) || (s == 0 && !force))) {
log_error("Unable to extract %sRAID image"
" while RAID array is not in-sync",
seg_is_mirrored(seg) ? "primary " : "");
" while RAID array is not in-sync%s",
seg_is_mirrored(seg) ? "primary " : "",
seg_is_mirrored(seg) ? " (use --force option to replace)" : "");
return 0;
}
}
@ -1185,7 +1206,7 @@ static int _raid_remove_images(struct logical_volume *lv,
if (!removal_lvs)
removal_lvs = &removed_lvs;
if (!_raid_extract_images(lv, new_count, allocate_pvs, 1,
if (!_raid_extract_images(lv, 0, new_count, allocate_pvs, 1,
removal_lvs, removal_lvs)) {
log_error("Failed to extract images from %s/%s",
lv->vg->name, lv->name);
@ -1375,7 +1396,7 @@ int lv_raid_split(struct logical_volume *lv, const char *split_name,
return_0;
}
if (!_raid_extract_images(lv, new_count, splittable_pvs, 1,
if (!_raid_extract_images(lv, 0, new_count, splittable_pvs, 1,
&removal_lvs, &data_list)) {
log_error("Failed to extract images from %s/%s",
lv->vg->name, lv->name);
@ -3869,6 +3890,7 @@ has_enough_space:
* new SubLVS are allocated on PVs on list @allocate_pvs.
*/
static int _lv_raid_rebuild_or_replace(struct logical_volume *lv,
int force,
struct dm_list *remove_pvs,
struct dm_list *allocate_pvs,
int rebuild)
@ -4043,7 +4065,8 @@ try_again:
* supplied - knowing that only the image with the error target
* will be affected.
*/
if (!_raid_extract_images(lv, raid_seg->area_count - match_count,
if (!_raid_extract_images(lv, force,
raid_seg->area_count - match_count,
partial_segment_removed ?
&lv->vg->pvs : remove_pvs, 0,
&old_lvs, &old_lvs)) {
@ -4148,7 +4171,7 @@ skip_alloc:
int lv_raid_rebuild(struct logical_volume *lv,
struct dm_list *rebuild_pvs)
{
return _lv_raid_rebuild_or_replace(lv, rebuild_pvs, NULL, 1);
return _lv_raid_rebuild_or_replace(lv, 0, rebuild_pvs, NULL, 1);
}
/*
@ -4161,10 +4184,11 @@ int lv_raid_rebuild(struct logical_volume *lv,
* allocating new SubLVs from PVs on list @allocate_pvs.
*/
int lv_raid_replace(struct logical_volume *lv,
int force,
struct dm_list *remove_pvs,
struct dm_list *allocate_pvs)
{
return _lv_raid_rebuild_or_replace(lv, remove_pvs, allocate_pvs, 0);
return _lv_raid_rebuild_or_replace(lv, force, remove_pvs, allocate_pvs, 0);
}
int lv_raid_remove_missing(struct logical_volume *lv)

View File

@ -1994,7 +1994,7 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
}
if (lp->replace)
return lv_raid_replace(lv, lp->replace_pvh, lp->pvh);
return lv_raid_replace(lv, lp->force, lp->replace_pvh, lp->pvh);
if (lp->repair) {
if (!lv_is_active_exclusive_locally(lv_lock_holder(lv))) {
@ -2017,7 +2017,7 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
if (!(failed_pvs = _failed_pv_list(lv->vg)))
return_0;
if (!lv_raid_replace(lv, failed_pvs, lp->pvh)) {
if (!lv_raid_replace(lv, lp->force, failed_pvs, lp->pvh)) {
log_error("Failed to replace faulty devices in %s.",
display_lvname(lv));
return 0;