]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - Manage.c
Make sure --auto=mdp is honoured properly
[thirdparty/mdadm.git] / Manage.c
index 91934822cf83c923dabeafa5d9559911d184f3ef..7a96d4509a513e9ecda638b93bb04f6baada1b0c 100644 (file)
--- a/Manage.c
+++ b/Manage.c
@@ -180,13 +180,17 @@ int Manage_subdevs(char *devname, int fd,
         *         try HOT_ADD_DISK
         *         If that fails EINVAL, try ADD_NEW_DISK
         *  'r' - remove the device HOT_REMOVE_DISK
+        *        device can be 'faulty' or 'detached' in which case all
+        *        matching devices are removed.
         *  'f' - set the device faulty SET_DISK_FAULTY
+        *        device can be 'detached' in which case any device that
+        *        is inaccessible will be marked faulty.
         */
        mdu_array_info_t array;
        mdu_disk_info_t disc;
-       mddev_dev_t dv;
+       mddev_dev_t dv, next = NULL;
        struct stat stb;
-       int j;
+       int j, jnext = 0;
        int tfd;
        struct supertype *st;
        void *dsuper = NULL;
@@ -199,18 +203,86 @@ int Manage_subdevs(char *devname, int fd,
                        devname);
                return 1;
        }
-       for (dv = devlist ; dv; dv=dv->next) {
+       for (dv = devlist, j=0 ; dv; dv = next, j = jnext) {
                unsigned long long ldsize;
+               char dvname[20];
+               char *dnprintable = dv->devname;
 
-               if (stat(dv->devname, &stb)) {
-                       fprintf(stderr, Name ": cannot find %s: %s\n",
-                               dv->devname, strerror(errno));
-                       return 1;
-               }
-               if ((stb.st_mode & S_IFMT) != S_IFBLK) {
-                       fprintf(stderr, Name ": %s is not a block device.\n",
-                               dv->devname);
-                       return 1;
+               next = dv->next;
+               jnext = 0;
+
+               if (strcmp(dv->devname, "failed")==0 ||
+                   strcmp(dv->devname, "faulty")==0) {
+                       if (dv->disposition != 'r') {
+                               fprintf(stderr, Name ": %s only meaningful "
+                                       "with -r, not -%c\n",
+                                       dv->devname, dv->disposition);
+                               return 1;
+                       }
+                       for (; j < array.raid_disks + array.nr_disks ; j++) {
+                               disc.number = j;
+                               if (ioctl(fd, GET_DISK_INFO, &disc))
+                                       continue;
+                               if (disc.major == 0 && disc.minor == 0)
+                                       continue;
+                               if ((disc.state & 1) == 0) /* faulty */
+                                       continue;
+                               stb.st_rdev = makedev(disc.major, disc.minor);
+                               next = dv;
+                               jnext = j+1;
+                               sprintf(dvname,"%d:%d", disc.major, disc.minor);
+                               dnprintable = dvname;
+                               break;
+                       }
+                       if (jnext == 0)
+                               continue;
+               } else if (strcmp(dv->devname, "detached") == 0) {
+                       if (dv->disposition != 'r' && dv->disposition != 'f') {
+                               fprintf(stderr, Name ": %s only meaningful "
+                                       "with -r of -f, not -%c\n",
+                                       dv->devname, dv->disposition);
+                               return 1;
+                       }
+                       for (; j < array.raid_disks + array.nr_disks; j++) {
+                               int sfd;
+                               disc.number = j;
+                               if (ioctl(fd, GET_DISK_INFO, &disc))
+                                       continue;
+                               if (disc.major == 0 && disc.minor == 0)
+                                       continue;
+                               sprintf(dvname,"%d:%d", disc.major, disc.minor);
+                               sfd = dev_open(dvname, O_RDONLY);
+                               if (sfd >= 0) {
+                                       close(sfd);
+                                       continue;
+                               }
+                               if (dv->disposition == 'f' &&
+                                   (disc.state & 1) == 1) /* already faulty */
+                                       continue;
+                               if (errno != ENXIO)
+                                       continue;
+                               stb.st_rdev = makedev(disc.major, disc.minor);
+                               next = dv;
+                               jnext = j+1;
+                               dnprintable = dvname;
+                               break;
+                       }
+                       if (jnext == 0)
+                               continue;
+               } else {
+                       j = 0;
+
+                       if (stat(dv->devname, &stb)) {
+                               fprintf(stderr, Name ": cannot find %s: %s\n",
+                                       dv->devname, strerror(errno));
+                               return 1;
+                       }
+                       if ((stb.st_mode & S_IFMT) != S_IFBLK) {
+                               fprintf(stderr, Name ": %s is not a "
+                                       "block device.\n",
+                                       dv->devname);
+                               return 1;
+                       }
                }
                switch(dv->disposition){
                default:
@@ -312,9 +384,9 @@ int Manage_subdevs(char *devname, int fd,
                                else 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
+                                               /* looks close enough for now.  Kernel
+                                                * will worry about whether a bitmap
+                                                * based reconstruction is possible.
                                                 */
                                                struct mdinfo mdi;
                                                st->ss->getinfo_super(&mdi, osuper);
@@ -323,6 +395,8 @@ int Manage_subdevs(char *devname, int fd,
                                                disc.number = mdi.disk.number;
                                                disc.raid_disk = mdi.disk.raid_disk;
                                                disc.state = mdi.disk.state;
+                                               if (dv->writemostly)
+                                                       disc.state |= 1 << MD_DISK_WRITEMOSTLY;
                                                if (ioctl(fd, ADD_NEW_DISK, &disc) == 0) {
                                                        if (verbose >= 0)
                                                                fprintf(stderr, Name ": re-added %s\n", dv->devname);
@@ -409,28 +483,43 @@ int Manage_subdevs(char *devname, int fd,
                        /* hot remove */
                        /* FIXME check that it is a current member */
                        if (ioctl(fd, HOT_REMOVE_DISK, (unsigned long)stb.st_rdev)) {
-                               fprintf(stderr, Name ": hot remove failed for %s: %s\n",
-                                       dv->devname, strerror(errno));
+                               fprintf(stderr, Name ": hot remove failed "
+                                       "for %s: %s\n", dnprintable,
+                                       strerror(errno));
                                return 1;
                        }
                        if (verbose >= 0)
-                               fprintf(stderr, Name ": hot removed %s\n", dv->devname);
+                               fprintf(stderr, Name ": hot removed %s\n",
+                                       dnprintable);
                        break;
 
                case 'f': /* set faulty */
                        /* FIXME check current member */
                        if (ioctl(fd, SET_DISK_FAULTY, (unsigned long) stb.st_rdev)) {
                                fprintf(stderr, Name ": set device faulty failed for %s:  %s\n",
-                                       dv->devname, strerror(errno));
+                                       dnprintable, strerror(errno));
                                return 1;
                        }
                        if (verbose >= 0)
                                fprintf(stderr, Name ": set %s faulty in %s\n",
-                                       dv->devname, devname);
+                                       dnprintable, devname);
                        break;
                }
        }
        return 0;
        
 }
+
+int autodetect(void)
+{
+       /* Open any md device, and issue the RAID_AUTORUN ioctl */
+       int rv = 1;
+       int fd = dev_open("9:0", O_RDONLY);
+       if (fd >= 0) {
+               if (ioctl(fd, RAID_AUTORUN, 0) == 0)
+                       rv = 0;
+               close(fd);
+       }
+       return rv;
+}
 #endif