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);
 }

Reply via email to