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.c330
1 files changed, 254 insertions, 76 deletions
diff --git a/sys/dev/softraid.c b/sys/dev/softraid.c
index ef8871e7858..c06cbb87958 100644
--- a/sys/dev/softraid.c
+++ b/sys/dev/softraid.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: softraid.c,v 1.40 2007/05/02 03:51:26 marco Exp $ */
+/* $OpenBSD: softraid.c,v 1.41 2007/05/08 23:54:37 marco Exp $ */
/*
* Copyright (c) 2007 Marco Peereboom <marco@peereboom.us>
*
@@ -130,11 +130,18 @@ void sr_raid1_startwu(struct sr_workunit *);
/* utility functions */
void sr_get_uuid(struct sr_uuid *);
+void sr_print_uuid(struct sr_uuid *, int);
u_int32_t sr_checksum(char *, u_int32_t *, u_int32_t);
int sr_save_metadata(struct sr_discipline *);
void sr_refresh_sensors(void *);
int sr_create_sensors(struct sr_discipline *);
+#ifdef SR_DEBUG
+void sr_print_metadata(struct sr_metadata *);
+#else
+#define sr_print_metadata(m)
+#endif
+
struct scsi_adapter sr_switch = {
sr_scsi_cmd, sr_minphys, NULL, NULL, sr_scsi_ioctl
};
@@ -759,6 +766,12 @@ sr_ioctl_createraid(struct sr_softc *sc, struct bioc_createraid *bc)
sd->sd_meta = malloc(SR_META_SIZE * 512 , M_DEVBUF, M_WAITOK);
bzero(sd->sd_meta, SR_META_SIZE * 512);
+ /* we have a valid list now create an array index */
+ sd->sd_vol.sv_chunks = malloc(sizeof(struct sr_chunk *) * no_chunk,
+ M_DEVBUF, M_WAITOK);
+ memset(sd->sd_vol.sv_chunks, 0,
+ sizeof(struct sr_chunk *) * no_chunk);
+
if ((no_meta = sr_read_meta(sd)) == 0) {
/* no metadata available */
switch (bc->bc_level) {
@@ -771,6 +784,11 @@ sr_ioctl_createraid(struct sr_softc *sc, struct bioc_createraid *bc)
goto unwind;
}
+ /* fill out chunk array */
+ i = 0;
+ SLIST_FOREACH(ch_entry, cl, src_link)
+ sd->sd_vol.sv_chunks[i++] = ch_entry;
+
/* fill out all chunk metadata */
sr_create_chunk_meta(sc, cl);
@@ -795,25 +813,15 @@ sr_ioctl_createraid(struct sr_softc *sc, struct bioc_createraid *bc)
updatemeta = 1;
} else if (no_meta == no_chunk) {
- /* we got metadata, validate it */
- printf("%s: METADATA BRINGUP IS NOT WORKING YET; "
- "TREATING AS VOLUME CREATION\n",
+ DNPRINTF(SR_D_META, "%s: disk assembled from metadata\n",
DEVNAME(sc));
+ updatemeta = 0;
} else {
panic("not yet partial bringup");
}
/* XXX metadata SHALL be fully filled in at this point */
- /* we have a valid list now create an array index into it */
- sd->sd_vol.sv_chunks = malloc(sizeof(struct sr_chunk *) * no_chunk,
- M_DEVBUF, M_WAITOK);
- memset(sd->sd_vol.sv_chunks, 0,
- sizeof(struct sr_chunk *) * no_chunk);
- i = 0;
- SLIST_FOREACH(ch_entry, cl, src_link)
- sd->sd_vol.sv_chunks[i++] = ch_entry;
-
switch (bc->bc_level) {
case 1:
/* fill out discipline members */
@@ -1088,14 +1096,20 @@ sr_read_meta(struct sr_discipline *sd)
{
struct sr_softc *sc = sd->sd_sc;
struct sr_chunk_head *cl = &sd->sd_vol.sv_chunk_list;
- struct sr_metadata *sm = sd->sd_meta;
+ struct sr_metadata *sm = sd->sd_meta, *m;
struct sr_chunk *ch_entry;
struct buf b;
- int mc = 0;
+ struct sr_vol_meta *mv;
+ struct sr_chunk_meta *mc;
size_t sz = SR_META_SIZE * 512;
+ int no_chunk = 0;
+ u_int32_t chk, volid;
DNPRINTF(SR_D_META, "%s: sr_read_meta\n", DEVNAME(sc));
+ m = malloc(sz , M_DEVBUF, M_WAITOK);
+ bzero(m, sz);
+
SLIST_FOREACH(ch_entry, cl, src_link) {
memset(&b, 0, sizeof(b));
@@ -1104,7 +1118,7 @@ sr_read_meta(struct sr_discipline *sd)
b.b_bcount = sz;
b.b_bufsize = sz;
b.b_resid = sz;
- b.b_data = (void *)sm;
+ b.b_data = (void *)m;
b.b_error = 0;
b.b_proc = curproc;
b.b_dev = ch_entry->src_dev_mm;
@@ -1123,19 +1137,164 @@ sr_read_meta(struct sr_discipline *sd)
continue;
}
- if (sm->ssd_magic != SR_MAGIC)
+ if (m->ssd_magic != SR_MAGIC)
continue;
+ /* validate metadata */
+ if (m->ssd_version != SR_META_VERSION) {
+ printf("%s: %s can not read metadata version %d, "
+ "expected %d\n", DEVNAME(sc),
+ ch_entry->src_devname, m->ssd_version,
+ SR_META_VERSION);
+ no_chunk = -1;
+ goto bad;
+ }
+ if (m->ssd_size != sizeof(struct sr_metadata)) {
+ printf("%s: %s invalid metadata size %d, "
+ "expected %d\n", DEVNAME(sc),
+ ch_entry->src_devname, m->ssd_size,
+ sizeof(struct sr_metadata));
+ no_chunk = -1;
+ goto bad;
+ }
+ chk = sr_checksum(DEVNAME(sc), (u_int32_t *)m, m->ssd_size);
+ /*
+ * since the checksum value is part of the checksum a good
+ * result equals 0
+ */
+ if (chk != 0) {
+ printf("%s: %s invalid metadata checksum 0x%x, "
+ "expected 0x%x\n", DEVNAME(sc),
+ ch_entry->src_devname, m->ssd_checksum, chk);
+ goto bad;
+ }
+
+ /* validate volume metadata */
+ if (m->ssd_vd_ver != SR_VOL_VERSION) {
+ printf("%s: %s can not read volume metadata version "
+ "%d, expected %d\n", DEVNAME(sc),
+ ch_entry->src_devname, m->ssd_vd_ver,
+ SR_VOL_VERSION);
+ no_chunk = -1;
+ goto bad;
+ }
+ if (m->ssd_vd_size != sizeof(struct sr_vol_meta)) {
+ printf("%s: %s invalid volume metadata size %d, "
+ "expected %d\n", DEVNAME(sc),
+ ch_entry->src_devname, m->ssd_vd_size,
+ sizeof(struct sr_vol_meta));
+ no_chunk = -1;
+ goto bad;
+ }
+ mv = (struct sr_vol_meta *)(m + 1);
+ chk = sr_checksum(DEVNAME(sc), (u_int32_t *)mv, m->ssd_vd_size);
+ if (chk != m->ssd_vd_chk) {
+ printf("%s: %s invalid volume metadata checksum 0x%x, "
+ "expected 0x%x\n", DEVNAME(sc),
+ ch_entry->src_devname, m->ssd_vd_chk, chk);
+ no_chunk = -1;
+ goto bad;
+ }
+
+ /* validate chunk metadata */
+ if (m->ssd_chunk_ver != SR_CHUNK_VERSION) {
+ printf("%s: %s can not read chunk metadata version "
+ "%d, expected %d\n", DEVNAME(sc),
+ ch_entry->src_devname, m->ssd_chunk_ver,
+ SR_CHUNK_VERSION);
+ no_chunk = -1;
+ goto bad;
+ }
+ if (m->ssd_chunk_size != sizeof(struct sr_chunk_meta)) {
+ printf("%s: %s invalid chunk metadata size %d, "
+ "expected %d\n", DEVNAME(sc),
+ ch_entry->src_devname, m->ssd_chunk_size,
+ sizeof(struct sr_chunk_meta));
+ no_chunk = -1;
+ goto bad;
+ }
+ mc = (struct sr_chunk_meta *)(mv + 1);
+ /* checksum is calculated over ALL chunks */
+ chk = sr_checksum(DEVNAME(sc), (u_int32_t *)(mc),
+ m->ssd_chunk_size * m->ssd_chunk_no);
+ if (chk != m->ssd_chunk_chk) {
+ printf("%s: %s invalid chunk metadata checksum 0x%x, "
+ "expected 0x%x\n", DEVNAME(sc),
+ ch_entry->src_devname, m->ssd_chunk_chk, chk);
+ no_chunk = -1;
+ goto bad;
+ }
+
+ /* we asssume that the first chunk has the initial metadata */
+ if (no_chunk++ == 0) {
+ bcopy(m, sm, sz);
+ bcopy(m, &sd->sd_meta, sizeof(sd->sd_meta));
+ bcopy(mv, &sd->sd_vol.sv_meta,
+ sizeof(sd->sd_vol.sv_meta));
+
+ volid = m->ssd_vd_volid;
+ }
+
+ if (bcmp(&sm->ssd_uuid, &sd->sd_vol.sv_meta.svm_uuid,
+ sizeof(struct sr_uuid))) {
+ printf("%s: %s invalid chunk uuid ",
+ DEVNAME(sc), ch_entry->src_devname);
+ sr_print_uuid(&sm->ssd_uuid, 0);
+ printf(", expected ");
+ sr_print_uuid(&sd->sd_vol.sv_meta.svm_uuid, 1);
+ no_chunk = -1;
+ goto bad;
+ }
+
/* we have meta data on disk */
- mc++;
ch_entry->src_meta_ondisk = 1;
+
+ /* make sure we are part of this vd */
+ if (volid != m->ssd_vd_volid) {
+ printf("%s: %s invalid volume id %d, expected %d\n",
+ DEVNAME(sc), ch_entry->src_devname,
+ volid, m->ssd_vd_volid);
+ no_chunk = -1;
+ goto bad;
+ }
+
+ if (m->ssd_chunk_id > m->ssd_chunk_no) {
+ printf("%s: %s chunk id out of range %d, expected "
+ "lower than %d\n", DEVNAME(sc),
+ ch_entry->src_devname,
+ m->ssd_chunk_id, m->ssd_chunk_no);
+ no_chunk = -1;
+ goto bad;
+ }
+
+ if (sd->sd_vol.sv_chunks[m->ssd_chunk_id]) {
+ printf("%s: %s chunk id %d already in use\n ",
+ DEVNAME(sc), ch_entry->src_devname,
+ m->ssd_chunk_id);
+ no_chunk = -1;
+ goto bad;
+ }
+
+ sd->sd_vol.sv_chunks[m->ssd_chunk_id] = ch_entry;
+ bcopy(mc, &ch_entry->src_meta, sizeof(ch_entry->src_meta));
+ }
+
+ if (no_chunk != m->ssd_chunk_no) {
+ DNPRINTF(SR_D_META, "%s: not enough chunks supplied\n",
+ DEVNAME(sc));
+ no_chunk = -1;
+ goto bad;
}
DNPRINTF(SR_D_META, "%s: sr_read_meta: found %d elements\n",
- DEVNAME(sc), mc);
+ DEVNAME(sc), no_chunk);
+
+ sr_print_metadata(m);
+bad:
/* return nr of chunks that contain metadata */
- return (mc);
+ free(m, M_DEVBUF);
+ return (no_chunk);
}
int
@@ -1191,6 +1350,7 @@ sr_create_chunk_meta(struct sr_softc *sc, struct sr_chunk_head *cl)
return (rv);
}
+
void
sr_unwind_chunks(struct sr_softc *sc, struct sr_chunk_head *cl)
{
@@ -1902,7 +2062,7 @@ die:
u_int32_t
sr_checksum(char *s, u_int32_t *p, u_int32_t size)
{
- u_int32_t chk = 0;
+ u_int32_t chk = 0xdeadbeef;
int i;
DNPRINTF(SR_D_MISC, "%s: sr_checksum %p %d\n", s, p, size);
@@ -1919,12 +2079,25 @@ sr_checksum(char *s, u_int32_t *p, u_int32_t size)
void
sr_get_uuid(struct sr_uuid *uuid)
{
- int i;
+ int i;
for (i = 0; i < SR_UUID_MAX; i++)
uuid->sui_id[i] = arc4random();
}
+void
+sr_print_uuid(struct sr_uuid *uuid, int cr)
+{
+ int i;
+
+ for (i = 0; i < SR_UUID_MAX; i++)
+ printf("%x%s", uuid->sui_id[i],
+ i < SR_UUID_MAX - 1 ? ":" : "");
+
+ if (cr)
+ printf("\n");
+}
+
int
sr_save_metadata(struct sr_discipline *sd)
{
@@ -1994,60 +2167,7 @@ sr_save_metadata(struct sr_discipline *sd)
sm->ssd_chunk_chk ^= sr_checksum(DEVNAME(sc),
(u_int32_t *)&im_sc[ch], sm->ssd_chunk_size);
-#ifdef SR_DEBUG
- /* metadata */
- DNPRINTF(SR_D_META, "\tmeta magic 0x%llx\n", sm->ssd_magic);
- DNPRINTF(SR_D_META, "\tmeta version %d\n", sm->ssd_version);
- DNPRINTF(SR_D_META, "\tmeta checksum 0x%x\n", sm->ssd_checksum);
- DNPRINTF(SR_D_META, "\tmeta size %d\n", sm->ssd_size);
- DNPRINTF(SR_D_META, "\tmeta on disk version %u\n", sm->ssd_ondisk);
- DNPRINTF(SR_D_META, "\tmeta uuid ");
- for (i = 0; i < SR_UUID_MAX; i++)
- DNPRINTF(SR_D_META, "%x%s", sm->ssd_uuid.sui_id[i],
- i < SR_UUID_MAX - 1 ? ":" : "\n");
- DNPRINTF(SR_D_META, "\tvd version %d\n", sm->ssd_vd_ver);
- DNPRINTF(SR_D_META, "\tvd size %lu\n", sm->ssd_vd_size);
- DNPRINTF(SR_D_META, "\tvd checksum 0x%x\n", sm->ssd_vd_chk);
- DNPRINTF(SR_D_META, "\tchunk version %d\n", sm->ssd_chunk_ver);
- DNPRINTF(SR_D_META, "\tchunks %d\n", sm->ssd_chunk_no);
- DNPRINTF(SR_D_META, "\tchunk size %u\n", sm->ssd_chunk_size);
- DNPRINTF(SR_D_META, "\tchunk checksum 0x%x\n", sm->ssd_chunk_chk);
-
- DNPRINTF(SR_D_META, "\t\tvol id %d\n", im_sv->svm_volid);
- DNPRINTF(SR_D_META, "\t\tvol status %d\n", im_sv->svm_status);
- DNPRINTF(SR_D_META, "\t\tvol flags 0x%x\n", im_sv->svm_flags);
- DNPRINTF(SR_D_META, "\t\tvol level %d\n", im_sv->svm_level);
- DNPRINTF(SR_D_META, "\t\tvol size %llu\n", im_sv->svm_size);
- DNPRINTF(SR_D_META, "\t\tvol name %s\n", im_sv->svm_devname);
- DNPRINTF(SR_D_META, "\t\tvol vendor %s\n", im_sv->svm_vendor);
- DNPRINTF(SR_D_META, "\t\tvol prod %s\n", im_sv->svm_product);
- DNPRINTF(SR_D_META, "\t\tvol rev %s\n", im_sv->svm_revision);
- DNPRINTF(SR_D_META, "\t\tvol no chunks %d\n", im_sv->svm_no_chunk);
- DNPRINTF(SR_D_META, "\t\tvol uuid ");
- for (i = 0; i < SR_UUID_MAX; i++)
- DNPRINTF(SR_D_META, "%x%s", im_sv->svm_uuid.sui_id[i],
- i < SR_UUID_MAX - 1 ? ":" : "\n");
-
- for (ch = 0; ch < im_sv->svm_no_chunk; ch++) {
- DNPRINTF(SR_D_META, "\t\t\tchunk vol id %d\n",
- im_sc[ch].scm_volid);
- DNPRINTF(SR_D_META, "\t\t\tchunk id %d\n",
- im_sc[ch].scm_chunk_id);
- DNPRINTF(SR_D_META, "\t\t\tchunk status %d\n",
- im_sc[ch].scm_status);
- DNPRINTF(SR_D_META, "\t\t\tchunk name %s\n",
- im_sc[ch].scm_devname);
- DNPRINTF(SR_D_META, "\t\t\tchunk size %llu\n",
- im_sc[ch].scm_size);
- DNPRINTF(SR_D_META, "\t\t\tchunk coerced size %llu\n",
- im_sc[ch].scm_coerced_size);
- DNPRINTF(SR_D_META, "\t\t\tchunk uuid ");
- for (i = 0; i < SR_UUID_MAX; i++)
- DNPRINTF(SR_D_META, "%x%s",
- im_sc[ch].scm_uuid.sui_id[i],
- i < SR_UUID_MAX - 1 ? ":" : "\n");
- }
-#endif
+ sr_print_metadata(sm);
for (i = 0; i < sm->ssd_chunk_no; i++) {
memset(&b, 0, sizeof(b));
@@ -2213,3 +2333,61 @@ sr_print_stats(void)
}
}
#endif
+
+#ifdef SR_DEBUG
+void
+sr_print_metadata(struct sr_metadata *sm)
+{
+ struct sr_vol_meta *im_sv;
+ struct sr_chunk_meta *im_sc;
+ int ch;
+
+ im_sv = (struct sr_vol_meta *)(sm + 1);
+ im_sc = (struct sr_chunk_meta *)(im_sv + 1);
+
+ DNPRINTF(SR_D_META, "\tmeta magic 0x%llx\n", sm->ssd_magic);
+ DNPRINTF(SR_D_META, "\tmeta version %d\n", sm->ssd_version);
+ DNPRINTF(SR_D_META, "\tmeta checksum 0x%x\n", sm->ssd_checksum);
+ DNPRINTF(SR_D_META, "\tmeta size %d\n", sm->ssd_size);
+ DNPRINTF(SR_D_META, "\tmeta on disk version %u\n", sm->ssd_ondisk);
+ DNPRINTF(SR_D_META, "\tmeta uuid ");
+ sr_print_uuid(&sm->ssd_uuid, 1);
+ DNPRINTF(SR_D_META, "\tvd version %d\n", sm->ssd_vd_ver);
+ DNPRINTF(SR_D_META, "\tvd size %lu\n", sm->ssd_vd_size);
+ DNPRINTF(SR_D_META, "\tvd checksum 0x%x\n", sm->ssd_vd_chk);
+ DNPRINTF(SR_D_META, "\tchunk version %d\n", sm->ssd_chunk_ver);
+ DNPRINTF(SR_D_META, "\tchunks %d\n", sm->ssd_chunk_no);
+ DNPRINTF(SR_D_META, "\tchunk size %u\n", sm->ssd_chunk_size);
+ DNPRINTF(SR_D_META, "\tchunk checksum 0x%x\n", sm->ssd_chunk_chk);
+
+ DNPRINTF(SR_D_META, "\t\tvol id %d\n", im_sv->svm_volid);
+ DNPRINTF(SR_D_META, "\t\tvol status %d\n", im_sv->svm_status);
+ DNPRINTF(SR_D_META, "\t\tvol flags 0x%x\n", im_sv->svm_flags);
+ DNPRINTF(SR_D_META, "\t\tvol level %d\n", im_sv->svm_level);
+ DNPRINTF(SR_D_META, "\t\tvol size %llu\n", im_sv->svm_size);
+ DNPRINTF(SR_D_META, "\t\tvol name %s\n", im_sv->svm_devname);
+ DNPRINTF(SR_D_META, "\t\tvol vendor %s\n", im_sv->svm_vendor);
+ DNPRINTF(SR_D_META, "\t\tvol prod %s\n", im_sv->svm_product);
+ DNPRINTF(SR_D_META, "\t\tvol rev %s\n", im_sv->svm_revision);
+ DNPRINTF(SR_D_META, "\t\tvol no chunks %d\n", im_sv->svm_no_chunk);
+ DNPRINTF(SR_D_META, "\t\tvol uuid ");
+ sr_print_uuid(& im_sv->svm_uuid, 1);
+
+ for (ch = 0; ch < im_sv->svm_no_chunk; ch++) {
+ DNPRINTF(SR_D_META, "\t\t\tchunk vol id %d\n",
+ im_sc[ch].scm_volid);
+ DNPRINTF(SR_D_META, "\t\t\tchunk id %d\n",
+ im_sc[ch].scm_chunk_id);
+ DNPRINTF(SR_D_META, "\t\t\tchunk status %d\n",
+ im_sc[ch].scm_status);
+ DNPRINTF(SR_D_META, "\t\t\tchunk name %s\n",
+ im_sc[ch].scm_devname);
+ DNPRINTF(SR_D_META, "\t\t\tchunk size %llu\n",
+ im_sc[ch].scm_size);
+ DNPRINTF(SR_D_META, "\t\t\tchunk coerced size %llu\n",
+ im_sc[ch].scm_coerced_size);
+ DNPRINTF(SR_D_META, "\t\t\tchunk uuid ");
+ sr_print_uuid(&im_sc[ch].scm_uuid, 1);
+ }
+}
+#endif