继续前行
接着上一篇 Linux Kernel - 探索Ram Disk 驱动(1) - 体验使用 , 我们来看一看Ram Disk驱动的实现.
代码源文件位于: drivers/block/brd.c, 总共不到700行, 至少从数字上来说, 看起来不麻烦.
在看代码之前, 我们可以思考一下磁盘设备应该具有的功能, 这样带着问题思考可能更有效率. 对于块设备来说, 无非就是读取一个块, 写入数据到一个块. 因此, 按照这个功能组织来分析代码, 基本就能了解个大概了.
要找到读写函数, 有两种方式, 我们可以直接按直觉搜索带read和write字眼的函数, 也可以从模块入口按图索骥. 不过直接找函数多少有点靠运气的感觉, 还是按一般思路来, 从模块初始化看起更好点.
对于驱动模块, 要找到其入口, 只要找到module_init就可以了, 在文件的末尾, 发现目标:
module_init(brd_init);
module_exit(brd_exit);
一般来说, 要找模块入口一般直接拖到文件最后就行. 为什么入口放在最后呢, 因为这样方便阅读, 那为什么一定要放在末尾而不是放在开头呢, 因为C语言里要引用一个符号必须先遇到声明或者定义, 如果写在开头, 就必须先写几行入口和出口函数声明, 然后是模块入口和出口的引用, 然后跟着入口函数和出口函数的定义; 而如果直接将出入口引用放在末尾的话, 就可以省去声明, 因为编译器在遇到引用之前已经发现出入口函数的定义了. —以上纯属个人推理, 请自行判断, ^-^
来看module_init(brd_init), 找到brd_init函数:
static int __init brd_init(void)
{
struct brd_device *brd, *next;
int i;
//....
//lqp comment: 注册RAMDISK_MAJOR(值为1)的为ramdisk的主设备号
if (register_blkdev(RAMDISK_MAJOR, "ramdisk"))
return -EIO;
if (unlikely(!max_part))
max_part = 1;
//lqp comment: 预分配brd设备
for (i = 0; i < rd_nr; i++) {
brd = brd_alloc(i);
if (!brd)
goto out_free;
list_add_tail(&brd->brd_list, &brd_devices);
}
/* point of no return */
//lqp comment: add_disk把预分配的disk注册到系统磁盘管理层
list_for_each_entry(brd, &brd_devices, brd_list)
add_disk(brd->brd_disk);
/*lqp comment: 这里注册整个RAMDISK_MAJOR的区域, 根据上下文的注释来看,
通过(RAMDISK_MAJOR, X)来访问brd设备的话, 如果X的值位于预分配的范围则
直接从预分配的设备中读取, 否则从brd_probe中分配, 对于我们研究brd操作来说,
只需要分析brd_alloc即可
*/
blk_register_region(