一,块设备的注册
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");