Messages in this thread | | | Date | Fri, 20 Aug 1999 16:51:25 +0800 | From | Tseng Chou Ming (Soft Eng) <> | Subject | modified rd.c(1) |
| |
/* * ramdisk.c - Multiple RAM disk driver - gzip-loading version - v. 0.8 beta. * * (C) Chad Page, Theodore Ts'o, et. al, 1995. * * This RAM disk is designed to have filesystems created on it and mounted * just like a regular floppy disk. * * It also does something suggested by Linus: use the buffer cache as the * RAM disk data. This makes it possible to dynamically allocate the RAM disk * buffer - with some consequences I have to deal with as I write this. * * This code is based on the original ramdisk.c, written mostly by * Theodore Ts'o (TYT) in 1991. The code was largely rewritten by * Chad Page to use the buffer cache to store the RAM disk data in * 1995; Theodore then took over the driver again, and cleaned it up * for inclusion in the mainline kernel. * * The original CRAMDISK code was written by Richard Lyons, and * adapted by Chad Page to use the new RAM disk interface. Theodore * Ts'o rewrote it so that both the compressed RAM disk loader and the * kernel decompressor uses the same inflate.c codebase. The RAM disk * loader now also loads into a dynamic (buffer cache based) RAM disk, * not the old static RAM disk. Support for the old static RAM disk has * been completely removed. * * Loadable module support added by Tom Dyas. * * Further cleanups by Chad Page (page0588@sundance.sjsu.edu): * Cosmetic changes in #ifdef MODULE, code movement, etc. * When the RAM disk module is removed, free the protected buffers * Default RAM disk size changed to 2.88 MB * * Added initrd: Werner Almesberger & Hans Lermen, Feb '96 * * 4/25/96 : Made RAM disk size a parameter (default is now 4 MB) * - Chad Page * * Add support for fs images split across >1 disk, Paul Gortmaker, Mar '98 * */
#include <linux/config.h> #include <linux/sched.h> #include <linux/minix_fs.h> #include <linux/ext2_fs.h> #include <linux/romfs_fs.h> #include <linux/fs.h> #include <linux/kernel.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/mman.h> #include <linux/malloc.h> #include <linux/ioctl.h> #include <linux/fd.h> #include <linux/module.h> #include <linux/init.h>
#include <asm/system.h> #include <asm/uaccess.h> #include <asm/byteorder.h>
extern void wait_for_keypress(void);
#define JMT_RD
/* * 35 has been officially registered as the RAMDISK major number, but * so is the original MAJOR number of 1. We're using 1 in * include/linux/major.h for now */ #define MAJOR_NR RAMDISK_MAJOR #include <linux/blk.h>
/* The RAM disk size is now a parameter */ #define NUM_RAMDISKS 1 /* (16) This cannot be overridden (yet) */
#ifndef MODULE /* We don't have to load RAM disks or gunzip them in a module. */ #define RD_LOADER #define BUILD_CRAMDISK
void rd_load(void); static int crd_load(struct file *fp, struct file *outfp);
#ifdef CONFIG_BLK_DEV_INITRD static int initrd_users = 0; #endif #endif
/* Various static variables go here. Most are used only in the RAM disk code. */
static int rd_length[NUM_RAMDISKS]; static int rd_blocksizes[NUM_RAMDISKS];
/* * Parameters for the boot-loading of the RAM disk. These are set by * init/main.c (from arguments to the kernel command line) or from the * architecture-specific setup routine (from the stored boot sector * information). */ int rd_size = 4567; /*4872;*/ /*4096;*/ /* Size of the RAM disks */
#ifndef MODULE int rd_doload = 0; /* "1" = load RAM disk, 0 = don't load */ int rd_prompt = 1; /* 1 = prompt for RAM disk, 0 = don't prompt */ int rd_image_start = 0; /* starting block # of image */ #ifdef CONFIG_BLK_DEV_INITRD unsigned long initrd_start,initrd_end; int mount_initrd = 1; /* zero if initrd should not be mounted */ int initrd_below_start_ok = 0; #endif #endif
/* * Basically, my strategy here is to set up a buffer-head which can't be * deleted, and make that my Ramdisk. If the request is outside of the * allocated size, we must get rid of it... * */ static void rd_request(void) { unsigned int minor; int offset, len;
loff_t pos; #if 0 printk("[.]in rd_request\n"); #endif
repeat: INIT_REQUEST; minor = MINOR(CURRENT->rq_dev);
if (minor >= NUM_RAMDISKS) { end_request(0); goto repeat; } offset = CURRENT->sector << 9;
pos=offset;
len = CURRENT->current_nr_sectors << 9;
if ((offset + len) > rd_length[minor]) { end_request(0); goto repeat; }
/* * If we're reading, fill the buffer with 0's. This is okay since * we're using protected buffers which should never get freed... * * If we're writing, we protect the buffer. */
if (CURRENT->cmd == READ) { memset(CURRENT->buffer, 0, len); #ifdef JMT_RD initrd_read(NULL,CURRENT->buffer,len,&pos); #endif } else set_bit(BH_Protected, &CURRENT->bh->b_state);
end_request(1); goto repeat; }
static int rd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int err;
printk("[.]in rd_ioctl\n"); if (!inode || !inode->i_rdev) return -EINVAL;
switch (cmd) { case BLKFLSBUF: if (!capable(CAP_SYS_ADMIN)) return -EACCES; invalidate_buffers(inode->i_rdev); break; case BLKGETSIZE: /* Return device size */ if (!arg) return -EINVAL; #ifndef JMT_RD err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long)); if (err) return err; #endif put_user(rd_length[MINOR(inode->i_rdev)] / 512, (long *) arg); return 0; default: break; };
return 0; }
#ifdef CONFIG_BLK_DEV_INITRD
static ssize_t initrd_read(struct file *file, char *buf, size_t count, loff_t *ppos) { int left;
left = initrd_end - initrd_start - *ppos; if (count > left) count = left; if (count == 0) return 0; copy_to_user(buf, (char *)initrd_start + *ppos, count); *ppos += count; #if 0 printk("[?]initrd_read(~,%d,%d)\n",count,*ppos); #endif return count; }
static int initrd_release(struct inode *inode,struct file *file) { unsigned long i;
if (--initrd_users) return 0;
#ifdef JMT_RD return 0; #endif
for (i = initrd_start; i < initrd_end; i += PAGE_SIZE) free_page(i); initrd_start = 0; return 0; }
static struct file_operations initrd_fops = { NULL, /* lseek */ initrd_read, /* read */ NULL, /* write */ NULL, /* readdir */ NULL, /* poll */ NULL, /* ioctl */ NULL, /* mmap */ NULL, /* open */ NULL, /* flush */ initrd_release, /* release */ NULL /* fsync */ };
#endif
#ifdef JMT_RD static int jmtrd_open(struct inode * inode, struct file * filp) { printk("[*]jmtrd_open(%s)\n",kdevname(inode->i_rdev));
if (DEVICE_NR(inode->i_rdev) >= NUM_RAMDISKS) return -ENXIO;
MOD_INC_USE_COUNT;
return 0; }
static int jmtrd_release(struct inode * inode, struct file * filp) { MOD_DEC_USE_COUNT; return 0; }
static struct file_operations jmtrd_fops = { NULL, /* lseek - default */ initrd_read, /* read - initrd dev read */ NULL, /*block_write, write - block dev write */ NULL, /* readdir - not here! */ NULL, /* poll */ rd_ioctl, /* ioctl */ NULL, /* mmap */ jmtrd_open, /* open */ NULL, /* flush */ jmtrd_release, /* module needs to decrement use count */ block_fsync /* fsync */ }; #endif
static int rd_open(struct inode * inode, struct file * filp) { #ifdef JMT_RD printk("[*]jmtrd_open(%s)\n",kdevname(inode->i_rdev)); if (MAJOR(inode->i_rdev)==RAMDISK_MAJOR && MINOR(inode->i_rdev)==0) { if (!initrd_start) return -ENODEV; MOD_INC_USE_COUNT; filp->f_op = &jmtrd_fops; printk("[.]in rd_open\n"); return 0; } #endif
#ifdef CONFIG_BLK_DEV_INITRD if (DEVICE_NR(inode->i_rdev) == INITRD_MINOR) { if (!initrd_start) return -ENODEV; initrd_users++; filp->f_op = &initrd_fops; return 0; } #endif
if (DEVICE_NR(inode->i_rdev) >= NUM_RAMDISKS) return -ENXIO;
MOD_INC_USE_COUNT;
return 0; }
static int rd_release(struct inode * inode, struct file * filp) { MOD_DEC_USE_COUNT; return 0; }
static struct file_operations fd_fops = { NULL, /* lseek - default */ initrd_read,/*block_read, read - block dev read */ block_write, /* write - block dev write */ NULL, /* readdir - not here! */ NULL, /* poll */ rd_ioctl, /* ioctl */ NULL, /* mmap */ rd_open, /* open */ NULL, /* flush */ rd_release, /* module needs to decrement use count */ block_fsync /* fsync */ };
/* This is the registration and initialization section of the RAM disk driver */ __initfunc(int rd_init(void)) { int i;
#ifdef JMT_RD if (register_blkdev(MAJOR_NR, "ramdisk", &jmtrd_fops)) { #else if (register_blkdev(MAJOR_NR, "ramdisk", &fd_fops)) { #endif printk("RAMDISK: Could not get major %d", MAJOR_NR); return -EIO; }
blk_dev[MAJOR_NR].request_fn = &rd_request;
for (i = 0; i < NUM_RAMDISKS; i++) { rd_length[i] = (rd_size * 1024); rd_blocksizes[i] = 1024; }
blksize_size[MAJOR_NR] = rd_blocksizes;
printk("RAM disk driver initialized: %d RAM disks of %dK size\n", NUM_RAMDISKS, rd_size);
return 0; }
/* loadable module support */
#ifdef MODULE
int init_module(void) { int error = rd_init(); if (!error) printk(KERN_INFO "RAMDISK: Loaded as module.\n"); return error; }
/* Before freeing the module, invalidate all of the protected buffers! */ void cleanup_module(void) { int i;
for (i = 0 ; i < NUM_RAMDISKS; i++) invalidate_buffers(MKDEV(MAJOR_NR, i));
unregister_blkdev( MAJOR_NR, "ramdisk" ); blk_dev[MAJOR_NR].request_fn = 0; }
#endif /* MODULE */
/* End of non-loading portions of the RAM disk driver */
#ifdef RD_LOADER /* * This routine tries to find a RAM disk image to load, and returns the * number of blocks to read for a non-compressed image, 0 if the image * is a compressed image, and -1 if an image with the right magic * numbers could not be found. * * We currently check for the following magic numbers: * minix * ext2 * romfs * gzip */
int identify_romfs_image(void) { const int size = 512; struct romfs_super_block *romfsb; int nblocks = -1; unsigned char *buf;
int start_block=0; loff_t pos; pos=0;
buf = kmalloc(size, GFP_KERNEL); if (buf == 0) return -1;
romfsb = (struct romfs_super_block *) buf; memset(buf, 0xe5, size);
/* * Read block 0 to test for romfs image */
initrd_read(NULL,buf,size,&pos);
/* romfs is at block zero too */ if (romfsb->word0 == ROMSB_WORD0 && romfsb->word1 == ROMSB_WORD1) { printk(KERN_NOTICE "RAMDISK: romfs filesystem found at block %d\n", start_block); nblocks = (ntohl(romfsb->size)+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS; goto done; }
printk(KERN_NOTICE "JMTRD: Couldn't find valid ROMFS disk image starting at %d.\n", start_block); done:
kfree(buf); return nblocks; }
__initfunc(int identify_ramdisk_image(kdev_t device, struct file *fp, int start_block)) { const int size = 512; struct minix_super_block *minixsb; struct ext2_super_block *ext2sb; struct romfs_super_block *romfsb; int nblocks = -1; unsigned char *buf;
buf = kmalloc(size, GFP_KERNEL); if (buf == 0) return -1;
minixsb = (struct minix_super_block *) buf; ext2sb = (struct ext2_super_block *) buf; romfsb = (struct romfs_super_block *) buf; memset(buf, 0xe5, size);
/* * Read block 0 to test for gzipped kernel */ if (fp->f_op->llseek) fp->f_op->llseek(fp, start_block * BLOCK_SIZE, 0); fp->f_pos = start_block * BLOCK_SIZE;
fp->f_op->read(fp, buf, size, &fp->f_pos);
/* * If it matches the gzip magic numbers, return -1 */ if (buf[0] == 037 && ((buf[1] == 0213) || (buf[1] == 0236))) { printk(KERN_NOTICE "RAMDISK: Compressed image found at block %d\n", start_block); nblocks = 0; goto done; }
/* romfs is at block zero too */ if (romfsb->word0 == ROMSB_WORD0 && romfsb->word1 == ROMSB_WORD1) { printk(KERN_NOTICE "RAMDISK: romfs filesystem found at block %d\n", start_block); nblocks = (ntohl(romfsb->size)+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS; goto done; }
/* * Read block 1 to test for minix and ext2 superblock */ if (fp->f_op->llseek) fp->f_op->llseek(fp, (start_block+1) * BLOCK_SIZE, 0); fp->f_pos = (start_block+1) * BLOCK_SIZE;
fp->f_op->read(fp, buf, size, &fp->f_pos); /* Try minix */ if (minixsb->s_magic == MINIX_SUPER_MAGIC || minixsb->s_magic == MINIX_SUPER_MAGIC2) { printk(KERN_NOTICE "RAMDISK: Minix filesystem found at block %d\n", start_block); nblocks = minixsb->s_nzones << minixsb->s_log_zone_size; goto done; }
/* Try ext2 */ if (ext2sb->s_magic == cpu_to_le16(EXT2_SUPER_MAGIC)) { printk(KERN_NOTICE "RAMDISK: ext2 filesystem found at block %d\n", start_block); nblocks = le32_to_cpu(ext2sb->s_blocks_count); goto done; }
printk(KERN_NOTICE "RAMDISK: Couldn't find valid RAM disk image starting at %d.\n", start_block); done: if (fp->f_op->llseek) fp->f_op->llseek(fp, start_block * BLOCK_SIZE, 0); fp->f_pos = start_block * BLOCK_SIZE;
kfree(buf); return nblocks; }
/* * This routine loads in the RAM disk image. */ #ifdef JMT_RD __initfunc(static void rd_load_image(kdev_t device,int offset)) { int nblocks;
nblocks=identify_romfs_image();
ROOT_DEV = MKDEV(MAJOR_NR,0); printk("[*]jmtrd loaded %d blocks\n",nblocks); } #else __initfunc(static void rd_load_image(kdev_t device,int offset)) { struct inode inode, out_inode; struct file infile, outfile; struct dentry in_dentry, out_dentry; mm_segment_t fs; kdev_t ram_device; int nblocks, i; char *buf; unsigned short rotate = 0; unsigned short devblocks = 0; char rotator[4] = { '|' , '/' , '-' , '\\' };
ram_device = MKDEV(MAJOR_NR, 0);
memset(&infile, 0, sizeof(infile)); memset(&inode, 0, sizeof(inode)); memset(&in_dentry, 0, sizeof(in_dentry)); inode.i_rdev = device; infile.f_mode = 1; /* read only */ infile.f_dentry = &in_dentry; in_dentry.d_inode = &inode;
memset(&outfile, 0, sizeof(outfile)); memset(&out_inode, 0, sizeof(out_inode)); memset(&out_dentry, 0, sizeof(out_dentry)); out_inode.i_rdev = ram_device; outfile.f_mode = 3; /* read/write */ outfile.f_dentry = &out_dentry; out_dentry.d_inode = &out_inode;
if (blkdev_open(&inode, &infile) != 0) return;
if (blkdev_open(&out_inode, &outfile) != 0) return;
fs = get_fs(); set_fs(KERNEL_DS); #if 0 printk("identify_ramdisk_image\n"); #endif nblocks = identify_ramdisk_image(device, &infile, offset); #if 0 printk("#nblocks:#%d\n",nblocks); #endif if (nblocks < 0) goto done;
if (nblocks == 0) { #ifdef BUILD_CRAMDISK if (crd_load(&infile, &outfile) == 0) goto successful_load; #else printk(KERN_NOTICE "RAMDISK: Kernel does not support compressed " "RAM disk images\n"); #endif goto done; }
if (nblocks > (rd_length[0] >> BLOCK_SIZE_BITS)) { printk("RAMDISK: image too big! (%d/%d blocks)\n", nblocks, rd_length[0] >> BLOCK_SIZE_BITS); goto done; } /* * OK, time to copy in the data */ buf = kmalloc(BLOCK_SIZE, GFP_KERNEL); if (buf == 0) { printk(KERN_ERR "RAMDISK: could not allocate buffer\n"); goto done; }
if (blk_size[MAJOR(device)]) devblocks = blk_size[MAJOR(device)][MINOR(device)];
#ifdef CONFIG_BLK_DEV_INITRD if (MAJOR(device) == MAJOR_NR && MINOR(device) == INITRD_MINOR) devblocks = nblocks; #endif
if (devblocks == 0) { printk(KERN_ERR "RAMDISK: could not determine device size\n"); goto done; }
printk(KERN_NOTICE "RAMDISK: Loading %d blocks [%d disk%s] into ram disk... ", nblocks, ((nblocks-1)/devblocks)+1, nblocks>devblocks ? "s" : ""); for (i=0; i < nblocks; i++) { if (i && (i % devblocks == 0)) { printk("done disk #%d.\n", i/devblocks); rotate = 0; invalidate_buffers(device); if (infile.f_op->release) infile.f_op->release(&inode, &infile); printk("Please insert disk #%d and press ENTER\n", i/devblocks+1); wait_for_keypress(); if (blkdev_open(&inode, &infile) != 0) { printk("Error opening disk.\n"); goto done; } infile.f_pos = 0; printk("Loading disk #%d... ", i/devblocks+1); } infile.f_op->read(&infile, buf, BLOCK_SIZE, &infile.f_pos); outfile.f_op->write(&outfile, buf, BLOCK_SIZE, &outfile.f_pos); if (!(i % 16)) { printk("%c\b", rotator[rotate & 0x3]); rotate++; } } printk("done.\n"); kfree(buf);
successful_load: invalidate_buffers(device);
printk("[*]old ROOT_DEV=%s\n",kdevname(ROOT_DEV));
ROOT_DEV = MKDEV(MAJOR_NR,0);
done: if (infile.f_op->release) infile.f_op->release(&inode, &infile); set_fs(fs); } #endif
__initfunc(void rd_load(void)) {
if (rd_doload == 0) return; if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR) return;
if (rd_prompt) { #ifdef CONFIG_BLK_DEV_FD floppy_eject(); #endif printk(KERN_NOTICE "VFS: Insert root floppy disk to be loaded into RAM disk and press ENTER\n"); wait_for_keypress(); }
rd_load_image(ROOT_DEV,rd_image_start);
}
#ifdef CONFIG_BLK_DEV_INITRD __initfunc(void initrd_load(void)) { #if 0 printk("[+]rd_load_image()\n"); #endif rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),0); } #endif
#endif /* RD_LOADER */
#ifdef BUILD_CRAMDISK
/* * gzip declarations */
#define OF(args) args
#define memzero(s, n) memset ((s), 0, (n))
typedef unsigned char uch; typedef unsigned short ush; typedef unsigned long ulg;
#define INBUFSIZ 4096 #define WSIZE 0x8000 /* window size--must be a power of two, and */ /* at least 32K for zip's deflate method */
static uch *inbuf; static uch *window;
static unsigned insize = 0; /* valid bytes in inbuf */ static unsigned inptr = 0; /* index of next byte to be processed in inbuf */ static unsigned outcnt = 0; /* bytes in output buffer */ static int exit_code = 0; static long bytes_out = 0; static struct file *crd_infp, *crd_outfp;
#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) /* Diagnostic functions (stubbed out) */ #define Assert(cond,msg) #define Trace(x) #define Tracev(x) #define Tracevv(x) #define Tracec(c,x) #define Tracecv(c,x)
#define STATIC static
static int fill_inbuf(void); static void flush_window(void); static void *malloc(int size); static void free(void *where); static void error(char *m); static void gzip_mark(void **); static void gzip_release(void **);
#include "../../lib/inflate.c"
__initfunc(static void *malloc(int size)) { return kmalloc(size, GFP_KERNEL); }
__initfunc(static void free(void *where)) { kfree(where); }
__initfunc(static void gzip_mark(void **ptr)) { }
__initfunc(static void gzip_release(void **ptr)) { }
/* =========================================================================== * Fill the input buffer. This is called only when the buffer is empty * and at least one byte is really needed. */ __initfunc(static int fill_inbuf(void)) { if (exit_code) return -1; insize = crd_infp->f_op->read(crd_infp, inbuf, INBUFSIZ, &crd_infp->f_pos); if (insize == 0) return -1;
inptr = 1;
return inbuf[0]; }
/* =========================================================================== * Write the output window window[0..outcnt-1] and update crc and bytes_out. * (Used for the decompressed data only.) */ __initfunc(static void flush_window(void)) { ulg c = crc; /* temporary variable */ unsigned n; uch *in, ch; crd_outfp->f_op->write(crd_outfp, window, outcnt, &crd_outfp->f_pos); in = window; for (n = 0; n < outcnt; n++) { ch = *in++; c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); } crc = c; bytes_out += (ulg)outcnt; outcnt = 0; }
__initfunc(static void error(char *x)) { printk(KERN_ERR "%s", x); exit_code = 1; }
__initfunc(static int crd_load(struct file * fp, struct file *outfp)) { int result; crd_infp = fp; crd_outfp = outfp; inbuf = kmalloc(INBUFSIZ, GFP_KERNEL); if (inbuf == 0) { printk(KERN_ERR "RAMDISK: Couldn't allocate gzip buffer\n"); return -1; } window = kmalloc(WSIZE, GFP_KERNEL); if (window == 0) { printk(KERN_ERR "RAMDISK: Couldn't allocate gzip window\n"); kfree(inbuf); return -1; } makecrc(); result = gunzip(); kfree(inbuf); kfree(window); return result; }
#endif /* BUILD_CRAMDISK */
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/
| |