X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fmdadm.git;a=blobdiff_plain;f=Manage.c;h=f7f3f6effe4f41ae58d0105f3fe2c7e85e830cee;hp=56cc1ad7ff1ffc77c331333590a26f05fabe7f5c;hb=313176636ee8c24cf1464cfec159d41ffcffacb3;hpb=b5e64645037e99b5f05c9499b27b422ae60d23a9 diff --git a/Manage.c b/Manage.c index 56cc1ad7..f7f3f6ef 100644 --- a/Manage.c +++ b/Manage.c @@ -72,7 +72,7 @@ int Manage_ro(char *devname, int fd, int readonly) return 0; } -int Manage_runstop(char *devname, int fd, int runstop) +int Manage_runstop(char *devname, int fd, int runstop, int quiet) { /* Run or stop the array. array must already be configured * required >= 0.90.0 @@ -81,8 +81,8 @@ int Manage_runstop(char *devname, int fd, int runstop) if (runstop == -1 && md_get_version(fd) < 9000) { if (ioctl(fd, STOP_MD, 0)) { - fprintf(stderr, Name ": stopping device %s failed: %s\n", - devname, strerror(errno)); + if (!quiet) fprintf(stderr, Name ": stopping device %s failed: %s\n", + devname, strerror(errno)); return 1; } } @@ -106,8 +106,9 @@ int Manage_runstop(char *devname, int fd, int runstop) } } else if (runstop < 0){ if (ioctl(fd, STOP_ARRAY, NULL)) { - fprintf(stderr, Name ": fail to stop array %s: %s\n", - devname, strerror(errno)); + if (!quiet) + fprintf(stderr, Name ": fail to stop array %s: %s\n", + devname, strerror(errno)); return 1; } } @@ -153,7 +154,7 @@ int Manage_reconfig(char *devname, int fd, int layout) } int Manage_subdevs(char *devname, int fd, - mddev_dev_t devlist) + mddev_dev_t devlist, int verbose) { /* do something to each dev. * devmode can be @@ -168,8 +169,12 @@ int Manage_subdevs(char *devname, int fd, mddev_dev_t dv; struct stat stb; int j; - int save_errno; - static char buf[4096]; + int tfd; + struct supertype *st; + void *dsuper = NULL; + void *osuper = NULL; /* original super */ + int duuid[4]; + int ouuid[4]; if (ioctl(fd, GET_ARRAY_INFO, &array)) { fprintf(stderr, Name ": cannot get array info for %s\n", @@ -194,27 +199,101 @@ int Manage_subdevs(char *devname, int fd, return 1; case 'a': /* add the device - hot or cold */ - if (ioctl(fd, HOT_ADD_DISK, (unsigned long)stb.st_rdev)==0) { - fprintf(stderr, Name ": hot added %s\n", - dv->devname); - continue; + st = super_by_version(array.major_version, + array.minor_version); + if (!st) { + fprintf(stderr, Name ": unsupport array - version %d.%d\n", + array.major_version, array.minor_version); + return 1; } - save_errno = errno; - if (read(fd, buf, sizeof(buf)) > 0) { - /* array is active, so don't try to add. - * i.e. something is wrong - */ + + /* Make sure it isn't in use (in 2.6 or later) */ + tfd = open(dv->devname, O_RDONLY|O_EXCL); + if (tfd < 0) { + fprintf(stderr, Name ": Cannot open %s: %s\n", + dv->devname, strerror(errno)); + return 1; + } + if (array.not_persistent==0) + st->ss->load_super(st, tfd, &osuper, NULL); + /* will use osuper later */ + close(tfd); + + if (array.major_version == 0 && + md_get_version(fd)%100 < 2) { + if (ioctl(fd, HOT_ADD_DISK, + (unsigned long)stb.st_rdev)==0) { + if (verbose >= 0) + fprintf(stderr, Name ": hot added %s\n", + dv->devname); + continue; + } + fprintf(stderr, Name ": hot add failed for %s: %s\n", - dv->devname, strerror(save_errno)); + dv->devname, strerror(errno)); return 1; } - /* try ADD_NEW_DISK. - * we might be creating, we might be assembling, - * it is hard to tell. - * set up number/raid_disk/state just - * in case - */ - for (j=0; jmax_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); + if (!dev) continue; + dfd = open(dev, O_RDONLY); + if (dfd < 0) continue; + if (st->ss->load_super(st, dfd, &dsuper, NULL)) { + close(dfd); + continue; + } + close(dfd); + break; + } + if (!dsuper) { + fprintf(stderr, Name ": cannot find valid superblock in this array - HELP\n"); + 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. + */ + st->ss->uuid_from_super(duuid, dsuper); + + if (osuper) { + st->ss->uuid_from_super(ouuid, osuper); + if (memcmp(duuid, ouuid, sizeof(ouuid))==0) { + /* look close enough for now. Kernel + * will worry about where a bitmap + * based reconstruct is possible + */ + struct mdinfo mdi; + st->ss->getinfo_super(&mdi, osuper); + 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 (ioctl(fd, ADD_NEW_DISK, &disc) == 0) { + if (verbose >= 0) + fprintf(stderr, Name ": re-added %s\n", dv->devname); + continue; + } + /* fall back on normal-add */ + } + } + } + for (j=0; j< st->max_devs; j++) { disc.number = j; if (ioctl(fd, GET_DISK_INFO, &disc)) break; @@ -223,17 +302,52 @@ int Manage_subdevs(char *devname, int fd, if (disc.state & 8) /* removed */ break; } + disc.major = major(stb.st_rdev); + disc.minor = minor(stb.st_rdev); disc.number =j; - disc.raid_disk = j; disc.state = 0; - disc.major = MAJOR(stb.st_rdev); - disc.minor = MINOR(stb.st_rdev); + if (array.not_persistent==0) { + if (dv->writemostly) + disc.state |= 1 << MD_DISK_WRITEMOSTLY; + st->ss->add_to_super(dsuper, &disc); + if (st->ss->write_init_super(st, dsuper, &disc, dv->devname)) + return 1; + } else if (dv->re_add) { + /* this had better be raid1. + * As we are "--re-add"ing we must find a spare slot + * to fill. + */ + char *used = malloc(array.raid_disks); + memset(used, 0, array.raid_disks); + for (j=0; j< st->max_devs; j++) { + mdu_disk_info_t disc2; + disc2.number = j; + if (ioctl(fd, GET_DISK_INFO, &disc2)) + continue; + if (disc2.major==0 && disc2.minor==0) + continue; + if (disc2.state & 8) /* removed */ + continue; + if (disc2.raid_disk < 0) + continue; + if (disc2.raid_disk > array.raid_disks) + continue; + used[disc2.raid_disk] = 1; + } + for (j=0 ; jdevname, strerror(errno)); + fprintf(stderr, Name ": add new device failed for %s as %d: %s\n", + dv->devname, j, strerror(errno)); return 1; } - fprintf(stderr, Name ": added %s\n", dv->devname); + if (verbose >= 0) + fprintf(stderr, Name ": added %s\n", dv->devname); break; case 'r': @@ -244,7 +358,8 @@ int Manage_subdevs(char *devname, int fd, dv->devname, strerror(errno)); return 1; } - fprintf(stderr, Name ": hot removed %s\n", dv->devname); + if (verbose >= 0) + fprintf(stderr, Name ": hot removed %s\n", dv->devname); break; case 'f': /* set faulty */ @@ -254,8 +369,9 @@ int Manage_subdevs(char *devname, int fd, dv->devname, strerror(errno)); return 1; } - fprintf(stderr, Name ": set %s faulty in %s\n", - dv->devname, devname); + if (verbose >= 0) + fprintf(stderr, Name ": set %s faulty in %s\n", + dv->devname, devname); break; } }