summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeil Brown <neilb@suse.de>2005-09-12 04:57:52 +0000
committerNeil Brown <neilb@suse.de>2005-09-12 04:57:52 +0000
commit265e0f17317e6d23864263c04ae581b35f946b5e (patch)
tree0b368c095b4cfa6081a1d74a8ae44a288d09e511
parent63f8c4c76bff7d45e9403908ed3591edac7a6e4f (diff)
downloadmdadm-265e0f17317e6d23864263c04ae581b35f946b5e.tar.gz
mdadm-265e0f17317e6d23864263c04ae581b35f946b5e.tar.xz
mdadm-265e0f17317e6d23864263c04ae581b35f946b5e.zip
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>
-rw-r--r--Assemble.c17
-rw-r--r--ChangeLog7
-rw-r--r--mdadm.h3
-rw-r--r--super0.c5
-rw-r--r--super1.c6
-rw-r--r--util.c25
6 files changed, 55 insertions, 8 deletions
diff --git a/Assemble.c b/Assemble.c
index 6a044b2..c522dab 100644
--- a/Assemble.c
+++ b/Assemble.c
@@ -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)
diff --git a/ChangeLog b/ChangeLog
index 9d7f815..e5a543a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
diff --git a/mdadm.h b/mdadm.h
index 6615ea1..65fa824 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -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);
diff --git a/super0.c b/super0.c
index ffa5cf7..916db54 100644
--- a/super0.c
+++ b/super0.c
@@ -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;
diff --git a/super1.c b/super1.c
index 170c52c..00da497 100644
--- a/super1.c
+++ b/super1.c
@@ -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);
diff --git a/util.c b/util.c
index db4fbf3..e702b8d 100644
--- a/util.c
+++ b/util.c
@@ -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;