spull.c
上传用户:wudi5211
上传日期:2010-01-21
资源大小:607k
文件大小:17k
源码类别:

嵌入式Linux

开发平台:

C/C++

  1. /*
  2.  * spull.c -- the simple partitionable utility
  3.  *
  4.  * Tested with 2.0 on the x86, Sparc
  5.  *********/
  6. #ifndef __KERNEL__
  7. #  define __KERNEL__
  8. #endif
  9. #ifndef MODULE
  10. #  define MODULE
  11. #endif
  12. #define __NO_VERSION__ /* don't define kernel_verion in module.h */
  13. #include <linux/module.h>
  14. #include <linux/version.h>
  15. char kernel_version [] = UTS_RELEASE;
  16. #include <linux/sched.h>
  17. #include <linux/kernel.h> /* printk() */
  18. #include <linux/malloc.h> /* kmalloc() */
  19. #include <linux/fs.h>     /* everything... */
  20. #include <linux/errno.h>  /* error codes */
  21. #include <linux/timer.h>
  22. #include <linux/types.h>  /* size_t */
  23. #include <linux/fcntl.h>        /* O_ACCMODE */
  24. #include <linux/hdreg.h>  /* HDIO_GETGEO */
  25. #include <asm/system.h>   /* cli(), *_flags */
  26. #define MAJOR_NR spull_major /* force definitions on in blk.h */
  27. int spull_major; /* must be known to the compiler */
  28. #define SPULL_SHIFT 4                         /* max 16 partitions  */
  29. #define SPULL_MAXNRDEV 4                      /* max 4 device units */
  30. #define DEVICE_NR(device) (MINOR(device)>>SPULL_SHIFT)
  31. #define DEVICE_NAME "pd"                      /* name for messaging */
  32. #define DEVICE_INTR spull_intrptr             /* pointer to the bottom half */
  33. #define DEVICE_NO_RANDOM                      /* no entropy to contribute */
  34. #define DEVICE_OFF(d) /* do-nothing */
  35. #if LINUX_VERSION_CODE < 0x10324 /* 1.3.36 */
  36. #  include <linux/../../drivers/block/blk.h>
  37. #else
  38. #  include <linux/blk.h>
  39. #endif
  40. #include "spull.h"        /* local definitions */
  41. #include "sysdep.h"
  42. /* Partitionable modules can't load before 1.3.7 */
  43. #if LINUX_VERSION_CODE < VERSION_CODE(1,3,7)
  44. #error "This modules requires at least Linux 1.3.7 to load"
  45. #endif
  46. /*
  47.  * Non-prefixed symbols are static. They are meant to be assigned at
  48.  * load time. Prefixed symbols are not static, so they can be used in
  49.  * debugging. They are hidden anyways by register_symtab() unless
  50.  * SPULL_DEBUG is defined.
  51.  */
  52. static int major    = SPULL_MAJOR;
  53. static int devs     = SPULL_DEVS;
  54. static int rahead   = SPULL_RAHEAD;
  55. static int size     = SPULL_SIZE;
  56. static int irq      = 0; /* no interrupt driven by default */
  57. int spull_devs, spull_rahead, spull_size, spull_irq;
  58. /* The following items are obtained through kmalloc() in init_module() */
  59. Spull_Dev *spull_devices = NULL;
  60. int *spull_blksizes = NULL;
  61. int *spull_sizes = NULL;
  62. int spull_revalidate(kdev_t i_rdev);
  63. /*
  64.  * Our generic hard disk
  65.  */
  66. struct gendisk spull_gendisk = {
  67.     0,                /* Major number, assigned after dynamic retrieval */
  68.     "pd",             /* Major name */
  69.     SPULL_SHIFT,      /* Bits to shift to get real from partition */
  70.     1 << SPULL_SHIFT, /* Number of partitions per real */
  71.     SPULL_MAXNRDEV,   /* Maximum nr of devices */
  72.     NULL,             /* No init function (isn't called, anyways) */
  73.     NULL,             /* Partition array, allocated by init_module */
  74.     NULL,             /* Block sizes, allocated by init_module */
  75.     0,                /* Number of units: set by init_module */
  76.     NULL,             /* "real_devices" pointer: not used */
  77.     NULL              /* Next */
  78. };
  79. struct hd_struct *spull_partitions = NULL;
  80. /*
  81.  * Open and close
  82.  */
  83. int spull_open (struct inode *inode, struct file *filp)
  84. {
  85.     Spull_Dev *dev; /* device information */
  86.     int num = DEVICE_NR(inode->i_rdev); /* the real device */
  87.     if (num >= spull_devs) return -ENODEV;
  88.     dev = spull_devices + num;
  89.     /* and use filp->private_data to point to the device data */
  90.     filp->private_data = dev;
  91.     /* kill the timer associated to the device: it might be active */
  92.     del_timer(&dev->timer);
  93.     /*
  94.      * If no data area is there, allocate it. Clear its head as
  95.      * well to prevent memory corruption due to bad partition info.
  96.      */
  97.     if (!dev->data) {
  98.         dev->data = vmalloc(dev->size);
  99.         memset(dev->data,0,2048);
  100.     }
  101.     if (!dev->data)
  102.         return -ENOMEM;
  103.     dev->usage++;
  104.     MOD_INC_USE_COUNT;
  105.     return 0;          /* success */
  106. }
  107. void spull_release (struct inode *inode, struct file *filp)
  108. {
  109.     Spull_Dev *dev = spull_devices + DEVICE_NR(inode->i_rdev);
  110.     dev->usage--;
  111.     /*
  112.      * Leave one minute timeout before deallocating the device.
  113.      */
  114.     if (!dev->usage) {
  115.         dev->timer.expires = jiffies + 60 * HZ;
  116.         add_timer(&dev->timer);
  117.         /* but flush it right now */
  118.         fsync_dev(inode->i_rdev);
  119.         invalidate_buffers(inode->i_rdev);
  120.     }
  121.     fsync_dev(inode->i_rdev);
  122.     invalidate_buffers(inode->i_rdev);
  123.     MOD_DEC_USE_COUNT;
  124. }
  125. /*
  126.  * The timer function. As argument it receives the device
  127.  */
  128. void spull_expires(unsigned long data)
  129. {
  130.     Spull_Dev *dev = (Spull_Dev *)data;
  131.     if (dev->usage || !dev->data) {
  132.         printk(KERN_WARNING "spull: timer mismatch for device %in",
  133.                dev - spull_devices);
  134.         return;
  135.     }
  136.     PDEBUG("freeing device %in",dev - spull_devices);
  137.     vfree(dev->data);
  138.     dev->data=0;
  139.     return;
  140. }    
  141. /*
  142.  * The ioctl() implementation
  143.  */
  144. int spull_ioctl (struct inode *inode, struct file *filp,
  145.                  unsigned int cmd, unsigned long arg)
  146. {
  147.     int err, size;
  148.     struct hd_geometry *geo = (struct hd_geometry *)arg;
  149.     PDEBUG("ioctl 0x%x 0x%lxn", cmd, arg);
  150.     switch(cmd) {
  151.       case BLKGETSIZE:
  152.         /* Return the device size, expressed in sectors */
  153.         if (!arg) return -EINVAL; /* NULL pointer: not valid */
  154.         err=verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
  155.         if (err) return err;
  156.         size = spull_gendisk.part[MINOR(inode->i_rdev)].nr_sects;
  157.         put_user (size, (long *) arg);
  158.         return 0;
  159.       case BLKFLSBUF: /* flush */
  160.         if (!suser()) return -EACCES; /* only root */
  161.         fsync_dev(inode->i_rdev);
  162.         invalidate_buffers(inode->i_rdev);
  163.         return 0;
  164.       case BLKRAGET: /* return the readahead value */
  165.         if (!arg)  return -EINVAL;
  166.         err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
  167.         if (err) return err;
  168.         put_user(read_ahead[MAJOR(inode->i_rdev)],(long *) arg);
  169.         return 0;
  170.       case BLKRASET: /* set the readahead value */
  171.         if (!suser()) return -EACCES;
  172.         if (arg > 0xff) return -EINVAL; /* limit it */
  173.         read_ahead[MAJOR(inode->i_rdev)] = arg;
  174.         return 0;
  175.       case BLKRRPART: /* re-read partition table: fake a disk change */
  176.         return spull_revalidate(inode->i_rdev);
  177.       RO_IOCTLS(inode->i_rdev, arg); /* the default RO operations */
  178.       case HDIO_GETGEO:
  179.         /*
  180.          * get geometry: we have to fake one...  trim the size to a
  181.          * multiple of 64 (32k): tell we have 16 sectors, 4 heads,
  182.          * whatever cylinders. Tell also that data starts at sector 4.
  183.          */
  184.         size = spull_size * 2; /* 2 sectors per kilobyte */
  185.         size &= ~0x3f; /* multiple of 64 */
  186.         if (geo==NULL) return -EINVAL;
  187.         err = verify_area(VERIFY_WRITE, geo, sizeof(*geo));
  188.         if (err) return err;
  189.         put_user(size >> 6, &geo->cylinders);
  190.         put_user(        4, &geo->heads);
  191.         put_user(       16, &geo->sectors);
  192.         put_user(        4, &geo->start);
  193.         return 0;
  194.     }
  195.     return -EINVAL; /* unknown command */
  196. }
  197. /*
  198.  * Support for removable devices
  199.  */
  200. int spull_check_change(kdev_t i_rdev)
  201. {
  202.     int devnr = DEVICE_NR(i_rdev);
  203.     Spull_Dev *dev = spull_devices + devnr;
  204.     if (devnr >= spull_devs) /* paranoid */
  205.         return 0;
  206.     PDEBUG("check_change for dev %in",MINOR(i_rdev));
  207.     if (dev->data)
  208.         return 0; /* still valid */
  209.     return 1; /* expired */
  210. }
  211. int spull_revalidate(kdev_t i_rdev)
  212. {
  213.     /* first partition, # of partitions */
  214.     int part1 = (DEVICE_NR(i_rdev) << SPULL_SHIFT) + 1;
  215.     int npart = (1 << SPULL_SHIFT) -1;
  216.     /* first clear old partition information */
  217.     memset(spull_gendisk.sizes+part1, 0, npart*sizeof(int));
  218.     memset(spull_gendisk.part +part1, 0, npart*sizeof(struct hd_struct));
  219.     /* then fill new info */
  220.     printk(KERN_INFO "Spull partition check: ");
  221.     resetup_one_dev(&spull_gendisk, DEVICE_NR(i_rdev));
  222.     return 0;
  223. }
  224. /*
  225.  * The file operations
  226.  */
  227. struct file_operations spull_fops = {
  228.     NULL,          /* lseek: default */
  229.     block_read,
  230.     block_write,
  231.     NULL,          /* spull_readdir */
  232.     NULL,          /* spull_select */
  233.     spull_ioctl,
  234.     NULL,          /* spull_mmap */
  235.     spull_open,
  236.     spull_release,
  237.     block_fsync,
  238.     NULL,          /* spull_fasync */
  239.     spull_check_change,
  240.     spull_revalidate
  241. };
  242. /*
  243.  * Block-driver specific functions
  244.  */
  245. void spull_request(void)
  246. {
  247.     Spull_Dev *device;
  248.     u8 *ptr;
  249.     int size, minor, devnr;
  250.     while(1) {
  251.         INIT_REQUEST;
  252.         devnr = DEVICE_NR(CURRENT_DEV);
  253.         minor = MINOR(CURRENT_DEV);
  254.         /* Check if the minor number is in range */
  255.         if (devnr > spull_devs) {
  256.             static int count = 0;
  257.             if (count++ < 5) /* print the message at most five times */
  258.                 printk(KERN_WARNING "spull: request for inexistent devicen");
  259.             end_request(0);
  260.             continue;
  261.         }
  262.         PDEBUGG("cmd %c for minor 0x%02x ( sec%li)n",
  263.                CURRENT->cmd==READ ? 'r' : 'w', minor,CURRENT->sector);
  264.         device = spull_devices + devnr;
  265. /* the sector size is 512 bytes */
  266.         ptr = device->data +
  267.             512 * (spull_partitions[minor].start_sect + CURRENT->sector);
  268.         size = CURRENT->current_nr_sectors * 512;
  269.         if (CURRENT->sector + CURRENT->current_nr_sectors >
  270.                 spull_gendisk.part[minor].nr_sects) {
  271.             printk(KERN_WARNING "spull: request past end of devicen");
  272.             end_request(0);
  273.             continue;
  274.         }
  275.         switch(CURRENT->cmd) {
  276.           case READ:
  277.             memcpy(CURRENT->buffer, ptr, size); /* from spull to buffer */
  278.             break;
  279.           case WRITE:
  280.             memcpy(ptr, CURRENT->buffer, size); /* from buffer to spull */
  281.             break;
  282.           default:
  283.             /* can't happen */
  284.             end_request(0);
  285.             continue;
  286.         }
  287.         end_request(1); /* success */
  288.     }
  289. }
  290. /*
  291.  * The fake interrupt-driven request
  292.  */
  293. struct timer_list spull_timer; /* the engine for async invocation */
  294. void spull_irqdriven_request(void)
  295. {
  296.     Spull_Dev *device;
  297.     u8 *ptr;
  298.     int size, minor, devnr;
  299.     /*
  300.      * Check for errors and start data transfer for the current request.
  301.      * The spull ramdisk performs the transfer right ahead,
  302.      * but delays acknolegment using a kernel timer.
  303.      */
  304.     while(1) {
  305.         INIT_REQUEST;
  306.         devnr = DEVICE_NR(CURRENT_DEV);
  307.         minor = MINOR(CURRENT_DEV);
  308.         /* then the core of the function is unchanged.... */
  309.         /* Check if the minor number is in range */
  310.         if (devnr > spull_devs) {
  311.             static int count = 0;
  312.             if (count++ < 5) /* print the message at most five times */
  313.                 printk(KERN_WARNING "spull: request for inexistent devicen");
  314.             end_request(0);
  315.             continue;
  316.         }
  317.         PDEBUGG("cmd %c for minor 0x%02x ( sec%li)n",
  318.                CURRENT->cmd==READ ? 'r' : 'w', minor,CURRENT->sector);
  319.         device = spull_devices + devnr;
  320.         ptr = device->data +
  321.             512 * (spull_partitions[minor].start_sect + CURRENT->sector);
  322.         size = CURRENT->current_nr_sectors * 512;
  323.         if (CURRENT->sector + CURRENT->current_nr_sectors >
  324.                 spull_gendisk.part[minor].nr_sects) {
  325.             printk(KERN_WARNING "spull: request past end of devicen");
  326.             end_request(0);
  327.             continue;
  328.         }
  329. /* ... and this is how the function completes: xfer now ... */
  330.         switch(CURRENT->cmd) {
  331.           case READ:
  332.             memcpy(CURRENT->buffer, ptr, size);
  333.             break;
  334.           case WRITE:
  335.             memcpy(ptr, CURRENT->buffer, size);
  336.             break;
  337.           default: /* should't happen */
  338.             end_request(0);
  339.             continue;
  340.         }
  341.         /* ... and wait for the timer to expire -- no end_request(1) */
  342.         spull_timer.expires = jiffies + spull_irq;
  343.         add_timer(&spull_timer);
  344.         return;
  345.     }
  346. }
  347. /* this is invoked when the timer expires */
  348. void spull_interrupt(unsigned long unused)
  349. {
  350.      /*
  351.       * arg to end_request(), default to success, a real device might
  352.       * signal a failure, if it detects one
  353.       */
  354.     int fulfilled = 1;
  355.     end_request(fulfilled);    /* done one */
  356.     if (CURRENT) /* more of them? */
  357.         spull_irqdriven_request();  /* schedule the next */
  358. }
  359. /*
  360.  * Finally, the module stuff
  361.  */
  362. int init_module(void)
  363. {
  364.     int result, i;
  365.     /*
  366.      * Copy the (static) cfg variables to public prefixed ones to allow
  367.      * snoozing with a debugger.
  368.      */
  369.     spull_major    = major;
  370.     spull_devs     = devs;
  371.     spull_rahead   = rahead;
  372.     spull_size     = size;
  373.     /*
  374.      * Register your major, and accept a dynamic number
  375.      */
  376.     result = register_blkdev(spull_major, "spull", &spull_fops);
  377.     if (result < 0) {
  378.         printk(KERN_WARNING "spull: can't get major %dn",spull_major);
  379.         return result;
  380.     }
  381.     if (spull_major == 0) spull_major = result; /* dynamic */
  382.     major = spull_major; /* Use `major' later on to save typing */
  383.     spull_gendisk.major = major; /* was unknown at load time */
  384.     /* 
  385.      * allocate the devices -- we can't have them static, as the number
  386.      * can be specified at load time
  387.      */
  388.     spull_devices = kmalloc(spull_devs * sizeof (Spull_Dev), GFP_KERNEL);
  389.     if (!spull_devices)
  390.         goto fail_malloc;
  391.     memset(spull_devices, 0, spull_devs * sizeof (Spull_Dev));
  392.     for (i=0; i < spull_devs; i++) {
  393.         /* data and usage remain zeroed */
  394.         spull_devices[i].size = 1024 * spull_size;
  395.         init_timer(&(spull_devices[i].timer));
  396.         spull_devices[i].timer.data = (unsigned long)(spull_devices+i);
  397.         spull_devices[i].timer.function = spull_expires;
  398.     }
  399.     blk_dev[major].request_fn = spull_request;
  400.     read_ahead[major] = spull_rahead;
  401.     result = -ENOMEM; /* for the possible errors */
  402.     /* Prepare the `size' array and zero it. */
  403.     spull_sizes = kmalloc( (spull_devs << SPULL_SHIFT) * sizeof(int),
  404.                           GFP_KERNEL);
  405.     if (!spull_sizes)
  406.         goto fail_malloc;
  407.     /* Start with zero-sized partitions, and correctly sized units */
  408.     memset(spull_sizes, 0, (spull_devs << SPULL_SHIFT) * sizeof(int));
  409.     for (i=0; i< spull_devs; i++)
  410.         spull_sizes[i<<SPULL_SHIFT] = spull_size;
  411.     blk_size[MAJOR_NR] = spull_gendisk.sizes = spull_sizes;
  412.     /* Allocate the partitions, and refer the array in spull_gendisk. */
  413.     spull_partitions = kmalloc( (spull_devs << SPULL_SHIFT) *
  414.                                sizeof(struct hd_struct), GFP_KERNEL);
  415.     if (!spull_partitions)
  416.         goto fail_malloc;
  417.     memset(spull_partitions, 0, (spull_devs << SPULL_SHIFT) *
  418.            sizeof(struct hd_struct));
  419.     /* fill whole-disk entries */
  420.     for (i=0; i < spull_devs; i++) {
  421.         /* start_sect is already 0, and sects are 512 bytes long */
  422.         spull_partitions[i << SPULL_SHIFT].nr_sects = 2 * spull_size;
  423.     }
  424.     spull_gendisk.part = spull_partitions;
  425. #if 0
  426.     /*
  427.      * Well, now a *real* driver should call resetup_one_dev().
  428.      * Avoid it here, as there's no allocated data in spull yet.
  429.      */
  430.     for (i=0; i< spull_devs; i++) {
  431.         printk(KERN INFO "Spull partition check: ");
  432.         resetup_one_dev(&spull_gendisk, i);
  433.     }
  434. #endif
  435.     /* dump the partition table to see it */
  436.     for (i=0; i < spull_devs << SPULL_SHIFT; i++)
  437.         PDEBUGG("part %i: beg %lx, size %lxn", i,
  438.                spull_partitions[i].start_sect,
  439.                spull_partitions[i].nr_sects);
  440. #ifndef SPULL_DEBUG
  441.     register_symtab(NULL); /* otherwise, leave global symbols visible */
  442. #endif
  443.     /*
  444.      * Allow interrupt-driven operation, if "irq=" has been specified
  445.      */
  446.     spull_irq = irq; /* copy the static variable to the visible one */
  447.     if (spull_irq) {
  448.         PDEBUG("setting timern");
  449.         spull_timer.function = spull_interrupt;
  450.         blk_dev[major].request_fn = spull_irqdriven_request;
  451.     }
  452.     
  453.     return 0; /* succeed */
  454.   fail_malloc:
  455.     read_ahead[major] = 0;
  456.     if (spull_sizes) kfree(spull_sizes);
  457.     blk_size[major] = NULL;
  458.     if (spull_partitions) kfree(spull_partitions);
  459.     if (spull_devices) kfree(spull_devices);
  460.     unregister_chrdev(major, "spull");
  461.     return result;
  462. }
  463. void cleanup_module(void)
  464. {
  465.     int i;
  466.     /* first of all, flush it all and reset all the data structures */
  467.     for (i = 0; i < (spull_devs << SPULL_SHIFT); i++)
  468.         fsync_dev(MKDEV(spull_major, i)); /* flush the devices */
  469.     blk_dev[major].request_fn = NULL;
  470.     read_ahead[major] = 0;
  471.     kfree(blk_size[major]); /* which is gendisk->sizes as well */
  472.     blk_size[major] = NULL;
  473.     kfree(spull_gendisk.part);
  474.     /* finally, the usual cleanup */
  475.     unregister_blkdev(major, "spull");
  476.     for (i=0; i < spull_devs; i++) {
  477.         if (spull_devices[i].data)
  478.             vfree(spull_devices[i].data);
  479.         del_timer(&spull_devices[i].timer);
  480.     }
  481.     kfree(spull_devices);
  482. }