diff options
author | Joel Sing <jsing@cvs.openbsd.org> | 2010-03-26 16:51:00 +0000 |
---|---|---|
committer | Joel Sing <jsing@cvs.openbsd.org> | 2010-03-26 16:51:00 +0000 |
commit | 0eed1f02202c01ba55015b01f6998293613e7d6d (patch) | |
tree | 7ab45f683f864896ace7c1a9abbbd66a4f0f1dfc /sys/dev | |
parent | 5c0668aeb3664e3654a9fa92c8bd300d21ec81e3 (diff) |
Add an ioctl to softraid to allow the boot block and boot loader to be
installed on a softraid volume. This is work in progress but can continue
in tree.
ok marco@
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/biovar.h | 14 | ||||
-rw-r--r-- | sys/dev/softraid.c | 157 |
2 files changed, 169 insertions, 2 deletions
diff --git a/sys/dev/biovar.h b/sys/dev/biovar.h index 2448903a74d..e5ff86850aa 100644 --- a/sys/dev/biovar.h +++ b/sys/dev/biovar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: biovar.h,v 1.37 2009/12/31 14:00:45 jsing Exp $ */ +/* $OpenBSD: biovar.h,v 1.38 2010/03/26 16:50:59 jsing Exp $ */ /* * Copyright (c) 2002 Niklas Hallqvist. All rights reserved. @@ -184,6 +184,7 @@ struct bioc_createraid { #define BIOC_SCFORCE 0x01 /* do not assemble, force create */ #define BIOC_SCDEVT 0x02 /* dev_t array or string in dev_list */ #define BIOC_SCNOAUTOASSEMBLE 0x04 /* do not assemble during autoconf */ +#define BIOC_SCBOOTABLE 0x08 /* device is bootable */ u_int32_t bc_opaque_size; u_int32_t bc_opaque_flags; #define BIOC_SOINVALID 0x00 /* no opaque pointer */ @@ -212,6 +213,16 @@ struct bioc_discipline { void *bd_data; }; +#define BIOCINSTALLBOOT _IOWR('B', 40, struct bioc_installboot) +struct bioc_installboot { + void *bb_cookie; + char bb_dev[16]; + void *bb_bootblk; + void *bb_bootldr; + u_int32_t bb_bootblk_size; + u_int32_t bb_bootldr_size; +}; + /* kernel and userspace defines */ #define BIOC_INQ 0x0001 #define BIOC_DISK 0x0002 @@ -222,6 +233,7 @@ struct bioc_discipline { #define BIOC_CREATERAID 0x0040 #define BIOC_DELETERAID 0x0080 #define BIOC_DISCIPLINE 0x0100 +#define BIOC_INSTALLBOOT 0x0200 /* user space defines */ #define BIOC_DEVLIST 0x10000 diff --git a/sys/dev/softraid.c b/sys/dev/softraid.c index b83bfc495be..202c1584601 100644 --- a/sys/dev/softraid.c +++ b/sys/dev/softraid.c @@ -1,4 +1,4 @@ -/* $OpenBSD: softraid.c,v 1.196 2010/03/26 11:20:34 jsing Exp $ */ +/* $OpenBSD: softraid.c,v 1.197 2010/03/26 16:50:59 jsing Exp $ */ /* * Copyright (c) 2007, 2008, 2009 Marco Peereboom <marco@peereboom.us> * Copyright (c) 2008 Chris Kuethe <ckuethe@openbsd.org> @@ -105,6 +105,8 @@ int sr_ioctl_deleteraid(struct sr_softc *, struct bioc_deleteraid *); int sr_ioctl_discipline(struct sr_softc *, struct bioc_discipline *); +int sr_ioctl_installboot(struct sr_softc *, + struct bioc_installboot *); void sr_chunks_unwind(struct sr_softc *, struct sr_chunk_head *); void sr_discipline_free(struct sr_discipline *); @@ -2030,6 +2032,10 @@ sr_ioctl(struct device *dev, u_long cmd, caddr_t addr) rv = sr_ioctl_discipline(sc, (struct bioc_discipline *)addr); break; + case BIOCINSTALLBOOT: + rv = sr_ioctl_installboot(sc, (struct bioc_installboot *)addr); + break; + default: DNPRINTF(SR_D_IOCTL, "invalid ioctl\n"); rv = ENOTTY; @@ -3097,6 +3103,155 @@ sr_ioctl_discipline(struct sr_softc *sc, struct bioc_discipline *bd) return (rv); } +int +sr_ioctl_installboot(struct sr_softc *sc, struct bioc_installboot *bb) +{ + void *bootblk = NULL, *bootldr = NULL; + struct sr_discipline *sd = NULL; + struct sr_chunk *chunk; + struct buf b; + u_int32_t bbs, bls; + int rv = EINVAL; + int i; + + DNPRINTF(SR_D_IOCTL, "%s: sr_ioctl_installboot %s\n", DEVNAME(sc), + bb->bb_dev); + + for (i = 0; i < SR_MAXSCSIBUS; i++) + if (sc->sc_dis[i]) { + if (!strncmp(sc->sc_dis[i]->sd_meta->ssd_devname, + bb->bb_dev, + sizeof(sc->sc_dis[i]->sd_meta->ssd_devname))) { + sd = sc->sc_dis[i]; + break; + } + } + + if (sd == NULL) + goto done; + + if (bb->bb_bootblk_size > SR_BOOT_BLOCKS_SIZE * 512) + goto done; + + if (bb->bb_bootldr_size > SR_BOOT_LOADER_SIZE * 512) + goto done; + + /* Copy in boot block. */ + bbs = howmany(bb->bb_bootblk_size, DEV_BSIZE) * DEV_BSIZE; + bootblk = malloc(bbs, M_DEVBUF, M_WAITOK | M_ZERO); + if (copyin(bb->bb_bootblk, bootblk, bb->bb_bootblk_size) != 0) + goto done; + + /* Copy in boot loader. */ + bls = howmany(bb->bb_bootldr_size, DEV_BSIZE) * DEV_BSIZE; + bootldr = malloc(bls, M_DEVBUF, M_WAITOK | M_ZERO); + if (copyin(bb->bb_bootldr, bootldr, bb->bb_bootldr_size) != 0) + goto done; + + /* Save boot block and boot loader to each chunk. */ + for (i = 0; i < sd->sd_meta->ssdi.ssd_chunk_no; i++) { + + chunk = sd->sd_vol.sv_chunks[i]; + + /* Save boot blocks. */ + DNPRINTF(SR_D_IOCTL, + "sr_ioctl_installboot: saving boot block to %s " + "(%u bytes)\n", chunk->src_devname, bbs); + + bzero(&b, sizeof(b)); + b.b_flags = B_WRITE | B_PHYS; + b.b_blkno = SR_BOOT_BLOCKS_OFFSET; + b.b_bcount = bbs; + b.b_bufsize = bbs; + b.b_resid = bbs; + b.b_data = bootblk; + b.b_error = 0; + b.b_proc = curproc; + b.b_dev = chunk->src_dev_mm; + b.b_vp = NULL; + b.b_iodone = NULL; + if (bdevvp(chunk->src_dev_mm, &b.b_vp)) { + printf("%s: sr_ioctl_installboot: vnode allocation " + "failed\n", DEVNAME(sc)); + goto done; + } + if ((b.b_flags & B_READ) == 0) + b.b_vp->v_numoutput++; + LIST_INIT(&b.b_dep); + VOP_STRATEGY(&b); + biowait(&b); + vput(b.b_vp); + + if (b.b_flags & B_ERROR) { + printf("%s: 0x%x i/o error on block %llu while " + "writing boot block %d\n", DEVNAME(sc), + chunk->src_dev_mm, b.b_blkno, b.b_error); + goto done; + } + + /* Save boot loader.*/ + DNPRINTF(SR_D_IOCTL, + "sr_ioctl_installboot: saving boot loader to %s " + "(%u bytes)\n", chunk->src_devname, bls); + + bzero(&b, sizeof(b)); + b.b_flags = B_WRITE | B_PHYS; + b.b_blkno = SR_BOOT_LOADER_OFFSET; + b.b_bcount = bls; + b.b_bufsize = bls; + b.b_resid = bls; + b.b_data = bootldr; + b.b_error = 0; + b.b_proc = curproc; + b.b_dev = chunk->src_dev_mm; + b.b_vp = NULL; + b.b_iodone = NULL; + if (bdevvp(chunk->src_dev_mm, &b.b_vp)) { + printf("%s: sr_ioctl_installboot: vnode alocation " + "failed\n", DEVNAME(sc)); + goto done; + } + if ((b.b_flags & B_READ) == 0) + b.b_vp->v_numoutput++; + LIST_INIT(&b.b_dep); + VOP_STRATEGY(&b); + biowait(&b); + vput(b.b_vp); + + if (b.b_flags & B_ERROR) { + printf("%s: 0x%x i/o error on block %llu while " + "writing boot blocks %d\n", DEVNAME(sc), + chunk->src_dev_mm, b.b_blkno, b.b_error); + goto done; + } + + } + + /* XXX - Install boot block on disk - MD code. */ + + /* Save boot details in metadata. */ + sd->sd_meta->ssdi.ssd_flags |= BIOC_SCBOOTABLE; + + /* XXX - Store size of boot block/loader in optional metadata. */ + + /* Save metadata. */ + if (sr_meta_save(sd, SR_META_DIRTY)) { + printf("%s: could not save metadata to %s\n", + DEVNAME(sc), chunk->src_devname); + goto done; + } + + rv = 0; + +done: + if (bootblk) + free(bootblk, M_DEVBUF); + if (bootldr) + free(bootldr, M_DEVBUF); + + return (rv); +} + void sr_chunks_unwind(struct sr_softc *sc, struct sr_chunk_head *cl) { |