summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeil Brown <neilb@suse.de>2005-09-05 01:14:26 +0000
committerNeil Brown <neilb@suse.de>2005-09-05 01:14:26 +0000
commit6e6dc574d60f108fdc49f3b755d9baeec1335ba2 (patch)
tree770cdad9dfa89f9e00b53aa10b59fe88a9f669ad
parentbaa2cd47e56f0a387685fb923ce9663b42df9fc2 (diff)
downloadmdadm-stable-1.zip
mdadm-stable-1.tar.gz
mdadm-stable-1.tar.xz
Fix assembling of raid10 in the face of missing devices.stable-1
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--mdadm.h3
-rw-r--r--util.c25
3 files changed, 37 insertions, 8 deletions
diff --git a/Assemble.c b/Assemble.c
index ace5717..49639cd 100644
--- a/Assemble.c
+++ b/Assemble.c
@@ -119,6 +119,7 @@ int Assemble(char *mddev, int mdfd,
int start_partial_ok = force || devlist==NULL;
unsigned int num_devs;
mddev_dev_t tmpdev;
+ char *avail;
vers = md_get_version(mdfd);
if (vers <= 0) {
@@ -389,6 +390,8 @@ int Assemble(char *mddev, int mdfd,
/* now we have some devices that might be suitable.
* I wonder how many
*/
+ avail = malloc(first_super.raid_disks);
+ memset(avail, 0, first_super.raid_disks);
okcnt = 0;
sparecnt=0;
for (i=0; i< bestcnt ;i++) {
@@ -407,13 +410,16 @@ int Assemble(char *mddev, int mdfd,
if (devices[j].events+event_margin >=
devices[most_recent].events) {
devices[j].uptodate = 1;
- if (i < first_super.raid_disks)
+ if (i < first_super.raid_disks) {
okcnt++;
- else
+ avail[i]=1;
+ } else
sparecnt++;
}
}
- while (force && !enough(first_super.level, first_super.raid_disks, okcnt)) {
+ while (force && !enough(first_super.level, first_super.raid_disks,
+ first_super.layout,
+ avail, okcnt)) {
/* Choose the newest best drive which is
* not up-to-date, update the superblock
* and add it.
@@ -466,6 +472,7 @@ int Assemble(char *mddev, int mdfd,
close(fd);
devices[chosen_drive].events = devices[most_recent].events;
devices[chosen_drive].uptodate = 1;
+ avail[chosen_drive] = 1;
okcnt++;
}
@@ -624,7 +631,7 @@ This doesnt work yet
if (runstop == 1 ||
(runstop == 0 &&
- ( enough(first_super.level, first_super.raid_disks, okcnt) &&
+ ( enough(first_super.level, first_super.raid_disks, first_super.layout, avail, okcnt) &&
(okcnt >= req_cnt || start_partial_ok)
))) {
if (ioctl(mdfd, RUN_ARRAY, NULL)==0) {
@@ -649,7 +656,7 @@ This doesnt work yet
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(first_super.level, first_super.raid_disks, okcnt))
+ if (!enough(first_super.level, first_super.raid_disks, first_super.layout, avail, okcnt))
fprintf(stderr, " - not enough to start the array.\n");
else {
if (req_cnt == first_super.raid_disks)
diff --git a/mdadm.h b/mdadm.h
index f4a8d20..8f0c32e 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -231,7 +231,8 @@ extern int same_uuid(int a[4], int b[4]);
extern int compare_super(mdp_super_t *first, mdp_super_t *second);
extern unsigned long calc_sb_csum(mdp_super_t *super);
extern int store_super(int fd, mdp_super_t *super);
-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/util.c b/util.c
index 5bac0ec..e94edc8 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;