On Sun, Jun 19, 2011 at 07:21:03PM -0700, Matthew Dempsky wrote: > The diff below makes rd(4) into a real device;
This idea was a little contentious, so diff below includes the rest of the cleanups I mentioned, but leaves rd(4) as a pseudo-device. (As before, the RAMDISK_HOOKS option can be removed, but they're harmless to leave in and there aren't any other necessary config changes with this diff, so omitting them for now.) Index: conf/files =================================================================== RCS file: /home/mdempsky/anoncvs/cvs/src/sys/conf/files,v retrieving revision 1.512 diff -u -p -r1.512 files --- conf/files 7 Apr 2011 13:42:53 -0000 1.512 +++ conf/files 20 Jun 2011 05:38:48 -0000 @@ -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_en 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 Index: dev/rd.c =================================================================== RCS file: /home/mdempsky/anoncvs/cvs/src/sys/dev/rd.c,v retrieving revision 1.2 diff -u -p -r1.2 rd.c --- dev/rd.c 22 Aug 2008 03:12:37 -0000 1.2 +++ dev/rd.c 20 Jun 2011 05:53:22 -0000 @@ -29,11 +29,20 @@ #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 +57,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); }