> I got the code, and merged it into CVS, but did not have time to test it. I
> am deeply involved in lots of other code at the moment. Please try mailing
> it to the list and see if you get someone there to test it. CVS is not

I have attached newest versions of ramdisk driver. In few words, driver
should be able to support variable size disks now and disk, larger than
one segment (64 KB). There were few bugs too that prevented the old
version to compile under 0.0.77.

I really _need_ people to test it out as i can't find one stupid bug
somwehere inthere. Creating/removing disks with sizes that are multiples
of 64 KB seems to work just fine while using other sizes (10 KB, 70 KB,
... for example) crashes the kernel at unexpected point (no crash with
stack info or anything). So what i need people to do is to test it out,
maybe it works on someone else's box .. You need some basic C skills to
do that though and understanding of kernel source is required too in
order to be able to follow source execution.

If you don't want to see all the messages from kernel and just want to
try it out for yourself #undef DEBUG in rd.c (but you won't be able to
debug it then either).

Put rd.c in arch/i86/drivers/block/rd.c, rd.h in include/linuxmt/rd.h,
ramdisk.c in elkscmd/disk_utils/ramdisk.c, recompile, update your root
disk and test it out.

BTW: is there some way to actually debug (step by step mode with fulkl
registers dump) ELKS ?? Afaik pcemu was able to do something like that,
anyone has any clues on that ??

                                        bye, Ab
/*
 * rd.c, written by Al Riddoch
 * modified: July 4th, 5th 1999, Blaz Antonic
 * - allow variable ramdisk size (in 4096 blocks)
 * - allow ramdisks larger than 64 KB (which is segment limit)
 */

#include <linuxmt/config.h>
#include <linuxmt/rd.h>
#include <linuxmt/major.h>
#include <linuxmt/kernel.h>
#include <linuxmt/debug.h>
#include <linuxmt/errno.h>

#ifdef CONFIG_BLK_DEV_RAM

#define MAJOR_NR RAM_MAJOR

#define RAMDISK
#include "blk.h"

#define SECTOR_SIZE 512
#define SEG_SIZE 16 /* # of 4 KB pages */
#define PAGE_SIZE 4096 /* 4 KB pages */
#define MULTIPLIER 8 /* PAGE_SIZE / SECTOR_SIZE */
#define MAX_ENTRIES 8

#define DEBUG
#ifdef DEBUG
#endif

static int rd_initialised = 0;
static struct rd_infot
{
        int index;
        int flags;
        int size; /* ramdisk size in 512 B blocks */
} rd_info[MAX_ENTRIES] = 
{
        {0,0,0},
        {0,0,0},
        {0,0,0},
        {0,0,0},
        {0,0,0},
        {0,0,0},
        {0,0,0},
        {0,0,0}
};

static struct rd_segmentt
{
        int segment;
        int next;
        int seg_size; /* segment size in 512 byte blocks */
} rd_segment[MAX_ENTRIES] = /* max 640 KB will be used for RAM disk(s) */
{
        {0,MAX_ENTRIES+1,0,},
        {0,MAX_ENTRIES+1,0,},
        {0,MAX_ENTRIES+1,0,},
        {0,MAX_ENTRIES+1,0,},
        {0,MAX_ENTRIES+1,0,},
        {0,MAX_ENTRIES+1,0,},
        {0,MAX_ENTRIES+1,0,},
        {0,MAX_ENTRIES+1,0,}
};

static int rd_open(inode, filp);
static int rd_release(inode, filp);
static int rd_ioctl(inode, file, cmd, arg);

void rd_load() {}

static struct file_operations rd_fops =
{
        NULL,                   /* lseek */
        block_read,             /* read */
        block_write,            /* write */
        NULL,                   /* readdir */
        NULL,                   /* select */
        rd_ioctl,               /* ioctl */
        rd_open,                /* open */
        rd_release,             /* release */
#ifdef BLOAT_FS
        NULL,                   /* fsync */
        NULL,                   /* check_media_change */
        NULL,                   /* revalidate */
#endif
};

void rd_init()
{
        int i;

        /* Al's very own ego boost :) */
        printk("rd driver Copyright (C) 1997 Alistair Riddoch\n");
        if ((i = register_blkdev(MAJOR_NR, DEVICE_NAME, &rd_fops)) == 0) {
                blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
                /* blksize_size[MAJOR_NR] = 1024; */
                /* read_ahead[MAJOR_NR] = 2; */
                rd_initialised = 1;
        } else {
                printk("rd: unable to register\n");
        }
}
        
static int rd_open(inode, filp)
struct inode *inode;
struct file *filp;
{
        int target;

        target = DEVICE_NR(inode->i_rdev);
        printd_rd1("RD_OPEN %d\n",target);
        if (rd_initialised == 0)
                return (-ENXIO);
/*      if (rd_info[target].flags && RD_BUSY)
                return (-EBUSY); */
        return 0;
}

static int rd_release(inode, filp)
struct inode *inode;
struct file *filp;
{
        printd_rd("RD_RELEASE \n");
/*      rd_info[DEVICE_NR(inode->i_rdev)].flags = 0; */ /* ioctl() takes care of it */
        return 0;
}

int find_free_seg()
{
        int i;
        for (i = 0; i < 8; i++) {
#ifdef DEBUG
                printk("find_free_seg: rd_segment[%d].seg_size = %d\n", i, 
rd_segment[i].seg_size);
#endif
                if (rd_segment[i].seg_size == 0)
                        return i;
        }
        return -1;
}

int rd_dealloc(target)
int target;
{
        int i, j;
#ifdef DEBUG
        int a = 0;
#endif
        i = rd_info[target].index;
#ifdef DEBUG
        printk("rd_dealloc: target = %d, first index = %d, size = %d blocks\n", 
target, i, rd_info[target].size);
#endif
        while ((rd_segment[i].seg_size != 0) && (i != MAX_ENTRIES + 1)) {
                j = i;
#ifdef DEBUG
                printk("rd_dealloc: pass: %d, purging rd_segment[%d].segment = 0x%x, 
next index %d, size = %d\n", a, j, rd_segment[j].segment, rd_segment[j].next, 
rd_segment[j].seg_size);
#endif
                mm_free(rd_segment[j].segment);
                rd_segment[j].segment = 0;
                rd_segment[j].seg_size = 0;
                i = rd_segment[j].next;
                rd_segment[j].next = MAX_ENTRIES + 1;
#ifdef DEBUG
                printk("rd_dealloc: pass: %d, status rd_segment[%d].segment = 0x%x, 
next index %d, size = %d\n", a, j, rd_segment[j].segment, rd_segment[j].next, 
rd_segment[j].seg_size);
                a++;
#endif
        }
        rd_info[target].flags = 0;
        
        return 0;
}

static int rd_ioctl(inode, file, cmd, arg)
register struct inode *inode;
struct file *file;
unsigned int cmd;
unsigned int arg;
{
        int target = DEVICE_NR(inode->i_rdev);
        int i, j, k;
        int size;

        if (!suser())
                return -EPERM;
        printd_rd2("RD_IOCTL %d %s\n", target, (cmd ? "kill" : "make"));
        switch(cmd) {
                case RDCREATE:
                        if (rd_info[target].flags && RD_BUSY) {
                                return -EBUSY;
                        } else {
                                /* allocate memory */
#if 0
                                rd_info[target].size = 0;
#endif
                                k = -1;
                                for (i = 0; i <= (arg - 1) / SEG_SIZE; i++) {
                                        j = find_free_seg(); /* find free place in 
queue */
#ifdef DEBUG
                                        printk("rd_ioctl(): find_free_seg() = %d\n", 
j);
#endif
                                        if (j == -1) {
                                                rd_dealloc(target);
                                                return -ENOMEM;
                                        }
                                        if (i == 0)
                                                rd_info[target].index = j;
                                        
                                        if (i == arg / SEG_SIZE)
                                                size = arg % SEG_SIZE;
                                                else
                                                size = SEG_SIZE;

                                        if ((rd_segment[j].segment = mm_alloc(size, 
0)) == -1) {
                                                rd_dealloc(target);
                                                return -ENOMEM;
                                        }
#ifdef DEBUG
                                        printk("rd_ioctl(): pass: %d, allocated %d 
pages\n", i, size);
#endif
                                        /* recalculate int size to reflect size in 
sectors, not pages */
                                        size = size * MULTIPLIER;

                                        rd_segment[j].seg_size = size; /* size in 
sectors */
#ifdef DEBUG
                                        printk("rd_ioctl(): rd_segment[%d].seg_size = 
%d\n", j, rd_segment[j].seg_size);
#endif
                                        rd_info[target].size += 
rd_segment[j].seg_size; /* size in 512 B blocks */
                                        fmemset(0, rd_segment[j].segment, 0, 
rd_segment[j].seg_size * SECTOR_SIZE); /* clear seg_size bytes */
                                        if (k != -1)
                                                rd_segment[k].next = j; /* set link to 
next index */
                                        k = j;
                                }
                                rd_info[target].flags = RD_BUSY;
#ifdef DEBUG
                                printk("rd_ioctl(): ramdisk %d created, size = %d 
blocks, index = %d\n", target, rd_info[target].size, rd_info[target].index);
#endif
                        }
#ifdef DEBUG
                        printk("rd_ioctl(): about to return(0);\n");
#endif
                        return 0;
                        break;
                case RDDESTROY:
                        if (rd_info[target].flags && RD_BUSY) {
                                invalidate_inodes(inode->i_rdev);
                                invalidate_buffers(inode->i_rdev);
                                rd_dealloc(target);
                                rd_info[target].flags = 0;
                                return 0;
                        } else
                                return -EINVAL;
                        break;
        }
        return -EINVAL;
}

static void do_rd_request()
{
/*      unsigned long count; */
        unsigned long start;
        register char *buff;
        int target;
        int offset, segnum;

        while(1) {
                if (!CURRENT || CURRENT->rq_dev <0)
                        return;

                INIT_REQUEST;

                if (CURRENT == NULL || CURRENT->rq_sector == -1)
                        return;

                if (rd_initialised != 1) {
                        end_request(0, CURRENT->rq_dev);
                        continue;
                }

                start = CURRENT->rq_sector;
                buff = CURRENT->rq_buffer;
                target = DEVICE_NR(CURRENT->rq_dev);

                /* FIXME (DONE): there is really no need for 3rd condition ... count 
isn't used anywhere, we only have 1024 byte requests */
#if 0 /* old code */
                if ((rd_info[target].flags != RD_BUSY) || (start >= 
rd_info[target].size) || (start + count >= rd_info[target].size)) {
#endif
                if ((rd_info[target].flags != RD_BUSY) || (start >= 
rd_info[target].size)) {
                        printd_rd("Bollocks request\n");
#ifdef DEBUG
                        printk("do_rd_request: dev %d not allocated, flags: %d, size: 
%d, start: %d\n", target, rd_info[target].flags, rd_info[target].size, start);
#endif                  
                        end_request(0, CURRENT->rq_dev);
                        continue;
                }
                offset = start; /* offset from segment start */
                segnum = rd_segment[rd_info[target].index].segment; /* first segment 
number */
                while ((offset - rd_segment[segnum].seg_size) > 0) {
                        offset -= rd_segment[segnum].seg_size; /* recalculate offset */
                        segnum = rd_segment[segnum].next; /* point to next segment in 
linked list */
                }
#ifdef DEBUG
                printk("do_rd_request: target: %d, start: %ld, segment %d, offset: 
%d\n", target, (long)start, segnum, offset);
#endif
                if (CURRENT->rq_cmd == WRITE) {
                        printd_rd2("RD_REQUEST writing to %ld size %ld\n", 
start,count);
                        fmemcpy(rd_segment[segnum].segment, offset, get_ds(), buff, 
1024);
                }
                if (CURRENT->rq_cmd == READ) {
                        printd_rd2("RD_REQUEST reading from %ld size %ld\n", 
start,count);
                        fmemcpy(get_ds(), buff, rd_segment[segnum].segment, offset, 
1024);
                }
                end_request(1, CURRENT->rq_dev);
        }
}

#endif /* CONFIG_BLK_DEV_RAM */
#ifndef __LINUXMT_RD_H_
#define __LINUXMT_RD_H_


#define RDCREATE 0
#define RDDESTROY 1

#define RD_BUSY 0x01

#endif /* __LINUXMT_RD_H_ */
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <linuxmt/rd.h>

#define MAX_SIZE 640 /* 1 KB blocks */

int main(argc, argv)
int argc;
char **argv;
{
        int i;
        int fd;
        int size = 0;

        if ((argc != 4) && (argc != 3)) {
                fprintf(stderr, "usage: ramdisk /dev/ram? {make | kill} [size in 1 KB 
blocks]\n");
                exit(1);
        }

        if (argc == 4)
                sscanf(argv[3], "%d", &size);
        else
                size = 64; /* default */
        
        if ((size < 1) || (size > MAX_SIZE)) {
                fprintf(stderr, "ramdisk: invalid size; use integer in range of 1 .. 
%d, ramdisk will round it up to nearest multiple of 4 KB\n", MAX_SIZE);
                exit(1);
        }
        if (( fd = open(argv[1], 0) ) == -1) {
                perror("ramdisk");
                exit(1);
        }
        if (strcmp(argv[2],"make") == 0) {
                /* recalculate size to # of 4 KB pages */
                        if ((size % 4) != 0) {
                                fprintf(stdout, "ramdisk: rounding size up to %d KB 
...\n", ((size / 4) + 1) * 4);
                                size = size / 4 + 1;
                        } else {
                                size = size / 4;
                        }

                if (ioctl(fd, RDCREATE, size)) {
                        perror("ramdisk");
                        exit(1);
                }
                fprintf(stdout,"ramdisk: %d KB ramdisk created on %s\n", size * 4, 
argv[1]);
                exit(0);
        }
        if (strcmp(argv[2],"kill") == 0) {
                if (ioctl(fd, RDDESTROY, 0)) {
                        perror("ramdisk");
                        exit(1);
                }
                fprintf(stdout,"ramdisk destroyed on %s\n", argv[1]);
                exit(0);
        }
}

Reply via email to