Re: "bugfree :)" ramdisk-1.3.4.tar.gz now available

David Foulds (foulds@netcom.com)
Wed, 28 Jun 1995 09:59:11 -0700


From: Drew Eckhardt <drew@poohsticks.org>
Date: Tue, 27 Jun 1995 09:52:01 -0600
Subject: Re: "bugfree :)" ramdisk-1.3.4.tar.gz now available

In message <Pine.BSF.3.91.950626231727.3635A-100000@shell1.best.com>, cpage@bes
t.com writes:
>
> I've made some changes to ramdisk-1.3.4 which should stabilize
>the buffer-cache ramdisks...

IMHO, a ramdisk block device is the wrong approach to getting a
memory based filesystem

- It allways uses a fixed ammount of memory, irregardless of
how full it is.

- It uses a "normal" filesystem on it, with the overhead associated
with that.

- You need to mkfs any ramdisk you want to use. PITA.

instead, we want a generic memory based filesystem; which would
eventually be pageable. We should do something along the lines of
Sun's tmpfs...

What follows is my entry in the ramdisk sweepstakes. This is
simply a block device driver for a portion of virtual memory,
hence the name 'vpart' or virtual partition. I implemented
this by looking at the 4.4BSD mfs code (for ideas only!),
accepting the idea of trapping a process in the kernel
to service the device i/o, and then grafting that onto the
(gratifyingly minimalist) original Linux ramdisk code.

The appropriate version number here is 0.01 and what is
provided is only the file which goes into drivers/block;
no configuration info, although all you have to do is
change blk.h, the Makefile, and major.h, I think; search
for 'CONFIG_SBPCD' or some other block device to confirm.

It works for me but it is not robust and not done. However,
it is a demonstration of concept.

What follows is vpart.c and test.c (a sample program analogous
to BSD's mount_mfs).

Cheers,

David

/*
* linux/kernel/blk_drv/vpart.c
*
* Written by David Foulds, 6/25/95
*
*/

#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/times.h>
#include <linux/utsname.h>
#include <linux/param.h>
#include <linux/resource.h>
#include <linux/signal.h>
#include <linux/stat.h>
#include <linux/mman.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/segment.h>
#define VPARTINIT 0x7101
#define VPARTDOWN 0x7102
#define VPARTQUERY 0x7103
#define MAJOR_NR VPART_MAJOR
#include "blk.h"
static int vpart_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg);
/*
static int vpart_open(struct inode * inode, struct file * file);
*/
static struct wait_queue *vpart_wait = NULL;

struct vpartstruct {
int flag;
unsigned int base;
unsigned int size;
int pid;
int minor;
int initted;
};

static struct vpartstruct myvpartstruct={0,0,0,0,0,0};

static int vpart_blocksizes[2] = {0, 0};

static void vpart_doio(void);
static struct file_operations vpart_fops = {
NULL, /* lseek - default */
block_read, /* read - general block-dev read */
block_write, /* write - general block-dev write */
NULL, /* readdir - bad */
NULL, /* select */
vpart_ioctl, /* ioctl */
NULL, /* mmap */
NULL, /* no special open code */
NULL, /* no special release code */
block_fsync /* fsync */
};
static void do_vpart_request(void)
{
if (!myvpartstruct.initted)
{
INIT_REQUEST;
end_request(0);
}

if (myvpartstruct.pid == current->pid)
vpart_doio();
else
wake_up(&vpart_wait);
}

unsigned long vpart_init(unsigned long mem_start, unsigned long length)
{
int i;

if (register_blkdev(VPART_MAJOR,"vpart",&vpart_fops)) {
printk("VPART: Unable to get major %d.\n", VPART_MAJOR);
return 0;
}
blk_dev[VPART_MAJOR].request_fn = DEVICE_REQUEST;

for(i=0;i<2;i++) vpart_blocksizes[i] = 1024;
blksize_size[MAJOR_NR] = vpart_blocksizes;
printk("in vpart_init\n");

return(mem_start);
}

/*
static int vpart_open(struct inode * inode, struct file * file)
{
if (!myvpartstruct.initted)
{
printk("vpart not initted\n");
return -EINVAL;
}
return 0;
}
*/
static int vpart_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg)
{
struct vpartstruct *vpartstruct2p;
int err;
switch(cmd)
{
case VPARTQUERY:
vpartstruct2p = (struct vpartstruct *)arg;
err = verify_area(VERIFY_WRITE, vpartstruct2p, sizeof(*vpartstruct2p));
if (err) return err;
put_fs_long(myvpartstruct.flag,&vpartstruct2p->flag);
put_fs_long(myvpartstruct.base,&vpartstruct2p->base);
put_fs_long(myvpartstruct.size,&vpartstruct2p->size);
put_fs_long(myvpartstruct.pid,&vpartstruct2p->pid);
put_fs_long(myvpartstruct.minor,&vpartstruct2p->minor);
put_fs_long(myvpartstruct.initted,&vpartstruct2p->initted);
return 0;
case VPARTINIT:
vpartstruct2p = (struct vpartstruct *)arg;
err = verify_area(VERIFY_WRITE, vpartstruct2p, sizeof(*vpartstruct2p));
if (err) return err;
myvpartstruct.base = get_fs_long(&vpartstruct2p->base);
myvpartstruct.size = get_fs_long(&vpartstruct2p->size);
myvpartstruct.pid = current->pid;
if (myvpartstruct.initted)
{
printk("vpart already initted\n");
return -EINVAL;
}
else
{
err = verify_area(VERIFY_WRITE, myvpartstruct.base,
myvpartstruct.size);
if (err) return err;
myvpartstruct.initted = 1;
}
while (myvpartstruct.flag != (-1)) {
while (CURRENT)
vpart_doio();
sleep_on(&vpart_wait);
}
while (CURRENT)
vpart_doio();

/* put the rest of the shutdown logic here */

return 0;
case VPARTDOWN:
myvpartstruct.flag = -1;
wake_up(&vpart_wait);
myvpartstruct.initted = 0;
myvpartstruct.flag = 0;
myvpartstruct.base = 0;
myvpartstruct.size = 0;
myvpartstruct.pid = 0;
myvpartstruct.minor = 0;
return 0;
default:
return -EINVAL;
}
}
static void vpart_doio(void)
{
unsigned long base=myvpartstruct.base,addr,len;
unsigned long size=myvpartstruct.size;
repeat:
INIT_REQUEST;
addr = base + (CURRENT->sector << 9);
len = CURRENT->current_nr_sectors << 9;
if (addr+len > base+size)
{
end_request(0);
goto repeat;
}
if (CURRENT->cmd == WRITE)
memcpy_tofs(addr,CURRENT->buffer,len);
else
if (CURRENT->cmd == READ)
memcpy_fromfs(CURRENT->buffer,addr,len);
else
panic("VPART: unknown VPART command !\n");
end_request(1);
goto repeat;
}



#define VPARTINIT 0x7101
#define VPARTDOWN 0x7102
#define VPARTQUERY 0x7103
struct vpartstruct {
int flag;
unsigned int base;
unsigned int size;
int pid;
int minor;
int initted;
} myvpartstruct;
int myfd;
#include <sys/ioctl.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/resource.h>
unsigned long memleft;
main(int argc,char **argv)
{
void started();
register u_long size;
char *base, *i;
static u_long pgsz;
struct rlimit rlp;
int ppid,status,retval;
if (argc != 2)
{
printf("Usage: test <size to malloc>\n");
exit(1);
}
if (!(size=strtoul(argv[1],0,0)))
{
printf("stroul returned 0: bad sytax or invalid input\n");
exit(1);
}
ppid = getpid();
(void) signal(SIGUSR1, started);
if (i = fork()) {
/* parent */
if (i == -1) {
printf("fork failed, will exit parent with code 10\n");
exit(10);
}
printf("Fork succeeded, in parent,pid=%d\n",getpid());

if (waitpid(i, &status, 0) != -1 && WIFEXITED(status))
{
printf("Exiting parent\n");
fflush(stdout);
exit(WEXITSTATUS(status));
}
printf("exiting from parent after wait with code 11\n");
fflush(stdout);
exit(11);
/* NOTREACHED */
}
/* child */
printf("This is child,pid=%d\n",getpid());
if ((base=malloc(size))==0)
{
printf("Not enough memory for %d bytes size\n",(int)size);
printf("Exiting child\n",(int)size);
exit(1);
} else
printf("malloc returned %d\n",(int)base);
kill(ppid, SIGUSR1);

myfd=open("/dev/vpart1",O_RDWR);
if (myfd == -1)
{
printf("open failed\n");
exit(1);
}
(void) setsid();
(void) close(0);
(void) close(1);
(void) close(2);
(void) chdir("/");
myvpartstruct.base=base;
myvpartstruct.size=size;
retval=ioctl(myfd,VPARTINIT,&myvpartstruct);
exit(0);

}
void
started()
{
printf("In started fn!\n");
return;
}