_RAM DISK DRIVER FOR UNIX_ by Jeff Reagen [LISTING ONE] /* The following is a RAM disk driver developed for Unix Sys V/386 * release 3.2. -- Author: Jeff Reagen 05-02-90. */ #include "sys/types.h" #include "sys/param.h" #include "sys/immu.h" #include "sys/fs/s5dir.h" #include "sys/signal.h" #include "sys/user.h" #include "sys/errno.h" #include "sys/cmn_err.h" #include "sys/buf.h" #define RD_SIZE_IN_PAGES 0x100L /* 256 4K pages => 1 MB */ #define RD_MAX 1 /* Max RAM Disks */ #define RAMDISK(x) (int)(x&0x0F) /* Ram disk number from dev */ #define DONT_SLEEP 1 /* sptalloc parameter */ /* For ioctl routines. */ #define RD_GETSIZE 1 /* return size of RAM disk */ struct rd_getsize { /* Structure passed to rdioctl */ daddr_t sectors; long in_bytes; }; /* Valid states for the RAM disk driver. */ #define RD_UNDEFINED 0x0000 /* Disk has not been setup */ #define RD_CONFIGURED 0x0001 /* Configured disk */ #define RD_OPEN 0x0002 /* Indicates disk has been opened */ /* The RAM disk is created iff the size field has been defined. Since * sptalloc only allocates pages, make sure the size is * some multiple of page size (4096). */ struct ram_config { int state; /* current state */ caddr_t virt; /* virtual address of RAM disk */ long size; /* RAM disk size in units of 4K */ }; struct ram_config rd_cfg = {RD_UNDEFINED, (caddr_t)0, RD_SIZE_IN_PAGES}; extern caddr_t sptalloc(); /* rdinit - initialize the RAM disk. */ rdinit (dev) dev_t dev; { /* Has a RAM disk been defined? */ if (rd_cfg.size == 0) { /* Just return silently - ram disk is not configured. */ return 0; } /* Last parameter 1 in sptalloc calls prevents sleep if no memory. */ if ((rd_cfg.virt = sptalloc (rd_cfg.size, PG_P,0,DONT_SLEEP)) == NULL) { cmn_err (CE_WARN,"Could not allocate enough memory for RAM disk.\n"); return 0; } rd_cfg.state |= RD_CONFIGURED; return; } /* rdopen */ rdopen (dev) dev_t dev; { int rdisk; rdisk = RAMDISK(dev); if ( rdisk >= RD_MAX) { /* RAM disk specified foes not exist. */ u.u_error = ENODEV; return; } /* Make sure ram disk has been configured. */ if ( (rd_cfg.state & RD_CONFIGURED) != RD_CONFIGURED) { /* disk has not been configured! */ u.u_error = ENOMEM; return; } /* RAM disk successfully opened. */ rd_cfg.state |= RD_OPEN; } /* rdclose - close the RAM disk. */ rdclose (dev) dev_t dev; { rd_cfg.state &= ~RD_OPEN; return; } /* rdstrategy - the entire synchronous transfer operation happens here. */ rdstrategy (bp) register struct buf *bp; { register long req_start; /* start of transfer */ register long byte_size; /* Max capacity of RAM disk in bytes. */ int disk; /* RAM disk being requested for service. */ disk = RAMDISK(bp->b_dev); /* Validate disk number. */ if (disk >= RD_MAX) { /* Disk does not exist. */ bp->b_flags |= B_ERROR; bp->b_error = ENODEV; iodone(bp); return; } /* Validate request range. Reads can be trimmed back... */ byte_size = rd_cfg.size * NBPP; req_start = bp->b_blkno * NBPSCTR; bp->b_resid = 0; /* Number of bytes remaining after transfer */ /* Check for requests exceeding the upper bound of the disk. */ if (req_start + bp->b_bcount > byte_size) { if (bp->b_flags & B_READ) { /* Read */ /* Adjust residual count. */ bp->b_resid = req_start + bp->b_bcount - byte_size; bp->b_bcount = byte_size - req_start; } else { /* Write - always fails */ bp->b_resid = bp->b_bcount; bp->b_flags |= B_ERROR; iodone (bp); return; } } /* Service the request. */ if (bp->b_flags & B_READ) { bcopy (rd_cfg.virt + req_start, bp->b_un.b_addr, bp->b_bcount); } else { bcopy (bp->b_un.b_addr, rd_cfg.virt + req_start, bp->b_bcount); } bp->b_flags &= ~B_ERROR; /* Make sure an error is NOT reported. */ iodone(bp); return; } /* rdread - character read interface. */ rdread (dev) dev_t dev; { /* Validate request based on number of 512 bytes sectors supported. */ if (physck ((daddr_t)rd_cfg.size << DPPSHFT, B_READ)) { /* Have physio allocate the buffer header, then call rdstrategy. */ physio (rdstrategy, (struct buf *)NULL, dev, B_READ); } } /* rdwrite - character write interface. */ rdwrite (dev) dev_t dev; { /* Validate request based on number of 512 bytes sectors supported. */ if (physck ((daddr_t)rd_cfg.size << DPPSHFT, B_WRITE)) { /* Have physio allocate the buffer header, then call rdstrategy. */ physio (rdstrategy, (struct buf *)NULL, dev, B_WRITE); } } /* rdioctl - returns size of RAM disk. */ rdioctl (dev, command, arg, mode) dev_t dev; int command; int *arg; int mode; { struct rd_getsize sizes; if ( RAMDISK(dev) > RD_MAX || !(rd_cfg.state&RD_CONFIGURED) ) { u.u_error = ENODEV; return; } switch (command) { case RD_GETSIZE: sizes.sectors = rd_cfg.size << DPPSHFT; sizes.in_bytes = rd_cfg.size * NBPP; /* Now transfer the request to user space */ if (copyout (&sizes, arg, sizeof (sizes)) ) { u.u_error = EFAULT; } break; default: /* Error - do not recognize command submitted. */ u.u_error = EINVAL; return; } } /* rdintr - the RAM disk does not generate hardware interrupts, * so this routine simply prints a warning message and returns. */ rdintr () { cmn_err (CE_WARN, "RAM disk took a spurious hardware interrupt.\n"); } /* rdprint - send messages concerning the RAM disk to the console. */ rdprint (dev, str) dev_t dev; char *str; { cmn_err (CE_NOTE, "%s on Ram Disk %d.\n", str, RAMDISK (dev)); } [Example 1: How an application queries the RAM disk's size] #include "sys/types.h" main () { int fd; struct rd_size { daddr_t sector_count; long b_count; } ram_disk_size; if ( (fd = open ("/dev/rdsk/rd0", O_RDONLY)) < 0) { printf ("Could not open RAM disk to do ioctl.\n"); exit (1); } if ( ioctl (fd, RD_GETSIZE, &ram_disk_size) < 0) { printf ("Could not determine size of RAM disk.\n"); exit (2); } printf ("The RAM disk consists of %d sectors occupying %d bytes.\n", ram_disk_size.sector_count, ram_disk_size.b_count); } [Exampl� 2(a)� Entr� fo� th� drive� i� th� /etc/conf/sdevice.� � file.] rd Y 1 0 0 0 0 0 0 0 [Example 2(b): Entry in the master device file.] rd ocrwiI icbo rd 0 0 1 2 -1 [Example 2(c): The idinstall command.] /etc/conf/bin/idinstall -a -m -k rd [Exampl� 2(d)� Th� tw� nodes� fo� characte� an� bloc� device� � respectively.] rd rdsk/rd0 c 0 rd dsk/rd0 b 0 [Exampl� 2(e)� Th� modifie� S01MOUNTFSY� file.] cd / # Make a filesystem on the RAM disk. /etc/mkfs /dev/dsk/rd0 2048:150 /etc/mountall /etc/fstab