summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Dempsky <matthew@cvs.openbsd.org>2011-06-23 17:06:08 +0000
committerMatthew Dempsky <matthew@cvs.openbsd.org>2011-06-23 17:06:08 +0000
commitec0f07a7f9b582f8beb0bca0c03b1bb682e7d137 (patch)
tree68833e7a3adf03485734b87a58dcbfbda8c0b6eb
parentd25e4532915241456e3e21357fe2bd065e55b261 (diff)
Complete rewrite for rd(4) to eliminate unnecessary functionality and
better follow current disk driver conventions. Prompted by oga@. "go ahead" deraadt@
-rw-r--r--sys/conf/files5
-rw-r--r--sys/dev/rd.c417
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);
}