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@intel.com>
Signed-off-by: Adam Kwolek <adam.kwolek@intel.com>
Signed-off-by: NeilBrown <neilb@suse.de>
This commit is contained in:
Adam Kwolek 2010-11-29 11:57:51 +11:00 committed by NeilBrown
parent 746a6567d3
commit 62a48395f6
1 changed files with 90 additions and 1 deletions

91
Grow.c
View File

@ -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.