[BACK]Return to md.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev

Annotation of src/sys/dev/md.c, Revision 1.26.4.2

1.26.4.2! fvdl        1: /*     $NetBSD: md.c,v 1.26.4.1 2001/09/07 04:45:23 thorpej Exp $      */
1.1       gwr         2:
                      3: /*
                      4:  * Copyright (c) 1995 Gordon W. Ross, Leo Weppelman.
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  * 3. The name of the author may not be used to endorse or promote products
                     16:  *    derived from this software without specific prior written permission.
                     17:  * 4. All advertising materials mentioning features or use of this software
                     18:  *    must display the following acknowledgement:
                     19:  *      This product includes software developed by
                     20:  *                     Gordon W. Ross and Leo Weppelman.
                     21:  *
                     22:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     23:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     24:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     25:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     26:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     27:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     28:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     29:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     30:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     31:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     32:  */
                     33:
                     34: /*
1.11      pk         35:  * This implements a general-purpose memory-disk.
1.13      jeremy     36:  * See md.h for notes on the config types.
1.1       gwr        37:  *
                     38:  * Note that this driver provides the same functionality
                     39:  * as the MFS filesystem hack, but this is better because
                     40:  * you can use this for any filesystem type you'd like!
                     41:  *
                     42:  * Credit for most of the kmem ramdisk code goes to:
                     43:  *   Leo Weppelman (atari) and Phil Nelson (pc532)
1.11      pk         44:  * Credit for the ideas behind the "user space memory" code goes
1.1       gwr        45:  * to the authors of the MFS implementation.
                     46:  */
1.16      mrg        47:
1.19      jonathan   48: #include "opt_md.h"
1.1       gwr        49:
                     50: #include <sys/param.h>
1.7       gwr        51: #include <sys/kernel.h>
                     52: #include <sys/malloc.h>
1.1       gwr        53: #include <sys/systm.h>
                     54: #include <sys/buf.h>
                     55: #include <sys/device.h>
1.4       thorpej    56: #include <sys/disk.h>
1.8       leo        57: #include <sys/proc.h>
                     58: #include <sys/conf.h>
1.14      leo        59: #include <sys/disklabel.h>
1.26.4.1  thorpej    60: #include <sys/vnode.h>
                     61:
                     62: #include <miscfs/specfs/specdev.h>
1.23      mrg        63:
                     64: #include <uvm/uvm_extern.h>
1.1       gwr        65:
1.11      pk         66: #include <dev/md.h>
1.1       gwr        67:
                     68: /*
                     69:  * By default, include the user-space functionality.
1.11      pk         70:  * Use  `options MEMORY_DISK_SERVER=0' to turn it off.
1.1       gwr        71:  */
1.11      pk         72: #ifndef MEMORY_DISK_SERVER
                     73: #define        MEMORY_DISK_SERVER 1
1.1       gwr        74: #endif
                     75:
                     76: /*
1.21      tsutsui    77:  * We should use the raw partition for ioctl.
1.1       gwr        78:  */
1.11      pk         79: #define MD_MAX_UNITS   0x10
1.21      tsutsui    80: #define MD_UNIT(unit)  DISKUNIT(unit)
1.1       gwr        81:
                     82: /* autoconfig stuff... */
                     83:
1.11      pk         84: struct md_softc {
1.1       gwr        85:        struct device sc_dev;   /* REQUIRED first entry */
1.4       thorpej    86:        struct disk sc_dkdev;   /* hook for generic disk handling */
1.11      pk         87:        struct md_conf sc_md;
1.22      thorpej    88:        struct buf_queue sc_buflist;
1.1       gwr        89: };
1.11      pk         90: /* shorthand for fields in sc_md: */
                     91: #define sc_addr sc_md.md_addr
                     92: #define sc_size sc_md.md_size
                     93: #define sc_type sc_md.md_type
1.1       gwr        94:
1.11      pk         95: void mdattach __P((int));
                     96: static void md_attach __P((struct device *, struct device *, void *));
1.6       thorpej    97:
1.11      pk         98: void mdstrategy __P((struct buf *bp));
                     99: struct dkdriver mddkdriver = { mdstrategy };
1.4       thorpej   100:
1.7       gwr       101: static int   ramdisk_ndevs;
1.11      pk        102: static void *ramdisk_devs[MD_MAX_UNITS];
1.4       thorpej   103:
1.7       gwr       104: /*
                    105:  * This is called if we are configured as a pseudo-device
                    106:  */
                    107: void
1.11      pk        108: mdattach(n)
1.7       gwr       109:        int n;
1.1       gwr       110: {
1.11      pk        111:        struct md_softc *sc;
1.7       gwr       112:        int i;
                    113:
                    114: #ifdef DIAGNOSTIC
                    115:        if (ramdisk_ndevs) {
1.10      christos  116:                printf("ramdisk: multiple attach calls?\n");
1.7       gwr       117:                return;
                    118:        }
1.5       leo       119: #endif
1.7       gwr       120:
                    121:        /* XXX:  Are we supposed to provide a default? */
                    122:        if (n <= 1)
                    123:                n = 1;
1.11      pk        124:        if (n > MD_MAX_UNITS)
                    125:                n = MD_MAX_UNITS;
1.7       gwr       126:        ramdisk_ndevs = n;
                    127:
                    128:        /* Attach as if by autoconfig. */
                    129:        for (i = 0; i < n; i++) {
                    130:
1.12      thorpej   131:                sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT);
1.7       gwr       132:                if (!sc) {
1.10      christos  133:                        printf("ramdisk: malloc for attach failed!\n");
1.7       gwr       134:                        return;
                    135:                }
1.26      thorpej   136:                memset((caddr_t)sc, 0, sizeof(*sc));
1.7       gwr       137:                ramdisk_devs[i] = sc;
                    138:                sc->sc_dev.dv_unit = i;
1.11      pk        139:                sprintf(sc->sc_dev.dv_xname, "md%d", i);
                    140:                md_attach(NULL, &sc->sc_dev, NULL);
1.7       gwr       141:        }
1.1       gwr       142: }
                    143:
                    144: static void
1.11      pk        145: md_attach(parent, self, aux)
1.1       gwr       146:        struct device   *parent, *self;
                    147:        void            *aux;
                    148: {
1.11      pk        149:        struct md_softc *sc = (struct md_softc *)self;
1.1       gwr       150:
1.22      thorpej   151:        BUFQ_INIT(&sc->sc_buflist);
                    152:
1.1       gwr       153:        /* XXX - Could accept aux info here to set the config. */
1.11      pk        154: #ifdef MEMORY_DISK_HOOKS
1.1       gwr       155:        /*
                    156:         * This external function might setup a pre-loaded disk.
1.11      pk        157:         * All it would need to do is setup the md_conf struct.
1.25      tsutsui   158:         * See sys/dev/md_root.c for an example.
1.1       gwr       159:         */
1.11      pk        160:        md_attach_hook(sc->sc_dev.dv_unit, &sc->sc_md);
1.1       gwr       161: #endif
1.4       thorpej   162:
                    163:        /*
                    164:         * Initialize and attach the disk structure.
                    165:         */
1.11      pk        166:        sc->sc_dkdev.dk_driver = &mddkdriver;
1.4       thorpej   167:        sc->sc_dkdev.dk_name = sc->sc_dev.dv_xname;
                    168:        disk_attach(&sc->sc_dkdev);
1.1       gwr       169: }
                    170:
                    171: /*
                    172:  * operational routines:
                    173:  * open, close, read, write, strategy,
                    174:  * ioctl, dump, size
                    175:  */
                    176:
1.11      pk        177: #if MEMORY_DISK_SERVER
                    178: static int md_server_loop __P((struct md_softc *sc));
                    179: static int md_ioctl_server __P((struct md_softc *sc,
                    180:                struct md_conf *umd, struct proc *proc));
1.1       gwr       181: #endif
1.11      pk        182: static int md_ioctl_kalloc __P((struct md_softc *sc,
                    183:                struct md_conf *umd, struct proc *proc));
1.8       leo       184:
1.11      pk        185: dev_type_open(mdopen);
                    186: dev_type_close(mdclose);
                    187: dev_type_read(mdread);
                    188: dev_type_write(mdwrite);
                    189: dev_type_ioctl(mdioctl);
                    190: dev_type_size(mdsize);
                    191: dev_type_dump(mddump);
1.1       gwr       192:
1.21      tsutsui   193: int
                    194: mddump(dev, blkno, va, size)
1.1       gwr       195:        dev_t dev;
                    196:        daddr_t blkno;
                    197:        caddr_t va;
                    198:        size_t size;
                    199: {
                    200:        return ENODEV;
                    201: }
                    202:
1.21      tsutsui   203: int
                    204: mdsize(dev_t dev)
1.1       gwr       205: {
                    206:        int unit;
1.11      pk        207:        struct md_softc *sc;
1.1       gwr       208:
1.21      tsutsui   209:        unit = MD_UNIT(dev);
1.7       gwr       210:        if (unit >= ramdisk_ndevs)
1.1       gwr       211:                return 0;
1.7       gwr       212:        sc = ramdisk_devs[unit];
1.1       gwr       213:        if (sc == NULL)
                    214:                return 0;
                    215:
1.11      pk        216:        if (sc->sc_type == MD_UNCONFIGURED)
1.1       gwr       217:                return 0;
                    218:
                    219:        return (sc->sc_size >> DEV_BSHIFT);
                    220: }
                    221:
1.8       leo       222: int
1.26.4.1  thorpej   223: mdopen(devvp, flag, fmt, proc)
                    224:        struct vnode *devvp;
1.21      tsutsui   225:        int flag, fmt;
1.1       gwr       226:        struct proc *proc;
                    227: {
1.21      tsutsui   228:        int unit;
1.11      pk        229:        struct md_softc *sc;
1.26.4.2! fvdl      230:        dev_t rdev;
1.1       gwr       231:
1.26.4.2! fvdl      232:        rdev = vdev_rdev(devvp);
        !           233:
        !           234:        unit = MD_UNIT(rdev);
1.7       gwr       235:        if (unit >= ramdisk_ndevs)
1.1       gwr       236:                return ENXIO;
1.7       gwr       237:        sc = ramdisk_devs[unit];
1.1       gwr       238:        if (sc == NULL)
                    239:                return ENXIO;
                    240:
1.26.4.2! fvdl      241:        vdev_setprivdata(devvp, sc);
1.26.4.1  thorpej   242:
1.1       gwr       243:        /*
1.21      tsutsui   244:         * The raw partition is used for ioctl to configure.
1.1       gwr       245:         */
1.26.4.2! fvdl      246:        if (DISKPART(rdev) == RAW_PART)
1.1       gwr       247:                return 0;
                    248:
1.11      pk        249: #ifdef MEMORY_DISK_HOOKS
1.1       gwr       250:        /* Call the open hook to allow loading the device. */
1.11      pk        251:        md_open_hook(unit, &sc->sc_md);
1.1       gwr       252: #endif
                    253:
                    254:        /*
                    255:         * This is a normal, "slave" device, so
1.21      tsutsui   256:         * enforce initialized.
1.1       gwr       257:         */
1.11      pk        258:        if (sc->sc_type == MD_UNCONFIGURED)
1.1       gwr       259:                return ENXIO;
                    260:
                    261:        return 0;
                    262: }
                    263:
1.8       leo       264: int
1.26.4.1  thorpej   265: mdclose(devvp, flag, fmt, proc)
                    266:        struct vnode *devvp;
1.21      tsutsui   267:        int flag, fmt;
1.1       gwr       268:        struct proc *proc;
                    269: {
                    270:
                    271:        return 0;
                    272: }
                    273:
                    274: int
1.26.4.1  thorpej   275: mdread(devvp, uio, flags)
                    276:        struct vnode *devvp;
1.21      tsutsui   277:        struct uio *uio;
                    278:        int flags;
1.1       gwr       279: {
1.26.4.2! fvdl      280:        struct md_softc *sc;
        !           281:
        !           282:        sc = vdev_privdata(devvp);
1.21      tsutsui   283:
                    284:        if (sc->sc_type == MD_UNCONFIGURED)
                    285:                return ENXIO;
                    286:
1.26.4.1  thorpej   287:        return (physio(mdstrategy, NULL, devvp, B_READ, minphys, uio));
1.1       gwr       288: }
                    289:
                    290: int
1.26.4.1  thorpej   291: mdwrite(devvp, uio, flags)
                    292:        struct vnode *devvp;
1.21      tsutsui   293:        struct uio *uio;
                    294:        int flags;
1.1       gwr       295: {
1.26.4.2! fvdl      296:        struct md_softc *sc;
        !           297:
        !           298:        sc = vdev_privdata(devvp);
1.21      tsutsui   299:
                    300:        if (sc->sc_type == MD_UNCONFIGURED)
                    301:                return ENXIO;
                    302:
1.26.4.1  thorpej   303:        return (physio(mdstrategy, NULL, devvp, B_WRITE, minphys, uio));
1.1       gwr       304: }
                    305:
                    306: /*
                    307:  * Handle I/O requests, either directly, or
                    308:  * by passing them to the server process.
                    309:  */
                    310: void
1.11      pk        311: mdstrategy(bp)
1.1       gwr       312:        struct buf *bp;
                    313: {
1.11      pk        314:        struct md_softc *sc;
1.21      tsutsui   315:        caddr_t addr;
                    316:        size_t off, xfer;
1.1       gwr       317:
1.26.4.2! fvdl      318:        sc = vdev_privdata(bp->b_devvp);
1.1       gwr       319:
1.21      tsutsui   320:        if (sc->sc_type == MD_UNCONFIGURED) {
                    321:                bp->b_error = ENXIO;
                    322:                bp->b_flags |= B_ERROR;
                    323:                goto done;
                    324:        }
                    325:
1.1       gwr       326:        switch (sc->sc_type) {
1.11      pk        327: #if MEMORY_DISK_SERVER
                    328:        case MD_UMEM_SERVER:
1.1       gwr       329:                /* Just add this job to the server's queue. */
1.22      thorpej   330:                BUFQ_INSERT_TAIL(&sc->sc_buflist, bp);
                    331:                if (BUFQ_FIRST(&sc->sc_buflist) == bp) {
1.1       gwr       332:                        /* server queue was empty. */
                    333:                        wakeup((caddr_t)sc);
1.11      pk        334:                        /* see md_server_loop() */
1.1       gwr       335:                }
                    336:                /* no biodone in this case */
                    337:                return;
1.11      pk        338: #endif /* MEMORY_DISK_SERVER */
1.1       gwr       339:
1.11      pk        340:        case MD_KMEM_FIXED:
                    341:        case MD_KMEM_ALLOCATED:
1.1       gwr       342:                /* These are in kernel space.  Access directly. */
                    343:                bp->b_resid = bp->b_bcount;
                    344:                off = (bp->b_blkno << DEV_BSHIFT);
                    345:                if (off >= sc->sc_size) {
                    346:                        if (bp->b_flags & B_READ)
                    347:                                break;  /* EOF */
                    348:                        goto set_eio;
                    349:                }
                    350:                xfer = bp->b_resid;
                    351:                if (xfer > (sc->sc_size - off))
                    352:                        xfer = (sc->sc_size - off);
                    353:                addr = sc->sc_addr + off;
                    354:                if (bp->b_flags & B_READ)
1.26      thorpej   355:                        memcpy(bp->b_data, addr, xfer);
1.1       gwr       356:                else
1.26      thorpej   357:                        memcpy(addr, bp->b_data, xfer);
1.1       gwr       358:                bp->b_resid -= xfer;
                    359:                break;
                    360:
                    361:        default:
                    362:                bp->b_resid = bp->b_bcount;
                    363:        set_eio:
                    364:                bp->b_error = EIO;
                    365:                bp->b_flags |= B_ERROR;
                    366:                break;
                    367:        }
1.21      tsutsui   368:  done:
1.1       gwr       369:        biodone(bp);
                    370: }
                    371:
                    372: int
1.26.4.1  thorpej   373: mdioctl(devvp, cmd, data, flag, proc)
                    374:        struct vnode *devvp;
1.21      tsutsui   375:        u_long cmd;
                    376:        int flag;
                    377:        caddr_t data;
                    378:        struct proc *proc;
1.1       gwr       379: {
1.26.4.2! fvdl      380:        struct md_softc *sc;
1.21      tsutsui   381:        struct md_conf *umd;
1.1       gwr       382:
1.26.4.2! fvdl      383:        sc = vdev_getprivdata(devvp);
        !           384:
1.21      tsutsui   385:        /* If this is not the raw partition, punt! */
1.26.4.2! fvdl      386:        if (DISKPART(vdev_rdev(devvp)) != RAW_PART)
1.1       gwr       387:                return ENOTTY;
                    388:
1.11      pk        389:        umd = (struct md_conf *)data;
1.1       gwr       390:        switch (cmd) {
1.11      pk        391:        case MD_GETCONF:
                    392:                *umd = sc->sc_md;
1.1       gwr       393:                return 0;
                    394:
1.11      pk        395:        case MD_SETCONF:
1.1       gwr       396:                /* Can only set it once. */
1.11      pk        397:                if (sc->sc_type != MD_UNCONFIGURED)
1.1       gwr       398:                        break;
1.11      pk        399:                switch (umd->md_type) {
                    400:                case MD_KMEM_ALLOCATED:
                    401:                        return md_ioctl_kalloc(sc, umd, proc);
                    402: #if MEMORY_DISK_SERVER
                    403:                case MD_UMEM_SERVER:
                    404:                        return md_ioctl_server(sc, umd, proc);
1.1       gwr       405: #endif
                    406:                default:
                    407:                        break;
                    408:                }
                    409:                break;
                    410:        }
                    411:        return EINVAL;
                    412: }
                    413:
                    414: /*
1.11      pk        415:  * Handle ioctl MD_SETCONF for (sc_type == MD_KMEM_ALLOCATED)
1.1       gwr       416:  * Just allocate some kernel memory and return.
                    417:  */
1.8       leo       418: static int
1.11      pk        419: md_ioctl_kalloc(sc, umd, proc)
                    420:        struct md_softc *sc;
                    421:        struct md_conf *umd;
1.21      tsutsui   422:        struct proc *proc;
1.1       gwr       423: {
1.17      eeh       424:        vaddr_t addr;
1.21      tsutsui   425:        vsize_t size;
1.1       gwr       426:
                    427:        /* Sanity check the size. */
1.11      pk        428:        size = umd->md_size;
1.15      mrg       429:        addr = uvm_km_zalloc(kernel_map, size);
1.1       gwr       430:        if (!addr)
                    431:                return ENOMEM;
                    432:
                    433:        /* This unit is now configured. */
                    434:        sc->sc_addr = (caddr_t)addr;    /* kernel space */
                    435:        sc->sc_size = (size_t)size;
1.11      pk        436:        sc->sc_type = MD_KMEM_ALLOCATED;
1.1       gwr       437:        return 0;
                    438: }
                    439:
1.11      pk        440: #if MEMORY_DISK_SERVER
1.1       gwr       441:
                    442: /*
1.11      pk        443:  * Handle ioctl MD_SETCONF for (sc_type == MD_UMEM_SERVER)
1.1       gwr       444:  * Set config, then become the I/O server for this unit.
                    445:  */
1.8       leo       446: static int
1.11      pk        447: md_ioctl_server(sc, umd, proc)
                    448:        struct md_softc *sc;
                    449:        struct md_conf *umd;
1.21      tsutsui   450:        struct proc *proc;
1.1       gwr       451: {
1.17      eeh       452:        vaddr_t end;
1.1       gwr       453:        int error;
                    454:
                    455:        /* Sanity check addr, size. */
1.17      eeh       456:        end = (vaddr_t) (umd->md_addr + umd->md_size);
1.1       gwr       457:
                    458:        if ((end >= VM_MAXUSER_ADDRESS) ||
1.17      eeh       459:                (end < ((vaddr_t) umd->md_addr)) )
1.1       gwr       460:                return EINVAL;
                    461:
                    462:        /* This unit is now configured. */
1.11      pk        463:        sc->sc_addr = umd->md_addr;     /* user space */
                    464:        sc->sc_size = umd->md_size;
                    465:        sc->sc_type = MD_UMEM_SERVER;
1.1       gwr       466:
                    467:        /* Become the server daemon */
1.11      pk        468:        error = md_server_loop(sc);
1.1       gwr       469:
                    470:        /* This server is now going away! */
1.11      pk        471:        sc->sc_type = MD_UNCONFIGURED;
1.1       gwr       472:        sc->sc_addr = 0;
                    473:        sc->sc_size = 0;
                    474:
                    475:        return (error);
                    476: }
                    477:
1.21      tsutsui   478: int md_sleep_pri = PWAIT | PCATCH;
1.1       gwr       479:
                    480: static int
1.11      pk        481: md_server_loop(sc)
                    482:        struct md_softc *sc;
1.1       gwr       483: {
                    484:        struct buf *bp;
                    485:        caddr_t addr;   /* user space address */
1.21      tsutsui   486:        size_t off;     /* offset into "device" */
                    487:        size_t xfer;    /* amount to transfer */
1.1       gwr       488:        int error;
                    489:
                    490:        for (;;) {
                    491:                /* Wait for some work to arrive. */
1.22      thorpej   492:                while ((bp = BUFQ_FIRST(&sc->sc_buflist)) == NULL) {
1.11      pk        493:                        error = tsleep((caddr_t)sc, md_sleep_pri, "md_idle", 0);
1.1       gwr       494:                        if (error)
                    495:                                return error;
                    496:                }
                    497:
                    498:                /* Unlink buf from head of list. */
1.22      thorpej   499:                BUFQ_REMOVE(&sc->sc_buflist, bp);
1.1       gwr       500:
                    501:                /* Do the transfer to/from user space. */
                    502:                error = 0;
                    503:                bp->b_resid = bp->b_bcount;
                    504:                off = (bp->b_blkno << DEV_BSHIFT);
                    505:                if (off >= sc->sc_size) {
                    506:                        if (bp->b_flags & B_READ)
                    507:                                goto done;      /* EOF (not an error) */
                    508:                        error = EIO;
                    509:                        goto done;
                    510:                }
                    511:                xfer = bp->b_resid;
                    512:                if (xfer > (sc->sc_size - off))
                    513:                        xfer = (sc->sc_size - off);
                    514:                addr = sc->sc_addr + off;
                    515:                if (bp->b_flags & B_READ)
                    516:                        error = copyin(addr, bp->b_data, xfer);
                    517:                else
                    518:                        error = copyout(bp->b_data, addr, xfer);
                    519:                if (!error)
                    520:                        bp->b_resid -= xfer;
                    521:
                    522:        done:
                    523:                if (error) {
                    524:                        bp->b_error = error;
                    525:                        bp->b_flags |= B_ERROR;
                    526:                }
                    527:                biodone(bp);
                    528:        }
                    529: }
1.11      pk        530: #endif /* MEMORY_DISK_SERVER */

CVSweb <webmaster@jp.NetBSD.org>