From 43dad3d6fb475bfefd2028e9dea1c15a83bb2d03 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 19 Aug 2008 17:19:51 +1000 Subject: [PATCH] mdadm: add device to a container 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 Signed-off-by: NeilBrown --- Manage.c | 66 ++++++++++++++++++++--- managemon.c | 38 ++++++++++++++ super-intel.c | 141 +++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 208 insertions(+), 37 deletions(-) diff --git a/Manage.c b/Manage.c index 714a33b0..98f9fb76 100644 --- 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; diff --git a/managemon.c b/managemon.c index d2925ae4..96120077 100644 --- a/managemon.c +++ b/managemon.c @@ -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; } diff --git a/super-intel.c b/super-intel.c index c96793f5..7a199353 100644 --- a/super-intel.c +++ b/super-intel.c @@ -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; } } -- 2.39.2