_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©: 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