diff options
-rw-r--r-- | sys/conf/files | 5 | ||||
-rw-r--r-- | sys/dev/rd.c | 417 |
2 files changed, 377 insertions, 45 deletions
diff --git a/sys/conf/files b/sys/conf/files index 1434ba20630..d34cfd060da 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $OpenBSD: files,v 1.512 2011/04/07 13:42:53 thib Exp $ +# $OpenBSD: files,v 1.513 2011/06/23 17:06:07 matthew Exp $ # $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 @@ -493,7 +493,7 @@ pseudo-device vnd: disk pseudo-device ccd: disk pseudo-device raid: disk pseudo-device rd: disk -file dev/ramdisk.c rd needs-flag +file dev/rd.c rd needs-flag pseudo-device pty: tty pseudo-device nmea: tty @@ -1015,7 +1015,6 @@ file uvm/uvm_swap_encrypt.c uvm_swap_encrypt file uvm/uvm_unix.c file uvm/uvm_user.c file uvm/uvm_vnode.c -file dev/rd.c ramdisk_hooks # IPv6 file net/if_faith.c faith needs-count diff --git a/sys/dev/rd.c b/sys/dev/rd.c index edc2f397883..c6a318e5aee 100644 --- a/sys/dev/rd.c +++ b/sys/dev/rd.c @@ -1,39 +1,37 @@ -/* $OpenBSD: rd.c,v 1.2 2008/08/22 03:12:37 deraadt Exp $ */ +/* $OpenBSD: rd.c,v 1.3 2011/06/23 17:06:07 matthew Exp $ */ /* - * Copyright (c) 1995 Gordon W. Ross - * All rights reserved. + * Copyright (c) 2011 Matthew Dempsky <matthew@dempsky.org> * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <sys/param.h> #include <sys/systm.h> -#include <sys/reboot.h> - -#include <dev/ramdisk.h> - -extern int boothowto; +#include <sys/proc.h> +#include <sys/errno.h> +#include <sys/buf.h> +#include <sys/malloc.h> +#include <sys/ioctl.h> +#include <sys/disklabel.h> +#include <sys/device.h> +#include <sys/disk.h> +#include <sys/stat.h> +#include <sys/file.h> +#include <sys/uio.h> +#include <sys/conf.h> +#include <sys/dkio.h> +#include <sys/vnode.h> #ifndef MINIROOTSIZE #define MINIROOTSIZE 512 @@ -48,25 +46,360 @@ extern int boothowto; u_int32_t rd_root_size = ROOTBYTES; char rd_root_image[ROOTBYTES] = "|This is the root ramdisk!\n"; -/* - * This is called during autoconfig. - */ +void rdattach(int); +int rd_match(struct device *, void *, void *); +void rd_attach(struct device *, struct device *, void *); +int rd_detach(struct device *, int); + +struct rd_softc { + struct device sc_dev; + struct disk sc_dk; +}; + +struct cfattach rd_ca = { + sizeof(struct rd_softc), + rd_match, + rd_attach, + rd_detach +}; + +struct cfdriver rd_cd = { + NULL, + "rd", + DV_DISK +}; + +#define rdlookup(unit) ((struct rd_softc *)disk_lookup(&rd_cd, (unit))) + +int rdgetdisklabel(dev_t, struct rd_softc *, struct disklabel *, int); + void -rd_attach_hook(int unit, struct rd_conf *rd) +rdattach(int num) { - if (unit == 0) { - /* Setup root ramdisk */ - rd->rd_addr = (caddr_t) rd_root_image; - rd->rd_size = (size_t) rd_root_size; - rd->rd_type = RD_KMEM_FIXED; - printf("rd%d: fixed, %d blocks\n", unit, MINIROOTSIZE); + static struct cfdata cf; /* Fake cf. */ + struct rd_softc *sc; + int i; + + /* There's only one rd_root_image, so only attach one rd. */ + num = 1; + + /* XXX: Fake up more? */ + cf.cf_attach = &rd_ca; + cf.cf_driver = &rd_cd; + + rd_cd.cd_ndevs = num; + rd_cd.cd_devs = malloc(num * sizeof(void *), M_DEVBUF, M_NOWAIT); + if (rd_cd.cd_devs == NULL) + panic("rdattach: out of memory"); + + for (i = 0; i < num; ++i) { + /* Allocate the softc and initialize it. */ + sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT|M_ZERO); + if (sc == NULL) + panic("rdattach: out of memory"); + sc->sc_dev.dv_class = DV_DISK; + sc->sc_dev.dv_cfdata = &cf; + sc->sc_dev.dv_flags = DVF_ACTIVE; + sc->sc_dev.dv_unit = i; + if (snprintf(sc->sc_dev.dv_xname, sizeof(sc->sc_dev.dv_xname), + "rd%d", i) >= sizeof(sc->sc_dev.dv_xname)) + panic("rdattach: device name too long"); + sc->sc_dev.dv_ref = 1; + + /* Attach it to the device tree. */ + rd_cd.cd_devs[i] = sc; + TAILQ_INSERT_TAIL(&alldevs, &sc->sc_dev, dv_list); + device_ref(&sc->sc_dev); + + /* Finish initializing. */ + rd_attach(NULL, &sc->sc_dev, NULL); } } -/* - * This is called during open (i.e. mountroot) - */ +int +rd_match(struct device *parent, void *match, void *aux) +{ + return (0); +} + +void +rd_attach(struct device *parent, struct device *self, void *aux) +{ + struct rd_softc *sc = (struct rd_softc *)self; + + /* Attach disk. */ + sc->sc_dk.dk_name = sc->sc_dev.dv_xname; + disk_attach(&sc->sc_dev, &sc->sc_dk); +} + +int +rd_detach(struct device *self, int flags) +{ + struct rd_softc *sc = (struct rd_softc *)self; + int bmaj, cmaj, mn; + + /* Locate the lowest minor number to be detached. */ + mn = DISKMINOR(self->dv_unit, 0); + + for (bmaj = 0; bmaj < nblkdev; bmaj++) + if (bdevsw[bmaj].d_open == rdopen) + vdevgone(bmaj, mn, mn + MAXPARTITIONS - 1, VBLK); + for (cmaj = 0; cmaj < nchrdev; cmaj++) + if (cdevsw[cmaj].d_open == rdopen) + vdevgone(cmaj, mn, mn + MAXPARTITIONS - 1, VCHR); + + /* Detach disk. */ + disk_detach(&sc->sc_dk); + + return (0); +} + +int +rdopen(dev_t dev, int flag, int fmt, struct proc *p) +{ + struct rd_softc *sc; + u_int unit, part; + int error; + + unit = DISKUNIT(dev); + part = DISKPART(dev); + + sc = rdlookup(unit); + if (sc == NULL) + return (ENXIO); + + if ((error = disk_lock(&sc->sc_dk)) != 0) + goto unref; + + if (sc->sc_dk.dk_openmask == 0) { + /* Load the partition info if not already loaded. */ + if ((error = rdgetdisklabel(dev, sc, sc->sc_dk.dk_label, 0)) + != 0) + goto unlock; + } + + /* Check that the partition exists. */ + if (part != RAW_PART && (part >= sc->sc_dk.dk_label->d_npartitions || + sc->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) { + error = ENXIO; + goto unlock; + } + + /* Ensure the partition doesn't get changed under our feet. */ + switch (fmt) { + case S_IFCHR: + sc->sc_dk.dk_copenmask |= (1 << part); + break; + case S_IFBLK: + sc->sc_dk.dk_bopenmask |= (1 << part); + break; + } + sc->sc_dk.dk_openmask = sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask; + + unlock: + disk_unlock(&sc->sc_dk); + unref: + device_unref(&sc->sc_dev); + return (error); +} + +int +rdclose(dev_t dev, int flag, int fmt, struct proc *p) +{ + struct rd_softc *sc; + u_int unit, part; + + unit = DISKUNIT(dev); + part = DISKPART(dev); + + sc = rdlookup(unit); + if (sc == NULL) + return (ENXIO); + + disk_lock_nointr(&sc->sc_dk); + + switch (fmt) { + case S_IFCHR: + sc->sc_dk.dk_copenmask &= ~(1 << part); + break; + case S_IFBLK: + sc->sc_dk.dk_bopenmask &= ~(1 << part); + break; + } + sc->sc_dk.dk_openmask = sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask; + + disk_unlock(&sc->sc_dk); + device_unref(&sc->sc_dev); + return (0); +} + void -rd_open_hook(int unit, struct rd_conf *rd) +rdstrategy(struct buf *bp) +{ + struct rd_softc *sc; + struct partition *p; + size_t off, xfer; + caddr_t addr; + int s; + + sc = rdlookup(DISKUNIT(bp->b_dev)); + if (sc == NULL) { + bp->b_error = ENXIO; + goto bad; + } + + /* If it's a null transfer, return immediately. */ + if (bp->b_bcount == 0) + goto done; + + /* The transfer must be a whole number of sectors. */ + if ((bp->b_bcount % sc->sc_dk.dk_label->d_secsize) != 0) { + bp->b_error = EINVAL; + goto bad; + } + + /* Check that the request is within the partition boundaries. */ + if (bounds_check_with_label(bp, sc->sc_dk.dk_label) <= 0) + goto done; + + /* Do the transfer. */ + /* XXX: Worry about overflow when computing off? */ + + p = &sc->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)]; + off = DL_GETPOFFSET(p) * sc->sc_dk.dk_label->d_secsize + + (u_int64_t)bp->b_blkno * DEV_BSIZE; + if (off > rd_root_size) + off = rd_root_size; + xfer = bp->b_bcount; + if (xfer > rd_root_size - off) + xfer = rd_root_size - off; + addr = rd_root_image + off; + if (bp->b_flags & B_READ) + memcpy(bp->b_data, addr, xfer); + else + memcpy(addr, bp->b_data, xfer); + bp->b_resid = bp->b_bcount - xfer; + goto done; + + bad: + bp->b_flags |= B_ERROR; + done: + s = splbio(); + biodone(bp); + splx(s); + device_unref(&sc->sc_dev); +} + +int +rdioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p) +{ + struct rd_softc *sc; + struct disklabel *lp; + int error = 0; + + sc = rdlookup(DISKUNIT(dev)); + if (sc == NULL) + return (ENXIO); + + switch (cmd) { + case DIOCRLDINFO: + lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK); + rdgetdisklabel(dev, sc, lp, 0); + bcopy(lp, sc->sc_dk.dk_label, sizeof(*lp)); + free(lp, M_TEMP); + goto done; + + case DIOCGPDINFO: + rdgetdisklabel(dev, sc, (struct disklabel *)data, 1); + goto done; + + case DIOCGDINFO: + *(struct disklabel *)data = *(sc->sc_dk.dk_label); + goto done; + + case DIOCGPART: + ((struct partinfo *)data)->disklab = sc->sc_dk.dk_label; + ((struct partinfo *)data)->part = + &sc->sc_dk.dk_label->d_partitions[DISKPART(dev)]; + goto done; + + case DIOCWDINFO: + case DIOCSDINFO: + if ((fflag & FWRITE) == 0) { + error = EBADF; + goto done; + } + + if ((error = disk_lock(&sc->sc_dk)) != 0) + goto done; + + error = setdisklabel(sc->sc_dk.dk_label, + (struct disklabel *)data, sc->sc_dk.dk_openmask); + if (error == 0) { + if (cmd == DIOCWDINFO) + error = writedisklabel(DISKLABELDEV(dev), + rdstrategy, sc->sc_dk.dk_label); + } + + disk_unlock(&sc->sc_dk); + goto done; + } + + done: + device_unref(&sc->sc_dev); + return (error); +} + +int +rdgetdisklabel(dev_t dev, struct rd_softc *sc, struct disklabel *lp, + int spoofonly) +{ + bzero(lp, sizeof(struct disklabel)); + + lp->d_secsize = DEV_BSIZE; + lp->d_ntracks = 1; + lp->d_nsectors = rd_root_size >> DEV_BSHIFT; + lp->d_ncylinders = 1; + lp->d_secpercyl = lp->d_nsectors; + if (lp->d_secpercyl == 0) { + lp->d_secpercyl = 100; + /* as long as it's not 0 - readdisklabel divides by it */ + } + + strncpy(lp->d_typename, "RAM disk", sizeof(lp->d_typename)); + lp->d_type = DTYPE_SCSI; + strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); + DL_SETDSIZE(lp, lp->d_nsectors); + lp->d_version = 1; + + lp->d_magic = DISKMAGIC; + lp->d_magic2 = DISKMAGIC; + lp->d_checksum = dkcksum(lp); + + /* Call the generic disklabel extraction routine. */ + return (readdisklabel(DISKLABELDEV(dev), rdstrategy, lp, spoofonly)); +} + +int +rdread(dev_t dev, struct uio *uio, int ioflag) +{ + return (physio(rdstrategy, dev, B_READ, minphys, uio)); +} + +int +rdwrite(dev_t dev, struct uio *uio, int ioflag) +{ + return (physio(rdstrategy, dev, B_WRITE, minphys, uio)); +} + +int +rddump(dev_t dev, daddr64_t blkno, caddr_t va, size_t size) +{ + return (ENXIO); +} + +daddr64_t +rdsize(dev_t dev) { + return (-1); } |