diff options
author | Heinz Mauelshagen <heinzm@redhat.com> | 2017-08-18 15:14:03 +0200 |
---|---|---|
committer | Heinz Mauelshagen <heinzm@redhat.com> | 2017-08-18 15:14:03 +0200 |
commit | adcaf772f773ce71b0cd968b636380cbbcbc732b (patch) | |
tree | edcacf2a623c120631757f3173b83d8bea5ef9d5 | |
parent | df5c2964269895b6f5ce16dbdb70edd57c5aa67d (diff) | |
download | lvm2-dev-lvmguy-more-validation-for-raid.tar.gz |
raid: more validation checks for RAID segmentsdev-lvmguy-more-validation-for-raid
Upgrade commit 222e1e3acee399b0acf31565f784716d67c465a8 with more checks.
-rw-r--r-- | lib/metadata/merge.c | 47 |
1 files changed, 43 insertions, 4 deletions
diff --git a/lib/metadata/merge.c b/lib/metadata/merge.c index b0adc5a11..4b171d752 100644 --- a/lib/metadata/merge.c +++ b/lib/metadata/merge.c @@ -98,6 +98,40 @@ int lv_merge_segments(struct logical_volume *lv) return; \ } +/* Check RAID @seg for proper delta disks flags */ +static void _check_raid_delta_disks(struct lv_segment *seg, int *error_count) +{ + uint32_t disks_minus = 0, disks_plus = 0, s; + + for (s = 0; s < seg->area_count; s++) { + if (seg_lv(seg, s)->status & LV_RESHAPE_DELTA_DISKS_PLUS) + disks_plus++; + if (seg_lv(seg, s)->status & LV_RESHAPE_DELTA_DISKS_MINUS) + disks_minus++; + if (seg_is_striped_raid(seg) && + (disks_plus || disks_minus) && + s < 2 * seg->segtype->parity_devs) + raid_seg_error("LV_RESHAPE_DELTA_DISK_PLUS/MINUS set on wrong rimage"); + } + + if (disks_plus && disks_minus) + raid_seg_error("both LV_RESHAPE_DELTA_DISK_PLUS flag and LV_RESHAPE_DELTA_DISK_MINUS"); + + if (seg->area_count + disks_plus > DEFAULT_RAID_MAX_IMAGES) + raid_seg_error("too many LV_RESHAPE_DELTA_DISK_PLUS rimages"); + + if (seg_is_striped_raid(seg) && + seg->area_count - disks_minus < 2 * seg->segtype->parity_devs) + raid_seg_error("too many LV_RESHAPE_DELTA_DISK_PLUS/MINUS rimage(s)"); + + if (!seg_is_striped_raid(seg)) { + if (disks_plus) + raid_seg_error("bogus LV_RESHAPE_DELTA_DISK_PLUS"); + if (disks_minus) + raid_seg_error("bogus LV_RESHAPE_DELTA_DISK_MINUS"); + } +} + /* Check raid0 segment properties in @seg */ static void _check_raid0_seg(struct lv_segment *seg, int *error_count) { @@ -119,8 +153,9 @@ static void _check_raid0_seg(struct lv_segment *seg, int *error_count) raid_seg_error_val("non-zero min recovery rate", seg->min_recovery_rate); if (seg->max_recovery_rate) raid_seg_error_val("non-zero max recovery rate", seg->max_recovery_rate); - if ((seg->lv->status & LV_RESHAPE_DATA_OFFSET) || seg->data_offset) + if ((seg->lv->status & LV_RESHAPE_DATA_OFFSET) || (seg->data_offset > 1)) raid_seg_error_val("data_offset", seg->data_offset); + _check_raid_delta_disks(seg, error_count); } /* Check RAID @seg for non-zero, power of 2 region size and min recovery rate <= max */ @@ -143,8 +178,9 @@ static void _check_raid1_seg(struct lv_segment *seg, int *error_count) raid_seg_error("no meta areas"); if (seg->stripe_size) raid_seg_error_val("non-zero stripe size", seg->stripe_size); - if ((seg->lv->status & LV_RESHAPE_DATA_OFFSET) || seg->data_offset) + if ((seg->lv->status & LV_RESHAPE_DATA_OFFSET) || (seg->data_offset > 1)) raid_seg_error_val("data_offset", seg->data_offset); + _check_raid_delta_disks(seg, error_count); _check_raid_region_recovery(seg, error_count); } @@ -170,11 +206,14 @@ static void _check_raid45610_seg(struct lv_segment *seg, int *error_count) /* END: checks applying to any raid4/5/6/10 */ if (seg->lv->status & LV_RESHAPE_DATA_OFFSET) { - if (seg->data_offset & (seg->lv->vg->extent_size - 1)) + if (seg->data_offset > 1 && + (seg->data_offset & (seg->lv->vg->extent_size - 1))) raid_seg_error_val("data_offset", seg->data_offset); - } else if (seg->data_offset) + } else if (seg->data_offset > 1) raid_seg_error_val("data_offset", seg->data_offset); + _check_raid_delta_disks(seg, error_count); + /* Specific checks per raid level */ if (seg_is_raid4(seg) || seg_is_any_raid5(seg)) { |