On Fri, 26 Nov 2010 09:06:00 +0100 Adam Kwolek <adam.kwolek@xxxxxxxxx> wrote: > Until now Raid10->Raid0 takeover was possible only if all the mirrors where removed before md starts the takeover. > Now mdadm, when performing Raid10->raid0 takeover, will remove all unwanted mirrors from the array before actual md takeover is called. > > Signed-off-by: Maciej Trela <maciej.trela@xxxxxxxxx> > Signed-off-by: Adam Kwolek <adam.kwolek@xxxxxxxxx> This patch makes sense, but I found the logic in choosing which devices to remove to be vary hard to follow. I have replaced it with the following: We select one disk to keep from each pair, then remove the remainder. Thanks, NeilBrown commit 62a48395f60965d04da1a9cbb937bda79dd071c8 Author: Adam Kwolek <adam.kwolek@xxxxxxxxx> Date: Mon Nov 29 11:57:51 2010 +1100 Disk removal support for Raid10->Raid0 takeover Until now Raid10->Raid0 takeover was possible only if all the mirrors where removed before md starts the takeover. Now mdadm, when performing Raid10->raid0 takeover, will remove all unwanted mirrors from the array before actual md takeover is called. Signed-off-by: Maciej Trela <maciej.trela@xxxxxxxxx> Signed-off-by: Adam Kwolek <adam.kwolek@xxxxxxxxx> Signed-off-by: NeilBrown <neilb@xxxxxxx> diff --git a/Grow.c b/Grow.c index ea8f493..1d92d68 100644 --- a/Grow.c +++ b/Grow.c @@ -771,6 +771,76 @@ static void revert_container_raid_disks(struct supertype *st, int fd, char *cont free_mdstat(ent); } +int remove_disks_on_raid10_to_raid0_takeover(struct supertype *st, + struct mdinfo *sra, + int layout) +{ + int nr_of_copies; + struct mdinfo *remaining; + int slot; + + nr_of_copies = layout & 0xff; + + remaining = sra->devs; + sra->devs = NULL; + /* for each 'copy', select one device and remove from the list. */ + for (slot = 0; slot < sra->array.raid_disks; slot += nr_of_copies) { + struct mdinfo **diskp; + int found = 0; + + /* Find a working device to keep */ + for (diskp = &remaining; *diskp ; diskp = &(*diskp)->next) { + struct mdinfo *disk = *diskp; + + if (disk->disk.raid_disk < slot) + continue; + if (disk->disk.raid_disk >= slot + nr_of_copies) + continue; + if (disk->disk.state & (1<<MD_DISK_REMOVED)) + continue; + if (disk->disk.state & (1<<MD_DISK_FAULTY)) + continue; + if (!(disk->disk.state & (1<<MD_DISK_SYNC))) + continue; + + /* We have found a good disk to use! */ + *diskp = disk->next; + disk->next = sra->devs; + sra->devs = disk; + found = 1; + break; + } + if (!found) + break; + } + + if (slot < sra->array.raid_disks) { + /* didn't find all slots */ + struct mdinfo **e; + e = &remaining; + while (*e) + e = &(*e)->next; + *e = sra->devs; + sra->devs = remaining; + return 1; + } + + /* Remove all 'remaining' devices from the array */ + while (remaining) { + struct mdinfo *sd = remaining; + remaining = sd->next; + + sysfs_set_str(sra, sd, "state", "faulty"); + sysfs_set_str(sra, sd, "slot", "none"); + sysfs_set_str(sra, sd, "state", "remove"); + sd->disk.state |= (1<<MD_DISK_REMOVED); + sd->disk.state &= ~(1<<MD_DISK_SYNC); + sd->next = sra->devs; + sra->devs = sd; + } + return 0; +} + int Grow_reshape(char *devname, int fd, int quiet, char *backup_file, long long size, int level, char *layout_str, int chunksize, int raid_disks) @@ -902,7 +972,7 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file, st->update_tail = &st->updates; } - sra = sysfs_read(fd, 0, GET_LEVEL); + sra = sysfs_read(fd, 0, GET_LEVEL | GET_DISKS | GET_DEVS | GET_STATE); if (sra) { if (st->ss->external && subarray == NULL) { array.level = LEVEL_CONTAINER; @@ -973,6 +1043,25 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file, size = array.size; } + /* ========= check for Raid10 -> Raid0 conversion =============== + * current implemenation assumes that following conditions must be met: + * - far_copies == 1 + * - near_copies == 2 + */ + if (level == 0 && array.level == 10 && + array.layout == ((1 << 8) + 2) && !(array.raid_disks & 1)) { + int err; + err = remove_disks_on_raid10_to_raid0_takeover(st, sra, array.layout); + if (err) { + dprintf(Name": Array cannot be reshaped\n"); + if (container) + free(container); + if (cfd > -1) + close(cfd); + return 1; + } + } + /* ======= set level =========== */ if (level != UnSet && level != array.level) { /* Trying to change the level. -- To unsubscribe from this list: send the line "unsubscribe linux-raid" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html