]> git.ipfire.org Git - thirdparty/mdadm.git/blobdiff - Manage.c
handle Manage_subdevs() for 'external' arrays
[thirdparty/mdadm.git] / Manage.c
index f17105a85202ff14092494d646246c9229f2c31c..003d81573fff87ce3c498a87bfa54badbe5fe4d0 100644 (file)
--- a/Manage.c
+++ b/Manage.c
@@ -171,6 +171,54 @@ int Manage_reconfig(char *devname, int fd, int layout)
        return 0;
 }
 
+static int
+add_remove_device_container(int fd, int add_remove, struct stat *stb)
+{
+       int devnum = fd2devnum(fd);
+       char *devname = devnum2devname(devnum);
+       int sfd = devname ? connect_monitor(devname) : -1;
+       struct md_message msg;
+       int err = 0;
+
+       if (devname && sfd < 0) {
+               fprintf(stderr, Name ": Cannot connect to monitor for %s: %s\n",
+                       devname, strerror(errno));
+               free(devname);
+               return 1;
+       } else if (sfd < 0) {
+               fprintf(stderr, Name ": Cannot determine container name for"
+                       " device number %d\n", devnum);
+               return 1;
+       }
+
+       if (add_remove)
+               ack(sfd, 0, 0);
+       else if (send_remove_device(sfd, stb->st_rdev, 0, 0) != 0) {
+               fprintf(stderr, Name ": Failed to send \'%s device\'"
+                       " message to the container monitor\n",
+                       add_remove ? "add" : "remove");
+               err = 1;
+       }
+
+       /* check the reply */
+       if (!err && receive_message(sfd, &msg, 0) != 0) {
+               fprintf(stderr, Name ": Failed to receive an acknowledgement"
+                       " from the container monitor\n");
+               err = 1;
+       }
+
+       if (!err && msg.seq != 0) {
+               fprintf(stderr, Name ": %s device failed error code %d\n",
+                       add_remove ? "Add" : "Remove", msg.seq);
+               err = 1;
+       }
+
+       free(devname);
+       close(sfd);
+
+       return err;
+}
+
 int Manage_subdevs(char *devname, int fd,
                   mddev_dev_t devlist, int verbose)
 {
@@ -188,6 +236,7 @@ int Manage_subdevs(char *devname, int fd,
         */
        mdu_array_info_t array;
        mdu_disk_info_t disc;
+       unsigned long long array_size;
        mddev_dev_t dv, next = NULL;
        struct stat stb;
        int j, jnext = 0;
@@ -202,6 +251,14 @@ int Manage_subdevs(char *devname, int fd,
                return 1;
        }
 
+       /* array.size is only 32 bit and may be truncated.
+        * So read from sysfs if possible, and record number of sectors
+        */
+
+       array_size = get_component_size(fd);
+       if (array_size <= 0)
+               array_size = array.size * 2;
+
        tst = super_by_fd(fd);
        if (!tst) {
                fprintf(stderr, Name ": unsupport array - version %d.%d\n",
@@ -297,7 +354,13 @@ int Manage_subdevs(char *devname, int fd,
                        return 1;
                case 'a':
                        /* add the device */
-
+                       if (tst == &supertype_container_member) {
+                               fprintf(stderr, Name ": Cannot add disks to a"
+                                       " \'member\' array, perform this"
+                                       " operation on the parent container\n");
+                               return 1;
+                       } else if (tst->ss->external)
+                               return add_remove_device_container(fd, 1, &stb);
                        /* Make sure it isn't in use (in 2.6 or later) */
                        tfd = open(dv->devname, O_RDONLY|O_EXCL);
                        if (tfd < 0) {
@@ -337,7 +400,7 @@ int Manage_subdevs(char *devname, int fd,
 
                                /* Make sure device is large enough */
                                if (tst->ss->avail_size(tst, ldsize/512) <
-                                   array.size) {
+                                   array_size) {
                                        fprintf(stderr, Name ": %s not large enough to join array\n",
                                                dv->devname);
                                        return 1;
@@ -412,7 +475,7 @@ int Manage_subdevs(char *devname, int fd,
                                /* non-persistent. Must ensure that new drive
                                 * is at least array.size big.
                                 */
-                               if (ldsize/512 < array.size) {
+                               if (ldsize/512 < array_size) {
                                        fprintf(stderr, Name ": %s not large enough to join array\n",
                                                dv->devname);
                                        return 1;
@@ -437,11 +500,14 @@ int Manage_subdevs(char *devname, int fd,
                        disc.number =j;
                        disc.state = 0;
                        if (array.not_persistent==0) {
+                               int dfd;
                                if (dv->writemostly)
                                        disc.state |= 1 << MD_DISK_WRITEMOSTLY;
-                               tst->ss->add_to_super(tst, &disc);
-                               if (tst->ss->write_init_super(tst, &disc,
-                                                             dv->devname))
+                               dfd = open(dv->devname, O_RDWR | O_EXCL);
+                               tst->ss->add_to_super(tst, &disc, dfd,
+                                                     dv->devname);
+                               /* write_init_super will close 'dfd' */
+                               if (tst->ss->write_init_super(tst))
                                        return 1;
                        } else if (dv->re_add) {
                                /*  this had better be raid1.
@@ -485,6 +551,13 @@ int Manage_subdevs(char *devname, int fd,
 
                case 'r':
                        /* hot remove */
+                       if (tst == &supertype_container_member) {
+                               fprintf(stderr, Name ": Cannot remove disks from a"
+                                       " \'member\' array, perform this"
+                                       " operation on the parent container\n");
+                               return 1;
+                       } else if (tst->ss->external)
+                               return add_remove_device_container(fd, 0, &stb);
                        /* 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 "