sbull虚拟的磁盘驱动的编写

原理指导:我们通过vmalloc在内存中开辟一部分空间,作为一个虚拟的磁盘,然后我们以块设备的方式来访问这片内存,例如这个sbull模型。

sbull(Simple Block Utility for Loading Localities),该驱动程序实现了一个使用系统内存的块设备,从本质上讲,属于一种 RAM 磁盘驱动程序。字符设备的IO操作则是直接不绕弯的,块设备的IO操作会配对和整合。驱动的任务是处理请求,对于这些请求的排队和整合的工作有IO调度算法处理。所以块设备的核心工作就是:请求处理函数或者是制造请求。Block_devices_operations结构体中没有读写一类的成员函数,而只是包含打开、释放和IO控制等函数。

块设备的流程:

(1)先把模块模型搭建好

MODULE_LICENSE("Dual BSD/GPL");

static struct block_device_operations sbull_ops = {

.owner           = THIS_MODULE,

.open           = sbull_open,

.release   = sbull_release,

.media_changed   = sbull_media_changed,

.revalidate_disk = sbull_revalidate,

.ioctl          = sbull_ioctl,

.getgeo = sbull_getgeo,

};

module_init(sbull_init);

module_exit(sbull_exit);

(2)定义一个我们用内存虚拟出来的块设备sbull_dev

struct sbull_dev {

        int size;                       /* Device size in sectors */

        u8 *data;                       /* The data array */

        short users;                    /* How many users */

        short media_change;             /* Flag a media change? */

        spinlock_t lock;                /* For mutual exclusion */

        struct request_queue *queue;    /* The device request queue */

        struct gendisk *gd;             /* The gendisk structure */

        struct timer_list timer;        /* For simulated media changes */

};

这个设备结构体是我们工作的核心,也许你不知道需要哪些成员,不要紧,还是那句话,编写驱动的时候,需要设备表现出那些性质和功能,相应的添加上就OK了。

(3)设备的初始化 

sbull_init(  ){

一、sbull_major = register_blkdev(sbull_major, "sbull");

二、Static struct sbull_dev *Devices = kmalloc(ndevices*sizeof (struct sbull_dev), GFP_KERNEL);//在这里可以对Kmalloc的结果判断下,然后进一步处理...

三、setup_device()跳到我们设备注册函数中去

}//初始化函数结束

(4)开始注册我们的这个设备

 setup_device(  ){  //安装(注册)一个设备前,一定要保证它被初始化了

这些成员都得出初始化好:

    一、    int size;                       /* Device size in sectors */

        u8 *data;                       /* The data array */

        short users;                    /* How many users */

        spinlock_t lock;                /* For mutual exclusion */

        struct request_queue *queue;    /* The device request queue */

        struct gendisk *gd;             /* The gendisk structure */

    二、add_disk(dev->gd);//这个重要的注册函数 }//函数结束

(5)扇区大小、data数组、user、锁lock的初始化:

一、dev->size = nsectors*hardsect_size;

dev->data = vmalloc(dev->size);

spin_lock_init(&dev->lock);

二、//dev->queue = blk_alloc_queue(GFP_KERNEL);           //RM_NOQUEUE

//dev->queue = blk_init_queue(sbull_full_request, &dev->lock);     //RM_FULL

dev->queue = blk_init_queue(sbull_request, &dev->lock);          //RM_SIMPLE

(6)告知内核硬件扇区尺寸、和timer模拟的初始化

blk_queue_logical_block_size(dev->queue, hardsect_size);

init_timer(&dev->timer);

dev->timer.data = (unsigned long) dev;

dev->timer.function = sbull_invalidate;gendisk初始化 

一、初始化gendisk:

dev->gd = alloc_disk(SBULL_MINORS);

二、 初始化gendisk的成员

dev->gd->major = sbull_major;

dev->gd->first_minor = which*SBULL_MINORS;

dev->gd->fops = &sbull_ops;

dev->gd->queue = dev->queue;

dev->gd->private_data = dev;

(7)设置gendisk容量为xxx_size个扇区大小 

set_capacity(dev->gd  , nsectors*(hardsect_size / KERNEL_SECTOR_SIZE));

(8)剩下的就是为devices_operation结构体里声明的那些接口进行实现:

.open  = sbull_open,

.release  = sbull_release,

.media_changed   = sbull_media_changed,

.revalidate_disk  = sbull_revalidate,

.ioctl = sbull_ioctl,

.getgeo = sbull_getgeo,

一、sbull_open(struct block_device *bdev,fmode_t mode )

二、sbull_release(struct gendisk *bd_disk, fmode_t mode)

三、sbull_media_changed(struct gendisk *gd)

四、sbull_revalidate(struct gendisk *gd)

五、sbull_invalidate(unsigned long ldev)

六、sbull_ioctl (struct block_device *bdev, fmode_t mode,

                   unsigned int cmd, unsigned long arg)

七、sbull_getgeo(struct block_device *bdev, struct hd_geometry *geo)

以下是代码:

  1. /* 
  2.  * Sample disk driver for 2.6.35. 
  3.  */  
  4.   
  5. //#include <linux/autoconf.h>  
  6. #include <linux/module.h>  
  7. #include <linux/moduleparam.h>  
  8. #include <linux/init.h>  
  9.   
  10. #include <linux/sched.h>  
  11. #include <linux/kernel.h> /* printk() */  
  12. #include <linux/slab.h>       /* kmalloc() */  
  13. #include <linux/fs.h>     /* everything... */  
  14. #include <linux/errno.h>  /* error codes */  
  15. #include <linux/timer.h>  
  16. #include <linux/types.h>  /* size_t */  
  17. #include <linux/fcntl.h>  /* O_ACCMODE */  
  18. #include <linux/hdreg.h>  /* HDIO_GETGEO */  
  19. #include <linux/kdev_t.h>  
  20. #include <linux/vmalloc.h>  
  21. #include <linux/genhd.h>  
  22. #include <linux/blkdev.h>  
  23. #include <linux/buffer_head.h>    /* invalidate_bdev */  
  24. #include <linux/bio.h>  
  25.   
  26. MODULE_LICENSE("Dual BSD/GPL");  
  27.   
  28. static int sbull_major = 0;  
  29. module_param(sbull_major, int, 0);  
  30. static int hardsect_size = 512;  
  31. module_param(hardsect_size, int, 0);  
  32. static int nsectors = 25600;    /* How big the drive is */  
  33. module_param(nsectors, int, 0);  
  34. static int ndevices = 1;  
  35. module_param(ndevices, int, 0);  
  36.   
  37. /* 
  38.  * The different "request modes" we can use. 
  39.  */  
  40. enum {  
  41.     RM_SIMPLE  = 0, /* The extra-simple request function */  
  42.     RM_FULL    = 1, /* The full-blown version */  
  43.     RM_NOQUEUE = 2, /* Use make_request */  
  44. };  
  45. //static int request_mode = RM_FULL;  
  46. //static int request_mode = RM_SIMPLE;  
  47. static int request_mode = RM_NOQUEUE;  
  48. module_param(request_mode, int, 0);  
  49.   
  50. /* 
  51.  * Minor number and partition management. 
  52.  */  
  53. #define SBULL_MINORS    16  
  54. #define MINOR_SHIFT 4  
  55. #define DEVNUM(kdevnum) (MINOR(kdev_t_to_nr(kdevnum)) >> MINOR_SHIFT  
  56.   
  57. /* 
  58.  * We can tweak our hardware sector size, but the kernel talks to us 
  59.  * in terms of small sectors, always. 
  60.  */  
  61. #define KERNEL_SECTOR_SIZE  512  
  62.   
  63. /* 
  64.  * After this much idle time, the driver will simulate a media change. 
  65.  */  
  66. #define INVALIDATE_DELAY    60*HZ  
  67.   
  68. /* 
  69.  * The internal representation of our device. 
  70.  */  
  71. struct sbull_dev {  
  72.         int size;                       /* Device size in sectors */  
  73.         u8 *data;                       /* The data array */  
  74.         short users;                    /* How many users */  
  75.         short media_change;             /* Flag a media change? */  
  76.         spinlock_t lock;                /* For mutual exclusion */  
  77.         struct request_queue *queue;    /* The device request queue */  
  78.         struct gendisk *gd;             /* The gendisk structure */  
  79.         struct timer_list timer;        /* For simulated media changes */  
  80. };  
  81.   
  82. static struct sbull_dev *Devices = NULL;  
  83.   
  84. /* 
  85.  * Handle an I/O request. 
  86.  */  
  87. static void sbull_transfer(struct sbull_dev *dev, unsigned long sector,  
  88.         unsigned long nsect, char *buffer, int write)  
  89. {  
  90.     unsigned long offset = sector*KERNEL_SECTOR_SIZE;  
  91.     unsigned long nbytes = nsect*KERNEL_SECTOR_SIZE;  
  92.     //printk("<0>""in %s offset=%d  nbytes=%d write=%d\n",__FUNCTION__,offset,nbytes,write);  
  93.     //buffer[10]='\0';  
  94.     //printk(buffer);  
  95.     //printk("\n");  
  96.     if ((offset + nbytes) > dev->size) {  
  97.         printk (KERN_NOTICE "Beyond-end write (%ld %ld)\n", offset, nbytes);  
  98.         return;  
  99.     }  
  100.     if (write)  
  101.         memcpy(dev->data + offset, buffer, nbytes);  
  102.     else  
  103.         memcpy(buffer, dev->data + offset, nbytes);  
  104. }  
  105.   
  106. /*The simple form of the request function.*/  
  107.   
  108. static void sbull_request(struct request_queue *q)  
  109. {  
  110.     struct request *req;  
  111.   
  112.     req = blk_fetch_request(q);  
  113.     while (req  != NULL) {  
  114.         struct sbull_dev *dev = req->rq_disk->private_data;  
  115.         if (! blk_fs_request(req)) {  //在有些内核并不支持该函数
  116.             printk (KERN_NOTICE "Skip non-fs request\n");  
  117.             __blk_end_request_all(req, -EIO);  
  118.             continue;  
  119.         }  
  120.     //      printk (KERN_NOTICE "Req dev %d dir %ld sec %ld, nr %d f %lx\n",  
  121.     //              dev - Devices, rq_data_dir(req),  
  122.     //              req->sector, req->current_nr_sectors,  
  123.     //              req->flags);  
  124.     //  printk("sectors=%d\n",req->current_nr_sectors);  
  125.         sbull_transfer(dev, blk_rq_pos(req), blk_rq_cur_sectors(req),  
  126.                 req->buffer, rq_data_dir(req));  
  127.         if ( ! __blk_end_request_cur(req, 0) ) {  
  128.             req = NULL;  
  129.         }  
  130.     }  
  131. }  
  132.   
  133.   
  134. /* 
  135.  * Transfer a single BIO. 
  136.  */  
  137. static int sbull_xfer_bio(struct sbull_dev *dev, struct bio *bio)  
  138. {  
  139.     int i;  
  140.     struct bio_vec *bvec;  
  141.     sector_t sector = bio->bi_sector;  
  142.   
  143.     /* Do each segment independently. */  
  144.     bio_for_each_segment(bvec, bio, i) {  
  145.         char *buffer = __bio_kmap_atomic(bio, i, KM_USER0);  
  146.         sbull_transfer(dev, sector, bio_cur_bytes(bio)>>9 ,  
  147.                 buffer, bio_data_dir(bio) == WRITE);  
  148.         sector += bio_cur_bytes(bio)>>9;  
  149.         __bio_kunmap_atomic(bio, KM_USER0);  
  150.     }  
  151.     return 0; /* Always "succeed" */  
  152. }  
  153.   
  154. /* 
  155.  * Transfer a full request. 
  156.  */  
  157. static int sbull_xfer_request(struct sbull_dev *dev, struct request *req)  
  158. {  
  159.     struct bio *bio;  
  160.     int nsect = 0;  
  161.       
  162.     __rq_for_each_bio(bio, req) {  
  163.         sbull_xfer_bio(dev, bio);  
  164.         nsect += bio->bi_size/KERNEL_SECTOR_SIZE;  
  165.     }  
  166.     return nsect;  
  167. }  
  168.   
  169.   
  170.   
  171. /* 
  172.  * Smarter request function that "handles clustering".*/  
  173. static void sbull_full_request(struct request_queue *q)  
  174. {  
  175.   
  176.     struct request *req;  
  177.     int nsect;  
  178.     struct sbull_dev *dev ;  
  179.     req = blk_fetch_request(q);  
  180.     dev = req->rq_disk->private_data;  
  181.     while (req  != NULL) {  
  182.         if (! blk_fs_request(req)) {  
  183.             printk (KERN_NOTICE "Skip non-fs request\n");  
  184.             __blk_end_request_all(req, -EIO);  
  185.             continue;  
  186.         }  
  187.     //      printk (KERN_NOTICE "Req dev %d dir %ld sec %ld, nr %d f %lx\n",  
  188.     //              dev - Devices, rq_data_dir(req),  
  189.     //              req->sector, req->current_nr_sectors,  
  190.     //              req->flags);  
  191.     //  printk("sectors=%d\n",req->current_nr_sectors);  
  192.          nsect = sbull_xfer_request(dev, req);  
  193.          __blk_end_request(req, 0, (nsect<<9));  
  194.     //  req = blk_fetch_request(q);  
  195.         req = NULL;  
  196.     }  
  197.   
  198. }  
  199.   
  200.   
  201.   
  202. //The direct make request version  
  203. static int sbull_make_request(struct request_queue *q, struct bio *bio)  
  204. {  
  205.     struct sbull_dev *dev = q->queuedata;  
  206.     int status;  
  207.   
  208.     status = sbull_xfer_bio(dev, bio);  
  209.     //bio_endio(bio, bio->bi_size, status);  
  210.     bio_endio(bio, status);  
  211.     return 0;  
  212. }  
  213.   
  214.   
  215. /* 
  216.  * Open and close. 
  217.  */  
  218.   
  219. static int sbull_open(struct block_device *bdev,fmode_t mode )  
  220. {  
  221.     struct sbull_dev *dev = bdev->bd_disk->private_data;  
  222.     //printk("<0>" "fdfjdlksjfdlkj\n");     
  223.     del_timer_sync(&dev->timer);  
  224.     spin_lock(&dev->lock);  
  225.     if (! dev->users)   
  226.         check_disk_change(bdev);  
  227.     dev->users++;  
  228.     spin_unlock(&dev->lock);  
  229.     return 0;  
  230. }  
  231.   
  232. static int sbull_release(struct gendisk *bd_disk, fmode_t mode)  
  233. {  
  234.     struct sbull_dev *dev = bd_disk->private_data;  
  235.   
  236.     spin_lock(&dev->lock);  
  237.     dev->users--;  
  238.   
  239.     if (!dev->users) {  
  240.         dev->timer.expires = jiffies + INVALIDATE_DELAY;  
  241.         add_timer(&dev->timer);  
  242.     }  
  243.     spin_unlock(&dev->lock);  
  244.   
  245.     return 0;  
  246. }  
  247.   
  248. /* 
  249.  * Look for a (simulated) media change. 
  250.  */  
  251. int sbull_media_changed(struct gendisk *gd)  
  252. {  
  253.     struct sbull_dev *dev = gd->private_data;  
  254.       
  255.     return dev->media_change;  
  256. }  
  257.   
  258. /* 
  259.  * Revalidate.  WE DO NOT TAKE THE LOCK HERE, for fear of deadlocking 
  260.  * with open.  That needs to be reevaluated. 
  261.  */  
  262. int sbull_revalidate(struct gendisk *gd)  
  263. {  
  264.     struct sbull_dev *dev = gd->private_data;  
  265.       
  266.     if (dev->media_change) {  
  267.         dev->media_change = 0;  
  268.         memset (dev->data, 0, dev->size);  
  269.     }  
  270.     return 0;  
  271. }  
  272.   
  273. /* 
  274.  * The "invalidate" function runs out of the device timer; it sets 
  275.  * a flag to simulate the removal of the media. 
  276.  */  
  277. void sbull_invalidate(unsigned long ldev)  
  278. {  
  279.     struct sbull_dev *dev = (struct sbull_dev *) ldev;  
  280.   
  281.     spin_lock(&dev->lock);  
  282.     if (dev->users || !dev->data)   
  283.         printk (KERN_WARNING "sbull: timer sanity check failed\n");  
  284.     else  
  285.         dev->media_change = 1;  
  286.     spin_unlock(&dev->lock);  
  287. }  
  288.   
  289. /* 
  290.  * The ioctl() implementation 
  291.  */  
  292.   
  293. int sbull_ioctl (struct block_device *bdev, fmode_t mode,  
  294.                  unsigned int cmd, unsigned long arg)  
  295. {  
  296.         return 0;  
  297. }  
  298.   
  299. static int sbull_getgeo(struct block_device *bdev, struct hd_geometry *geo)  
  300. {  
  301.     unsigned long size;  
  302.     struct sbull_dev *pdev = bdev->bd_disk->private_data;  
  303.   
  304.     size = pdev->size;  
  305.     geo->cylinders = (size & ~0x3f) >> 6;  
  306.     geo->heads   = 4;  
  307.     geo->sectors = 16;  
  308.     geo->start = 0;  
  309.     return 0;  
  310. }  
  311.   
  312.   
  313. /* 
  314.  * The device operations structure. 
  315.  */  
  316. static struct block_device_operations sbull_ops = {  
  317.     .owner           = THIS_MODULE,  
  318.     .open            = sbull_open,  
  319.     .release     = sbull_release,  
  320.     .media_changed   = sbull_media_changed,  
  321.     .revalidate_disk = sbull_revalidate,  
  322.     .ioctl           = sbull_ioctl,  
  323.     .getgeo         = sbull_getgeo,  
  324. };  
  325.   
  326.   
  327. /* 
  328.  * Set up our internal device. 
  329.  */  
  330. static void setup_device(struct sbull_dev *dev, int which)  
  331. {  
  332.     /* 
  333.      * Get some memory. 
  334.      */  
  335.     memset (dev, 0, sizeof (struct sbull_dev));  
  336.     dev->size = nsectors*hardsect_size;  
  337.     dev->data = vmalloc(dev->size);  
  338.     if (dev->data == NULL) {  
  339.         printk (KERN_NOTICE "vmalloc failure.\n");  
  340.         return;  
  341.     }  
  342.     spin_lock_init(&dev->lock);  
  343.       
  344.     /* 
  345.      * The timer which "invalidates" the device. 
  346.      */  
  347.     init_timer(&dev->timer);  
  348.     dev->timer.data = (unsigned long) dev;  
  349.     dev->timer.function = sbull_invalidate;  
  350.       
  351.     /* 
  352.      * The I/O queue, depending on whether we are using our own 
  353.      * make_request function or not. 
  354.      */  
  355.     switch (request_mode) {  
  356.         case RM_NOQUEUE:  
  357.         dev->queue = blk_alloc_queue(GFP_KERNEL);  
  358.         if (dev->queue == NULL)  
  359.             goto out_vfree;  
  360.         blk_queue_make_request(dev->queue, sbull_make_request);  
  361.         break;  
  362.   
  363.         case RM_FULL:  
  364.         dev->queue = blk_init_queue(sbull_full_request, &dev->lock);  
  365.         if (dev->queue == NULL)  
  366.             goto out_vfree;  
  367.         break;  
  368.   
  369.         default:  
  370.         printk(KERN_NOTICE "Bad request mode %d, using simple\n", request_mode);  
  371.             /* fall into.. */  
  372.       
  373.         case RM_SIMPLE:  
  374.         dev->queue = blk_init_queue(sbull_request, &dev->lock);  
  375.         if (dev->queue == NULL)  
  376.             goto out_vfree;  
  377.         break;  
  378.     }  
  379. //  blk_queue_hardsect_size(dev->queue, hardsect_size);  
  380.     blk_queue_logical_block_size(dev->queue, hardsect_size);  
  381.     dev->queue->queuedata = dev;  
  382.     /* 
  383.      * And the gendisk structure. 
  384.      */  
  385.     dev->gd = alloc_disk(SBULL_MINORS);  
  386.     if (! dev->gd) {  
  387.         printk (KERN_NOTICE "alloc_disk failure\n");  
  388.         goto out_vfree;  
  389.     }  
  390.     dev->gd->major = sbull_major;  
  391.     dev->gd->first_minor = which*SBULL_MINORS;  
  392.     dev->gd->fops = &sbull_ops;  
  393.     dev->gd->queue = dev->queue;  
  394.     dev->gd->private_data = dev;  
  395.     snprintf (dev->gd->disk_name, 32, "sbull%c", which + 'a');  
  396.     set_capacity(dev->gd, nsectors*(hardsect_size/KERNEL_SECTOR_SIZE));  
  397.     add_disk(dev->gd);  
  398.     return;  
  399.   
  400.   out_vfree:  
  401.     if (dev->data)  
  402.         vfree(dev->data);  
  403. }  
  404.   
  405.   
  406.   
  407. static int __init sbull_init(void)  
  408. {  
  409.     int i;  
  410.     /* 
  411.      * Get registered. 
  412.      */  
  413.     //  printk("<0>" "add by lht\n");  
  414.     sbull_major = register_blkdev(sbull_major, "sbull");  
  415.     if (sbull_major <= 0) {  
  416.         printk(KERN_WARNING "sbull: unable to get major number\n");  
  417.         return -EBUSY;  
  418.     }  
  419.     /* 
  420.      * Allocate the device array, and initialize each one. 
  421.      */  
  422.     Devices = kmalloc(ndevices*sizeof (struct sbull_dev), GFP_KERNEL);  
  423.     if (Devices == NULL)  
  424.         goto out_unregister;  
  425.     for (i = 0; i < ndevices; i++)   
  426.         setup_device(Devices + i, i);  
  427.       
  428.     return 0;  
  429.   
  430.   out_unregister:  
  431.     unregister_blkdev(sbull_major, "sbd");  
  432.     return -ENOMEM;  
  433. }  
  434.   
  435. static void sbull_exit(void)  
  436. {  
  437.     int i;  
  438.   
  439.     for (i = 0; i < ndevices; i++) {  
  440.         struct sbull_dev *dev = Devices + i;  
  441.   
  442.         del_timer_sync(&dev->timer);  
  443.         if (dev->gd) {  
  444.             del_gendisk(dev->gd);  
  445.             put_disk(dev->gd);  
  446.         }  
  447.         if (dev->queue) {  
  448.             if (request_mode == RM_NOQUEUE)  
  449.             //  blk_put_queue(dev->queue);  
  450.             kobject_put(&(dev->queue)->kobj);  
  451.             else  
  452.                 blk_cleanup_queue(dev->queue);  
  453.         }  
  454.         if (dev->data)  
  455.             vfree(dev->data);  
  456.     }  
  457.     unregister_blkdev(sbull_major, "sbull");  
  458.     kfree(Devices);  
  459. }  
  460.       
  461. module_init(sbull_init);  
  462. module_exit(sbull_exit); 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值