root/dev/ramdisk.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rdattach
  2. rd_attach
  3. rddump
  4. rdsize
  5. rdopen
  6. rdclose
  7. rdread
  8. rdwrite
  9. rdstrategy
  10. rdioctl
  11. rdgetdisklabel
  12. rd_ioctl_kalloc
  13. rd_ioctl_server
  14. rd_server_loop

    1 /*      $OpenBSD: ramdisk.c,v 1.37 2007/06/20 18:15:46 deraadt Exp $    */
    2 /*      $NetBSD: ramdisk.c,v 1.8 1996/04/12 08:30:09 leo Exp $  */
    3 
    4 /*
    5  * Copyright (c) 1995 Gordon W. Ross, Leo Weppelman.
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. The name of the author may not be used to endorse or promote products
   17  *    derived from this software without specific prior written permission.
   18  * 4. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *      This product includes software developed by
   21  *                      Gordon W. Ross and Leo Weppelman.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   26  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   28  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   30  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   32  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   33  */
   34 
   35 /*
   36  * This implements a general-purpose RAM-disk.
   37  * See ramdisk.h for notes on the config types.
   38  *
   39  * Note that this driver provides the same functionality
   40  * as the MFS filesystem hack, but this is better because
   41  * you can use this for any filesystem type you'd like!
   42  *
   43  * Credit for most of the kmem ramdisk code goes to:
   44  *   Leo Weppelman (atari) and Phil Nelson (pc532)
   45  * Credit for the ideas behind the "user space RAM" code goes
   46  * to the authors of the MFS implementation.
   47  */
   48 
   49 #include <sys/param.h>
   50 #include <sys/kernel.h>
   51 #include <sys/malloc.h>
   52 #include <sys/systm.h>
   53 #include <sys/buf.h>
   54 #include <sys/device.h>
   55 #include <sys/file.h>
   56 #include <sys/disk.h>
   57 #include <sys/proc.h>
   58 #include <sys/conf.h>
   59 #include <sys/disklabel.h>
   60 #include <sys/dkio.h>
   61 
   62 #include <uvm/uvm_extern.h>
   63 
   64 #include <dev/ramdisk.h>
   65 
   66 /*
   67  * By default, include the user-space functionality.
   68  * Use:  option RAMDISK_SERVER=0 to turn it off.
   69  */
   70 #if !defined(RAMDISK_SERVER) && !defined(SMALL_KERNEL)
   71 #define RAMDISK_SERVER 1
   72 #endif
   73 
   74 /*
   75  * XXX: the "control" unit is (base unit + 16).
   76  * We should just use the cdev as the "control", but
   77  * that interferes with the security stuff preventing
   78  * simultaneous use of raw and block devices.
   79  *
   80  * XXX Assumption: 16 RAM-disks are enough!
   81  */
   82 #define RD_MAX_UNITS    0x10
   83 #define RD_IS_CTRL(dev) (DISKPART(dev) == RAW_PART)
   84 
   85 /* autoconfig stuff... */
   86 
   87 struct rd_softc {
   88         struct device sc_dev;   /* REQUIRED first entry */
   89         struct disk sc_dkdev;   /* hook for generic disk handling */
   90         struct rd_conf sc_rd;
   91 #if RAMDISK_SERVER
   92         struct buf *sc_buflist;
   93 #endif
   94 };
   95 /* shorthand for fields in sc_rd: */
   96 #define sc_addr sc_rd.rd_addr
   97 #define sc_size sc_rd.rd_size
   98 #define sc_type sc_rd.rd_type
   99 
  100 void rdattach(int);
  101 void rd_attach(struct device *, struct device *, void *);
  102 void rdgetdisklabel(dev_t, struct rd_softc *, struct disklabel *, int);
  103 
  104 /*
  105  * Some ports (like i386) use a swapgeneric that wants to
  106  * snoop around in this rd_cd structure.  It is preserved
  107  * (for now) to remain compatible with such practice.
  108  * XXX - that practice is questionable...
  109  */
  110 struct cfdriver rd_cd = {
  111         NULL, "rd", DV_DULL
  112 };
  113 
  114 void rdstrategy(struct buf *bp);
  115 struct dkdriver rddkdriver = { rdstrategy };
  116 
  117 int   ramdisk_ndevs;
  118 void *ramdisk_devs[RD_MAX_UNITS];
  119 
  120 /*
  121  * This is called if we are configured as a pseudo-device
  122  */
  123 void
  124 rdattach(n)
  125         int n;
  126 {
  127         struct rd_softc *sc;
  128         int i;
  129 
  130 #ifdef  DIAGNOSTIC
  131         if (ramdisk_ndevs) {
  132                 printf("ramdisk: multiple attach calls?\n");
  133                 return;
  134         }
  135 #endif
  136 
  137         /* XXX:  Are we supposed to provide a default? */
  138         if (n <= 1)
  139                 n = 1;
  140         if (n > RD_MAX_UNITS)
  141                 n = RD_MAX_UNITS;
  142         ramdisk_ndevs = n;
  143 
  144         /* XXX: Fake-up rd_cd (see above) */
  145         rd_cd.cd_ndevs = ramdisk_ndevs;
  146         rd_cd.cd_devs  = ramdisk_devs;
  147 
  148         /* Attach as if by autoconfig. */
  149         for (i = 0; i < n; i++) {
  150                 sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK);
  151                 bzero((caddr_t)sc, sizeof(*sc));
  152                 if (snprintf(sc->sc_dev.dv_xname, sizeof(sc->sc_dev.dv_xname),
  153                     "rd%d", i) >= sizeof(sc->sc_dev.dv_xname)) {
  154                         printf("rdattach: device name too long\n");
  155                         free(sc, M_DEVBUF);
  156                         return;
  157                 }
  158                 ramdisk_devs[i] = sc;
  159                 sc->sc_dev.dv_unit = i;
  160                 rd_attach(NULL, &sc->sc_dev, NULL);
  161         }
  162 }
  163 
  164 void
  165 rd_attach(parent, self, aux)
  166         struct device   *parent, *self;
  167         void            *aux;
  168 {
  169         struct rd_softc *sc = (struct rd_softc *)self;
  170 
  171         /* XXX - Could accept aux info here to set the config. */
  172 #ifdef  RAMDISK_HOOKS
  173         /*
  174          * This external function might setup a pre-loaded disk.
  175          * All it would need to do is setup the rd_conf struct.
  176          * See sys/arch/sun3/dev/rd_root.c for an example.
  177          */
  178         rd_attach_hook(sc->sc_dev.dv_unit, &sc->sc_rd);
  179 #endif
  180 
  181         /*
  182          * Initialize and attach the disk structure.
  183          */
  184         sc->sc_dkdev.dk_driver = &rddkdriver;
  185         sc->sc_dkdev.dk_name = sc->sc_dev.dv_xname;
  186         disk_attach(&sc->sc_dkdev);
  187 }
  188 
  189 /*
  190  * operational routines:
  191  * open, close, read, write, strategy,
  192  * ioctl, dump, size
  193  */
  194 
  195 #if RAMDISK_SERVER
  196 int rd_server_loop(struct rd_softc *sc);
  197 int rd_ioctl_server(struct rd_softc *sc,
  198                 struct rd_conf *urd, struct proc *proc);
  199 #endif
  200 int rd_ioctl_kalloc(struct rd_softc *sc,
  201                 struct rd_conf *urd, struct proc *proc);
  202 
  203 dev_type_open(rdopen);
  204 dev_type_close(rdclose);
  205 dev_type_read(rdread);
  206 dev_type_write(rdwrite);
  207 dev_type_ioctl(rdioctl);
  208 dev_type_size(rdsize);
  209 dev_type_dump(rddump);
  210 
  211 int
  212 rddump(dev, blkno, va, size)
  213         dev_t dev;
  214         daddr64_t blkno;
  215         caddr_t va;
  216         size_t size;
  217 {
  218         return ENODEV;
  219 }
  220 
  221 daddr64_t
  222 rdsize(dev_t dev)
  223 {
  224         int part, unit;
  225         struct rd_softc *sc;
  226 
  227         /* Disallow control units. */
  228         unit = DISKUNIT(dev);
  229         if (unit >= ramdisk_ndevs)
  230                 return 0;
  231         sc = ramdisk_devs[unit];
  232         if (sc == NULL)
  233                 return 0;
  234 
  235         if (sc->sc_type == RD_UNCONFIGURED)
  236                 return 0;
  237 
  238         rdgetdisklabel(dev, sc, sc->sc_dkdev.dk_label, 0);
  239         part = DISKPART(dev);
  240         if (part >= sc->sc_dkdev.dk_label->d_npartitions)
  241                 return 0;
  242         else
  243                 return DL_GETPSIZE(&sc->sc_dkdev.dk_label->d_partitions[part]) *
  244                     (sc->sc_dkdev.dk_label->d_secsize / DEV_BSIZE);
  245 }
  246 
  247 int
  248 rdopen(dev, flag, fmt, proc)
  249         dev_t   dev;
  250         int     flag, fmt;
  251         struct proc *proc;
  252 {
  253         int unit;
  254         struct rd_softc *sc;
  255 
  256         unit = DISKUNIT(dev);
  257         if (unit >= ramdisk_ndevs)
  258                 return ENXIO;
  259         sc = ramdisk_devs[unit];
  260         if (sc == NULL)
  261                 return ENXIO;
  262 
  263         /*
  264          * The control device is not exclusive, and can
  265          * open uninitialized units (so you can setconf).
  266          */
  267         if (RD_IS_CTRL(dev))
  268                 return 0;
  269 
  270 #ifdef  RAMDISK_HOOKS
  271         /* Call the open hook to allow loading the device. */
  272         rd_open_hook(unit, &sc->sc_rd);
  273 #endif
  274 
  275         /*
  276          * This is a normal, "slave" device, so
  277          * enforce initialized, exclusive open.
  278          */
  279         if (sc->sc_type == RD_UNCONFIGURED)
  280                 return ENXIO;
  281 
  282         return 0;
  283 }
  284 
  285 int
  286 rdclose(dev, flag, fmt, proc)
  287         dev_t   dev;
  288         int     flag, fmt;
  289         struct proc *proc;
  290 {
  291 
  292         return 0;
  293 }
  294 
  295 int
  296 rdread(dev, uio, flags)
  297         dev_t           dev;
  298         struct uio      *uio;
  299         int             flags;
  300 {
  301         return (physio(rdstrategy, NULL, dev, B_READ, minphys, uio));
  302 }
  303 
  304 int
  305 rdwrite(dev, uio, flags)
  306         dev_t           dev;
  307         struct uio      *uio;
  308         int             flags;
  309 {
  310         return (physio(rdstrategy, NULL, dev, B_WRITE, minphys, uio));
  311 }
  312 
  313 /*
  314  * Handle I/O requests, either directly, or
  315  * by passing them to the server process.
  316  */
  317 void
  318 rdstrategy(bp)
  319         struct buf *bp;
  320 {
  321         int unit, part;
  322         struct rd_softc *sc;
  323         caddr_t addr;
  324         size_t off, xfer;
  325         int s;
  326 
  327         unit = DISKUNIT(bp->b_dev);
  328         sc = ramdisk_devs[unit];
  329 
  330         /* Sort rogue requests out */
  331         if (sc == NULL || bp->b_blkno < 0 ||
  332             (bp->b_bcount % sc->sc_dkdev.dk_label->d_secsize) != 0) {
  333                 bp->b_error = EINVAL;
  334                 goto bad;
  335         }
  336 
  337         /* Do not write on "no trespassing" areas... */
  338         part = DISKPART(bp->b_dev);
  339         if (part != RAW_PART &&
  340             bounds_check_with_label(bp, sc->sc_dkdev.dk_label, 1) <= 0)
  341                 goto bad;
  342 
  343         switch (sc->sc_type) {
  344 #if RAMDISK_SERVER
  345         case RD_UMEM_SERVER:
  346                 /* Just add this job to the server's queue. */
  347                 bp->b_actf = sc->sc_buflist;
  348                 sc->sc_buflist = bp;
  349                 if (bp->b_actf == NULL) {
  350                         /* server queue was empty. */
  351                         wakeup((caddr_t)sc);
  352                         /* see rd_server_loop() */
  353                 }
  354                 /* no biodone in this case */
  355                 return;
  356 #endif  /* RAMDISK_SERVER */
  357 
  358         case RD_KMEM_FIXED:
  359         case RD_KMEM_ALLOCATED:
  360                 /* These are in kernel space.  Access directly. */
  361                 bp->b_resid = bp->b_bcount;
  362                 off = (bp->b_blkno << DEV_BSHIFT);
  363                 xfer = bp->b_bcount;
  364                 if (xfer > (sc->sc_size - off))
  365                         xfer = (sc->sc_size - off);
  366                 addr = sc->sc_addr + off;
  367                 if (bp->b_flags & B_READ)
  368                         bcopy(addr, bp->b_data, xfer);
  369                 else
  370                         bcopy(bp->b_data, addr, xfer);
  371                 bp->b_resid -= xfer;
  372                 break;
  373 
  374         default:
  375                 bp->b_error = EIO;
  376 bad:
  377                 bp->b_flags |= B_ERROR;
  378                 bp->b_resid = bp->b_bcount;
  379                 break;
  380         }
  381 
  382         s = splbio();
  383         biodone(bp);
  384         splx(s);
  385 }
  386 
  387 int
  388 rdioctl(dev, cmd, data, flag, proc)
  389         dev_t   dev;
  390         u_long  cmd;
  391         int             flag;
  392         caddr_t data;
  393         struct proc     *proc;
  394 {
  395         int unit;
  396         struct disklabel *lp;
  397         struct rd_softc *sc;
  398         struct rd_conf *urd;
  399         int error;
  400 
  401         unit = DISKUNIT(dev);
  402         sc = ramdisk_devs[unit];
  403 
  404         urd = (struct rd_conf *)data;
  405         switch (cmd) {
  406         case DIOCRLDINFO:
  407                 if (sc->sc_type == RD_UNCONFIGURED)
  408                         break;
  409                 lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK);
  410                 rdgetdisklabel(dev, sc, lp, 0);
  411                 bcopy(lp, sc->sc_dkdev.dk_label, sizeof(*lp));
  412                 free(lp, M_TEMP);
  413                 return 0;
  414 
  415         case DIOCGPDINFO:
  416                 if (sc->sc_type == RD_UNCONFIGURED)
  417                         break;
  418                 rdgetdisklabel(dev, sc, (struct disklabel *)data, 1);
  419                 return 0;
  420 
  421         case DIOCGDINFO:
  422                 if (sc->sc_type == RD_UNCONFIGURED) {
  423                         break;
  424                 }
  425                 *(struct disklabel *)data = *(sc->sc_dkdev.dk_label);
  426                 return 0;
  427 
  428         case DIOCGPART:
  429                 ((struct partinfo *)data)->disklab = sc->sc_dkdev.dk_label;
  430                 ((struct partinfo *)data)->part =
  431                     &sc->sc_dkdev.dk_label->d_partitions[DISKPART(dev)];
  432                 return 0;
  433 
  434         case DIOCWDINFO:
  435         case DIOCSDINFO:
  436                 if (sc->sc_type == RD_UNCONFIGURED) {
  437                         break;
  438                 }
  439                 if ((flag & FWRITE) == 0)
  440                         return EBADF;
  441 
  442                 error = setdisklabel(sc->sc_dkdev.dk_label,
  443                     (struct disklabel *)data, /*sd->sc_dk.dk_openmask : */0);
  444                 if (error == 0) {
  445                         if (cmd == DIOCWDINFO)
  446                                 error = writedisklabel(DISKLABELDEV(dev),
  447                                     rdstrategy, sc->sc_dkdev.dk_label);
  448                 }
  449 
  450                 return error;
  451 
  452         case DIOCWLABEL:
  453                 if (sc->sc_type == RD_UNCONFIGURED) {
  454                         break;
  455                 }
  456                 if ((flag & FWRITE) == 0)
  457                         return EBADF;
  458                 return 0;
  459 
  460         case RD_GETCONF:
  461                 /* If this is not the control device, punt! */
  462                 if (RD_IS_CTRL(dev) == 0) {
  463                         break;
  464                 }
  465                 *urd = sc->sc_rd;
  466                 return 0;
  467 
  468         case RD_SETCONF:
  469                 /* If this is not the control device, punt! */
  470                 if (RD_IS_CTRL(dev) == 0) {
  471                         break;
  472                 }
  473                 /* Can only set it once. */
  474                 if (sc->sc_type != RD_UNCONFIGURED) {
  475                         break;
  476                 }
  477                 switch (urd->rd_type) {
  478                 case RD_KMEM_ALLOCATED:
  479                         return rd_ioctl_kalloc(sc, urd, proc);
  480 #if RAMDISK_SERVER
  481                 case RD_UMEM_SERVER:
  482                         return rd_ioctl_server(sc, urd, proc);
  483 #endif
  484                 default:
  485                         break;
  486                 }
  487                 break;
  488         }
  489         return EINVAL;
  490 }
  491 
  492 void
  493 rdgetdisklabel(dev_t dev, struct rd_softc *sc, struct disklabel *lp,
  494     int spoofonly)
  495 {
  496         bzero(lp, sizeof(struct disklabel));
  497 
  498         lp->d_secsize = DEV_BSIZE;
  499         lp->d_ntracks = 1;
  500         lp->d_nsectors = sc->sc_size >> DEV_BSHIFT;
  501         lp->d_ncylinders = 1;
  502         lp->d_secpercyl = lp->d_nsectors;
  503         if (lp->d_secpercyl == 0) {
  504                 lp->d_secpercyl = 100;
  505                 /* as long as it's not 0 - readdisklabel divides by it (?) */
  506         }
  507 
  508         strncpy(lp->d_typename, "RAM disk", sizeof(lp->d_typename));
  509         lp->d_type = DTYPE_SCSI;
  510         strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
  511         DL_SETDSIZE(lp, lp->d_nsectors);
  512         lp->d_rpm = 3600;
  513         lp->d_interleave = 1;
  514         lp->d_version = 1;
  515 
  516         lp->d_magic = DISKMAGIC;
  517         lp->d_magic2 = DISKMAGIC;
  518         lp->d_checksum = dkcksum(lp);
  519 
  520         /*
  521          * Call the generic disklabel extraction routine
  522          */
  523         readdisklabel(DISKLABELDEV(dev), rdstrategy, lp, spoofonly);
  524 }
  525 
  526 /*
  527  * Handle ioctl RD_SETCONF for (sc_type == RD_KMEM_ALLOCATED)
  528  * Just allocate some kernel memory and return.
  529  */
  530 int
  531 rd_ioctl_kalloc(sc, urd, proc)
  532         struct rd_softc *sc;
  533         struct rd_conf *urd;
  534         struct proc     *proc;
  535 {
  536         vaddr_t addr;
  537         vsize_t size;
  538 
  539         /* Sanity check the size. */
  540         size = urd->rd_size;
  541         addr = uvm_km_zalloc(kernel_map, size);
  542         if (!addr)
  543                 return ENOMEM;
  544 
  545         /* This unit is now configured. */
  546         sc->sc_addr = (caddr_t)addr;    /* kernel space */
  547         sc->sc_size = (size_t)size;
  548         sc->sc_type = RD_KMEM_ALLOCATED;
  549         return 0;
  550 }       
  551 
  552 #if RAMDISK_SERVER
  553 
  554 /*
  555  * Handle ioctl RD_SETCONF for (sc_type == RD_UMEM_SERVER)
  556  * Set config, then become the I/O server for this unit.
  557  */
  558 int
  559 rd_ioctl_server(sc, urd, proc)
  560         struct rd_softc *sc;
  561         struct rd_conf *urd;
  562         struct proc     *proc;
  563 {
  564         vaddr_t end;
  565         int error;
  566 
  567         /* Sanity check addr, size. */
  568         end = (vaddr_t) (urd->rd_addr + urd->rd_size);
  569 
  570         if ((end >= VM_MAXUSER_ADDRESS) || (end < ((vaddr_t) urd->rd_addr)) )
  571                 return EINVAL;
  572 
  573         /* This unit is now configured. */
  574         sc->sc_addr = urd->rd_addr;     /* user space */
  575         sc->sc_size = urd->rd_size;
  576         sc->sc_type = RD_UMEM_SERVER;
  577 
  578         /* Become the server daemon */
  579         error = rd_server_loop(sc);
  580 
  581         /* This server is now going away! */
  582         sc->sc_type = RD_UNCONFIGURED;
  583         sc->sc_addr = 0;
  584         sc->sc_size = 0;
  585 
  586         return (error);
  587 }       
  588 
  589 int     rd_sleep_pri = PWAIT | PCATCH;
  590 
  591 int
  592 rd_server_loop(sc)
  593         struct rd_softc *sc;
  594 {
  595         struct buf *bp;
  596         caddr_t addr;   /* user space address */
  597         size_t  off;    /* offset into "device" */
  598         size_t  xfer;   /* amount to transfer */
  599         int error;
  600         int s;
  601 
  602         for (;;) {
  603                 /* Wait for some work to arrive. */
  604                 while (sc->sc_buflist == NULL) {
  605                         error = tsleep((caddr_t)sc, rd_sleep_pri, "rd_idle", 0);
  606                         if (error)
  607                                 return error;
  608                 }
  609 
  610                 /* Unlink buf from head of list. */
  611                 bp = sc->sc_buflist;
  612                 sc->sc_buflist = bp->b_actf;
  613                 bp->b_actf = NULL;
  614 
  615                 /* Do the transfer to/from user space. */
  616                 error = 0;
  617                 bp->b_resid = bp->b_bcount;
  618                 off = (bp->b_blkno << DEV_BSHIFT);
  619                 if (off >= sc->sc_size) {
  620                         if (bp->b_flags & B_READ)
  621                                 goto done;      /* EOF (not an error) */
  622                         error = EIO;
  623                         goto done;
  624                 }
  625                 xfer = bp->b_resid;
  626                 if (xfer > (sc->sc_size - off))
  627                         xfer = (sc->sc_size - off);
  628                 addr = sc->sc_addr + off;
  629                 if (bp->b_flags & B_READ)
  630                         error = copyin(addr, bp->b_data, xfer);
  631                 else
  632                         error = copyout(bp->b_data, addr, xfer);
  633                 if (!error)
  634                         bp->b_resid -= xfer;
  635 
  636         done:
  637                 if (error) {
  638                         bp->b_error = error;
  639                         bp->b_flags |= B_ERROR;
  640                 }
  641                 s = splbio();
  642                 biodone(bp);
  643                 splx(s);
  644         }
  645 }
  646 
  647 #endif  /* RAMDISK_SERVER */

/* [<][>][^][v][top][bottom][index][help] */