]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
mdadm: add device to a container
authorDan Williams <dan.j.williams@intel.com>
Tue, 19 Aug 2008 07:19:51 +0000 (17:19 +1000)
committerNeilBrown <neilb@suse.de>
Tue, 19 Aug 2008 07:19:51 +0000 (17:19 +1000)
Adding a device updates the container and then mdmon takes action upon
noticing a change in devices.  This reuses the container version of
add_to_super to create a new record for the device.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: NeilBrown <neilb@suse.de>
Manage.c
managemon.c
super-intel.c

index 714a33b0a3df01430ffd561ab84ff29a813bf30a..98f9fb7684e3b13e54b14f7af92bb40f0a756047 100644 (file)
--- a/Manage.c
+++ b/Manage.c
@@ -404,8 +404,7 @@ int Manage_subdevs(char *devname, int fd,
                                return 1;
                        }
 
-                       if (array.not_persistent == 0) {
-
+                       if (array.not_persistent == 0 || tst->ss->external) {
                                /* Make sure device is large enough */
                                if (tst->ss->avail_size(tst, ldsize/512) <
                                    array_size) {
@@ -415,9 +414,13 @@ int Manage_subdevs(char *devname, int fd,
                                }
 
                                /* need to find a sample superblock to copy, and
-                                * a spare slot to use
+                                * a spare slot to use.
+                                * For 'external' array (well, container based),
+                                * We can just load the metadata for the array.
                                 */
-                               for (j = 0; j < tst->max_devs; j++) {
+                               if (tst->ss->external) {
+                                       tst->ss->load_super(tst, fd, NULL);
+                               } else for (j = 0; j < tst->max_devs; j++) {
                                        char *dev;
                                        int dfd;
                                        disc.number = j;
@@ -439,6 +442,7 @@ int Manage_subdevs(char *devname, int fd,
                                        close(dfd);
                                        break;
                                }
+                               /* FIXME this is a bad test to be using */
                                if (!tst->sb) {
                                        fprintf(stderr, Name ": cannot find valid superblock in this array - HELP\n");
                                        return 1;
@@ -507,7 +511,7 @@ int Manage_subdevs(char *devname, int fd,
                        disc.minor = minor(stb.st_rdev);
                        disc.number =j;
                        disc.state = 0;
-                       if (array.not_persistent==0) {
+                       if (array.not_persistent==0 || tst->ss->external) {
                                int dfd;
                                if (dv->writemostly)
                                        disc.state |= 1 << MD_DISK_WRITEMOSTLY;
@@ -515,7 +519,10 @@ int Manage_subdevs(char *devname, int fd,
                                tst->ss->add_to_super(tst, &disc, dfd,
                                                      dv->devname);
                                /* write_init_super will close 'dfd' */
-                               if (tst->ss->write_init_super(tst))
+                               if (tst->ss->external)
+                                       /* mdmon will write the metadata */
+                                       close(dfd);
+                               else if (tst->ss->write_init_super(tst))
                                        return 1;
                        } else if (dv->re_add) {
                                /*  this had better be raid1.
@@ -548,7 +555,52 @@ int Manage_subdevs(char *devname, int fd,
                        }
                        if (dv->writemostly)
                                disc.state |= (1 << MD_DISK_WRITEMOSTLY);
-                       if (ioctl(fd,ADD_NEW_DISK, &disc)) {
+                       if (tst->ss->external) {
+                               /* add a disk to an external metadata container
+                                * only if mdmon is around to see it
+                                */
+                               struct mdinfo new_mdi;
+                               struct mdinfo *sra;
+                               int container_fd;
+                               int devnum = fd2devnum(fd);
+
+                               container_fd = open_dev_excl(devnum);
+                               if (container_fd < 0) {
+                                       fprintf(stderr, Name ": add failed for %s:"
+                                               " could not get exclusive access to container\n",
+                                               dv->devname);
+                                       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",
+                                               dv->devname);
+                                       close(container_fd);
+                                       return 1;
+                               }
+                               sra->array.level = LEVEL_CONTAINER;
+                               /* Need to set data_offset and component_size */
+                               tst->ss->getinfo_super(tst, &new_mdi);
+                               new_mdi.disk.major = disc.major;
+                               new_mdi.disk.minor = disc.minor;
+                               if (sysfs_add_disk(sra, &new_mdi) != 0) {
+                                       fprintf(stderr, Name ": add new device to external metadata"
+                                               " failed for %s\n", dv->devname);
+                                       close(container_fd);
+                                       return 1;
+                               }
+                               ping_monitor(devnum2devname(devnum));
+                               sysfs_free(sra);
+                               close(container_fd);
+                       } else if (ioctl(fd, ADD_NEW_DISK, &disc)) {
                                fprintf(stderr, Name ": add new device failed for %s as %d: %s\n",
                                        dv->devname, j, strerror(errno));
                                return 1;
index d2925ae482061ea63f5523c5d0659c32f9da2bda..9612007752e1cd6f1771b45629fea2313e6b4780 100644 (file)
@@ -218,6 +218,34 @@ static void queue_metadata_update(struct metadata_update *mu)
        *qp = mu;
 }
 
+static void add_disk_to_container(struct supertype *st, struct mdinfo *sd)
+{
+       int dfd;
+       char nm[20];
+       struct metadata_update *update = NULL;
+       mdu_disk_info_t dk = {
+               .number = -1,
+               .major = sd->disk.major,
+               .minor = sd->disk.minor,
+               .raid_disk = -1,
+               .state = 0,
+       };
+
+       dprintf("%s: add %d:%d to container\n",
+               __func__, sd->disk.major, sd->disk.minor);
+
+       sprintf(nm, "%d:%d", sd->disk.major, sd->disk.minor);
+       dfd = dev_open(nm, O_RDWR);
+       if (dfd < 0)
+               return;
+
+       st->update_tail = &update;
+       st->ss->add_to_super(st, &dk, dfd, NULL);
+       st->ss->write_init_super(st);
+       queue_metadata_update(update);
+       st->update_tail = NULL;
+}
+
 static void manage_container(struct mdstat_ent *mdstat,
                             struct supertype *container)
 {
@@ -256,6 +284,16 @@ static void manage_container(struct mdstat_ent *mdstat,
                        } else
                                cdp = &(*cdp)->next;
                }
+
+               /* check for additions */
+               for (di = mdi->devs; di; di = di->next) {
+                       for (cd = container->devs; cd; cd = cd->next)
+                               if (di->disk.major == cd->disk.major &&
+                                   di->disk.minor == cd->disk.minor)
+                                       break;
+                       if (!cd)
+                               add_disk_to_container(container, di);
+               }
                sysfs_free(mdi);
                container->devcnt = mdstat->devcnt;
        }
index c96793f562cd5e568516501790a9eacbf498f416..7a199353183be4e0b708c0355a69f53666e1f151 100644 (file)
@@ -174,7 +174,8 @@ struct intel_super {
                struct imsm_disk disk;
                int fd;
        } *disks;
-    struct bbm_log *bbm_log;
+       struct dl *add; /* list of disks to add while mdmon active */
+       struct bbm_log *bbm_log;
 };
 
 struct extent {
@@ -185,6 +186,7 @@ struct extent {
 enum imsm_update_type {
        update_activate_spare,
        update_create_array,
+       update_add_disk,
 };
 
 struct imsm_update_activate_spare {
@@ -201,6 +203,10 @@ struct imsm_update_create_array {
        struct imsm_dev dev;
 };
 
+struct imsm_update_add_disk {
+       enum imsm_update_type type;
+};
+
 static int imsm_env_devname_as_serial(void)
 {
        char *val = getenv("IMSM_DEVNAME_AS_SERIAL");
@@ -564,7 +570,13 @@ static int match_home_imsm(struct supertype *st, char *homehost)
 
 static void uuid_from_super_imsm(struct supertype *st, int uuid[4])
 {
-       printf("%s\n", __FUNCTION__);
+       /* imsm does not track uuid's so just make sure we never return
+        * the same value twice to break uuid matching in Manage_subdevs
+        * FIXME what about the use of uuid's with bitmap's?
+        */
+       static int dummy_id = 0;
+
+       uuid[0] = dummy_id++;
 }
 
 #if 0
@@ -1264,11 +1276,11 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
        }
 
        *sbp = super;
+       st->container_dev = fd2devnum(fd);
        if (st->ss == NULL) {
                st->ss = &super_imsm;
                st->minor_version = 0;
                st->max_devs = IMSM_MAX_DEVICES;
-               st->container_dev = fd2devnum(fd);
        }
 
        return 0;
@@ -1556,7 +1568,6 @@ static void add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
        dd->minor = minor(stb.st_rdev);
        dd->index = -1;
        dd->devname = devname ? strdup(devname) : NULL;
-       dd->next = super->disks;
        dd->fd = fd;
        rv = imsm_read_serial(fd, devname, dd->serial);
        if (rv) {
@@ -1576,7 +1587,14 @@ static void add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
                dd->disk.scsi_id = __cpu_to_le32(id);
        else
                dd->disk.scsi_id = __cpu_to_le32(0);
-       super->disks = dd;
+
+       if (st->update_tail) {
+               dd->next = super->add;
+               super->add = dd;
+       } else {
+               dd->next = super->disks;
+               super->disks = dd;
+       }
 }
 
 static int store_imsm_mpb(int fd, struct intel_super *super);
@@ -1688,43 +1706,76 @@ static int write_super_imsm(struct intel_super *super, int doclose)
        return 0;
 }
 
+static int create_array(struct supertype *st)
+{
+       size_t len;
+       struct imsm_update_create_array *u;
+       struct intel_super *super = st->sb;
+       struct imsm_dev *dev = get_imsm_dev(super, super->current_vol);
+
+       len = sizeof(*u) - sizeof(*dev) + sizeof_imsm_dev(dev, 0);
+       u = malloc(len);
+       if (!u) {
+               fprintf(stderr, "%s: failed to allocate update buffer\n",
+                       __func__);
+               return 1;
+       }
+
+       u->type = update_create_array;
+       u->dev_idx = super->current_vol;
+       imsm_copy_dev(&u->dev, dev);
+       append_metadata_update(st, u, len);
+
+       return 0;
+}
+
+static int add_disk(struct supertype *st)
+{
+       struct intel_super *super = st->sb;
+       size_t len;
+       struct imsm_update_add_disk *u;
+
+       if (!super->add)
+               return 0;
+
+       len = sizeof(*u);
+       u = malloc(len);
+       if (!u) {
+               fprintf(stderr, "%s: failed to allocate update buffer\n",
+                       __func__);
+               return 1;
+       }
+
+       u->type = update_add_disk;
+       append_metadata_update(st, u, len);
+
+       return 0;
+}
+
 static int write_init_super_imsm(struct supertype *st)
 {
        if (st->update_tail) {
-               /* queue the recently created array as a metadata update */
-               size_t len;
-               struct imsm_update_create_array *u;
+               /* queue the recently created array / added disk
+                * as a metadata update */
                struct intel_super *super = st->sb;
-               struct imsm_dev *dev;
                struct dl *d;
+               int rv;
 
-               if (super->current_vol < 0 ||
-                   !(dev = get_imsm_dev(super, super->current_vol))) {
-                       fprintf(stderr, "%s: could not determine sub-array\n",
-                               __func__);
-                       return 1;
-               }
-
-
-               len = sizeof(*u) - sizeof(*dev) + sizeof_imsm_dev(dev, 0);
-               u = malloc(len);
-               if (!u) {
-                       fprintf(stderr, "%s: failed to allocate update buffer\n",
-                               __func__);
-                       return 1;
-               }
-
-               u->type = update_create_array;
-               u->dev_idx = super->current_vol;
-               imsm_copy_dev(&u->dev, dev);
-               append_metadata_update(st, u, len);
+               /* determine if we are creating a volume or adding a disk */
+               if (super->current_vol < 0) {
+                       /* in the add disk case we are running in mdmon
+                        * context, so don't close fd's
+                        */
+                       return add_disk(st);
+               } else
+                       rv = create_array(st);
 
                for (d = super->disks; d ; d = d->next) {
                        close(d->fd);
                        d->fd = -1;
                }
 
-               return 0;
+               return rv;
        } else
                return write_super_imsm(st->sb, 1);
 }
@@ -2779,6 +2830,36 @@ static void imsm_process_update(struct supertype *st,
                }
                break;
        }
+       case update_add_disk:
+
+               /* we may be able to repair some arrays if disks are
+                * being added */
+               if (super->add) {
+                       struct active_array *a;
+                       for (a = st->arrays; a; a = a->next)
+                               a->check_degraded = 1;
+               }
+               /* check if we can add / replace some disks in the
+                * metadata */
+               while (super->add) {
+                       struct dl **dlp, *dl, *al;
+                       al = super->add;
+                       super->add = al->next;
+                       for (dlp = &super->disks; *dlp ; ) {
+                               if (memcmp(al->serial, (*dlp)->serial,
+                                          MAX_RAID_SERIAL_LEN) == 0) {
+                                       dl = *dlp;
+                                       *dlp = (*dlp)->next;
+                                       __free_imsm_disk(dl);
+                                       break;
+                               } else
+                                       dlp = &(*dlp)->next;
+                       }
+                       al->next = super->disks;
+                       super->disks = al;
+               }
+
+               break;
        }
 }