root/drivers/block/rd.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rd_request
  2. rd_ioctl
  3. rd_open
  4. rd_release
  5. rd_init
  6. identify_ramdisk_image
  7. rd_load
  8. malloc
  9. free
  10. gzip_mark
  11. gzip_release
  12. fill_inbuf
  13. flush_window
  14. error
  15. crd_load
  16. init_module
  17. cleanup_module

   1 /*
   2  * ramdisk.c - Multiple ramdisk driver - gzip-loading version - v. 0.8 beta.
   3  * 
   4  * (C) Chad Page, Theodore Ts'o, et. al, 1995. 
   5  *
   6  * This ramdisk is designed to have filesystems created on it and mounted
   7  * just like a regular floppy disk.  
   8  *  
   9  * It also does something suggested by Linus: use the buffer cache as the
  10  * ramdisk data.  This makes it possible to dynamically allocate the ramdisk
  11  * buffer - with some consequences I have to deal with as I write this. 
  12  * 
  13  * This code is based on the original ramdisk.c, written mostly by
  14  * Theodore Ts'o (TYT) in 1991.  The code was largely rewritten by
  15  * Chad Page to use the buffer cache to store the ramdisk data in
  16  * 1995; Theodore then took over the driver again, and cleaned it up
  17  * for inclusion in the mainline kernel.
  18  *
  19  * The original CRAMDISK code was written by Richard Lyons, and
  20  * adapted by Chad Page to use the new ramdisk interface.  Theodore
  21  * Ts'o rewrote it so that both the compressed ramdisk loader and the
  22  * kernel decompressor uses the same inflate.c codebase.  The ramdisk
  23  * loader now also loads into a dynamic (buffer cache based) ramdisk,
  24  * not the old static ramdisk.  Support for the old static ramdisk has
  25  * been completely removed.
  26  *
  27  * Loadable module support added by Tom Dyas.
  28  */
  29 
  30 #include <linux/sched.h>
  31 #include <linux/minix_fs.h>
  32 #include <linux/ext2_fs.h>
  33 #include <linux/fs.h>
  34 #include <linux/kernel.h>
  35 #include <linux/string.h>
  36 #include <linux/mm.h>
  37 #include <linux/mman.h>
  38 #include <linux/malloc.h>
  39 #include <linux/ioctl.h>
  40 #include <linux/module.h>
  41 
  42 #include <asm/system.h>
  43 #include <asm/segment.h>
  44 
  45 extern void wait_for_keypress(void);
  46 
  47 /*
  48  * 35 has been officially registered as the RAMDISK major number, but
  49  * so is the original MAJOR number of 1.  We're using 1 in
  50  * include/linux/major.h for now
  51  */
  52 #define MAJOR_NR RAMDISK_MAJOR
  53 #include <linux/blk.h>
  54 
  55 #define BUILD_CRAMDISK
  56 #define NUM_RAMDISKS 8
  57 
  58 #ifndef MODULE
  59 void rd_load(void);
  60 static int crd_load(struct file *fp, struct file *outfp);
  61 #endif
  62 
  63 /* Various static variables go here... mostly used within the ramdisk code only. */
  64 
  65 static int rd_length[NUM_RAMDISKS];
  66 static int rd_blocksizes[NUM_RAMDISKS];
  67 
  68 /*
  69  * Parameters for the boot-loading of the ramdisk.  These are set by
  70  * init/main.c (from arguments to the kernel command line) or from the
  71  * architecture-specific setup routine (from the stored bootsector
  72  * information). 
  73  */
  74 #ifndef MODULE
  75 int rd_doload = 0;              /* 1 = load ramdisk, 0 = don't load */
  76 int rd_prompt = 1;              /* 1 = prompt for ramdisk, 0 = don't prompt */
  77 int rd_image_start = 0;         /* starting block # of image */
  78 #endif
  79 
  80 /*
  81  *  Basically, my strategy here is to set up a buffer-head which can't be
  82  *  deleted, and make that my Ramdisk.  If the request is outside of the
  83  *  allocated size, we must get rid of it...
  84  *
  85  */
  86 static void rd_request(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  87 {
  88         unsigned int minor;
  89         int offset, len;
  90 
  91 repeat:
  92         INIT_REQUEST;
  93         
  94         minor = MINOR(CURRENT->rq_dev);
  95 
  96         if (minor >= NUM_RAMDISKS) {
  97                 end_request(0);
  98                 goto repeat;
  99         }
 100         
 101         offset = CURRENT->sector << 9;
 102         len = CURRENT->current_nr_sectors << 9;
 103 
 104         if ((offset + len) > rd_length[minor]) {
 105                 end_request(0);
 106                 goto repeat;
 107         }
 108 
 109         if (CURRENT->cmd == READ) {     
 110                 memset(CURRENT->buffer, 0, len); 
 111         }
 112         set_bit(BH_Protected, &CURRENT->bh->b_state);
 113 
 114         end_request(1);
 115         goto repeat;
 116 } 
 117 
 118 static int rd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 119 {
 120         int err;
 121         
 122         if (!inode || !inode->i_rdev)   
 123                 return -EINVAL;
 124 
 125         switch (cmd) {
 126                 case BLKFLSBUF:
 127                         if (!suser()) return -EACCES;
 128                         invalidate_buffers(inode->i_rdev);
 129                         break;
 130                 case BLKGETSIZE:   /* Return device size */
 131                         if (!arg)  return -EINVAL;
 132                         err = verify_area(VERIFY_WRITE, (long *) arg,
 133                                           sizeof(long));
 134                         if (err)
 135                                 return err;
 136                         put_user(rd_length[MINOR(inode->i_rdev)] / 512, 
 137                                  (long *) arg);
 138                         return 0;
 139                         
 140                 default:
 141                         break;
 142         };
 143 
 144         return 0;
 145 }
 146 
 147 static int rd_open(struct inode * inode, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 148 {
 149 
 150         if (DEVICE_NR(inode->i_rdev) >= NUM_RAMDISKS)
 151                 return -ENODEV;
 152 
 153         MOD_INC_USE_COUNT;
 154 
 155         return 0;
 156 }
 157 
 158 #ifdef MODULE
 159 static void rd_release(struct inode * inode, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 160 {
 161         MOD_DEC_USE_COUNT;
 162 }
 163 #endif
 164 
 165 static struct file_operations fd_fops = {
 166         NULL,           /* lseek - default */
 167         block_read,     /* read - block dev write */
 168         block_write,    /* write - block dev write */
 169         NULL,           /* readdir - not here! */
 170         NULL,           /* select */
 171         rd_ioctl,       /* ioctl */
 172         NULL,           /* mmap */
 173         rd_open,        /* open */
 174 #ifndef MODULE
 175         NULL,           /* no special release code... */
 176 #else
 177         rd_release,     /* module needs to decrement use count */
 178 #endif
 179         block_fsync             /* fsync */ 
 180 };
 181 
 182 /* This is the registration and initialization section of the ramdisk driver */
 183 int rd_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 184 {
 185         int             i;
 186 
 187         if (register_blkdev(MAJOR_NR, "ramdisk", &fd_fops)) {
 188                 printk("RAMDISK: Could not get major %d", MAJOR_NR);
 189                 return -EIO;
 190         }
 191 
 192         blk_dev[MAJOR_NR].request_fn = &rd_request;
 193 
 194         for (i = 0; i < NUM_RAMDISKS; i++) {
 195                 rd_length[i] = (16384 * 1024);
 196                 rd_blocksizes[i] = 1024;
 197         }
 198 
 199         blksize_size[MAJOR_NR] = rd_blocksizes;
 200 
 201         return 0;
 202 }
 203 
 204 #ifndef MODULE
 205 /*
 206  * This routine tries to a ramdisk image to load, and returns the
 207  * number of blocks to read for a non-compressed image, 0 if the image
 208  * is a compressed image, and -1 if an image with the right magic
 209  * numbers could not be found.
 210  *
 211  * We currently check for the following magic numbers:
 212  *      minix
 213  *      ext2
 214  *      gzip
 215  */
 216 int
 217 identify_ramdisk_image(int device, struct file *fp, int start_block)
     /* [previous][next][first][last][top][bottom][index][help] */
 218 {
 219         const int size = 512;
 220         struct minix_super_block *minixsb;
 221         struct ext2_super_block *ext2sb;
 222         int nblocks = -1;
 223         int max_blocks;
 224         unsigned char *buf;
 225 
 226         buf = kmalloc(size, GFP_KERNEL);
 227         if (buf == 0)
 228                 return -1;
 229 
 230         minixsb = (struct minix_super_block *) buf;
 231         ext2sb = (struct ext2_super_block *) buf;
 232         memset(buf, 0xe5, size);
 233 
 234         /*
 235          * Read block 0 to test for gzipped kernel
 236          */
 237         if (fp->f_op->lseek)
 238                 fp->f_op->lseek(fp->f_inode, fp, start_block * BLOCK_SIZE, 0);
 239         fp->f_pos = start_block * BLOCK_SIZE;
 240         
 241         fp->f_op->read(fp->f_inode, fp, buf, size);
 242 
 243         /*
 244          * If it matches the gzip magic numbers, return -1
 245          */
 246         if (buf[0] == 037 && ((buf[1] == 0213) || (buf[1] == 0236))) {
 247                 printk(KERN_NOTICE
 248                        "RAMDISK: Compressed image found at block %d\n",
 249                        start_block);
 250                 nblocks = 0;
 251                 goto done;
 252         }
 253 
 254         /*
 255          * Read block 1 to test for minix and ext2 superblock
 256          */
 257         if (fp->f_op->lseek)
 258                 fp->f_op->lseek(fp->f_inode, fp,
 259                                 (start_block+1) * BLOCK_SIZE, 0);
 260         fp->f_pos = (start_block+1) * BLOCK_SIZE;
 261 
 262         fp->f_op->read(fp->f_inode, fp, buf, size);
 263                 
 264         /* Try minix */
 265         if (minixsb->s_magic == MINIX_SUPER_MAGIC ||
 266             minixsb->s_magic == MINIX_SUPER_MAGIC2) {
 267                 printk(KERN_NOTICE
 268                        "RAMDISK: Minix filesystem found at block %d\n",
 269                        start_block);
 270                 nblocks = minixsb->s_nzones << minixsb->s_log_zone_size;
 271                 goto done;
 272         }
 273 
 274         /* Try ext2 */
 275         if (ext2sb->s_magic == EXT2_SUPER_MAGIC) {
 276                 printk(KERN_NOTICE
 277                        "RAMDISK: Ext2 filesystem found at block %d\n",
 278                        start_block);
 279                 nblocks = ext2sb->s_blocks_count;
 280                 goto done;
 281         }
 282         printk(KERN_NOTICE
 283                "RAMDISK: Couldn't find valid ramdisk image starting at %d.\n",
 284                start_block);
 285         
 286 done:
 287         if (fp->f_op->lseek)
 288                 fp->f_op->lseek(fp->f_inode, fp, start_block * BLOCK_SIZE, 0);
 289         fp->f_pos = start_block * BLOCK_SIZE;   
 290 
 291         if ((nblocks > 0) && blk_size[MAJOR(device)]) {
 292                 max_blocks = blk_size[MAJOR(device)][MINOR(device)];
 293                 max_blocks -= start_block;
 294                 if (nblocks > max_blocks) {
 295                         printk(KERN_NOTICE
 296                                "RAMDISK: Restricting filesystem size "
 297                                "from %d to %d blocks.\n",
 298                                nblocks, max_blocks);
 299                         nblocks = max_blocks;
 300                 }
 301         }
 302         kfree(buf);
 303         return nblocks;
 304 }
 305 
 306 /*
 307  * This routine loads in the ramdisk image.
 308  */
 309 void rd_load()
     /* [previous][next][first][last][top][bottom][index][help] */
 310 {
 311         struct inode inode, out_inode;
 312         struct file infile, outfile;
 313         unsigned short fs;
 314         int device, ram_device;
 315         int nblocks, i;
 316         char *buf;
 317         unsigned short rotate = 0;
 318         char rotator[4] = { '|' , '/' , '-' , '\\' };
 319 
 320         if (rd_doload == 0)
 321                 return;
 322         
 323         device = ROOT_DEV;
 324         ram_device = (MAJOR_NR << 8);
 325 
 326         if (MAJOR(device) != FLOPPY_MAJOR) return;
 327 
 328         if (rd_prompt) {
 329                 printk(KERN_NOTICE
 330                        "VFS: Insert ramdisk floppy and press ENTER\n");
 331                 wait_for_keypress();
 332         }
 333 
 334         memset(&infile, 0, sizeof(infile));
 335         memset(&inode, 0, sizeof(inode));
 336         inode.i_rdev = device;
 337         infile.f_mode = 1; /* read only */
 338         infile.f_inode = &inode;
 339 
 340         memset(&outfile, 0, sizeof(outfile));
 341         memset(&out_inode, 0, sizeof(out_inode));
 342         out_inode.i_rdev = ram_device;
 343         outfile.f_mode = 3; /* read/write */
 344         outfile.f_inode = &out_inode;
 345 
 346         if (blkdev_open(&inode, &infile) != 0) return;
 347         if (blkdev_open(&out_inode, &outfile) != 0) return;
 348 
 349         fs = get_fs();
 350         set_fs(KERNEL_DS);
 351         
 352         nblocks = identify_ramdisk_image(device, &infile, rd_image_start);
 353         if (nblocks < 0)
 354                 goto done;
 355 
 356         if (nblocks == 0) {
 357 #ifdef BUILD_CRAMDISK
 358                 if (crd_load(&infile, &outfile) == 0)
 359                         goto successful_load;
 360 #else
 361                 printk(KERN_NOTICE
 362                        "RAMDISK: Kernel does not support compressed "
 363                        "ramdisk images\n");
 364 #endif
 365                 goto done;
 366         }
 367 
 368         if (nblocks > (rd_length[0] >> BLOCK_SIZE_BITS)) {
 369                 printk("RAMDISK: image too big! (%d/%d blocks)\n",
 370                        nblocks, rd_length[0] >> BLOCK_SIZE_BITS);
 371                 goto done;
 372         }
 373                 
 374         /*
 375          * OK, time to copy in the data
 376          */
 377         buf = kmalloc(BLOCK_SIZE, GFP_KERNEL);
 378         if (buf == 0) {
 379                 printk(KERN_ERR "RAMDISK: could not allocate buffer\n");
 380                 goto done;
 381         }
 382 
 383         printk(KERN_NOTICE "RAMDISK: Loading %d blocks into ram disk... ", nblocks);
 384         for (i=0; i < nblocks; i++) {
 385                 infile.f_op->read(infile.f_inode, &infile, buf,
 386                                   BLOCK_SIZE);
 387                 outfile.f_op->write(outfile.f_inode, &outfile, buf,
 388                                     BLOCK_SIZE);
 389                 if (!(i % 16)) {
 390                         printk("%c\b", rotator[rotate & 0x3]);
 391                         rotate++;
 392                 }
 393         }
 394         printk("done.\n");
 395         kfree(buf);
 396 
 397 successful_load:
 398         invalidate_buffers(ROOT_DEV);
 399         ROOT_DEV = (MAJOR_NR << 8);
 400 
 401 done:
 402         if (infile.f_op->release)
 403                 infile.f_op->release(&inode, &infile);
 404         set_fs(fs);
 405 }
 406 
 407 #ifdef BUILD_CRAMDISK
 408 
 409 /*
 410  * gzip declarations
 411  */
 412 
 413 #define OF(args)  args
 414 
 415 #define memzero(s, n)     memset ((s), 0, (n))
 416 
 417 
 418 typedef unsigned char  uch;
 419 typedef unsigned short ush;
 420 typedef unsigned long  ulg;
 421 
 422 #define INBUFSIZ 4096
 423 #define WSIZE 0x8000    /* window size--must be a power of two, and */
 424                         /*  at least 32K for zip's deflate method */
 425 
 426 static uch *inbuf;
 427 static uch *window;
 428 
 429 static unsigned insize = 0;  /* valid bytes in inbuf */
 430 static unsigned inptr = 0;   /* index of next byte to be processed in inbuf */
 431 static unsigned outcnt = 0;  /* bytes in output buffer */
 432 static exit_code = 0;
 433 static long bytes_out = 0;
 434 static struct file *crd_infp, *crd_outfp;
 435 
 436 #define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
 437                 
 438 /* Diagnostic functions (stubbed out) */
 439 #define Assert(cond,msg)
 440 #define Trace(x)
 441 #define Tracev(x)
 442 #define Tracevv(x)
 443 #define Tracec(c,x)
 444 #define Tracecv(c,x)
 445 
 446 #define STATIC static
 447 
 448 static int  fill_inbuf(void);
 449 static void flush_window(void);
 450 static void *malloc(int size);
 451 static void free(void *where);
 452 static void error(char *m);
 453 static void gzip_mark(void **);
 454 static void gzip_release(void **);
 455 
 456 #include "../../lib/inflate.c"
 457 
 458 static void *malloc(int size)
     /* [previous][next][first][last][top][bottom][index][help] */
 459 {
 460         return kmalloc(size, GFP_KERNEL);
 461 }
 462 
 463 static void free(void *where)
     /* [previous][next][first][last][top][bottom][index][help] */
 464 {
 465         kfree(where);
 466 }
 467 
 468 static void gzip_mark(void **ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 469 {
 470 }
 471 
 472 static void gzip_release(void **ptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 473 {
 474 }
 475 
 476 
 477 /* ===========================================================================
 478  * Fill the input buffer. This is called only when the buffer is empty
 479  * and at least one byte is really needed.
 480  */
 481 static int fill_inbuf()
     /* [previous][next][first][last][top][bottom][index][help] */
 482 {
 483         if (exit_code) return -1;
 484         
 485         insize = crd_infp->f_op->read(crd_infp->f_inode, crd_infp,
 486                                       inbuf, INBUFSIZ);
 487         if (insize == 0) return -1;
 488 
 489         inptr = 1;
 490 
 491         return inbuf[0];
 492 }
 493 
 494 /* ===========================================================================
 495  * Write the output window window[0..outcnt-1] and update crc and bytes_out.
 496  * (Used for the decompressed data only.)
 497  */
 498 static void flush_window()
     /* [previous][next][first][last][top][bottom][index][help] */
 499 {
 500     ulg c = crc;         /* temporary variable */
 501     unsigned n;
 502     uch *in, ch;
 503     
 504     crd_outfp->f_op->write(crd_outfp->f_inode, crd_outfp, window,
 505                            outcnt);
 506     in = window;
 507     for (n = 0; n < outcnt; n++) {
 508             ch = *in++;
 509             c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
 510     }
 511     crc = c;
 512     bytes_out += (ulg)outcnt;
 513     outcnt = 0;
 514 }
 515 
 516 static void error(char *x)
     /* [previous][next][first][last][top][bottom][index][help] */
 517 {
 518         printk(KERN_ERR "%s", x);
 519         exit_code = 1;
 520 }
 521 
 522 static int
 523 crd_load(struct file * fp, struct file *outfp)
     /* [previous][next][first][last][top][bottom][index][help] */
 524 {
 525         int result;
 526         
 527         crd_infp = fp;
 528         crd_outfp = outfp;
 529         inbuf = kmalloc(INBUFSIZ, GFP_KERNEL);
 530         if (inbuf == 0) {
 531                 printk(KERN_ERR "RAMDISK: Couldn't allocate gzip buffer\n");
 532                 return -1;
 533         }
 534         window = kmalloc(WSIZE, GFP_KERNEL);
 535         if (window == 0) {
 536                 printk(KERN_ERR "RAMDISK: Couldn't allocate gzip window\n");
 537                 kfree(inbuf);
 538                 return -1;
 539         }
 540         makecrc();
 541         result = gunzip();
 542         kfree(inbuf);
 543         kfree(window);
 544         return result;
 545 }
 546 
 547 #endif  /* BUILD_CRAMDISK */
 548 
 549 #endif  /* MODULE */
 550 
 551 
 552 /* loadable module support */
 553 
 554 #ifdef MODULE
 555 
 556 int init_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 557 {
 558         int error = rd_init();
 559         if (!error)
 560                 printk(KERN_INFO "RAMDISK: Loaded as module.\n");
 561         return error;
 562 }
 563 
 564 void cleanup_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 565 {
 566         unregister_blkdev( MAJOR_NR, "ramdisk" );
 567         blk_dev[MAJOR_NR].request_fn = 0;
 568 }
 569 
 570 #endif  /* MODULE */

/* [previous][next][first][last][top][bottom][index][help] */