Fix assembling of raid10 in the face of missing devices.

We now check if enough devices are present properly, so
--force can be used to good effect.

Signed-off-by: Neil Brown <neilb@suse.de>
This commit is contained in:
Neil Brown 2005-09-12 04:57:52 +00:00
parent 63f8c4c76b
commit 265e0f1731
6 changed files with 55 additions and 8 deletions

View File

@ -118,6 +118,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
mddev_dev_t tmpdev;
struct mdinfo info;
struct mddev_ident_s ident2;
char *avail;
vers = md_get_version(mdfd);
if (vers <= 0) {
@ -359,6 +360,8 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
/* now we have some devices that might be suitable.
* I wonder how many
*/
avail = malloc(info.array.raid_disks);
memset(avail, 0, info.array.raid_disks);
okcnt = 0;
sparecnt=0;
for (i=0; i< bestcnt ;i++) {
@ -377,13 +380,16 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
if (devices[j].events+event_margin >=
devices[most_recent].events) {
devices[j].uptodate = 1;
if (i < info.array.raid_disks)
if (i < info.array.raid_disks) {
okcnt++;
else
avail[i]=1;
} else
sparecnt++;
}
}
while (force && !enough(info.array.level, info.array.raid_disks, okcnt)) {
while (force && !enough(info.array.level, info.array.raid_disks,
info.array.layout,
avail, okcnt)) {
/* Choose the newest best drive which is
* not up-to-date, update the superblock
* and add it.
@ -434,6 +440,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
close(fd);
devices[chosen_drive].events = devices[most_recent].events;
devices[chosen_drive].uptodate = 1;
avail[chosen_drive] = 1;
okcnt++;
free(super);
}
@ -599,7 +606,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
if (runstop == 1 ||
(runstop == 0 &&
( enough(info.array.level, info.array.raid_disks, okcnt) &&
( enough(info.array.level, info.array.raid_disks, info.array.layout, avail, okcnt) &&
(okcnt >= req_cnt || start_partial_ok)
))) {
if (ioctl(mdfd, RUN_ARRAY, NULL)==0) {
@ -627,7 +634,7 @@ int Assemble(struct supertype *st, char *mddev, int mdfd,
fprintf(stderr, Name ": %s assembled from %d drive%s", mddev, okcnt, okcnt==1?"":"s");
if (sparecnt)
fprintf(stderr, " and %d spare%s", sparecnt, sparecnt==1?"":"s");
if (!enough(info.array.level, info.array.raid_disks, okcnt))
if (!enough(info.array.level, info.array.raid_disks, info.array.layout, avail, okcnt))
fprintf(stderr, " - not enough to start the array.\n");
else {
if (req_cnt == info.array.raid_disks)

View File

@ -1,4 +1,11 @@
Changes Prior to this release
- Fix assembling of raid10 array when devices are missing.
mdadm now correctly detects if a array is workable or not
depending on which devices are present, and so will correctly
handle "--assemble --force" if multiple devices have failed.
- Report raid10 layout in --examine output.
Changes Prior to 2.0
- Support assembling from byte-swapped superblocks
metadata type "0.swap" and --update=byteorder
- write-mostly and write-behind support for raid1.

View File

@ -291,7 +291,8 @@ extern void uuid_from_super(int uuid[4], mdp_super_t *super);
extern int same_uuid(int a[4], int b[4], int swapuuid);
/* extern int compare_super(mdp_super_t *first, mdp_super_t *second);*/
extern unsigned long calc_csum(void *super, int bytes);
extern int enough(int level, int raid_disks, int avail_disks);
extern int enough(int level, int raid_disks, int layout,
char *avail, int avail_disks);
extern int ask(char *mesg);

View File

@ -131,6 +131,10 @@ static void examine_super0(void *sbv)
c = map_num(r5layout, sb->layout);
printf(" Layout : %s\n", c?c:"-unknown-");
}
if (sb->level == 10) {
printf(" Layout : near=%d, far=%d\n",
sb->layout&255, (sb->layout>>8)&255);
}
switch(sb->level) {
case 0:
case 4:
@ -234,6 +238,7 @@ static void getinfo_super0(struct mdinfo *info, mddev_ident_t ident, void *sbv)
info->array.patch_version = sb->patch_version;
info->array.raid_disks = sb->raid_disks;
info->array.level = sb->level;
info->array.layout = sb->layout;
info->array.md_minor = sb->md_minor;
info->array.ctime = sb->ctime;

View File

@ -180,6 +180,11 @@ static void examine_super1(void *sbv)
c = map_num(r5layout, __le32_to_cpu(sb->layout));
printf(" Layout : %s\n", c?c:"-unknown-");
}
if (__le32_to_cpu(sb->level) == 10) {
int lo = __le32_to_cpu(sb->layout);
printf(" Layout : near=%d, far=%d\n",
lo&255, (lo>>8)&255);
}
switch(__le32_to_cpu(sb->level)) {
case 0:
case 4:
@ -290,6 +295,7 @@ static void getinfo_super1(struct mdinfo *info, mddev_ident_t ident, void *sbv)
info->array.patch_version = 0;
info->array.raid_disks = __le32_to_cpu(sb->raid_disks);
info->array.level = __le32_to_cpu(sb->level);
info->array.layout = __le32_to_cpu(sb->layout);
info->array.md_minor = -1;
info->array.ctime = __le64_to_cpu(sb->ctime);

25
util.c
View File

@ -118,10 +118,31 @@ int get_linux_version()
return (a*1000000)+(b*1000)+c;
}
int enough(int level, int raid_disks, int avail_disks)
int enough(int level, int raid_disks, int layout,
char *avail, int avail_disks)
{
int copies, first;
switch (level) {
case 10: return 1; /* a lie, but it is hard to tell */
case 10:
/* This is the tricky one - we need to check
* which actual disks are present.
*/
copies = (layout&255)* (layout>>8);
first=0;
do {
/* there must be one of the 'copies' form 'first' */
int n = copies;
int cnt=0;
while (n--) {
if (avail[first])
cnt++;
first = (first+1) % raid_disks;
}
if (cnt == 0)
return 0;
} while (first != 0);
return 1;
case -4:
return avail_disks>= 1;