summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Manage.c66
-rw-r--r--managemon.c38
-rw-r--r--super-intel.c141
3 files changed, 208 insertions, 37 deletions
diff --git a/Manage.c b/Manage.c
index 714a33b..98f9fb7 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 d2925ae..9612007 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 c96793f..7a19935 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;
}
}