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
|
|||
|
|