Annotation of sys/dev/ramdisk.c, Revision 1.1.1.1
1.1 nbrk 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 */
CVSweb