From eb6491236f283eb6ebc5421fcdb14b86701a7e36 Mon Sep 17 00:00:00 2001 From: Jonathan Brassow Date: Thu, 11 Oct 2012 13:40:09 +1100 Subject: DM RAID: Move 'rebuild' checking code to its own function DM RAID: Move chunk of code to it's own function The code that checks whether device replacements/rebuilds are possible given a specific RAID type is moved to it's own function. It will further expand when the code to check RAID10 is added. A separate function makes it easier to read. Signed-off-by: Jonathan Brassow Signed-off-by: NeilBrown --- drivers/md/dm-raid.c | 75 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 25 deletions(-) (limited to 'drivers/md/dm-raid.c') diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index 982e3e390c45..10635e965fec 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c @@ -337,6 +337,52 @@ static int validate_region_size(struct raid_set *rs, unsigned long region_size) return 0; } +/* + * validate_rebuild_devices + * @rs + * + * Determine if the devices specified for rebuild can result in a valid + * usable array that is capable of rebuilding the given devices. + * + * Returns: 0 on success, -EINVAL on failure. + */ +static int validate_rebuild_devices(struct raid_set *rs) +{ + unsigned i, rebuild_cnt = 0; + + if (!(rs->print_flags & DMPF_REBUILD)) + return 0; + + for (i = 0; i < rs->md.raid_disks; i++) + if (!test_bit(In_sync, &rs->dev[i].rdev.flags)) + rebuild_cnt++; + + switch (rs->raid_type->level) { + case 1: + if (rebuild_cnt >= rs->md.raid_disks) + goto too_many; + break; + case 4: + case 5: + case 6: + if (rebuild_cnt > rs->raid_type->parity_devs) + goto too_many; + break; + case 10: + default: + DMERR("The rebuild parameter is not supported for %s", + rs->raid_type->name); + rs->ti->error = "Rebuild not supported for this RAID type"; + return -EINVAL; + } + + return 0; + +too_many: + rs->ti->error = "Too many rebuild devices specified"; + return -EINVAL; +} + /* * Possible arguments are... * [optional_args] @@ -365,7 +411,7 @@ static int parse_raid_params(struct raid_set *rs, char **argv, { char *raid10_format = "near"; unsigned raid10_copies = 2; - unsigned i, rebuild_cnt = 0; + unsigned i; unsigned long value, region_size = 0; sector_t sectors_per_dev = rs->ti->len; sector_t max_io_len; @@ -461,30 +507,6 @@ static int parse_raid_params(struct raid_set *rs, char **argv, /* Parameters that take a numeric value are checked here */ if (!strcasecmp(key, "rebuild")) { - rebuild_cnt++; - - switch (rs->raid_type->level) { - case 1: - if (rebuild_cnt >= rs->md.raid_disks) { - rs->ti->error = "Too many rebuild devices specified"; - return -EINVAL; - } - break; - case 4: - case 5: - case 6: - if (rebuild_cnt > rs->raid_type->parity_devs) { - rs->ti->error = "Too many rebuild devices specified for given RAID type"; - return -EINVAL; - } - break; - case 10: - default: - DMERR("The rebuild parameter is not supported for %s", rs->raid_type->name); - rs->ti->error = "Rebuild not supported for this RAID type"; - return -EINVAL; - } - if (value > rs->md.raid_disks) { rs->ti->error = "Invalid rebuild index given"; return -EINVAL; @@ -608,6 +630,9 @@ static int parse_raid_params(struct raid_set *rs, char **argv, } rs->md.dev_sectors = sectors_per_dev; + if (validate_rebuild_devices(rs)) + return -EINVAL; + /* Assume there are no metadata devices until the drives are parsed */ rs->md.persistent = 0; rs->md.external = 1; -- cgit v1.2.3 From 4ec1e369af83f7ecdfbd48a905e44fc9910115ba Mon Sep 17 00:00:00 2001 From: Jonathan Brassow Date: Thu, 11 Oct 2012 13:40:24 +1100 Subject: DM RAID: Add rebuild capability for RAID10 DM RAID: Add code to validate replacement slots for RAID10 arrays RAID10 can handle 'copies - 1' failures for each mirror group. This code ensures the user has provided a valid array - one whose devices specified for rebuild do not exceed the amount of redundancy available. Signed-off-by: Jonathan Brassow Signed-off-by: NeilBrown --- Documentation/device-mapper/dm-raid.txt | 9 +++++++++ drivers/md/dm-raid.c | 34 ++++++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) (limited to 'drivers/md/dm-raid.c') diff --git a/Documentation/device-mapper/dm-raid.txt b/Documentation/device-mapper/dm-raid.txt index 1c1844957166..728c38c242d6 100644 --- a/Documentation/device-mapper/dm-raid.txt +++ b/Documentation/device-mapper/dm-raid.txt @@ -132,3 +132,12 @@ Here we can see the RAID type is raid4, there are 5 devices - all of which are 'A'live, and the array is 2/490221568 complete with recovery. Faulty or missing devices are marked 'D'. Devices that are out-of-sync are marked 'a'. + + +Version History +--------------- +1.0.0 Initial version. Support for RAID 4/5/6 +1.1.0 Added support for RAID 1 +1.2.0 Handle creation of arrays that contain failed devices. +1.3.0 Added support for RAID 10 +1.3.1 Allow device replacement/rebuild for RAID 10 diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index 10635e965fec..4e79ebaab3c1 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c @@ -349,6 +349,7 @@ static int validate_region_size(struct raid_set *rs, unsigned long region_size) static int validate_rebuild_devices(struct raid_set *rs) { unsigned i, rebuild_cnt = 0; + unsigned rebuilds_per_group, copies, d; if (!(rs->print_flags & DMPF_REBUILD)) return 0; @@ -369,6 +370,37 @@ static int validate_rebuild_devices(struct raid_set *rs) goto too_many; break; case 10: + copies = raid10_md_layout_to_copies(rs->md.layout); + if (rebuild_cnt < copies) + break; + + /* + * It is possible to have a higher rebuild count for RAID10, + * as long as the failed devices occur in different mirror + * groups (i.e. different stripes). + * + * Right now, we only allow for "near" copies. When other + * formats are added, we will have to check those too. + * + * When checking "near" format, make sure no adjacent devices + * have failed beyond what can be handled. In addition to the + * simple case where the number of devices is a multiple of the + * number of copies, we must also handle cases where the number + * of devices is not a multiple of the number of copies. + * E.g. dev1 dev2 dev3 dev4 dev5 + * A A B B C + * C D D E E + */ + rebuilds_per_group = 0; + for (i = 0; i < rs->md.raid_disks * copies; i++) { + d = i % rs->md.raid_disks; + if (!test_bit(In_sync, &rs->dev[d].rdev.flags) && + (++rebuilds_per_group >= copies)) + goto too_many; + if (!((i + 1) % copies)) + rebuilds_per_group = 0; + } + break; default: DMERR("The rebuild parameter is not supported for %s", rs->raid_type->name); @@ -1385,7 +1417,7 @@ static void raid_resume(struct dm_target *ti) static struct target_type raid_target = { .name = "raid", - .version = {1, 3, 0}, + .version = {1, 3, 1}, .module = THIS_MODULE, .ctr = raid_ctr, .dtr = raid_dtr, -- cgit v1.2.3 From 7386199c471f70526bbcc629f072a5a8effe218f Mon Sep 17 00:00:00 2001 From: Jonathan Brassow Date: Thu, 11 Oct 2012 13:40:36 +1100 Subject: DM RAID: Fix comparison of index and quantity for "rebuild" parameter DM RAID: Fix comparison of index and quantity for "rebuild" parameter The "rebuild" parameter takes an index argument that starts counting from zero. The conditional used to validate the index was using '>' rather than '>=', leaving the door open for an index value that would be 1 too large. Reported-by: Neil Brown Signed-off-by: Jonathan Brassow Signed-off-by: NeilBrown --- drivers/md/dm-raid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/md/dm-raid.c') diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index 4e79ebaab3c1..89a06a361332 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c @@ -539,7 +539,7 @@ static int parse_raid_params(struct raid_set *rs, char **argv, /* Parameters that take a numeric value are checked here */ if (!strcasecmp(key, "rebuild")) { - if (value > rs->md.raid_disks) { + if (value >= rs->md.raid_disks) { rs->ti->error = "Invalid rebuild index given"; return -EINVAL; } -- cgit v1.2.3 From 761becff016b82a6a7a1b2ef224248da5f46bae9 Mon Sep 17 00:00:00 2001 From: Jonathan Brassow Date: Thu, 11 Oct 2012 13:42:19 +1100 Subject: DM RAID: Fix for "sync" directive ineffectiveness There are two table arguments that can be given to a DM RAID target that control whether the array is forced to (re)synchronize or skip initialization: "sync" and "nosync". When "sync" is given, we set mddev->recovery_cp to 0 in order to cause the device to resynchronize. This is insufficient if there is a bitmap in use, because the array will simply look at the bitmap and see that there is no recovery necessary. The fix is to skip over the loading of the superblocks when "sync" is given, causing new superblocks to be written that will force the array to go through initialization (i.e. synchronization). Signed-off-by: Jonathan Brassow Signed-off-by: NeilBrown --- drivers/md/dm-raid.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/md/dm-raid.c') diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index 89a06a361332..45d94a7e7f6d 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c @@ -1017,6 +1017,19 @@ static int analyse_superblocks(struct dm_target *ti, struct raid_set *rs) freshest = NULL; rdev_for_each_safe(rdev, tmp, mddev) { + /* + * Skipping super_load due to DMPF_SYNC will cause + * the array to undergo initialization again as + * though it were new. This is the intended effect + * of the "sync" directive. + * + * When reshaping capability is added, we must ensure + * that the "sync" directive is disallowed during the + * reshape. + */ + if (rs->print_flags & DMPF_SYNC) + continue; + if (!rdev->meta_bdev) continue; -- cgit v1.2.3