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

嵌入式Linux

开发平台:

C/C++

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