一,块设备的注册
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 ",
- 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 ",
- 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 ");
- 72. return 0;
- 73. }
- 74. static int blk_release(struct gendisk *gd , fmode_t no)
- 75. {
- 76. printk("blk umount succeed ");
- 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 ");
- 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! ");
- 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! ");
- 123. }
- 124.
- 125. module_init(block_module_init);
- 126. module_exit(block_module_exit);
- 127.
- 128. MODULE_LICENSE("GPL");