[linux驱动]linux块设备学习笔记(三)——程序设计

本文详细介绍了Linux中块设备的注册过程,包括使用register_blkdev函数为块设备分配主设备号,并通过blk_init_queue初始化请求队列。此外,文章还展示了如何创建一个简单的块设备实例,包括数据传输和请求处理函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一,块设备的注册

1,linux中默认的块设备的最大主设备号为255,调用register_blkdev(unsigned int major,const char*name)来注册块设备,如果major参数为0的时候那么从系统1到255中选择一个最大的没有使用的号作为当前设备的块设备号,name是在/proc/devices节点里显示的名字。

数组major_names[]有255个元素,每个元素都是一个指针,指向blk_major_name结构体,同一个指针指向的多个blk_major_name通过链表相连,有点类似hash表

static struct blk_major_name{
	struct blk_major_name *next;
	int major;
	char name[16];
}*major_names[255]

279 int register_blkdev(unsigned int major, const char *name)
280 {
281         struct blk_major_name **n, *p;
282         int index, ret = 0;
284         mutex_lock(&block_class_lock);285 
287         if (major == 0) {
288                 for (index = ARRAY_SIZE(major_names)-1; index > 0; index--) {
289                         if (major_names[index] == NULL)
290                                 break;
291                 }
293                 if (index == 0) {
294                         printk("register_blkdev: failed to get major for %s\n",
295                                name);
296                         ret = -EBUSY;
297                         goto out;
298                 }
299                 major = index;
300                 ret = major;
301         }
303         p = kmalloc(sizeof(struct blk_major_name), GFP_KERNEL);
304         if (p == NULL) {
305                 ret = -ENOMEM;
306                 goto out;
307         }
309         p->major = major;
310         strlcpy(p->name, name, sizeof(p->name));
311         p->next = NULL;
312         index = major_to_index(major);
314         for (n = &major_names[index]; *n; n = &(*n)->next) {
315                 if ((*n)->major == major)
316                         break;
317         }
318         if (!*n)
319                 *n = p;
320         else
321                 ret = -EBUSY;
322 
323         if (ret < 0) {
324                 printk("register_blkdev: cannot get major %d for %s\n",
325                        major, name);
326                 kfree(p);
327         }
328 out:
329         mutex_unlock(&block_class_lock);
330         return ret;
331 }


 二:块设备请求队列的初始化

以下代码转自点击打开链接

调用函数blk_init_queue来初始化请求队列。当处理在队列上的请求时,必须持有队列自旋锁。初始化请求队列,

request_queue_t *blk_init_queue(request_fn_proc *rfn, spinlock_t *lock);//该函数的第1个参数是请求处理函数的指针,第2个参数是控制访问队列权限的自旋锁

#include <linux/init.h>    
02. #include <linux/module.h>    
03. #include <linux/kernel.h>    
04. #include <linux/fs.h>  
05. #include <asm/uaccess.h>  
06. #include <linux/spinlock.h>  
07. #include <linux/sched.h>  
08. #include <linux/types.h>  
09. #include <linux/fcntl.h>  
10. #include <linux/hdreg.h>  
11. #include <linux/genhd.h>  
12. #include <linux/blkdev.h>  
13.   
14. #define MAXBUF 1024   
15.   
16.   
17. #define BLK_MAJOR 253  
18.   
19. char blk_dev_name[]="blk_dev";  
20. static char flash[1024*16];  
21.   
22.   
23. int major;  
24. spinlock_t lock;  
25. struct gendisk *gd;  
26.   
27.   
28.   
29. /*块设备数据传输*/  
30. static void blk_transfer(unsigned long sector, unsigned long nsect, char *buffer, int write)  
31. {  
32.     int read = !write;  
33.     if(read)  
34.     {  
35.         memcpy(buffer, flash+sector*512, nsect*512);  
36.     }  
37.     else  
38.     {  
39.         memcpy(flash+sector*512, buffer, nsect*512);  
40.     }  
41. }  
42.   
43. /*块设备请求处理函数*/  
44. static void blk_request_func(struct request_queue *q)  
45. {  
46.     struct request *req;  
47.     while((req = elv_next_request(q)) != NULL)    
48.     {  
49.         if(!blk_fs_request(req))  
50.         {  
51.             end_request(req, 0);  
52.             continue;  
53.         }  
54.           
55.         blk_transfer(req->sector, req->current_nr_sectors, req->buffer, rq_data_dir(req));  
56.         /*rq_data_dir从request获得数据传送的方向*/  
57.         /*req->current_nr_sectors 在当前段中将完成的扇区数*/  
58.         /*req->sector 将提交的下一个扇区*/  
59.         end_request(req, 1);  
60.     }  
61. }  
62.   
63. /*strcut block_device_operations*/  
64. static  int blk_ioctl(struct block_device *dev, fmode_t no, unsigned cmd, unsigned long arg)  
65. {  
66.        return -ENOTTY;  
67. }  
68.   
69. static int blk_open (struct block_device *dev , fmode_t no)  
70. {  
71.     printk("blk mount succeed\n");  
72.     return 0;  
73. }  
74. static int blk_release(struct gendisk *gd , fmode_t no)  
75. {  
76.     printk("blk umount succeed\n");  
77.     return 0;  
78. }  
79. struct block_device_operations blk_ops=  
80. {  
81.     .owner = THIS_MODULE,  
82.     .open = blk_open,  
83.     .release = blk_release,  
84.     .ioctl = blk_ioctl,  
85. };  
86.   
87. //-----------------------------------------------  
88.   
89. static int __init block_module_init(void)  
90. {  
91.       
92.       
93.     if(!register_blkdev(BLK_MAJOR, blk_dev_name)) //注册一个块设备  
94.     {  
95.         major = BLK_MAJOR;    
96.         printk("regiser blk dev succeed\n");  
97.     }  
98.     else  
99.     {  
100.         return -EBUSY;  
101.     }  
102.     gd = alloc_disk(1);  //分配一个gendisk,分区是一个  
103.     spin_lock_init(&lock); //初始化一个自旋锁  
104.     gd->major = major;  
105.     gd->first_minor = 0;   //第一个次设备号  
106.     gd->fops = &blk_ops;   //关联操作函数  
107.   
108.     gd->queue = blk_init_queue(blk_request_func, &lock); //初始化请求队列并关联到gendisk  
109.   
110.     snprintf(gd->disk_name, 32, "blk%c", 'a');    
111.     blk_queue_hardsect_size(gd->queue, 512);  //设置扇区大小512字节  
112.     set_capacity(gd, 32);  //设置块设备大小 512*32=16K  
113.     add_disk(gd);  
114.     printk("gendisk init success!\n");  
115.     return 0;  
116. }  
117. static void __exit block_module_exit(void)  
118. {  
119.     blk_cleanup_queue(gd->queue);  
120.     del_gendisk(gd);   
121.     unregister_blkdev(BLK_MAJOR, blk_dev_name);  
122.     printk("block module exit succeed!\n");  
123. }  
124.   
125. module_init(block_module_init);  
126. module_exit(block_module_exit);  
127.   
128. MODULE_LICENSE("GPL");  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值