]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - Manage.c
fix array_size in child_monitor
[thirdparty/mdadm.git] / Manage.c
index 81fa986d770c2f8ee201b61b90944c62390db624..4e6afb50390e6df10e162c39a6d69c7ac600e434 100644 (file)
--- a/Manage.c
+++ b/Manage.c
@@ -800,16 +800,16 @@ int Manage_subdevs(char *devname, int fd,
                                if (dv->writemostly == 1)
                                        disc.state |= 1 << MD_DISK_WRITEMOSTLY;
                                dfd = dev_open(dv->devname, O_RDWR | O_EXCL|O_DIRECT);
+                               if (tst->ss->external &&
+                                   mdmon_running(tst->container_dev))
+                                       tst->update_tail = &tst->updates;
                                if (tst->ss->add_to_super(tst, &disc, dfd,
                                                          dv->devname)) {
                                        close(dfd);
                                        return 1;
                                }
                                /* write_init_super will close 'dfd' */
-                               if (tst->ss->external)
-                                       /* mdmon will write the metadata */
-                                       close(dfd);
-                               else if (tst->ss->write_init_super(tst))
+                               if (tst->ss->write_init_super(tst))
                                        return 1;
                        } else if (dv->re_add) {
                                /*  this had better be raid1.
@@ -844,9 +844,8 @@ int Manage_subdevs(char *devname, int fd,
                        if (dv->writemostly == 1)
                                disc.state |= (1 << MD_DISK_WRITEMOSTLY);
                        if (tst->ss->external) {
-                               /* add a disk to an external metadata container
-                                * only if mdmon is around to see it
-                                */
+                               /* add a disk
+                                * to an external metadata container */
                                struct mdinfo new_mdi;
                                struct mdinfo *sra;
                                int container_fd;
@@ -860,13 +859,6 @@ int Manage_subdevs(char *devname, int fd,
                                        return 1;
                                }
 
-                               if (!mdmon_running(devnum)) {
-                                       fprintf(stderr, Name ": add failed for %s: mdmon not running\n",
-                                               dv->devname);
-                                       close(container_fd);
-                                       return 1;
-                               }
-
                                sra = sysfs_read(container_fd, -1, 0);
                                if (!sra) {
                                        fprintf(stderr, Name ": add failed for %s: sysfs_read failed\n",
@@ -884,6 +876,7 @@ int Manage_subdevs(char *devname, int fd,
                                        fprintf(stderr, Name ": add new device to external metadata"
                                                " failed for %s\n", dv->devname);
                                        close(container_fd);
+                                       sysfs_free(sra);
                                        return 1;
                                }
                                ping_monitor(devnum2devname(devnum));
@@ -1096,4 +1089,48 @@ int Update_subarray(char *dev, char *subarray, char *update, struct mddev_ident
 
        return rv;
 }
+
+/* Move spare from one array to another
+ * If adding to destination array fails
+ * add back to original array
+ * Returns 1 on success, 0 on failure */
+int move_spare(char *from_devname, char *to_devname, dev_t devid)
+{
+       struct mddev_dev devlist;
+       char devname[20];
+
+       /* try to remove and add */
+       int fd1 = open(to_devname, O_RDONLY);
+       int fd2 = open(from_devname, O_RDONLY);
+
+       if (fd1 < 0 || fd2 < 0) {
+               if (fd1>=0) close(fd1);
+               if (fd2>=0) close(fd2);
+               return 0;
+       }
+
+       devlist.next = NULL;
+       devlist.used = 0;
+       devlist.re_add = 0;
+       devlist.writemostly = 0;
+       devlist.devname = devname;
+       sprintf(devname, "%d:%d", major(devid), minor(devid));
+
+       devlist.disposition = 'r';
+       if (Manage_subdevs(from_devname, fd2, &devlist, -1, 0, NULL) == 0) {
+               devlist.disposition = 'a';
+               if (Manage_subdevs(to_devname, fd1, &devlist, -1, 0, NULL) == 0) {
+                       /* make sure manager is aware of changes */
+                       ping_manager(to_devname);
+                       ping_manager(from_devname);
+                       close(fd1);
+                       close(fd2);
+                       return 1;
+               }
+               else Manage_subdevs(from_devname, fd2, &devlist, -1, 0, NULL);
+       }
+       close(fd1);
+       close(fd2);
+       return 0;
+}
 #endif