When switching from Raid10 to Raid0 remove all unwanted mirrors from the array using sysfs and run takeover procedure. --- Grow.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 113 insertions(+), 1 deletions(-) diff --git a/Grow.c b/Grow.c index 8b4f1d0..ee792fe 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_LEVEL | GET_VERSION); + 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" @@ -582,6 +582,118 @@ 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)) { + int container_fd; + st = super_by_fd(fd); + + if ((st != NULL) && (st->ss->external)) { + int dn = devname2devnum(sra->text_version + 1); + container_fd = open_dev_excl(dn); + if (container_fd < 0) { + fprintf(stderr, Name ": Cannot get exclusive access " + "to container.\n"); + rv = 1; + goto release; + } + } + + int max_disks = MD_SB_DISKS; /* just a default */ + if (st != NULL) + max_disks = st->max_devs; + + /* Prepare temporary disk table */ + struct mdinfo *de; + mdu_disk_info_t *disks; + 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 (de = sra->devs; de; de = de->next) { + if (de->disk.raid_disk >= 0 && de->disk.raid_disk < array.raid_disks) + disks[de->disk.raid_disk] = de->disk; + } + + /* Get near_copies */ + int nr_of_copies = array.layout & 0xff; + int in_sync, copies; + in_sync = copies = nr_of_copies; + + /* Find devices that will be removed from the array */ + for (d = 0; d < max_disks; d++) { + if (disks[d].state & (1<<MD_DISK_REMOVED)) + continue; + /* Count in_sync copies */ + 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; + } + + int i, remove_all = 0; + /* 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); + else { + if (disks[i].state & (1<<MD_DISK_SYNC)) { + /* this will be the candidate for Raid 0, leave it */ + remove_all = 1; + continue; + } else { + /* make sure it will be removed */ + disks[i].state |= (1<<MD_DISK_FAULTY); + } + } + } + /* update in_sync and copies for the next set of devices */ + in_sync = copies = nr_of_copies; + } + } + + /* Remove unwanted devices from the array */ + for (de = sra->devs; de; de = de->next) { + d = de->disk.raid_disk; + if (disks[d].state & (1<<MD_DISK_FAULTY)) { + sysfs_set_str(sra, de, "state", "faulty"); + sysfs_set_str(sra, de, "slot", "none"); + sysfs_set_str(sra, de, "state", "remove"); + } + } + + if (disks) { + free(disks); + disks = NULL; + } + /* ping mdmon */ + if ((st != NULL) && (st->ss->external)) { + int devnum = fd2devnum(container_fd); + ping_monitor(devnum2devname(devnum)); + close(container_fd); + } + } + /* ======= 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