]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - Manage.c
Create: over-ride "start_ro" setting when creating an array.
[thirdparty/mdadm.git] / Manage.c
index e3d30412ad0324f5a1809b7322e34d861b4dc9ae..b4d73e8902e6f397ce030352ff0d7d181799f47b 100644 (file)
--- a/Manage.c
+++ b/Manage.c
@@ -209,9 +209,9 @@ int Manage_runstop(char *devname, int fd, int runstop,
                        pr_err("started %s\n", devname);
        } else if (runstop < 0){
                struct map_ent *map = NULL;
-               struct stat stb;
                struct mdinfo *mdi;
                char devnm[32];
+               char container[32];
                int err;
                int count;
                /* If this is an mdmon managed array, just write 'inactive'
@@ -221,11 +221,30 @@ int Manage_runstop(char *devname, int fd, int runstop,
                /* Get EXCL access first.  If this fails, then attempting
                 * to stop is probably a bad idea.
                 */
+               mdi = sysfs_read(fd, NULL, GET_LEVEL|GET_VERSION);
+               if (mdi && is_subarray(mdi->text_version)) {
+                       char *sl;
+                       strncpy(container, mdi->text_version+1, sizeof(container));
+                       container[sizeof(container)-1] = 0;
+                       sl = strchr(container, '/');
+                       if (sl)
+                               *sl = 0;
+               } else
+                       container[0] = 0;
                close(fd);
-               if (devnm[0] == '/')
-                       fd = open(devname, O_RDONLY|O_EXCL);
-               else
-                       fd = open_dev_flags(devnm, O_RDONLY|O_EXCL);
+               count = 5;
+               while (((fd = ((devnm[0] == '/')
+                              ?open(devname, O_RDONLY|O_EXCL)
+                              :open_dev_flags(devnm, O_RDONLY|O_EXCL))) < 0
+                       || strcmp(fd2devnm(fd), devnm) != 0)
+                      && container[0]
+                      && mdmon_running(container)
+                      && count) {
+                       if (fd >= 0)
+                               close(fd);
+                       flush_mdmon(container);
+                       count--;
+               }
                if (fd < 0 || strcmp(fd2devnm(fd), devnm) != 0) {
                        if (fd >= 0)
                                close(fd);
@@ -237,7 +256,6 @@ int Manage_runstop(char *devname, int fd, int runstop,
                                       devname);
                        return 1;
                }
-               mdi = sysfs_read(fd, NULL, GET_LEVEL|GET_VERSION);
                if (mdi &&
                    mdi->array.level > 0 &&
                    is_subarray(mdi->text_version)) {
@@ -340,9 +358,7 @@ int Manage_runstop(char *devname, int fd, int runstop,
                if (mdi)
                        sysfs_uevent(mdi, "change");
 
-               if (devnm[0] &&
-                   (stat("/dev/.udev", &stb) != 0 ||
-                    check_env("MDADM_NO_UDEV"))) {
+               if (devnm[0] && use_udev()) {
                        struct map_ent *mp = map_by_devnm(&map, devnm);
                        remove_devices(devnm, mp ? mp->path : NULL);
                }
@@ -433,6 +449,40 @@ static void add_detached(struct mddev_dev *dv, int fd, char disp)
        }
 }
 
+static void add_set(struct mddev_dev *dv, int fd, char set_char)
+{
+       mdu_array_info_t array;
+       mdu_disk_info_t disk;
+       int remaining_disks;
+       int copies, set;
+       int i;
+
+       if (ioctl(fd, GET_ARRAY_INFO, &array) != 0)
+               return;
+       if (array.level != 10)
+               return;
+       copies = ((array.layout & 0xff) *
+                 ((array.layout >> 8) & 0xff));
+       if (array.raid_disks % copies)
+               return;
+
+       remaining_disks = array.nr_disks;
+       for (i = 0; i < MAX_DISKS && remaining_disks > 0; i++) {
+               char buf[40];
+               disk.number = i;
+               if (ioctl(fd, GET_DISK_INFO, &disk) != 0)
+                       continue;
+               if (disk.major == 0 && disk.minor == 0)
+                       continue;
+               remaining_disks--;
+               set = disk.raid_disk % copies;
+               if (set_char != set + 'A')
+                       continue;
+               sprintf(buf, "%d:%d", disk.major, disk.minor);
+               dv = add_one(dv, buf, dv->disposition);
+       }
+}
+
 int attempt_re_add(int fd, int tfd, struct mddev_dev *dv,
                   struct supertype *dev_st, struct supertype *tst,
                   unsigned long rdev,
@@ -1176,6 +1226,35 @@ int Manage_subdevs(char *devname, int fd,
                        continue;
                }
 
+               if (strncmp(dv->devname, "set-", 4) == 0 &&
+                   strlen(dv->devname) == 5) {
+                       int copies;
+
+                       if (dv->disposition != 'r' &&
+                           dv->disposition != 'f') {
+                               pr_err("'%s' only meaningful with -r or -f\n",
+                                      dv->devname);
+                               goto abort;
+                       }
+                       if (array.level != 10) {
+                               pr_err("'%s' only meaningful with RAID10 arrays\n",
+                                      dv->devname);
+                               goto abort;
+                       }
+                       copies = ((array.layout & 0xff) *
+                                 ((array.layout >> 8) & 0xff));
+                       if (array.raid_disks % copies != 0 ||
+                           dv->devname[4] < 'A' ||
+                           dv->devname[4] >= 'A' + copies ||
+                           copies > 26) {
+                               pr_err("'%s' not meaningful with this array\n",
+                                      dv->devname);
+                               goto abort;
+                       }
+                       add_set(dv, fd, dv->devname[4]);
+                       continue;
+               }
+
                if (strchr(dv->devname, '/') == NULL &&
                    strchr(dv->devname, ':') == NULL &&
                    strlen(dv->devname) < 50) {