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

嵌入式Linux

开发平台:

C/C++

  1. /*
  2.  * spull.c -- the Simple Partitionable Utility
  3.  *
  4.  * $Id: spull.c,v 1.15 2001/07/11 08:46:55 rubini Exp $
  5.  *********/
  6. #ifndef __KERNEL__
  7. #  define __KERNEL__
  8. #endif
  9. #ifndef MODULE
  10. #  define MODULE
  11. #endif
  12. #include <linux/config.h>
  13. #include <linux/module.h>
  14. #include <linux/sched.h>
  15. #include <linux/kernel.h> /* printk() */
  16. #include <linux/malloc.h> /* kmalloc() */
  17. #include <linux/fs.h>     /* everything... */
  18. #include <linux/errno.h>  /* error codes */
  19. #include <linux/timer.h>
  20. #include <linux/types.h>  /* size_t */
  21. #include <linux/fcntl.h>        /* O_ACCMODE */
  22. #include <linux/hdreg.h>  /* HDIO_GETGEO */
  23. #include <asm/system.h>   /* cli(), *_flags */
  24. #define MAJOR_NR spull_major /* force definitions on in blk.h */
  25. int spull_major; /* must be declared before including blk.h */
  26. #define SPULL_SHIFT 4                         /* max 16 partitions  */
  27. #define SPULL_MAXNRDEV 4                      /* max 4 device units */
  28. #define DEVICE_NR(device) (MINOR(device)>>SPULL_SHIFT)
  29. #define DEVICE_NAME "pd"                      /* name for messaging */
  30. #define DEVICE_INTR spull_intrptr         /* pointer to the bottom half */
  31. #define DEVICE_NO_RANDOM                  /* no entropy to contribute */
  32. #define DEVICE_REQUEST spull_request
  33. #define DEVICE_OFF(d) /* do-nothing */
  34. #include <linux/blk.h>
  35. #include "spull.h"        /* local definitions */
  36. #ifdef HAVE_BLKPG_H
  37. #include <linux/blkpg.h>  /* blk_ioctl() */
  38. #endif
  39. /*
  40.  * Non-prefixed symbols are static. They are meant to be assigned at
  41.  * load time. Prefixed symbols are not static, so they can be used in
  42.  * debugging. They are hidden anyways by register_symtab() unless
  43.  * SPULL_DEBUG is defined.
  44.  */
  45. static int major    = SPULL_MAJOR;
  46. static int devs     = SPULL_DEVS;
  47. static int rahead   = SPULL_RAHEAD;
  48. static int size     = SPULL_SIZE;
  49. static int irq      = 0;
  50. static int blksize  = SPULL_BLKSIZE;
  51. MODULE_PARM(major, "i");
  52. MODULE_PARM(devs, "i");
  53. MODULE_PARM(rahead, "i");
  54. MODULE_PARM(size, "i");
  55. MODULE_PARM(blksize, "i");
  56. MODULE_PARM(irq, "i");
  57. MODULE_AUTHOR("Alessandro Rubini");
  58. int spull_devs, spull_rahead, spull_size;
  59. int spull_blksize, spull_irq;
  60. /* The following items are obtained through kmalloc() in spull_init() */
  61. Spull_Dev *spull_devices = NULL;
  62. int *spull_sizes = NULL;
  63. /* Forwards */
  64. int spull_revalidate(kdev_t i_rdev);
  65. #ifdef LINUX_24
  66. struct block_device_operations spull_bdops;
  67. #endif
  68. /*
  69.  * Time for our genhd structure.
  70.  */
  71. struct gendisk spull_gendisk = {
  72.     major:              0,              /* Major number assigned later */
  73.     major_name:         "pd",           /* Name of the major device */
  74.     minor_shift:        SPULL_SHIFT,    /* Shift to get device number */
  75.     max_p:              1 << SPULL_SHIFT, /* Number of partitions */
  76. #ifdef LINUX_24                         
  77.     fops:               &spull_bdops,   /* Block dev operations */
  78. #endif                                  
  79. /* everything else is dynamic */
  80. };
  81. struct hd_struct *spull_partitions = NULL;
  82. /*
  83.  * Flag used in "irq driven" mode to mark when we have operations
  84.  * outstanding.
  85.  */
  86. volatile int spull_busy = 0;
  87. /*
  88.  * Open and close
  89.  */
  90. int spull_open (struct inode *inode, struct file *filp)
  91. {
  92.     Spull_Dev *dev; /* device information */
  93.     int num = DEVICE_NR(inode->i_rdev);
  94.     if (num >= spull_devs) return -ENODEV;
  95.     dev = spull_devices + num;
  96.     /* kill the timer associated to the device: it might be active */
  97.     del_timer(&dev->timer);
  98.     spin_lock(&dev->lock);
  99.     /*
  100.      * If no data area is there, allocate it. Clear its head as
  101.      * well to prevent memory corruption due to bad partition info.
  102.      */
  103.     if (!dev->data) {
  104.         dev->data = vmalloc(dev->size);
  105.         memset(dev->data,0,2048);
  106.     }
  107.     if (!dev->data)
  108.     {
  109.         spin_unlock(&dev->lock);
  110.         return -ENOMEM;
  111.     }
  112.     
  113.     dev->usage++;
  114.     MOD_INC_USE_COUNT;
  115.     spin_unlock(&dev->lock);
  116.     return 0;          /* success */
  117. }
  118. int spull_release (struct inode *inode, struct file *filp)
  119. {
  120.     Spull_Dev *dev = spull_devices + DEVICE_NR(inode->i_rdev);
  121.     spin_lock(&dev->lock);
  122.     dev->usage--;
  123.     /*
  124.      * If the device is closed for the last time, start a timer
  125.      * to release RAM in half a minute. The function and argument
  126.      * for the timer have been setup in spull_init()
  127.      */
  128.     if (!dev->usage) {
  129.         dev->timer.expires = jiffies + 60 * HZ;
  130.         add_timer(&dev->timer);
  131.         /* but flush it right now */
  132.         fsync_dev(inode->i_rdev);
  133.         invalidate_buffers(inode->i_rdev);
  134.     }
  135.     MOD_DEC_USE_COUNT;
  136.     spin_unlock(&dev->lock);
  137.     return 0;
  138. }
  139. /*
  140.  * The timer function. As argument it receives the device
  141.  */
  142. void spull_expires(unsigned long data)
  143. {
  144.     Spull_Dev *dev = (Spull_Dev *)data;
  145.     spin_lock(&dev->lock);
  146.     if (dev->usage || !dev->data) {
  147.         spin_unlock(&dev->lock);
  148.         printk(KERN_WARNING "spull: timer mismatch for device %in",
  149.                dev - spull_devices);
  150.         return;
  151.     }
  152.     PDEBUG("freeing device %in",dev - spull_devices);
  153.     vfree(dev->data);
  154.     dev->data=0;
  155.     spin_unlock(&dev->lock);
  156.     return;
  157. }    
  158. /*
  159.  * The ioctl() implementation
  160.  */
  161. int spull_ioctl (struct inode *inode, struct file *filp,
  162.                  unsigned int cmd, unsigned long arg)
  163. {
  164.     int err, size;
  165.     struct hd_geometry geo;
  166.     PDEBUG("ioctl 0x%x 0x%lxn", cmd, arg);
  167.     switch(cmd) {
  168.       case BLKGETSIZE:
  169.         /* Return the device size, expressed in sectors */
  170.         err = ! access_ok (VERIFY_WRITE, arg, sizeof(long));
  171.         if (err) return -EFAULT;
  172.         size = spull_gendisk.part[MINOR(inode->i_rdev)].nr_sects;
  173. if (copy_to_user((long *) arg, &size, sizeof (long)))
  174.     return -EFAULT;
  175.         return 0;
  176.       case BLKFLSBUF: /* flush */
  177.         if (! capable(CAP_SYS_RAWIO)) return -EACCES; /* only root */
  178.         fsync_dev(inode->i_rdev);
  179.         invalidate_buffers(inode->i_rdev);
  180.         return 0;
  181.       case BLKRAGET: /* return the readahead value */
  182.         err = ! access_ok(VERIFY_WRITE, arg, sizeof(long));
  183.         if (err) return -EFAULT;
  184.         PUT_USER(read_ahead[MAJOR(inode->i_rdev)],(long *) arg);
  185.         return 0;
  186.       case BLKRASET: /* set the readahead value */
  187.         if (!capable(CAP_SYS_RAWIO)) return -EACCES;
  188.         if (arg > 0xff) return -EINVAL; /* limit it */
  189.         read_ahead[MAJOR(inode->i_rdev)] = arg;
  190.         return 0;
  191.       case BLKRRPART: /* re-read partition table */
  192.         return spull_revalidate(inode->i_rdev);
  193.       case HDIO_GETGEO:
  194.         /*
  195.          * get geometry: we have to fake one...  trim the size to a
  196.          * multiple of 64 (32k): tell we have 16 sectors, 4 heads,
  197.          * whatever cylinders. Tell also that data starts at sector. 4.
  198.          */
  199.         err = ! access_ok(VERIFY_WRITE, arg, sizeof(geo));
  200.         if (err) return -EFAULT;
  201.         size = spull_size * blksize / SPULL_HARDSECT;
  202.         geo.cylinders = (size & ~0x3f) >> 6;
  203. geo.heads = 4;
  204. geo.sectors = 16;
  205. geo.start = 4;
  206. if (copy_to_user((void *) arg, &geo, sizeof(geo)))
  207.     return -EFAULT;
  208.         return 0;
  209.       default:
  210.         /*
  211.          * For ioctls we don't understand, let the block layer handle them.
  212.          */
  213.         return blk_ioctl(inode->i_rdev, cmd, arg);
  214.     }
  215.     return -ENOTTY; /* unknown command */
  216. }
  217. /*
  218.  * Support for removable devices
  219.  */
  220. int spull_check_change(kdev_t i_rdev)
  221. {
  222.     int minor = DEVICE_NR(i_rdev);
  223.     Spull_Dev *dev = spull_devices + minor;
  224.     if (minor >= spull_devs) /* paranoid */
  225.         return 0;
  226.     PDEBUG("check_change for dev %in",minor);
  227.     if (dev->data)
  228.         return 0; /* still valid */
  229.     return 1; /* expired */
  230. }
  231. /*
  232.  * The file operations
  233.  */
  234. #ifdef LINUX_24
  235. struct block_device_operations spull_bdops = {
  236.     open:       spull_open,
  237.     release:    spull_release,
  238.     ioctl:      spull_ioctl,
  239.     revalidate: spull_revalidate,
  240.     check_media_change: spull_check_change,
  241. };
  242. #else
  243. #ifdef LINUX_20
  244. void spull_release_20 (struct inode *inode, struct file *filp)
  245. {
  246.         (void) spull_release (inode, filp);
  247. }
  248. #define spull_release spull_release_20
  249. #endif
  250. struct file_operations spull_bdops = {
  251.     read:       block_read,
  252.     write:      block_write,
  253.     ioctl:      spull_ioctl,
  254.     open:       spull_open,
  255.     release:    spull_release,
  256.     fsync:      block_fsync,
  257.     check_media_change: spull_check_change,
  258.     revalidate: spull_revalidate
  259. };
  260. # endif /* LINUX_24 */
  261. /*
  262.  * Note no locks taken out here.  In a worst case scenario, we could drop
  263.  * a chunk of system memory.  But that should never happen, since validation
  264.  * happens at open or mount time, when locks are held.
  265.  */
  266. int spull_revalidate(kdev_t i_rdev)
  267. {
  268.     /* first partition, # of partitions */
  269.     int part1 = (DEVICE_NR(i_rdev) << SPULL_SHIFT) + 1;
  270.     int npart = (1 << SPULL_SHIFT) -1;
  271.     /* first clear old partition information */
  272.     memset(spull_gendisk.sizes+part1, 0, npart*sizeof(int));
  273.     memset(spull_gendisk.part +part1, 0, npart*sizeof(struct hd_struct));
  274.     spull_gendisk.part[DEVICE_NR(i_rdev) << SPULL_SHIFT].nr_sects =
  275.             spull_size << 1;
  276.     /* then fill new info */
  277.     printk(KERN_INFO "Spull partition check: (%d) ", DEVICE_NR(i_rdev));
  278.     register_disk(&spull_gendisk, i_rdev, SPULL_MAXNRDEV, &spull_bdops,
  279.                     spull_size << 1);
  280.     return 0;
  281. }
  282. /*
  283.  * Block-driver specific functions
  284.  */
  285. /*
  286.  * Find the device for this request.
  287.  */
  288. static Spull_Dev *spull_locate_device(const struct request *req)
  289. {
  290.     int devno;
  291.     Spull_Dev *device;
  292.     /* Check if the minor number is in range */
  293.     devno = DEVICE_NR(req->rq_dev);
  294.     if (devno >= spull_devs) {
  295.         static int count = 0;
  296.         if (count++ < 5) /* print the message at most five times */
  297.             printk(KERN_WARNING "spull: request for unknown devicen");
  298.         return NULL;
  299.     }
  300.     device = spull_devices + devno;
  301.     return device;
  302. }
  303. /*
  304.  * Perform an actual transfer.
  305.  */
  306. static int spull_transfer(Spull_Dev *device, const struct request *req)
  307. {
  308.     int size, minor = MINOR(req->rq_dev);
  309.     u8 *ptr;
  310.     
  311.     ptr = device->data +
  312.             (spull_partitions[minor].start_sect + req->sector)*SPULL_HARDSECT;
  313.     size = req->current_nr_sectors*SPULL_HARDSECT;
  314.     /*
  315.      * Make sure that the transfer fits within the device.
  316.      */
  317.     if (req->sector + req->current_nr_sectors >
  318.                     spull_partitions[minor].nr_sects) {
  319.         static int count = 0;
  320.         if (count++ < 5)
  321.             printk(KERN_WARNING "spull: request past end of partitionn");
  322.         return 0;
  323.     }
  324.     /*
  325.      * Looks good, do the transfer.
  326.      */
  327.     switch(req->cmd) {
  328.         case READ:
  329.             memcpy(req->buffer, ptr, size); /* from spull to buffer */
  330.             return 1;
  331.         case WRITE:
  332.             memcpy(ptr, req->buffer, size); /* from buffer to spull */
  333.             return 1;
  334.         default:
  335.             /* can't happen */
  336.             return 0;
  337.         }
  338. }
  339. #ifdef LINUX_24
  340. void spull_request(request_queue_t *q)
  341. #else           
  342. void spull_request()
  343. #endif  
  344. {
  345.     Spull_Dev *device;
  346.     int status;
  347.     long flags;
  348.     while(1) {
  349.         INIT_REQUEST;  /* returns when queue is empty */
  350.         /* Which "device" are we using?  (Is returned locked) */
  351.         device = spull_locate_device (CURRENT);
  352.         if (device == NULL) {
  353.             end_request(0);
  354.             continue;
  355.         }
  356. spin_lock_irqsave(&device->lock, flags);
  357.         /* Perform the transfer and clean up. */
  358.         status = spull_transfer(device, CURRENT);
  359.         spin_unlock_irqrestore(&device->lock, flags);
  360.         end_request(status); /* success */
  361.     }
  362. }
  363. /*
  364.  * The fake interrupt-driven request
  365.  */
  366. struct timer_list spull_timer; /* the engine for async invocation */
  367. #ifdef LINUX_24
  368. void spull_irqdriven_request(request_queue_t *q)
  369. #else                                           
  370. void spull_irqdriven_request()                  
  371. #endif                                          
  372. {
  373.     Spull_Dev *device;
  374.     int status;
  375.     long flags;
  376.     /* If we are already processing requests, don't do any more now. */
  377.     if (spull_busy)
  378.             return;
  379.     while(1) {
  380.         INIT_REQUEST;  /* returns when queue is empty */
  381.         /* Which "device" are we using? */
  382.         device = spull_locate_device (CURRENT);
  383.         if (device == NULL) {
  384.             end_request(0);
  385.             continue;
  386.         }
  387. spin_lock_irqsave(&device->lock, flags);
  388.         /* Perform the transfer and clean up. */
  389.         status = spull_transfer(device, CURRENT);
  390.         spin_unlock_irqrestore(&device->lock, flags);
  391.         /* ... and wait for the timer to expire -- no end_request(1) */
  392.         spull_timer.expires = jiffies + spull_irq;
  393.         add_timer(&spull_timer);
  394.         spull_busy = 1;
  395.         return;
  396.     }
  397. }
  398. /* this is invoked when the timer expires */
  399. void spull_interrupt(unsigned long unused)
  400. {
  401.     unsigned long flags;
  402.     spin_lock_irqsave(&io_request_lock, flags);
  403.     end_request(1);    /* This request is done - we always succeed */
  404.     spull_busy = 0;  /* We have io_request_lock, no conflict with request */
  405.     if (! QUEUE_EMPTY) /* more of them? */
  406. #ifdef LINUX_24                         
  407.         spull_irqdriven_request(NULL);  /* Start the next transfer */
  408. #else                                   
  409.         spull_irqdriven_request();      
  410. #endif                                  
  411.     spin_unlock_irqrestore(&io_request_lock, flags);
  412. }
  413. /*
  414.  * Finally, the module stuff
  415.  */
  416. int spull_init(void)
  417. {
  418.     int result, i;
  419.     /*
  420.      * Copy the (static) cfg variables to public prefixed ones to allow
  421.      * snoozing with a debugger.
  422.      */
  423.     spull_major    = major;
  424.     spull_devs     = devs;
  425.     spull_rahead   = rahead;
  426.     spull_size     = size;
  427.     spull_blksize  = blksize;
  428.     /*
  429.      * Register your major, and accept a dynamic number
  430.      */
  431.     result = register_blkdev(spull_major, "spull", &spull_bdops);
  432.     if (result < 0) {
  433.         printk(KERN_WARNING "spull: can't get major %dn",spull_major);
  434.         return result;
  435.     }
  436.     if (spull_major == 0) spull_major = result; /* dynamic */
  437.     major = spull_major; /* Use `major' later on to save typing */
  438.     spull_gendisk.major = major; /* was unknown at load time */
  439.     /* 
  440.      * allocate the devices -- we can't have them static, as the number
  441.      * can be specified at load time
  442.      */
  443.     spull_devices = kmalloc(spull_devs * sizeof (Spull_Dev), GFP_KERNEL);
  444.     if (!spull_devices)
  445.         goto fail_malloc;
  446.     memset(spull_devices, 0, spull_devs * sizeof (Spull_Dev));
  447.     for (i=0; i < spull_devs; i++) {
  448.         /* data and usage remain zeroed */
  449.         spull_devices[i].size = blksize * spull_size;
  450.         init_timer(&(spull_devices[i].timer));
  451.         spull_devices[i].timer.data = (unsigned long)(spull_devices+i);
  452.         spull_devices[i].timer.function = spull_expires;
  453.         spin_lock_init(&spull_devices[i].lock);
  454.     }
  455.     /*
  456.      * Assign the other needed values: request, rahead, size, blksize,
  457.      * hardsect. All the minor devices feature the same value.
  458.      * Note that `spull' defines all of them to allow testing non-default
  459.      * values. A real device could well avoid setting values in global
  460.      * arrays if it uses the default values.
  461.      */
  462.     read_ahead[major] = spull_rahead;
  463.     result = -ENOMEM; /* for the possible errors */
  464.     spull_sizes = kmalloc( (spull_devs << SPULL_SHIFT) * sizeof(int),
  465.                           GFP_KERNEL);
  466.     if (!spull_sizes)
  467.         goto fail_malloc;
  468.     /* Start with zero-sized partitions, and correctly sized units */
  469.     memset(spull_sizes, 0, (spull_devs << SPULL_SHIFT) * sizeof(int));
  470.     for (i=0; i< spull_devs; i++)
  471.         spull_sizes[i<<SPULL_SHIFT] = spull_size;
  472.     blk_size[MAJOR_NR] = spull_gendisk.sizes = spull_sizes;
  473.     /* Allocate the partitions array. */
  474.     spull_partitions = kmalloc( (spull_devs << SPULL_SHIFT) *
  475.                                sizeof(struct hd_struct), GFP_KERNEL);
  476.     if (!spull_partitions)
  477.         goto fail_malloc;
  478.     memset(spull_partitions, 0, (spull_devs << SPULL_SHIFT) *
  479.            sizeof(struct hd_struct));
  480.     /* fill in whole-disk entries */
  481.     for (i=0; i < spull_devs; i++) 
  482.         spull_partitions[i << SPULL_SHIFT].nr_sects =
  483. spull_size*(blksize/SPULL_HARDSECT);
  484.     spull_gendisk.part = spull_partitions;
  485.     spull_gendisk.nr_real = spull_devs;
  486. #ifndef LINUX_24
  487.     spull_gendisk.max_nr = spull_devs;
  488. #endif
  489.     /*
  490.      * Put our gendisk structure on the list.
  491.      */
  492.     spull_gendisk.next = gendisk_head;
  493.     gendisk_head = &spull_gendisk; 
  494.     /* dump the partition table to see it */
  495.     for (i=0; i < spull_devs << SPULL_SHIFT; i++)
  496.         PDEBUGG("part %i: beg %lx, size %lxn", i,
  497.                spull_partitions[i].start_sect,
  498.                spull_partitions[i].nr_sects);
  499.     /*
  500.      * Allow interrupt-driven operation, if "irq=" has been specified
  501.      */
  502.     spull_irq = irq; /* copy the static variable to the visible one */
  503.     if (spull_irq) {
  504.         PDEBUG("setting timern");
  505.         spull_timer.function = spull_interrupt;
  506.         blk_init_queue(BLK_DEFAULT_QUEUE(major), spull_irqdriven_request);
  507.     }
  508.     else
  509.         blk_init_queue(BLK_DEFAULT_QUEUE(major), spull_request);
  510. #ifdef NOTNOW
  511.     for (i = 0; i < spull_devs; i++)
  512.             register_disk(NULL, MKDEV(major, i), 1, &spull_bdops,
  513.                             spull_size << 1);
  514. #endif
  515. #ifndef SPULL_DEBUG
  516.     EXPORT_NO_SYMBOLS; /* otherwise, leave global symbols visible */
  517. #endif
  518.     printk ("<1>spull: init complete, %d devs, size %d blks %dn",
  519.                     spull_devs, spull_size, spull_blksize);
  520.     return 0; /* succeed */
  521.   fail_malloc:
  522.     read_ahead[major] = 0;
  523.     if (spull_sizes) kfree(spull_sizes);
  524.     if (spull_partitions) kfree(spull_partitions);
  525.     blk_size[major] = NULL;
  526.     if (spull_devices) kfree(spull_devices);
  527.     unregister_blkdev(major, "spull");
  528.     return result;
  529. }
  530. void spull_cleanup(void)
  531. {
  532.     int i;
  533.     struct gendisk **gdp;
  534. /*
  535.  * Before anything else, get rid of the timer functions.  Set the "usage"
  536.  * flag on each device as well, under lock, so that if the timer fires up
  537.  * just before we delete it, it will either complete or abort.  Otherwise
  538.  * we have nasty race conditions to worry about.
  539.  */
  540.     for (i = 0; i < spull_devs; i++) {
  541.         Spull_Dev *dev = spull_devices + i;
  542.         del_timer(&dev->timer);
  543.         spin_lock(&dev->lock);
  544.         dev->usage++;
  545.         spin_unlock(&dev->lock);
  546.     }
  547.     /* flush it all and reset all the data structures */
  548. /*
  549.  * Unregister the device now to avoid further operations during cleanup.
  550.  */
  551.     unregister_blkdev(major, "spull");
  552.     for (i = 0; i < (spull_devs << SPULL_SHIFT); i++)
  553.         fsync_dev(MKDEV(spull_major, i)); /* flush the devices */
  554.     blk_cleanup_queue(BLK_DEFAULT_QUEUE(major));
  555.     read_ahead[major] = 0;
  556.     kfree(blk_size[major]); /* which is gendisk->sizes as well */
  557.     blk_size[major] = NULL;
  558.     kfree(spull_gendisk.part);
  559.     kfree(blksize_size[major]);
  560.     blksize_size[major] = NULL;
  561.     /*
  562.      * Get our gendisk structure off the list.
  563.      */
  564.     for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next))
  565.         if (*gdp == &spull_gendisk) {
  566.             *gdp = (*gdp)->next;
  567.             break;
  568.         }
  569.     /* finally, the usual cleanup */
  570.     for (i=0; i < spull_devs; i++) {
  571.         if (spull_devices[i].data)
  572.             vfree(spull_devices[i].data);
  573.     }
  574.     kfree(spull_devices);
  575. }
  576. module_init(spull_init);
  577. module_exit(spull_cleanup);