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

嵌入式Linux

开发平台:

C/C++

  1. /*
  2.  * sbull.c -- the Simple Block Utility
  3.  *
  4.  * $Id: sbull.c,v 1.30 2001/04/27 18:03:56 corbet 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 sbull_major /* force definitions on in blk.h */
  25. static int sbull_major; /* must be declared before including blk.h */
  26. #define DEVICE_NR(device) MINOR(device)   /* sbull has no partition bits */
  27. #define DEVICE_NAME "sbull"               /* name for messaging */
  28. #define DEVICE_INTR sbull_intrptr         /* pointer to the bottom half */
  29. #define DEVICE_NO_RANDOM                  /* no entropy to contribute */
  30. #define DEVICE_REQUEST sbull_request
  31. #define DEVICE_OFF(d) /* do-nothing */
  32. #include <linux/blk.h>
  33. #include "sbull.h"        /* local definitions */
  34. #ifdef HAVE_BLKPG_H
  35. #include <linux/blkpg.h>  /* blk_ioctl() */
  36. #endif
  37. /*
  38.  * Do the raw char interface in 2.4.
  39.  */
  40. #ifdef LINUX_24
  41. #  define DO_RAW_INTERFACE
  42. #  include <linux/iobuf.h>
  43. static void sbullr_init();
  44. static void sbullr_release();
  45. #  define SBULLR_SECTOR 512  /* insist on this */
  46. #  define SBULLR_SECTOR_MASK (SBULLR_SECTOR - 1)
  47. #  define SBULLR_SECTOR_SHIFT 9
  48. #endif
  49. /*
  50.  * Non-prefixed symbols are static. They are meant to be assigned at
  51.  * load time. Prefixed symbols are not static, so they can be used in
  52.  * debugging. They are hidden anyways by register_symtab() unless
  53.  * SBULL_DEBUG is defined.
  54.  */
  55. static int major    = SBULL_MAJOR;
  56. static int devs     = SBULL_DEVS;
  57. static int rahead   = SBULL_RAHEAD;
  58. static int size     = SBULL_SIZE;
  59. static int blksize  = SBULL_BLKSIZE;
  60. static int hardsect = SBULL_HARDSECT;
  61. MODULE_PARM(major, "i");
  62. MODULE_PARM(devs, "i");
  63. MODULE_PARM(rahead, "i");
  64. MODULE_PARM(size, "i");
  65. MODULE_PARM(blksize, "i");
  66. MODULE_PARM(hardsect, "i");
  67. MODULE_AUTHOR("Alessandro Rubini");
  68. int sbull_devs, sbull_rahead, sbull_size;
  69. int sbull_blksize, sbull_hardsect;
  70. /* The following items are obtained through kmalloc() in sbull_init() */
  71. Sbull_Dev *sbull_devices = NULL;
  72. int *sbull_blksizes = NULL;
  73. int *sbull_sizes = NULL;
  74. int *sbull_hardsects = NULL;
  75. /*
  76.  * We can do without a request queue, but only in 2.4
  77.  */
  78. #if defined(LINUX_24) && !defined(SBULL_MULTIQUEUE)
  79. static int noqueue = 0;         /* Use request queue by default */
  80. MODULE_PARM(noqueue, "i");
  81. #endif
  82. #ifdef DO_RAW_INTERFACE
  83. int sbullr_major = SBULLR_MAJOR;
  84. MODULE_PARM(sbullr_major, "i");
  85. #endif
  86. int sbull_revalidate(kdev_t i_rdev);
  87. /*
  88.  * Open and close
  89.  */
  90. int sbull_open (struct inode *inode, struct file *filp)
  91. {
  92.     Sbull_Dev *dev; /* device information */
  93.     int num = MINOR(inode->i_rdev);
  94.     if (num >= sbull_devs) return -ENODEV;
  95.     dev = sbull_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.     /* revalidate on first open and fail if no data is there */
  100.     if (!dev->usage) {
  101.         check_disk_change(inode->i_rdev);
  102.         if (!dev->data)
  103.         {
  104.             spin_unlock (&dev->lock);
  105.             return -ENOMEM;
  106.         }
  107.     }
  108.     dev->usage++;
  109.     spin_unlock(&dev->lock);
  110.     MOD_INC_USE_COUNT;
  111.     return 0;          /* success */
  112. }
  113. int sbull_release (struct inode *inode, struct file *filp)
  114. {
  115.     Sbull_Dev *dev = sbull_devices + MINOR(inode->i_rdev);
  116.     spin_lock(&dev->lock);
  117.     dev->usage--;
  118.     /*
  119.      * If the device is closed for the last time, start a timer
  120.      * to release RAM in half a minute. The function and argument
  121.      * for the timer have been setup in sbull_init()
  122.      */
  123.     if (!dev->usage) {
  124.         dev->timer.expires = jiffies + 30 * HZ;
  125.         add_timer(&dev->timer);
  126.         /* but flush it right now */
  127.         fsync_dev(inode->i_rdev);
  128.         invalidate_buffers(inode->i_rdev);
  129.     }
  130.     MOD_DEC_USE_COUNT;
  131.     spin_unlock(&dev->lock);
  132.     return 0;
  133. }
  134. /*
  135.  * The timer function. As argument it receives the device
  136.  */
  137. void sbull_expires(unsigned long data)
  138. {
  139.     Sbull_Dev *dev = (Sbull_Dev *)data;
  140.     spin_lock(&dev->lock);
  141.     if (dev->usage || !dev->data) {
  142.         spin_unlock(&dev->lock);
  143.         printk(KERN_WARNING "sbull: timer mismatch for device %in",
  144.                dev - sbull_devices);
  145.         return;
  146.     }
  147.     PDEBUG("freeing device %in",dev - sbull_devices);
  148.     vfree(dev->data);
  149.     dev->data=0;
  150.     spin_unlock(&dev->lock);
  151.     return;
  152. }    
  153. /*
  154.  * The ioctl() implementation
  155.  */
  156. int sbull_ioctl (struct inode *inode, struct file *filp,
  157.                  unsigned int cmd, unsigned long arg)
  158. {
  159.     int err;
  160.     long size;
  161.     struct hd_geometry geo;
  162.     PDEBUG("ioctl 0x%x 0x%lxn", cmd, arg);
  163.     switch(cmd) {
  164.       case BLKGETSIZE:
  165.         /* Return the device size, expressed in sectors */
  166.         if (!arg) return -EINVAL; /* NULL pointer: not valid */
  167.         err = ! access_ok (VERIFY_WRITE, arg, sizeof(long));
  168.         if (err) return -EFAULT;
  169.         size = blksize*sbull_sizes[MINOR(inode->i_rdev)]
  170. / sbull_hardsects[MINOR(inode->i_rdev)];
  171. if (copy_to_user((long *) arg, &size, sizeof (long)))
  172.     return -EFAULT;
  173.         return 0;
  174.       case BLKRRPART: /* re-read partition table: can't do it */
  175.         return -ENOTTY;
  176.       case HDIO_GETGEO:
  177.         /*
  178.  * Get geometry: since we are a virtual device, we have to make
  179.  * up something plausible.  So we claim 16 sectors, four heads,
  180.  * and calculate the corresponding number of cylinders.  We set the
  181.  * start of data at sector four.
  182.          */
  183.         err = ! access_ok(VERIFY_WRITE, arg, sizeof(geo));
  184.         if (err) return -EFAULT;
  185.         size = sbull_size * blksize / sbull_hardsect;
  186.         geo.cylinders = (size & ~0x3f) >> 6;
  187. geo.heads = 4;
  188. geo.sectors = 16;
  189. geo.start = 4;
  190. if (copy_to_user((void *) arg, &geo, sizeof(geo)))
  191.     return -EFAULT;
  192.         return 0;
  193.       default:
  194.         /*
  195.          * For ioctls we don't understand, let the block layer handle them.
  196.          */
  197.         return blk_ioctl(inode->i_rdev, cmd, arg);
  198.     }
  199.     return -ENOTTY; /* unknown command */
  200. }
  201. /*
  202.  * Support for removable devices
  203.  */
  204. int sbull_check_change(kdev_t i_rdev)
  205. {
  206.     int minor = MINOR(i_rdev);
  207.     Sbull_Dev *dev = sbull_devices + minor;
  208.     if (minor >= sbull_devs) /* paranoid */ 
  209.         return 0;                           
  210.                                             
  211.     PDEBUG("check_change for dev %in",minor);
  212.     if (dev->data)
  213.         return 0; /* still valid */
  214.     return 1; /* expired */
  215. }
  216. /*
  217.  * Note no locks taken out here.  In a worst case scenario, we could drop
  218.  * a chunk of system memory.  But that should never happen, since validation
  219.  * happens at open or mount time, when locks are held.
  220.  */
  221. int sbull_revalidate(kdev_t i_rdev)
  222. {
  223.     Sbull_Dev *dev = sbull_devices + MINOR(i_rdev);
  224.     PDEBUG("revalidate for dev %in",MINOR(i_rdev));
  225.     if (dev->data)
  226.         return 0;
  227.     dev->data = vmalloc(dev->size);
  228.     if (!dev->data)
  229.         return -ENOMEM;
  230.     return 0;
  231. }
  232. /*
  233.  * The file operations
  234.  */
  235. #ifdef LINUX_24
  236. struct block_device_operations sbull_bdops = {
  237.     open:               sbull_open,
  238.     release:            sbull_release,
  239.     ioctl:              sbull_ioctl,
  240.     check_media_change: sbull_check_change,
  241.     revalidate:         sbull_revalidate,
  242. };
  243. #else
  244. #ifdef LINUX_20
  245. void sbull_release_20 (struct inode *inode, struct file *filp)
  246. {
  247.         (void) sbull_release (inode, filp);
  248. }
  249. #define sbull_release sbull_release_20
  250. #endif
  251. struct file_operations sbull_bdops = {
  252.     read:       block_read,
  253.     write:      block_write,
  254.     ioctl:      sbull_ioctl,
  255.     open:       sbull_open,
  256.     release:    sbull_release,
  257.     fsync:      block_fsync,
  258.     check_media_change: sbull_check_change,
  259.     revalidate: sbull_revalidate
  260. };
  261. # endif /* LINUX_24 */
  262. /*
  263.  * Block-driver specific functions
  264.  */
  265. /*
  266.  * Find the device for this request.
  267.  */
  268. static Sbull_Dev *sbull_locate_device(const struct request *req)
  269. {
  270.     int devno;
  271.     Sbull_Dev *device;
  272.     /* Check if the minor number is in range */
  273.     devno = DEVICE_NR(req->rq_dev);
  274.     if (devno >= sbull_devs) {
  275.         static int count = 0;
  276.         if (count++ < 5) /* print the message at most five times */
  277.             printk(KERN_WARNING "sbull: request for unknown devicen");
  278.         return NULL;
  279.     }
  280.     device = sbull_devices + devno;  /* Pick it out of our device array */
  281.     return device;
  282. }
  283. /*
  284.  * Perform an actual transfer.
  285.  */
  286. static int sbull_transfer(Sbull_Dev *device, const struct request *req)
  287. {
  288.     int size;
  289.     u8 *ptr;
  290.     
  291.     ptr = device->data + req->sector * sbull_hardsect;
  292.     size = req->current_nr_sectors * sbull_hardsect;
  293.     /* Make sure that the transfer fits within the device. */
  294.     if (ptr + size > device->data + sbull_blksize*sbull_size) {
  295.         static int count = 0;
  296.         if (count++ < 5)
  297.             printk(KERN_WARNING "sbull: request past end of devicen");
  298.         return 0;
  299.     }
  300.     /* Looks good, do the transfer. */
  301.     switch(req->cmd) {
  302.         case READ:
  303.             memcpy(req->buffer, ptr, size); /* from sbull to buffer */
  304.             return 1;
  305.         case WRITE:
  306.             memcpy(ptr, req->buffer, size); /* from buffer to sbull */
  307.             return 1;
  308.         default:
  309.             /* can't happen */
  310.             return 0;
  311.     }
  312. }
  313. #ifdef LINUX_24
  314. /*
  315.  * Transfer a buffer directly, without going through the request queue.
  316.  */
  317. int sbull_make_request(request_queue_t *queue, int rw, struct buffer_head *bh)
  318. {
  319.     u8 *ptr;
  320.     /* Figure out what we are doing */
  321.     Sbull_Dev *device = sbull_devices + MINOR(bh->b_rdev);
  322.     ptr = device->data + bh->b_rsector * sbull_hardsect;
  323.     /* Paranoid check, this apparently can really happen */
  324.     if (ptr + bh->b_size > device->data + sbull_blksize*sbull_size) {
  325.         static int count = 0;
  326.         if (count++ < 5)
  327.             printk(KERN_WARNING "sbull: request past end of devicen");
  328.         bh->b_end_io(bh, 0);
  329.         return 0;
  330.     }
  331.     /* This could be a high memory buffer, shift it down */
  332. #if CONFIG_HIGHMEM
  333.     bh = create_bounce(rw, bh);
  334. #endif
  335.     /* Do the transfer */
  336.     switch(rw) {
  337.         case READ:
  338.         case READA:  /* Readahead */
  339.             memcpy(bh->b_data, ptr, bh->b_size); /* from sbull to buffer */
  340.             bh->b_end_io(bh, 1);
  341.             break;
  342.         case WRITE:
  343.             refile_buffer(bh);
  344.             memcpy(ptr, bh->b_data, bh->b_size); /* from buffer to sbull */
  345.             mark_buffer_uptodate(bh, 1);
  346.             bh->b_end_io(bh, 1);
  347.             break;
  348.         default:
  349.             /* can't happen */
  350.             bh->b_end_io(bh, 0);
  351.             break;
  352.     }
  353.     /* Nonzero return means we're done */
  354.     return 0;
  355. }
  356. void sbull_unused_request(request_queue_t *q)
  357. {
  358.     static int count = 0;
  359.     if (count++ < 5)
  360.         printk(KERN_WARNING "sbull: unused_request calledn");
  361. }
  362.         
  363. #endif /* LINUX_24 */
  364. #if defined(SBULL_EMPTY_REQUEST)
  365. /*
  366.  * This empty request function just prints the interesting items
  367.  * of the current request. The sectors affected by the request
  368.  * are printed as <first-sector>-<number-of-sectors>.
  369.  */
  370. #ifdef LINUX_24
  371. void sbull_request(request_queue_t *q)
  372. #else                                   
  373. void sbull_request()                    
  374. #endif                                  
  375. {
  376.     while(1) {
  377.         INIT_REQUEST;
  378.         printk("<1>request %p: cmd %i sec %li (nr. %li)n", CURRENT,
  379.                CURRENT->cmd,
  380.                CURRENT->sector,
  381.                CURRENT->current_nr_sectors);
  382.         end_request(1); /* success */
  383.     }
  384. }
  385. #elif defined(SBULL_MULTIQUEUE)  /* 2.4 only */
  386. /*
  387.  * Clean up this request.
  388.  */
  389. int sbull_end_request(struct request *req, int status)
  390. {
  391.     if (end_that_request_first(req, status, DEVICE_NAME))
  392.         return 1;
  393.     end_that_request_last(req);
  394.     return 0;
  395. }
  396. void sbull_request(request_queue_t *q)
  397. {
  398.     Sbull_Dev *device;
  399.     struct request *req;
  400.     int status;
  401.     /* Find our device */
  402.     device = sbull_locate_device (blkdev_entry_next_request(&q->queue_head));
  403.     if (device->busy) /* no race here - io_request_lock held */
  404.         return;
  405.     device->busy = 1;
  406.     /* Process requests in the queue */
  407.     while(! list_empty(&q->queue_head)) {
  408.     /* Pull the next request off the list. */
  409.         req = blkdev_entry_next_request(&q->queue_head);
  410.         blkdev_dequeue_request(req);
  411.         spin_unlock_irq (&io_request_lock);
  412.         spin_lock(&device->lock);
  413.     /* Process all of the buffers in this (possibly clustered) request. */
  414.         do {
  415.             status = sbull_transfer(device, req);
  416.         } while (end_that_request_first(req, status, DEVICE_NAME));
  417.         spin_unlock(&device->lock);
  418.         spin_lock_irq (&io_request_lock);
  419.         end_that_request_last(req);
  420.     }
  421.     device->busy = 0;
  422. }
  423. /*
  424.  * Tell the block layer where to queue a request.
  425.  */
  426. request_queue_t *sbull_find_queue(kdev_t device)
  427. {
  428.     int devno = DEVICE_NR(device);
  429.     if (devno >= sbull_devs) {
  430.         static int count = 0;
  431.         if (count++ < 5) /* print the message at most five times */
  432.             printk(KERN_WARNING "sbull: request for unknown devicen");
  433.         return NULL;
  434.     }
  435.     return &sbull_devices[devno].queue;
  436. }
  437. #else /* not SBULL_MULTIQUEUE */
  438. #ifdef LINUX_24                                 
  439. void sbull_request(request_queue_t *q)
  440. #else                                           
  441. void sbull_request()                            
  442. #endif                                          
  443. {
  444.     Sbull_Dev *device;
  445.     int status;
  446.     while(1) {
  447.         INIT_REQUEST;  /* returns when queue is empty */
  448.         /* Which "device" are we using? */
  449.         device = sbull_locate_device (CURRENT);
  450.         if (device == NULL) {
  451.             end_request(0);
  452.             continue;
  453.         }
  454.         /* Perform the transfer and clean up. */
  455. spin_lock(&device->lock);
  456.         status = sbull_transfer(device, CURRENT);
  457.         spin_unlock(&device->lock);
  458.         end_request(status); 
  459.     }
  460. }
  461. #endif /* not SBULL_EMPTY_REQUEST nor SBULL_MULTIQUEUE */
  462. /*
  463.  * Finally, the module stuff
  464.  */
  465. int sbull_init(void)
  466. {
  467.     int result, i;
  468.     /*
  469.      * Copy the (static) cfg variables to public prefixed ones to allow
  470.      * snoozing with a debugger.
  471.      */
  472.     sbull_major    = major;
  473.     sbull_devs     = devs;
  474.     sbull_rahead   = rahead;
  475.     sbull_size     = size;
  476.     sbull_blksize  = blksize;
  477.     sbull_hardsect = hardsect;
  478. #ifdef LINUX_20
  479.     /* Hardsect can't be changed :( */
  480.     if (hardsect != 512) {
  481.         printk(KERN_ERR "sbull: can't change hardsect sizen");
  482.         hardsect = sbull_hardsect = 512;
  483.     }
  484. #endif
  485.     /*
  486.      * Register your major, and accept a dynamic number
  487.      */
  488.     result = register_blkdev(sbull_major, "sbull", &sbull_bdops);
  489.     if (result < 0) {
  490.         printk(KERN_WARNING "sbull: can't get major %dn",sbull_major);
  491.         return result;
  492.     }
  493.     if (sbull_major == 0) sbull_major = result; /* dynamic */
  494.     major = sbull_major; /* Use `major' later on to save typing */
  495.     /*
  496.      * Assign the other needed values: request, rahead, size, blksize,
  497.      * hardsect. All the minor devices feature the same value.
  498.      * Note that `sbull' defines all of them to allow testing non-default
  499.      * values. A real device could well avoid setting values in global
  500.      * arrays if it uses the default values.
  501.      */
  502.     read_ahead[major] = sbull_rahead;
  503.     result = -ENOMEM; /* for the possible errors */
  504.     sbull_sizes = kmalloc(sbull_devs * sizeof(int), GFP_KERNEL);
  505.     if (!sbull_sizes)
  506.         goto fail_malloc;
  507.     for (i=0; i < sbull_devs; i++) /* all the same size */
  508.         sbull_sizes[i] = sbull_size;
  509.     blk_size[major]=sbull_sizes;
  510.     sbull_blksizes = kmalloc(sbull_devs * sizeof(int), GFP_KERNEL);
  511.     if (!sbull_blksizes)
  512.         goto fail_malloc;
  513.     for (i=0; i < sbull_devs; i++) /* all the same blocksize */
  514.         sbull_blksizes[i] = sbull_blksize;
  515.     blksize_size[major]=sbull_blksizes;
  516.     sbull_hardsects = kmalloc(sbull_devs * sizeof(int), GFP_KERNEL);
  517.     if (!sbull_hardsects)
  518.         goto fail_malloc;
  519.     for (i=0; i < sbull_devs; i++) /* all the same hardsect */
  520.         sbull_hardsects[i] = sbull_hardsect;
  521.     hardsect_size[major]=sbull_hardsects;
  522.     /* FIXME: max_readahead and max_sectors */ 
  523.     
  524.     /* 
  525.      * allocate the devices -- we can't have them static, as the number
  526.      * can be specified at load time
  527.      */
  528.     sbull_devices = kmalloc(sbull_devs * sizeof (Sbull_Dev), GFP_KERNEL);
  529.     if (!sbull_devices)
  530.         goto fail_malloc;
  531.     memset(sbull_devices, 0, sbull_devs * sizeof (Sbull_Dev));
  532.     for (i=0; i < sbull_devs; i++) {
  533.         /* data and usage remain zeroed */
  534.         sbull_devices[i].size = 1024 * sbull_size;
  535.         init_timer(&(sbull_devices[i].timer));
  536.         sbull_devices[i].timer.data = (unsigned long)(sbull_devices+i);
  537.         sbull_devices[i].timer.function = sbull_expires;
  538.         spin_lock_init(&sbull_devices[i].lock);
  539.     }
  540.     /*
  541.      * Get the queue set up, and register our (nonexistent) partitions.
  542.      */  
  543. #ifdef SBULL_MULTIQUEUE
  544.     for (i = 0; i < sbull_devs; i++) {
  545.         blk_init_queue(&sbull_devices[i].queue, sbull_request);
  546.         blk_queue_headactive(&sbull_devices[i].queue, 0);
  547.     }
  548.     blk_dev[major].queue = sbull_find_queue;
  549. #else
  550. #  ifdef LINUX_24
  551.     if (noqueue)
  552.         blk_queue_make_request(BLK_DEFAULT_QUEUE(major), sbull_make_request);
  553.     else
  554. #  endif /* LINUX_24 */
  555.         blk_init_queue(BLK_DEFAULT_QUEUE(major), sbull_request);
  556. #endif
  557.     /* A no-op in 2.4.0, but all drivers seem to do it anyway */
  558.     for (i = 0; i < sbull_devs; i++)
  559.             register_disk(NULL, MKDEV(major, i), 1, &sbull_bdops,
  560.                             sbull_size << 1);
  561. #ifndef SBULL_DEBUG
  562.     EXPORT_NO_SYMBOLS; /* otherwise, leave global symbols visible */
  563. #endif
  564.     printk ("<1>sbull: init complete, %d devs, size %d blks %d hs %dn",
  565.                     sbull_devs, sbull_size, sbull_blksize, sbull_hardsect);
  566. #ifdef SBULL_MULTIQUEUE
  567.     printk ("<1>sbull: Using multiqueue requestn");
  568. #elif defined(LINUX_24)
  569.     if (noqueue)
  570.             printk (KERN_INFO "sbull: using direct make_requestn");
  571. #endif
  572. #ifdef DO_RAW_INTERFACE
  573.     sbullr_init();
  574. #endif
  575.     return 0; /* succeed */
  576.   fail_malloc:
  577.     read_ahead[major] = 0;
  578.     if (sbull_sizes) kfree(sbull_sizes);
  579.     blk_size[major] = NULL;
  580.     if (sbull_blksizes) kfree(sbull_blksizes);
  581.     blksize_size[major] = NULL;
  582.     if (sbull_hardsects) kfree(sbull_hardsects);
  583.     hardsect_size[major] = NULL;
  584.     if (sbull_devices) kfree(sbull_devices);
  585.     unregister_blkdev(major, "sbull");
  586.     return result;
  587. }
  588. void sbull_cleanup(void)
  589. {
  590.     int i;
  591. /*
  592.  * Before anything else, get rid of the timer functions.  Set the "usage"
  593.  * flag on each device as well, under lock, so that if the timer fires up
  594.  * just before we delete it, it will either complete or abort.  Otherwise
  595.  * we have nasty race conditions to worry about.
  596.  */
  597.     for (i = 0; i < sbull_devs; i++) {
  598.         Sbull_Dev *dev = sbull_devices + i;
  599.         del_timer(&dev->timer);
  600.         spin_lock(&dev->lock);
  601.         dev->usage++;
  602.         spin_unlock(&dev->lock);
  603.     }
  604. #ifdef DO_RAW_INTERFACE
  605.     sbullr_release();
  606. #endif
  607.     
  608.     /* flush it all and reset all the data structures */
  609.     for (i=0; i<sbull_devs; i++)
  610.         fsync_dev(MKDEV(sbull_major, i)); /* flush the devices */
  611.     unregister_blkdev(major, "sbull");
  612. /*
  613.  * Fix up the request queue(s)
  614.  */
  615. #ifdef SBULL_MULTIQUEUE
  616.     for (i = 0; i < sbull_devs; i++)
  617.             blk_cleanup_queue(&sbull_devices[i].queue);
  618.     blk_dev[major].queue = NULL;
  619. #else
  620.     blk_cleanup_queue(BLK_DEFAULT_QUEUE(major));
  621. #endif   
  622.     /* Clean up the global arrays */
  623.     read_ahead[major] = 0;
  624.     kfree(blk_size[major]);
  625.     blk_size[major] = NULL;
  626.     kfree(blksize_size[major]);
  627.     blksize_size[major] = NULL;
  628.     kfree(hardsect_size[major]);
  629.     hardsect_size[major] = NULL;
  630.     /* FIXME: max_readahead and max_sectors */ 
  631.     /* finally, the usual cleanup */
  632.     for (i=0; i < sbull_devs; i++) {
  633.         if (sbull_devices[i].data)
  634.             vfree(sbull_devices[i].data);
  635.     }
  636.     kfree(sbull_devices);
  637. }
  638. /*
  639.  * Below here is the "raw device" implementation, available only
  640.  * in 2.4.
  641.  */
  642. #ifdef DO_RAW_INTERFACE
  643. /*
  644.  * Transfer an iovec
  645.  */
  646. static int sbullr_rw_iovec(Sbull_Dev *dev, struct kiobuf *iobuf, int rw,
  647.                 int sector, int nsectors)
  648. {
  649.     struct request fakereq;
  650.     struct page *page;
  651.     int offset = iobuf->offset, ndone = 0, pageno, result;
  652.     /* Perform I/O on each sector */
  653.     fakereq.sector = sector;
  654.     fakereq.current_nr_sectors = 1;
  655.     fakereq.cmd = rw;
  656.     
  657.     for (pageno = 0; pageno < iobuf->nr_pages; pageno++) {
  658.         page = iobuf->maplist[pageno];
  659.         while (ndone < nsectors) {
  660.             /* Fake up a request structure for the operation */
  661.             fakereq.buffer = (void *) (kmap(page) + offset);
  662.             result = sbull_transfer(dev, &fakereq);
  663.     kunmap(page);
  664.             if (result == 0)
  665.                 return ndone;
  666.             /* Move on to the next one */
  667.             ndone++;
  668.             fakereq.sector++;
  669.             offset += SBULLR_SECTOR;
  670.             if (offset >= PAGE_SIZE) {
  671.                 offset = 0;
  672.                 break;
  673.             }
  674.         }
  675.     }
  676.     return ndone;
  677. }
  678. /*
  679.  * Handle actual transfers of data.
  680.  */
  681. static int sbullr_transfer (Sbull_Dev *dev, char *buf, size_t count,
  682.                 loff_t *offset, int rw)
  683. {
  684.     struct kiobuf *iobuf;       
  685.     int result;
  686.     
  687.     /* Only block alignment and size allowed */
  688.     if ((*offset & SBULLR_SECTOR_MASK) || (count & SBULLR_SECTOR_MASK))
  689.         return -EINVAL;
  690.     if ((unsigned long) buf & SBULLR_SECTOR_MASK)
  691.         return -EINVAL;
  692.     /* Allocate an I/O vector */
  693.     result = alloc_kiovec(1, &iobuf);
  694.     if (result)
  695.         return result;
  696.     /* Map the user I/O buffer and do the I/O. */
  697.     result = map_user_kiobuf(rw, iobuf, (unsigned long) buf, count);
  698.     if (result) {
  699.         free_kiovec(1, &iobuf);
  700.         return result;
  701.     }
  702.     spin_lock(&dev->lock);
  703.     result = sbullr_rw_iovec(dev, iobuf, rw, *offset >> SBULLR_SECTOR_SHIFT,
  704.                     count >> SBULLR_SECTOR_SHIFT);
  705.     spin_unlock(&dev->lock);
  706.     /* Clean up and return. */
  707.     unmap_kiobuf(iobuf);
  708.     free_kiovec(1, &iobuf);
  709.     if (result > 0)
  710.         *offset += result << SBULLR_SECTOR_SHIFT;
  711.     return result << SBULLR_SECTOR_SHIFT;
  712. }
  713. /*
  714.  * Read and write syscalls.
  715.  */
  716. ssize_t sbullr_read(struct file *filp, char *buf, size_t size, loff_t *off)
  717. {
  718.     Sbull_Dev *dev = sbull_devices + MINOR(filp->f_dentry->d_inode->i_rdev);
  719.     return sbullr_transfer(dev, buf, size, off, READ);
  720. }
  721. ssize_t sbullr_write(struct file *filp, const char *buf, size_t size,
  722.                 loff_t *off)
  723. {
  724.     Sbull_Dev *dev = sbull_devices + MINOR(filp->f_dentry->d_inode->i_rdev);
  725.     return sbullr_transfer(dev, (char *) buf, size, off, WRITE);
  726. }
  727. static int sbullr_registered = 0;
  728. static struct file_operations sbullr_fops = {
  729.    read:        sbullr_read,
  730.    write:       sbullr_write,
  731.    open:        sbull_open,
  732.    release:     sbull_release,
  733.    ioctl: sbull_ioctl,
  734. };
  735. static void sbullr_init()
  736. {
  737.     int result;
  738.         
  739.     /* Simplify the math */
  740.     if (sbull_hardsect != SBULLR_SECTOR) {
  741.         printk(KERN_NOTICE "Sbullr requires hardsect = %dn", SBULLR_SECTOR);
  742.         return;
  743.     }
  744.     SET_MODULE_OWNER(&sbullr_fops);
  745.     result = register_chrdev(sbullr_major, "sbullr", &sbullr_fops);
  746.     if (result >= 0)
  747.         sbullr_registered = 1;
  748.     if (sbullr_major == 0)
  749.         sbullr_major = result;
  750. }
  751. static void sbullr_release()
  752. {
  753.     if (sbullr_registered)
  754.         unregister_chrdev(sbullr_major, "sbullr");
  755. }
  756. #endif /* DO_RAW_INTERFACE */
  757. module_init(sbull_init);
  758. module_exit(sbull_cleanup);