}
int Assemble(struct supertype *st, char *mddev, int mdfd,
- mddev_ident_t ident, char *conffile,
+ mddev_ident_t ident,
mddev_dev_t devlist, char *backup_file,
int readonly, int runstop,
char *update, char *homehost,
* START_ARRAY
*
*/
+ int clean = 0;
int must_close = 0;
int old_linux = 0;
int vers = 0; /* Keep gcc quite - it really is initialised */
int chosen_drive;
int change = 0;
int inargv = 0;
+ int bitmap_done;
int start_partial_ok = (runstop >= 0) && (force || devlist==NULL || mdfd < 0);
unsigned int num_devs;
mddev_dev_t tmpdev;
return 1;
}
if (devlist == NULL)
- devlist = conf_get_devs(conffile);
+ devlist = conf_get_devs();
else if (mdfd >= 0)
inargv = 1;
+ try_again:
+
tmpdev = devlist; num_devs = 0;
while (tmpdev) {
if (tmpdev->used)
else
asprintf(&mddev, "/dev/md/%s", c);
mdfd = open_mddev(mddev, ident->autof);
- if (mdfd < 0)
- return mdfd;
+ if (mdfd < 0) {
+ free(first_super);
+ free(devices);
+ first_super = NULL;
+ goto try_again;
+ }
vers = md_get_version(mdfd);
if (ioctl(mdfd, GET_ARRAY_INFO, &inf)==0) {
+ for (tmpdev = devlist ;
+ tmpdev && tmpdev->used != 1;
+ tmpdev = tmpdev->next)
+ ;
fprintf(stderr, Name ": %s already active, cannot restart it!\n", mddev);
+ if (tmpdev)
+ fprintf(stderr, Name ": %s needed for %s...\n",
+ mddev, tmpdev->devname);
close(mdfd);
+ mdfd = -1;
free(first_super);
- return 1;
+ free(devices);
+ first_super = NULL;
+ goto try_again;
}
must_close = 1;
}
/* Ok, no bad inconsistancy, we can try updating etc */
+ bitmap_done = 0;
for (tmpdev = devlist; tmpdev; tmpdev=tmpdev->next) if (tmpdev->used == 1) {
char *devname = tmpdev->devname;
struct stat stb;
}
dfd = dev_open(devname, O_RDWR|O_EXCL);
+ remove_partitions(dfd);
+
if (super) {
free(super);
super = NULL;
close(dfd);
if (strcmp(update, "uuid")==0 &&
- ident->bitmap_fd)
- if (bitmap_update_uuid(ident->bitmap_fd, info.uuid) != 0)
- fprintf(stderr, Name ": Could not update uuid on %s.\n",
- devname);
+ ident->bitmap_fd >= 0 && !bitmap_done) {
+ if (bitmap_update_uuid(ident->bitmap_fd, info.uuid, st->ss->swapuuid) != 0)
+ fprintf(stderr, Name ": Could not update uuid on external bitmap.\n");
+ else
+ bitmap_done = 1;
+ }
} else
#endif
{
int dfd;
dfd = dev_open(devname, O_RDWR|O_EXCL);
+ remove_partitions(dfd);
+
if (super) {
free(super);
super = NULL;
if (nextspare < info.array.raid_disks)
nextspare = info.array.raid_disks;
i = nextspare++;
+ } else {
+ if (i >= info.array.raid_disks &&
+ i >= nextspare)
+ nextspare = i+1;
}
if (i < 10000) {
if (i >= bestcnt) {
" to have very similar superblocks.\n"
" If they are really different, "
"please --zero the superblock on one\n"
- " If they are the same, please remove "
- "one from the list.\n",
- devices[best[i]].devname, devname);
+ " If they are the same or overlap,"
+ " please remove one from %s.\n",
+ devices[best[i]].devname, devname,
+ inargv ? "the list" :
+ "the\n DEVICE list in mdadm.conf"
+ );
if (must_close) close(mdfd);
return 1;
}
}
st->ss->getinfo_super(&info, first_super);
+ clean = info.array.state & 1;
/* now we have some devices that might be suitable.
* I wonder how many
}
}
while (force && !enough(info.array.level, info.array.raid_disks,
- info.array.layout,
+ info.array.layout, 1,
avail, okcnt)) {
/* Choose the newest best drive which is
* not up-to-date, update the superblock
* and add it.
*/
int fd;
+ long long current_events;
chosen_drive = -1;
for (i=0; i<info.array.raid_disks && i < bestcnt; i++) {
int j = best[i];
}
if (chosen_drive < 0)
break;
+ current_events = devices[chosen_drive].events;
+ add_another:
if (verbose >= 0)
fprintf(stderr, Name ": forcing event count in %s(%d) from %d upto %d\n",
devices[chosen_drive].devname, devices[chosen_drive].raid_disk,
continue;
}
info.events = devices[most_recent].events;
- st->ss->update_super(&info, super, "force", devices[chosen_drive].devname, verbose, 0, NULL);
+ st->ss->update_super(&info, super, "force-one",
+ devices[chosen_drive].devname, verbose,
+ 0, NULL);
if (st->ss->store_super(st, fd, super)) {
close(fd);
avail[chosen_drive] = 1;
okcnt++;
free(super);
+
+ /* If there are any other drives of the same vintage,
+ * add them in as well. We can't lose and we might gain
+ */
+ for (i=0; i<info.array.raid_disks && i < bestcnt ; i++) {
+ int j = best[i];
+ if (j >= 0 &&
+ !devices[j].uptodate &&
+ devices[j].events > 0 &&
+ devices[j].events == current_events) {
+ chosen_drive = j;
+ goto add_another;
+ }
+ }
}
/* Now we want to look at the superblock which the kernel will base things on
}
#endif
}
- if (force && okcnt == info.array.raid_disks-1) {
- /* FIXME check event count */
- change += st->ss->update_super(&info, super, "force",
- devices[chosen_drive].devname, verbose, 0, NULL);
+ if (force && !clean &&
+ !enough(info.array.level, info.array.raid_disks,
+ info.array.layout, clean,
+ avail, okcnt)) {
+ change += st->ss->update_super(&info, super, "force-array",
+ devices[chosen_drive].devname, verbose,
+ 0, NULL);
+ clean = 1;
}
if (change) {
if (runstop == 1 ||
(runstop <= 0 &&
- ( enough(info.array.level, info.array.raid_disks, info.array.layout, avail, okcnt) &&
+ ( enough(info.array.level, info.array.raid_disks,
+ info.array.layout, clean, avail, okcnt) &&
(okcnt >= req_cnt || start_partial_ok)
))) {
if (ioctl(mdfd, RUN_ARRAY, NULL)==0) {
while (usecs < 1000) {
mdfd = open(mddev, O_RDONLY);
if (mdfd >= 0) {
- unsigned long size;
- if (ioctl(mdfd, BLKGETSIZE, &size) == 0 &&
+ unsigned long long size;
+ if (get_dev_size(mdfd, NULL, &size) &&
size > 0)
break;
close(mdfd);
}
fprintf(stderr, Name ": failed to RUN_ARRAY %s: %s\n",
mddev, strerror(errno));
+
+ if (!enough(info.array.level, info.array.raid_disks,
+ info.array.layout, 1, avail, okcnt))
+ fprintf(stderr, Name ": Not enough devices to "
+ "start the array.\n");
+ else if (!enough(info.array.level,
+ info.array.raid_disks,
+ info.array.layout, clean,
+ avail, okcnt))
+ fprintf(stderr, Name ": Not enough devices to "
+ "start the array while not clean "
+ "- consider --force.\n");
+
if (must_close) close(mdfd);
return 1;
}
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, info.array.layout, avail, okcnt))
+ if (!enough(info.array.level, info.array.raid_disks,
+ info.array.layout, 1, avail, okcnt))
fprintf(stderr, " - not enough to start the array.\n");
+ else if (!enough(info.array.level,
+ info.array.raid_disks,
+ info.array.layout, clean,
+ avail, okcnt))
+ fprintf(stderr, " - not enough to start the "
+ "array while not clean - consider "
+ "--force.\n");
else {
if (req_cnt == info.array.raid_disks)
fprintf(stderr, " - need all %d to start it", req_cnt);