305 lines
7.8 KiB
Plaintext
305 lines
7.8 KiB
Plaintext
_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<70> 2(a)<29> Entr<74> fo<66> th<74> drive<76> i<> th<74> /etc/conf/sdevice.<2E> <20>
|
||
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<70> 2(d)<29> Th<54> tw<74> nodes<65> fo<66> characte<74> an<61> bloc<6F> device<63> <20>
|
||
respectively.]
|
||
|
||
rd rdsk/rd0 c 0
|
||
rd dsk/rd0 b 0
|
||
|
||
[Exampl<70> 2(e)<29> Th<54> modifie<69> S01MOUNTFSY<53> file.]
|
||
|
||
cd /
|
||
# Make a filesystem on the RAM disk.
|
||
/etc/mkfs /dev/dsk/rd0 2048:150
|
||
/etc/mountall /etc/fstab
|
||
|