diff options
author | 2011-09-18 19:40:49 +0000 | |
---|---|---|
committer | 2011-09-18 19:40:49 +0000 | |
commit | ee4e3de1f33cb4e00584fe4483e204f62c95357a (patch) | |
tree | fb5a8e7ab0b2dafc93e795aa1b21794579bb6979 /sys/dev/softraid.c | |
parent | Fix exchanged arguments in a "can't happen" printf (diff) | |
download | wireguard-openbsd-ee4e3de1f33cb4e00584fe4483e204f62c95357a.tar.xz wireguard-openbsd-ee4e3de1f33cb4e00584fe4483e204f62c95357a.zip |
Add support for variable length optional metadata in softraid(4). This
will allow new optional metadata types to be added without needing to
change the softraid metadata version.
Note that this commit changes the softraid metadata version, however
an upgrade from older metadata is handled automatically. A full backup
prior to upgrading is still strongly recommended.
With feedback from stsp@ and marco.
Diffstat (limited to 'sys/dev/softraid.c')
-rw-r--r-- | sys/dev/softraid.c | 142 |
1 files changed, 113 insertions, 29 deletions
diff --git a/sys/dev/softraid.c b/sys/dev/softraid.c index de95e4460db..33654c730bf 100644 --- a/sys/dev/softraid.c +++ b/sys/dev/softraid.c @@ -1,4 +1,4 @@ -/* $OpenBSD: softraid.c,v 1.247 2011/09/18 13:11:08 jsing Exp $ */ +/* $OpenBSD: softraid.c,v 1.248 2011/09/18 19:40:49 jsing Exp $ */ /* * Copyright (c) 2007, 2008, 2009 Marco Peereboom <marco@peereboom.us> * Copyright (c) 2008 Chris Kuethe <ckuethe@openbsd.org> @@ -150,7 +150,7 @@ void sr_meta_chunks_create(struct sr_softc *, void sr_meta_init(struct sr_discipline *, struct sr_chunk_head *); void sr_meta_opt_handler(struct sr_discipline *, - struct sr_meta_opt *); + struct sr_meta_opt_hdr *); /* hotplug magic */ void sr_disk_attach(struct disk *, int); @@ -605,9 +605,9 @@ sr_meta_init(struct sr_discipline *sd, struct sr_chunk_head *cl) } void -sr_meta_opt_handler(struct sr_discipline *sd, struct sr_meta_opt *om) +sr_meta_opt_handler(struct sr_discipline *sd, struct sr_meta_opt_hdr *om) { - if (om->somi.som_type != SR_OPT_BOOT) + if (om->som_type != SR_OPT_BOOT) panic("unknown optional metadata type"); } @@ -636,8 +636,8 @@ sr_meta_save(struct sr_discipline *sd, u_int32_t flags) struct sr_chunk *src; struct sr_meta_chunk *cm; struct sr_workunit wu; + struct sr_meta_opt_hdr *omh; struct sr_meta_opt_item *omi; - struct sr_meta_opt *om; int i; DNPRINTF(SR_D_META, "%s: sr_meta_save %s\n", @@ -672,12 +672,17 @@ restart: } /* Optional metadata. */ - om = (struct sr_meta_opt *)(cm); + omh = (struct sr_meta_opt_hdr *)(cm); SLIST_FOREACH(omi, &sd->sd_meta_opt, omi_link) { - bcopy(&omi->omi_om, om, sizeof(*om)); - sr_checksum(sc, om, &om->som_checksum, - sizeof(struct sr_meta_opt_invariant)); - om++; + DNPRINTF(SR_D_META, "%s: saving optional metadata type %u with " + "length %u\n", DEVNAME(sc), omi->omi_som->som_type, + omi->omi_som->som_length); + bzero(&omi->omi_som->som_checksum, MD5_DIGEST_LENGTH); + sr_checksum(sc, omi->omi_som, &omi->omi_som->som_checksum, + omi->omi_som->som_length); + bcopy(omi->omi_som, omh, omi->omi_som->som_length); + omh = (struct sr_meta_opt_hdr *)((u_int8_t *)omh + + omi->omi_som->som_length); } for (i = 0; i < sm->ssdi.ssd_chunk_no; i++) { @@ -793,8 +798,8 @@ sr_meta_read(struct sr_discipline *sd) sr_meta_opt_load(sc, sm, &sd->sd_meta_opt); SLIST_FOREACH(omi, &sd->sd_meta_opt, omi_link) if (sd->sd_meta_opt_handler == NULL || - sd->sd_meta_opt_handler(sd, &omi->omi_om) != 0) - sr_meta_opt_handler(sd, &omi->omi_om); + sd->sd_meta_opt_handler(sd, omi->omi_som) != 0) + sr_meta_opt_handler(sd, omi->omi_som); cp++; no_disk++; @@ -814,21 +819,85 @@ void sr_meta_opt_load(struct sr_softc *sc, struct sr_metadata *sm, struct sr_meta_opt_head *som) { + struct sr_meta_opt_hdr *omh; struct sr_meta_opt_item *omi; - struct sr_meta_opt *om; + u_int8_t checksum[MD5_DIGEST_LENGTH]; int i; /* Process optional metadata. */ - om = (struct sr_meta_opt *)((u_int8_t *)(sm + 1) + + omh = (struct sr_meta_opt_hdr *)((u_int8_t *)(sm + 1) + sizeof(struct sr_meta_chunk) * sm->ssdi.ssd_chunk_no); for (i = 0; i < sm->ssdi.ssd_opt_no; i++) { omi = malloc(sizeof(struct sr_meta_opt_item), M_DEVBUF, M_WAITOK | M_ZERO); - bcopy(om, &omi->omi_om, sizeof(struct sr_meta_opt)); SLIST_INSERT_HEAD(som, omi, omi_link); - om++; + if (omh->som_length == 0) { + + /* Load old fixed length optional metadata. */ + DNPRINTF(SR_D_META, "%s: old optional metadata of type " + "%u\n", DEVNAME(sc), omh->som_type); + + /* Validate checksum. */ + sr_checksum(sc, (void *)omh, &checksum, + SR_OLD_META_OPT_SIZE - MD5_DIGEST_LENGTH); + if (bcmp(&checksum, (void *)omh + SR_OLD_META_OPT_MD5, + sizeof(checksum))) + panic("%s: invalid optional metadata " + "checksum", DEVNAME(sc)); + + /* Determine correct length. */ + switch (omh->som_type) { + case SR_OPT_CRYPTO: + omh->som_length = sizeof(struct sr_meta_crypto); + break; + case SR_OPT_BOOT: + omh->som_length = sizeof(struct sr_meta_boot); + break; + case SR_OPT_KEYDISK: + omh->som_length = + sizeof(struct sr_meta_keydisk); + break; + default: + panic("unknown old optional metadata " + "type %u\n", omh->som_type); + } + + omi->omi_som = malloc(omh->som_length, M_DEVBUF, + M_WAITOK | M_ZERO); + bcopy((u_int8_t *)omh + SR_OLD_META_OPT_OFFSET, + (u_int8_t *)omi->omi_som + sizeof(*omi->omi_som), + omh->som_length - sizeof(*omi->omi_som)); + omi->omi_som->som_type = omh->som_type; + omi->omi_som->som_length = omh->som_length; + + omh = (struct sr_meta_opt_hdr *)((void *)omh + + SR_OLD_META_OPT_SIZE); + } else { + + /* Load variable length optional metadata. */ + DNPRINTF(SR_D_META, "%s: optional metadata of type %u, " + "length %u\n", DEVNAME(sc), omh->som_type, + omh->som_length); + omi->omi_som = malloc(omh->som_length, M_DEVBUF, + M_WAITOK | M_ZERO); + bcopy(omh, omi->omi_som, omh->som_length); + + /* Validate checksum. */ + bcopy(&omi->omi_som->som_checksum, &checksum, + MD5_DIGEST_LENGTH); + bzero(&omi->omi_som->som_checksum, MD5_DIGEST_LENGTH); + sr_checksum(sc, omi->omi_som, + &omi->omi_som->som_checksum, omh->som_length); + if (bcmp(&checksum, &omi->omi_som->som_checksum, + sizeof(checksum))) + panic("%s: invalid optional metadata checksum", + DEVNAME(sc)); + + omh = (struct sr_meta_opt_hdr *)((void *)omh + + omh->som_length); + } } } @@ -841,9 +910,9 @@ sr_meta_validate(struct sr_discipline *sd, dev_t dev, struct sr_metadata *sm, #ifdef SR_DEBUG struct sr_meta_chunk *mc; #endif + u_int8_t checksum[MD5_DIGEST_LENGTH]; char devname[32]; int rv = 1; - u_int8_t checksum[MD5_DIGEST_LENGTH]; DNPRINTF(SR_D_META, "%s: sr_meta_validate(%p)\n", DEVNAME(sc), sm); @@ -880,13 +949,10 @@ sr_meta_validate(struct sr_discipline *sd, dev_t dev, struct sr_metadata *sm, * Version 3 - update metadata version and fix up data offset * value since this did not exist in version 3. */ - sm->ssdi.ssd_version = SR_META_VERSION; - snprintf(sm->ssdi.ssd_revision, sizeof(sm->ssdi.ssd_revision), - "%03d", SR_META_VERSION); if (sm->ssd_data_offset == 0) sm->ssd_data_offset = SR_META_V3_DATA_OFFSET; - } else if (sm->ssdi.ssd_version == SR_META_VERSION) { + } else if (sm->ssdi.ssd_version == 4) { /* * Version 4 - original metadata format did not store @@ -895,6 +961,14 @@ sr_meta_validate(struct sr_discipline *sd, dev_t dev, struct sr_metadata *sm, if (sm->ssd_data_offset == 0) sm->ssd_data_offset = SR_DATA_OFFSET; + } else if (sm->ssdi.ssd_version == SR_META_VERSION) { + + /* + * Version 5 - variable length optional metadata. Migration + * from earlier fixed length optional metadata is handled + * in sr_meta_read(). + */ + } else { printf("%s: %s can not read metadata version %u, expected %u\n", @@ -904,6 +978,11 @@ sr_meta_validate(struct sr_discipline *sd, dev_t dev, struct sr_metadata *sm, } + /* Update version number and revision string. */ + sm->ssdi.ssd_version = SR_META_VERSION; + snprintf(sm->ssdi.ssd_revision, sizeof(sm->ssdi.ssd_revision), + "%03d", SR_META_VERSION); + #ifdef SR_DEBUG /* warn if disk changed order */ mc = (struct sr_meta_chunk *)(sm + 1); @@ -3377,7 +3456,7 @@ void sr_discipline_free(struct sr_discipline *sd) { struct sr_softc *sc; - struct sr_meta_opt_head *omh; + struct sr_meta_opt_head *som; struct sr_meta_opt_item *omi, *omi_next; if (!sd) @@ -3397,9 +3476,11 @@ sr_discipline_free(struct sr_discipline *sd) if (sd->sd_meta_foreign) free(sd->sd_meta_foreign, M_DEVBUF); - omh = &sd->sd_meta_opt; - for (omi = SLIST_FIRST(omh); omi != SLIST_END(omh); omi = omi_next) { + som = &sd->sd_meta_opt; + for (omi = SLIST_FIRST(som); omi != SLIST_END(som); omi = omi_next) { omi_next = SLIST_NEXT(omi, omi_link); + if (omi->omi_som) + free(omi->omi_som, M_DEVBUF); free(omi, M_DEVBUF); } @@ -4217,7 +4298,7 @@ sr_meta_print(struct sr_metadata *m) { int i; struct sr_meta_chunk *mc; - struct sr_meta_opt *mo; + struct sr_meta_opt_hdr *omh; if (!(sr_debug & SR_D_META)) return; @@ -4259,12 +4340,15 @@ sr_meta_print(struct sr_metadata *m) printf("\t\tscm_status %d\n", mc->scm_status); } - mo = (struct sr_meta_opt *)(mc); - for (i = 0; i < m->ssdi.ssd_opt_no; i++, mo++) { - printf("\t\t\tsom_type %d\n", mo->somi.som_type); + omh = (struct sr_meta_opt_hdr *)((u_int8_t *)(m + 1) + + sizeof(struct sr_meta_chunk) * m->ssdi.ssd_chunk_no); + for (i = 0; i < m->ssdi.ssd_opt_no; i++) { + printf("\t\t\tsom_type %d\n", omh->som_type); printf("\t\t\tsom_checksum "); - sr_checksum_print(mo->som_checksum); + sr_checksum_print(omh->som_checksum); printf("\n"); + omh = (struct sr_meta_opt_hdr *)((void *)omh + + omh->som_length); } } |