免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 6832 | 回复: 6
打印 上一主题 下一主题

写了一个简单的linux 块设备驱动程序,加载后死机(源码) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-10-06 19:47 |只看该作者 |倒序浏览
本帖最后由 954423389 于 2011-10-08 07:43 编辑

谢谢您的时间
我写了一个简单的块设备驱动程序,加载后死机,不知道为啥。

就卡在这里,我的驱动程序源码在下面,根据《写一个块设备驱动程序》这个教程写的,
  1. #include <linux/genhd.h>
  2. #include <linux/fs.h>
  3. #include <linux/blkdev.h>
  4. #include <linux/types.h>
  5. #include <linux/module.h>

  6. /*全局数组,表示本设备*/
  7. unsigned char array_data[16*1024*1024];

  8. /*全局变量,表示本设备*/
  9. struct gendisk *my_gendisk;
  10. /*全局变量,主设备号*/
  11. int major_num = -1;

  12. /*全局变量,本设备关联的请求队列*/
  13. struct request_queue *my_request_queue = NULL;
  14. /*全局变量,内核访问请求队列的自旋锁*/
  15. spinlock_t lock;


  16. /*对块设备的操作函数集合(函数指针集合)*/
  17. struct block_device_operations my_operations=
  18. {
  19.     .owner        = THIS_MODULE,
  20. };


  21. static void
  22. my_process_on_request_queue(struct request_queue *q)
  23. {
  24.     struct request *req;
  25.     sector_t sector = 0;
  26.     unsigned int current_nr_sectors = 0;


  27.    
  28.    

  29.     while (NULL != (req = blk_fetch_request (q)))/*linux/blkdev.h*/
  30.     {
  31.         sector = blk_rq_pos (req);
  32.         current_nr_sectors = blk_rq_cur_sectors (req);

  33.         if( (sector+current_nr_sectors)<<9 >16*1024*1024)
  34.         {
  35.             printk(KERN_ERR"bad request\n");
  36.             blk_end_request_all (req,0);/*linux/blkdev.h*/
  37.             continue;
  38.         }
  39.    
  40.    
  41.       switch (rq_data_dir (req))/*1为write   0为read*/
  42.       {
  43.         case 1:
  44.             memcpy(req->buffer,array_data+(sector<<9),(current_nr_sectors<<9));   
  45.             blk_end_request_all (req,1);
  46.             break;
  47.         case 0:
  48.             memcpy(array_data+(sector<<9),req->buffer,(current_nr_sectors<<9));   
  49.             blk_end_request_all (req,1);

  50.         default:break;
  51.             
  52.       }
  53.     }

  54.     return;
  55. }


  56. static int __init
  57. my_init(void)
  58. {   
  59.    
  60.    
  61.     /*1、为代表本设备的结构体申请内存
  62.          这里的参数是本磁盘使用的次设备号的数目,一经申请,这个数字就不可更改   
  63.     */
  64.     my_gendisk = alloc_disk (1);/*linux/genhd.h*/
  65.     if (NULL == my_gendisk)
  66.     {
  67.         printk(KERN_NOTICE"alloc gendisk failure\n");
  68.         return -ENOMEM;
  69.     }
  70.     /*2、为这个结构体成员变量复制,必须的赋值有5个*/
  71.     /*申请"主"设备号,这个名字是出现在:估计是设备号数据库那里的名字 /proc/devices下显示的(下面还有一个名字)事实证明的确如此“251 blocksimple”*/   

  72.     major_num = register_blkdev (0,"blocksimple");/*linux/fs.h*/
  73.     if (major_num<=0)
  74.     {
  75.         printk(KERN_WARNING"no major number\n");
  76.         /*申请主设备号失败的时候,驱动程序就无法正常加载,要释放已经申请的资源,目前资源只有gendisk*/
  77.         goto major_alloc_error;
  78.         
  79.     }
  80.     /*3、我们提到过,每个块设备关联了一个请求队列,我们这里申请一个,需要注意的是:
  81.     1)每个请求队列都对应一个”请求队列处理函数“,这个是设备相关的        
  82.     2)每次分配一个请求队列的时候,必须提供一个自旋锁来控制对请求队列的访问,我们先不考虑并发访问
  83.     */
  84.     spin_lock_init (&lock);

  85.     my_request_queue = blk_init_queue (my_process_on_request_queue,&lock);
  86.     if (NULL == my_request_queue)
  87.     {
  88.         printk("request queue error");
  89.         goto requeue_alloc_error;   
  90.    
  91.     }
  92.     /*4、使用前面申请的资源为gendisk赋值*/
  93.     strcpy(my_gendisk->disk_name ,"BlockSimple");/*本设备的名称,这个名称是出现在“/dev/”目录下的cd */
  94.     my_gendisk->major = major_num;
  95.     my_gendisk->first_minor = 0;
  96.     my_gendisk->queue = my_request_queue;
  97.     my_gendisk->fops = &my_operations;
  98.     /*设置块设备的大小,以扇区为单位,因为内核总是认为扇区大小是512B,所以用函数设定*/
  99.     set_capacity (my_gendisk,16*1024*2);

  100.    
  101.     /*5、注册gendisk*/
  102.     add_disk (my_gendisk);
  103.     return 0;




  104. requeue_alloc_error:
  105.     /*释放主设备号,和gendisk*/
  106.     unregister_blkdev(major_num, "blocksimple");
  107. major_alloc_error:
  108.     /*释放gendisk*/
  109.     del_gendisk(my_gendisk);
  110.     return -ENOMEM;

  111. }


  112. static void __exit
  113. my_exit(void)
  114. {
  115.     blk_cleanup_queue (my_request_queue);
  116.    
  117.     unregister_blkdev(major_num, "blocksimple");

  118.     del_gendisk(my_gendisk);
  119.    


  120. }

  121. module_init (my_init);
  122. module_exit (my_exit);
复制代码

论坛徽章:
0
2 [报告]
发表于 2011-10-06 20:36 |只看该作者
:wink:先谢谢各位了

论坛徽章:
0
3 [报告]
发表于 2011-10-10 11:14 |只看该作者
如果你机器的内存大于2G那你的那个全局变量开得太大了。
具体不懂可以再问啊。

论坛徽章:
0
4 [报告]
发表于 2011-10-10 13:51 |只看该作者
你可以参考一下这个帖子,我在这个帖子中做过回复~
http://bbs.chinaunix.net/viewthr ... ;page=1#pid21155610

论坛徽章:
0
5 [报告]
发表于 2011-10-12 18:34 |只看该作者
回复 4# npuazm


    你好,我的问题解决了,我函数用错了,汗颜了,我并没有仔细研究那些函数,本想简单的实现个例子。
     blk_end_request_all   换成 __blk_end_request_all  就可以了。

     谢谢你的回复。
      下面是我的源码,希望有相同问题的人参考 内核版本是2.6.32 ubuntu 10.04
  1. /*为了便于讲解,一律没有使用宏*/
  2. #include <linux/genhd.h>
  3. #include <linux/fs.h>
  4. #include <linux/blkdev.h>
  5. #include <linux/types.h>
  6. #include <linux/module.h>

  7. /*全局数组,表示本设备*/
  8. unsigned char array_data[16*1024*1024];

  9. /*全局变量,表示本设备*/
  10. struct gendisk *my_gendisk;
  11. /*全局变量,主设备号*/
  12. int major_num = -1;

  13. /*全局变量,本设备关联的请求队列*/
  14. struct request_queue *my_request_queue = NULL;
  15. /*全局变量,内核访问请求队列的自旋锁*/
  16. static DEFINE_SPINLOCK (lock);


  17. /*对块设备的操作函数集合(函数指针集合)*/
  18. struct block_device_operations my_operations=
  19. {
  20.         .owner                = THIS_MODULE,
  21. };

  22. static void sbd_transfer(sector_t sector,unsigned long nsect, char *buffer, int write)
  23. {
  24.         unsigned long offset = sector<<9;
  25.         unsigned long nbytes = nsect<<9;

  26.         if ((offset + nbytes) > 16*1024*1024) {
  27.                 printk (KERN_NOTICE "sbd: Beyond-end write (%ld %ld)\n", offset, nbytes);
  28.                 return;
  29.         }
  30.         if (write)
  31.                 memcpy(array_data + offset, buffer, nbytes);
  32.         else
  33.                 memcpy(buffer, array_data + offset, nbytes);
  34. }

  35. static void
  36. my_process_on_request_queue(struct request_queue *q)
  37. {

  38.         struct request *req;

  39.         req = blk_fetch_request(q);
  40.         while (req != NULL)
  41.         {
  42.                 if (req == NULL || (req->cmd_type != REQ_TYPE_FS))
  43.                 {
  44.                         printk (KERN_NOTICE "Skip non-CMD request\n");
  45.                         __blk_end_request_all(req, -EIO);
  46.                         continue;
  47.                 }
  48.                 sbd_transfer(blk_rq_pos(req), blk_rq_cur_sectors(req),req->buffer, rq_data_dir(req));
  49.                 if ( ! __blk_end_request_cur(req, 0) ) {
  50.                         req = blk_fetch_request(q);
  51.                 }
  52.         }
  53. }


  54. static int __init
  55. my_init(void)
  56. {       
  57.        
  58.        
  59.         /*1、为代表本设备的结构体申请内存
  60.              这里的参数是本磁盘使用的次设备号的数目,一经申请,这个数字就不可更改       
  61.         */
  62.         my_gendisk = alloc_disk (1);/*linux/genhd.h*/
  63.         if (NULL == my_gendisk)
  64.         {
  65.                 printk(KERN_NOTICE"alloc gendisk failure\n");
  66.                 return -ENOMEM;
  67.         }
  68.         /*2、为这个结构体成员变量复制,必须的赋值有5个*/
  69.         /*申请"主"设备号,这个名字是出现在:估计是设备号数据库那里的名字 /proc/devices下显示的(下面还有一个名字)事实证明的确如此“251 blocksimple”*/       

  70.         major_num = register_blkdev (0,"blocksimple");/*linux/fs.h*/
  71.         if (major_num<=0)
  72.         {
  73.                 printk(KERN_WARNING"no major number\n");
  74.                 /*申请主设备号失败的时候,驱动程序就无法正常加载,要释放已经申请的资源,目前资源只有gendisk*/
  75.                 goto major_alloc_error;
  76.                
  77.         }
  78.         /*3、我们提到过,每个块设备关联了一个请求队列,我们这里申请一个,需要注意的是:
  79.         1)每个请求队列都对应一个”请求队列处理函数“,这个是设备相关的               
  80.         2)每次分配一个请求队列的时候,必须提供一个自旋锁来控制对请求队列的访问,我们先不考虑并发访问
  81.         */
  82.         //spin_lock_init (&lock);

  83.         my_request_queue = blk_init_queue (my_process_on_request_queue,&lock);

  84.         if (NULL == my_request_queue)
  85.         {
  86.                 printk("request queue error");
  87.                 goto requeue_alloc_error;       
  88.        
  89.         }
  90.         /*4、使用前面申请的资源为gendisk赋值*/
  91.         strcpy(my_gendisk->disk_name ,"BlockSimple");/*本设备的名称,这个名称是出现在“/dev/”目录下的 */
  92.         my_gendisk->major = major_num;
  93.         my_gendisk->first_minor = 0;
  94.         my_gendisk->queue = my_request_queue;
  95.         my_gendisk->fops = &my_operations;
  96.         /*设置块设备的大小,以扇区为单位,因为内核总是认为扇区大小是512B,所以用函数设定*/
  97.         set_capacity (my_gendisk,16*1024*2);

  98.        
  99.         /*5、注册gendisk*/
  100.         add_disk (my_gendisk);
  101.         return 0;




  102. requeue_alloc_error:
  103.         /*释放主设备号,和gendisk*/
  104.         unregister_blkdev(major_num, "blocksimple");
  105. major_alloc_error:
  106.         /*释放gendisk*/
  107.         del_gendisk(my_gendisk);
  108.         return -ENOMEM;

  109. }


  110. static void __exit
  111. my_exit(void)
  112. {
  113.         blk_cleanup_queue (my_request_queue);
  114.        
  115.         unregister_blkdev(major_num, "blocksimple");

  116.         del_gendisk(my_gendisk);
  117.         put_disk (my_gendisk);
  118. }


  119. module_init (my_init);
  120. module_exit (my_exit);
复制代码

论坛徽章:
0
6 [报告]
发表于 2011-10-12 18:38 |只看该作者
回复 3# lovehahaforever


    谢谢你的回答,我的问题解决了,不是内存这边的事。
   我大体上能听明白你的回答,不过我不知道,高端内存大了之后,申请个16M的空间就会死机么,我的电脑是1G的,我对内存也是刚刚了解。非线性区那么紧缺么,以后下次找机会试试,呵呵

论坛徽章:
0
7 [报告]
发表于 2011-10-22 13:01 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP