+ }
+
+ infos = malloc(sizeof(*infos) * total_slots);
+
+ for (pass=1; pass <=2 ; pass++) {
+ mddev_dev_t moved_disk = NULL; /* the disk that was moved out of the insert point */
+
+ for (dnum=0, dv = devlist ; dv ;
+ dv=(dv->next)?(dv->next):moved_disk, dnum++) {
+ int fd;
+ struct stat stb;
+ struct mdinfo *inf = &infos[dnum];
+
+ if (dnum >= total_slots)
+ abort();
+ if (dnum == insert_point) {
+ moved_disk = dv;
+ }
+ if (dnum == insert_point ||
+ strcasecmp(dv->devname, "missing")==0)
+ continue;
+
+ switch(pass) {
+ case 1:
+ *inf = info;
+
+ inf->disk.number = dnum;
+ inf->disk.raid_disk = dnum;
+ if (inf->disk.raid_disk < raiddisks)
+ inf->disk.state = (1<<MD_DISK_ACTIVE) |
+ (1<<MD_DISK_SYNC);
+ else
+ inf->disk.state = 0;
+
+ if (dv->writemostly)
+ inf->disk.state |= (1<<MD_DISK_WRITEMOSTLY);
+
+ if (st->ss->external && st->subarray[0])
+ fd = open(dv->devname, O_RDWR, 0);
+ else
+ fd = open(dv->devname, O_RDWR|O_EXCL,0);
+
+ if (fd < 0) {
+ fprintf(stderr, Name ": failed to open %s "
+ "after earlier success - aborting\n",
+ dv->devname);
+ return 1;
+ }
+ fstat(fd, &stb);
+ inf->disk.major = major(stb.st_rdev);
+ inf->disk.minor = minor(stb.st_rdev);
+
+ remove_partitions(fd);
+ st->ss->add_to_super(st, &inf->disk,
+ fd, dv->devname);
+ st->ss->getinfo_super(st, inf);
+
+ /* getinfo_super might have lost these ... */
+ inf->disk.major = major(stb.st_rdev);
+ inf->disk.minor = minor(stb.st_rdev);
+ break;
+ case 2:
+ inf->errors = 0;
+ rv = 0;
+
+ if (st->ss->external)
+ rv = sysfs_add_disk(sra, inf);
+ else
+ rv = ioctl(mdfd, ADD_NEW_DISK,
+ &inf->disk);
+
+ if (rv) {
+ fprintf(stderr,
+ Name ": ADD_NEW_DISK for %s "
+ "failed: %s\n",
+ dv->devname, strerror(errno));
+ st->ss->free_super(st);
+ return 1;
+ }
+ break;
+ }
+ if (dv == moved_disk && dnum != insert_point) break;
+ }
+ if (pass == 1) {
+ st->ss->write_init_super(st);
+ flush_metadata_updates(st);
+ }
+ }
+ free(infos);
+ st->ss->free_super(st);
+
+ /* param is not actually used */
+ if (level == LEVEL_CONTAINER)
+ /* No need to start */
+ ;
+ else if (runstop == 1 || subdevs >= raiddisks) {
+ if (st->ss->external) {
+ switch(level) {
+ case LEVEL_LINEAR:
+ case LEVEL_MULTIPATH:
+ case 0:
+ sysfs_set_str(sra, NULL, "array_state",
+ "active");
+ need_mdmon = 0;
+ break;
+ default:
+ sysfs_set_str(sra, NULL, "array_state",
+ "readonly");
+ break;
+ }
+ } else {
+ mdu_param_t param;
+ if (ioctl(mdfd, RUN_ARRAY, ¶m)) {
+ fprintf(stderr, Name ": RUN_ARRAY failed: %s\n",
+ strerror(errno));
+ Manage_runstop(mddev, mdfd, -1, 0);
+ return 1;
+ }
+ }
+ if (verbose >= 0)
+ fprintf(stderr, Name ": array %s started.\n", mddev);
+ if (st->ss->external && st->subarray[0]) {
+ if (need_mdmon) {
+ int dn = st->container_dev;
+ int i;
+ switch(fork()) {
+ case 0:
+ /* FIXME yuk. CLOSE_EXEC?? */
+ for (i=3; i < 100; i++)
+ close(i);
+ execl("./mdmon", "mdmon",
+ map_dev(dev2major(dn),
+ dev2minor(dn),
+ 1), NULL);
+ exit(1);
+ case -1: fprintf(stderr, Name ": cannot fork. "
+ "Array remains readonly\n");
+ return 1;
+ default: ; /* parent - good */
+ }
+ } else
+ signal_mdmon(st->container_dev);
+ /* FIXME wait for mdmon to set array to read-auto */
+ sleep(1);
+ close(container_fd);
+ }