Until now Raid10->Raid0 takeover was possible only if all the mirrors where removed before md starts the takover. 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> --- Grow.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 97 insertions(+), 1 deletions(-) diff --git a/Grow.c b/Grow.c index ff04fc0..284d31d 100644 --- a/Grow.c +++ b/Grow.c @@ -540,7 +540,7 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file, " Please use a newer kernel\n"); return 1; } - sra = sysfs_read(fd, 0, GET_VERSION | GET_LEVEL); + sra = sysfs_read(fd, 0, GET_VERSION | GET_LEVEL | GET_DEVS | GET_STATE); frozen = freeze_array(sra); if (frozen < 0) { fprintf(stderr, Name ": %s is performing resync/recovery and cannot" @@ -586,6 +586,102 @@ 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 + * - disks number must be even + */ + if (level == 0 && array.level == 10 && + array.layout == ((1 << 8) + 2) && !(array.raid_disks & 1)) { + mdu_disk_info_t *disks; + int max_disks = MD_SB_DISKS; + int nr_of_copies, in_sync, copies; + + st = super_by_fd(fd); + if (st != NULL) + max_disks = st->max_devs; + + /* Prepare temporary disk table */ + disks = malloc(max_disks * sizeof(mdu_disk_info_t)); + if (!disks) { + fprintf(stderr, Name ": malloc failed: grow aborted\n"); + rv = 1; + goto release; + } + for (d = 0; d < max_disks; d++) { + disks[d].state = (1<<MD_DISK_REMOVED); + disks[d].major = disks[d].minor = 0; + disks[d].number = disks[d].raid_disk = d; + } + + /* initialize temporary disk table with current devices*/ + for (sd = sra->devs; sd; sd = sd->next) + if ((sd->disk.raid_disk >= 0) && + (sd->disk.raid_disk < array.raid_disks)) + disks[sd->disk.raid_disk] = sd->disk; + + nr_of_copies = array.layout & 0xff; + in_sync = nr_of_copies; + copies = nr_of_copies; + + /* Find devices that will be removed from the array */ + for (d = 0; d < max_disks; d++) { + int i, remove_all = 0; + + if (disks[d].state & (1<<MD_DISK_REMOVED)) + continue; + if (!(disks[d].state & (1<<MD_DISK_SYNC))) + in_sync--; + + copies--; + if (!copies) { + /* We reached end of "mirrored" set of devices */ + if (!in_sync) { + /* The array is failed and cannot be reshaped */ + free(disks); + return 1; + } + + /* Now mark all disks to be removed as faulty + * (leave only one in_sync disk) */ + for (i = (d-nr_of_copies+1); i <= d; i++) { + if (remove_all) { + disks[i].state |= (1<<MD_DISK_FAULTY); + continue; + } + if (disks[i].state & (1<<MD_DISK_SYNC)) { + /* this will be the candidate for Raid 0, + * leave it */ + remove_all = 1; + continue; + } else { + /* this one will be removed */ + disks[i].state |= (1<<MD_DISK_FAULTY); + } + } + /* update in_sync and copies for the next set of devices */ + in_sync = nr_of_copies; + copies = nr_of_copies; + } + } + + /* Remove unwanted devices from the array */ + for (sd = sra->devs; sd; sd = sd->next) { + d = sd->disk.raid_disk; + if (disks[d].state & (1<<MD_DISK_FAULTY)) { + sysfs_set_str(sra, sd, "state", "faulty"); + sysfs_set_str(sra, sd, "slot", "none"); + sysfs_set_str(sra, sd, "state", "remove"); + } + } + + if (disks) { + free(disks); + disks = NULL; + } + } + /* ======= set level =========== */ if (level != UnSet && level != array.level) { /* Trying to change the level. ��.n��������+%������w��{.n�����{����w��ܨ}���Ơz�j:+v�����w����ޙ��&�)ߡ�a����z�ޗ���ݢj��w�f