- tfd = dev_open(add_dev, O_RDONLY|O_EXCL|O_DIRECT);
- if (tfd < 0 && add_dev != dv->devname)
- continue;
- if (tfd < 0) {
- fprintf(stderr, Name ": Cannot open %s: %s\n",
- dv->devname, strerror(errno));
- return 1;
- }
-
- st = dup_super(tst);
-
- if (array.not_persistent==0)
- st->ss->load_super(st, tfd, NULL);
-
- if (add_dev == dv->devname) {
- if (!get_dev_size(tfd, dv->devname, &ldsize)) {
- close(tfd);
- return 1;
- }
- } else if (!get_dev_size(tfd, NULL, &ldsize)) {
- close(tfd);
- tfd = -1;
- continue;
- }
-
- if (!tst->ss->external &&
- array.major_version == 0 &&
- md_get_version(fd)%100 < 2) {
- close(tfd);
- tfd = -1;
- if (ioctl(fd, HOT_ADD_DISK,
- (unsigned long)stb.st_rdev)==0) {
- if (verbose >= 0)
- fprintf(stderr, Name ": hot added %s\n",
- add_dev);
- continue;
- }
-
- fprintf(stderr, Name ": hot add failed for %s: %s\n",
- add_dev, strerror(errno));
- return 1;
- }
-
- if (array.not_persistent == 0 || tst->ss->external) {
-
- /* need to find a sample superblock to copy, and
- * a spare slot to use.
- * For 'external' array (well, container based),
- * We can just load the metadata for the array.
- */
- if (tst->sb)
- /* already loaded */;
- else if (tst->ss->external) {
- tst->ss->load_super(tst, fd, NULL);
- } else for (j = 0; j < tst->max_devs; j++) {
- char *dev;
- int dfd;
- disc.number = j;
- if (ioctl(fd, GET_DISK_INFO, &disc))
- continue;
- if (disc.major==0 && disc.minor==0)
- continue;
- if ((disc.state & 4)==0) continue; /* sync */
- /* Looks like a good device to try */
- dev = map_dev(disc.major, disc.minor, 1);
- if (!dev) continue;
- dfd = dev_open(dev, O_RDONLY);
- if (dfd < 0) continue;
- if (tst->ss->load_super(tst, dfd,
- NULL)) {
- close(dfd);
- continue;
- }
- close(dfd);
- break;
- }
- /* FIXME this is a bad test to be using */
- if (!tst->sb) {
- close(tfd);
- fprintf(stderr, Name ": cannot find valid superblock in this array - HELP\n");
- return 1;
- }
-
- /* Make sure device is large enough */
- if (tst->ss->avail_size(tst, ldsize/512) <
- array_size) {
- close(tfd);
- tfd = -1;
- if (add_dev != dv->devname)
- continue;
- fprintf(stderr, Name ": %s not large enough to join array\n",
- dv->devname);
- return 1;
- }
-
- /* Possibly this device was recently part of the array
- * and was temporarily removed, and is now being re-added.
- * If so, we can simply re-add it.
- */
- tst->ss->uuid_from_super(tst, duuid);
-
- /* re-add doesn't work for version-1 superblocks
- * before 2.6.18 :-(
- */
- if (array.major_version == 1 &&
- get_linux_version() <= 2006018)
- ;
- else if (st->sb) {
- struct mdinfo mdi;
- st->ss->getinfo_super(st, &mdi);
- st->ss->uuid_from_super(st, ouuid);
- if ((mdi.disk.state & (1<<MD_DISK_ACTIVE)) &&
- !(mdi.disk.state & (1<<MD_DISK_FAULTY)) &&
- memcmp(duuid, ouuid, sizeof(ouuid))==0) {
- /* look like it is worth a try. Need to
- * make sure kernel will accept it though.
- */
- disc.number = mdi.disk.number;
- if (ioctl(fd, GET_DISK_INFO, &disc) != 0
- || disc.major != 0 || disc.minor != 0
- || !enough_fd(fd))
- goto skip_re_add;
- disc.major = major(stb.st_rdev);
- disc.minor = minor(stb.st_rdev);
- disc.number = mdi.disk.number;
- disc.raid_disk = mdi.disk.raid_disk;
- disc.state = mdi.disk.state;
- if (dv->writemostly == 1)
- disc.state |= 1 << MD_DISK_WRITEMOSTLY;
- if (dv->writemostly == 2)
- disc.state &= ~(1 << MD_DISK_WRITEMOSTLY);
- remove_partitions(tfd);
- close(tfd);
- tfd = -1;
- /* don't even try if disk is marked as faulty */
- errno = 0;
- if (ioctl(fd, ADD_NEW_DISK, &disc) == 0) {
- if (verbose >= 0)
- fprintf(stderr, Name ": re-added %s\n", add_dev);
- count++;
- continue;
- }
- if (errno == ENOMEM || errno == EROFS) {
- fprintf(stderr, Name ": add new device failed for %s: %s\n",
- add_dev, strerror(errno));
- if (add_dev != dv->devname)
- continue;
- return 1;
- }
- skip_re_add:
- re_add_failed = 1;
- }
- }
- if (add_dev != dv->devname) {
- if (verbose > 0)
- fprintf(stderr, Name
- ": --re-add for %s to %s is not possible\n",
- add_dev, devname);
- if (tfd >= 0) {
- close(tfd);
- tfd = -1;
- }
- continue;
- }
- if (dv->re_add) {
- if (tfd >= 0)
- close(tfd);
- fprintf(stderr, Name
- ": --re-add for %s to %s is not possible\n",
- dv->devname, devname);
- return 1;
- }
- if (re_add_failed) {
- fprintf(stderr, Name ": %s reports being an active member for %s, but a --re-add fails.\n",
- dv->devname, devname);
- fprintf(stderr, Name ": not performing --add as that would convert %s in to a spare.\n",
- dv->devname);
- fprintf(stderr, Name ": To make this a spare, use \"mdadm --zero-superblock %s\" first.\n",
- dv->devname);
- if (tfd >= 0)
- close(tfd);
- return 1;
- }
- } else {
- /* non-persistent. Must ensure that new drive
- * is at least array.size big.
- */
- if (ldsize/512 < array_size) {
- fprintf(stderr, Name ": %s not large enough to join array\n",
- dv->devname);
- if (tfd >= 0)
- close(tfd);
- return 1;
- }
- }
- /* committed to really trying this device now*/