summaryrefslogtreecommitdiff
path: root/sys/dev/softraid.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/softraid.c')
-rw-r--r--sys/dev/softraid.c194
1 files changed, 148 insertions, 46 deletions
diff --git a/sys/dev/softraid.c b/sys/dev/softraid.c
index 999e5341e6b..458df7de334 100644
--- a/sys/dev/softraid.c
+++ b/sys/dev/softraid.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: softraid.c,v 1.160 2009/06/24 12:08:15 jsing Exp $ */
+/* $OpenBSD: softraid.c,v 1.161 2009/06/26 14:50:44 jsing Exp $ */
/*
* Copyright (c) 2007 Marco Peereboom <marco@peereboom.us>
* Copyright (c) 2008 Chris Kuethe <ckuethe@openbsd.org>
@@ -955,12 +955,17 @@ int
sr_boot_assembly(struct sr_softc *sc)
{
struct device *dv;
- struct sr_metadata_list_head mlh;
- struct sr_metadata_list *mle, *mle2;
- struct sr_metadata *m1, *m2;
struct bioc_createraid bc;
- int rv = 0, no_dev, i;
- dev_t *dt = NULL;
+ struct sr_metadata_list_head mlh;
+ struct sr_metadata_list *mle, *mlenext, *mle1, *mle2;
+ struct sr_metadata *metadata;
+ struct sr_boot_volume_head bvh;
+ struct sr_boot_volume *vol, *vp1, *vp2;
+ u_int32_t chunk_id;
+ u_int64_t *ondisk = NULL;
+ dev_t *devs = NULL;
+ char devname[32];
+ int rv = 0, i;
DNPRINTF(SR_D_META, "%s: sr_boot_assembly\n", DEVNAME(sc));
@@ -984,72 +989,169 @@ sr_boot_assembly(struct sr_softc *sc)
}
/*
- * XXX poor mans hack that doesn't keep disks in order and does not
- * roam disks correctly. replace this with something smarter that
- * orders disks by volid, chunkid and uuid.
+ * Create a list of volumes and associate chunks with each volume.
*/
- dt = malloc(BIOC_CRMAXLEN * sizeof(dev_t), M_DEVBUF, M_WAITOK);
- for (i = 0; i < BIOC_CRMAXLEN; i++)
- dt[i] = NODEV; /* mark device as illegal */
- SLIST_FOREACH(mle, &mlh, sml_link) {
- /* chunk used already? */
- if (mle->sml_used)
- continue;
+ SLIST_INIT(&bvh);
+ for (mle = SLIST_FIRST(&mlh); mle != SLIST_END(&mlh); mle = mlenext) {
- no_dev = 0;
- m1 = (struct sr_metadata *)&mle->sml_metadata;
- SLIST_FOREACH(mle2, &mlh, sml_link) {
- /* chunk used already? */
- if (mle2->sml_used)
- continue;
+ mlenext = SLIST_NEXT(mle, sml_link);
+ SLIST_REMOVE(&mlh, mle, sr_metadata_list, sml_link);
- m2 = (struct sr_metadata *)&mle2->sml_metadata;
+ metadata = (struct sr_metadata *)&mle->sml_metadata;
+ mle->sml_chunk_id = metadata->ssdi.ssd_chunk_id;
- /* are we the same volume? */
- if (m1->ssdi.ssd_volid != m2->ssdi.ssd_volid)
- continue;
-
- /* same uuid? */
- if (bcmp(&m1->ssdi.ssd_uuid, &m2->ssdi.ssd_uuid,
- sizeof(m1->ssdi.ssd_uuid)))
- continue;
+ SLIST_FOREACH(vol, &bvh, sbv_link) {
+ if (bcmp(&metadata->ssdi.ssd_uuid, &vol->sbv_uuid,
+ sizeof(metadata->ssdi.ssd_uuid)) == 0)
+ break;
+ }
- /* sanity */
- if (dt[m2->ssdi.ssd_chunk_id] != NODEV) {
- printf("%s: chunk id already in use; can not "
- "assemble volume\n", DEVNAME(sc));
+ if (vol == NULL) {
+ vol = malloc(sizeof(struct sr_boot_volume),
+ M_DEVBUF, M_NOWAIT | M_CANFAIL | M_ZERO);
+ if (vol == NULL) {
+ printf("%s: failed to allocate boot volume!\n",
+ DEVNAME(sc));
goto unwind;
}
- dt[m2->ssdi.ssd_chunk_id] = mle2->sml_mm;
- no_dev++;
- mle2->sml_used = 1;
+
+ vol->sbv_level = metadata->ssdi.ssd_level;
+ vol->sbv_volid = metadata->ssdi.ssd_volid;
+ vol->sbv_chunk_no = metadata->ssdi.ssd_chunk_no;
+ bcopy(&metadata->ssdi.ssd_uuid, &vol->sbv_uuid,
+ sizeof(metadata->ssdi.ssd_uuid));
+ SLIST_INIT(&vol->sml);
+
+ /* Maintain volume order. */
+ vp2 = NULL;
+ SLIST_FOREACH(vp1, &bvh, sbv_link) {
+ if (vp1->sbv_volid > vol->sbv_volid)
+ break;
+ vp2 = vp1;
+ }
+ if (vp2 == NULL) {
+ DNPRINTF(SR_D_META, "%s: insert volume %u "
+ "at head\n", DEVNAME(sc), vol->sbv_volid);
+ SLIST_INSERT_HEAD(&bvh, vol, sbv_link);
+ } else {
+ DNPRINTF(SR_D_META, "%s: insert volume %u "
+ "after %u\n", DEVNAME(sc), vol->sbv_volid,
+ vp2->sbv_volid);
+ SLIST_INSERT_AFTER(vp2, vol, sbv_link);
+ }
}
- if (m1->ssdi.ssd_chunk_no != no_dev) {
+
+ /* Maintain chunk order. */
+ mle2 = NULL;
+ SLIST_FOREACH(mle1, &vol->sml, sml_link) {
+ if (mle1->sml_chunk_id > mle->sml_chunk_id)
+ break;
+ mle2 = mle1;
+ }
+ if (mle2 == NULL) {
+ DNPRINTF(SR_D_META, "%s: volume %u insert chunk %u "
+ "at head\n", DEVNAME(sc), vol->sbv_volid,
+ mle->sml_chunk_id);
+ SLIST_INSERT_HEAD(&vol->sml, mle, sml_link);
+ } else {
+ DNPRINTF(SR_D_META, "%s: volume %u insert chunk %u "
+ "after %u\n", DEVNAME(sc), vol->sbv_volid,
+ mle->sml_chunk_id, mle2->sml_chunk_id);
+ SLIST_INSERT_AFTER(mle2, mle, sml_link);
+ }
+
+ vol->sbv_dev_no++;
+ }
+
+ /* Allocate memory for device and ondisk version arrays. */
+ devs = malloc(BIOC_CRMAXLEN * sizeof(dev_t), M_DEVBUF,
+ M_NOWAIT | M_CANFAIL);
+ if (devs == NULL) {
+ printf("%s: failed to allocate device array\n", DEVNAME(sc));
+ goto unwind;
+ }
+ ondisk = malloc(BIOC_CRMAXLEN * sizeof(u_int64_t), M_DEVBUF,
+ M_NOWAIT | M_CANFAIL);
+ if (ondisk == NULL) {
+ printf("%s: failed to allocate ondisk array\n", DEVNAME(sc));
+ goto unwind;
+ }
+
+ SLIST_FOREACH(vol, &bvh, sbv_link) {
+
+#ifdef SR_DEBUG
+ DNPRINTF(SR_D_META, "%s: assembling volume ", DEVNAME(sc));
+ if (sr_debug & SR_D_META)
+ sr_uuid_print(&vol->sbv_uuid, 0);
+ DNPRINTF(SR_D_META, " volid %u with %u chunks\n",
+ vol->sbv_volid, vol->sbv_chunk_no);
+#endif
+
+ for (i = 0; i < BIOC_CRMAXLEN; i++) {
+ devs[i] = NODEV; /* mark device as illegal */
+ ondisk[i] = 0;
+ }
+
+ SLIST_FOREACH(mle, &vol->sml, sml_link) {
+ metadata = (struct sr_metadata *)&mle->sml_metadata;
+ chunk_id = metadata->ssdi.ssd_chunk_id;
+
+ if (devs[chunk_id] != NODEV) {
+ vol->sbv_dev_no--;
+ sr_meta_getdevname(sc, mle->sml_mm, devname,
+ sizeof(devname));
+ printf("%s: found duplicate chunk %u for "
+ "volume %u on device %s\n", DEVNAME(sc),
+ chunk_id, vol->sbv_volid, devname);
+ }
+
+ if (devs[chunk_id] == NODEV ||
+ metadata->ssd_ondisk > ondisk[chunk_id]) {
+ devs[chunk_id] = mle->sml_mm;
+ ondisk[chunk_id] = metadata->ssd_ondisk;
+ DNPRINTF(SR_D_META, "%s: using ondisk "
+ "metadata version %llu for chunk %u\n",
+ DEVNAME(sc), ondisk[chunk_id], chunk_id);
+ }
+ }
+
+ if (vol->sbv_chunk_no != vol->sbv_dev_no) {
printf("%s: not all chunks were provided; "
"attempting to bring volume %d online\n",
- DEVNAME(sc), m1->ssdi.ssd_volid);
- no_dev = m1->ssdi.ssd_chunk_no;
+ DEVNAME(sc), vol->sbv_volid);
}
bzero(&bc, sizeof(bc));
- bc.bc_level = m1->ssdi.ssd_level;
- bc.bc_dev_list_len = no_dev * sizeof(dev_t);
- bc.bc_dev_list = dt;
+ bc.bc_level = vol->sbv_level;
+ bc.bc_dev_list_len = vol->sbv_chunk_no * sizeof(dev_t);
+ bc.bc_dev_list = devs;
bc.bc_flags = BIOC_SCDEVT;
sr_ioctl_createraid(sc, &bc, 0);
+
rv++;
}
/* done with metadata */
unwind:
+ for (vp1 = SLIST_FIRST(&bvh); vp1 != SLIST_END(&bvh); vp1 = vp2) {
+ vp2 = SLIST_NEXT(vp1, sbv_link);
+ for (mle1 = SLIST_FIRST(&vp1->sml);
+ mle1 != SLIST_END(&vp1->sml); mle1 = mle2) {
+ mle2 = SLIST_NEXT(mle1, sml_link);
+ free(mle1, M_DEVBUF);
+ }
+ free(vp1, M_DEVBUF);
+ }
for (mle = SLIST_FIRST(&mlh); mle != SLIST_END(&mlh); mle = mle2) {
mle2 = SLIST_NEXT(mle, sml_link);
free(mle, M_DEVBUF);
}
SLIST_INIT(&mlh);
- if (dt)
- free(dt, M_DEVBUF);
+ if (devs)
+ free(devs, M_DEVBUF);
+ if (ondisk)
+ free(ondisk, M_DEVBUF);
return (rv);
}