在上两篇博客中我们学习了块设备子系统数据组织结构,但是块设备子系统的总体上的初始化还没有涉及到,本章就开始学习块设备子系统的一系列初始化。
块设备子系统简而言之是Linux中管理块设备的一个子系统,是Linux中一个重要的子系统,没有块设备子系统我们的硬盘,光驱,USB在我们的linux 系统中都不可能感知,更别提热插拔的USB了。
块设备主要的子系统的初始话是在genhd_device_init
函数中下面就依照这个函数来进行解析:
static int __init genhd_device_init(void)
{
int error;
block_class.dev_kobj = sysfs_dev_block_kobj;
error = class_register(&block_class); //块设备类的注册
if (unlikely(error)) //如果错误返回错误值
return error;
bdev_map = kobj_map_init(base_probe, &block_class_lock); //块设备的管理初始化,主要管理着255个散列表,用于申请块设备以及注册块设备的时候时候
blk_dev_init(); //块设备最基础的设备使用
register_blkdev(BLOCK_EXT_MAJOR, "blkext"); //注册设备号为259的块设备文件系统
#ifndef CONFIG_SYSFS_DEPRECATED
/* create top-level block dir */
block_depr = kobject_create_and_add("block", NULL); //用于在驱动模型中/sys目录下生成block目录
#endif
return 0;
}
以上函数看起来很容易,但是俗话说:麻雀虽小五脏俱全。如果仔细理解的话可能就不太容易理解了,下面先对于函数中各个变量做一个简短的说明。
struct class block_class;
主要使用类设备的链表结构,把gendisk结构放入block_class类的private->class_device->i_klist链表下面便于寻找
struct kobj_map * bdev_map;
主要使用此散列表完成每个主设备号下面维护着若干个链表,每个链表每个节点下注册若干个块次设备号
struct kobject block_depr;
主要完成在/sys目录下生成一个block目录
各个不同的简略说明已经在注释中有说明,下面对各个不同的调用进行一一说明。
class_register(&block_class);
说明此函数之前我们先看一下此函数前后的调用关系,主要有两句C语言调用,如下:
block_class.dev_kobj = sysfs_dev_block_kobj;
error = class_register(&block_class);
其中block_class
变量是一个全局变量,定义在genhd_device_init
函数上面。sysfs_dev_block_kobj
也是一个全局变量,其主要作用是在/sys/dev/驱动模型下面生成一个block目录,并在class_register调用之后完成block_class注册。
我们再看一下block_class的作用,如下图:
其主要作用是在block_class->p->class_device->i_klist下面链接各个通用磁盘,链接的通用磁盘指针在上图有说明,不一一细说。然后在遍历驱动的时候先根据主磁盘的设备号查找磁盘,找到主设备号之后,然后根据次设备号查找磁盘分区。比较方便。
kobj_map_init(base_probe, &block_class_lock)
主要生成bdev_map全局变量,bdev_map为块设备驱动的散列表,主要管理着块设备驱动注册时候主设备号和次设备号的申请和释放。
bdev_map散列表总共有255个链表节点,每个链表节点下面有若干个节点组成,块设备在注册的时候用于查找未使用的主次设备号。
bdev_init
此函数原型如下:
int __init blk_dev_init(void)
{
BUILD_BUG_ON(__REQ_NR_BITS > 8 *
sizeof(((struct request *)0)->cmd_flags));
kblockd_workqueue = create_workqueue("kblockd");
if (!kblockd_workqueue)
panic("Failed to create kblockd\n");
request_cachep = kmem_cache_create("blkdev_requests",
sizeof(struct request), 0, SLAB_PANIC, NULL);
blk_requestq_cachep = kmem_cache_create("blkdev_queue",
sizeof(struct request_queue), 0, SLAB_PANIC, NULL);
return 0;
}
其函数主要有如下功能:
1.创建一个名为kblocked的工作队列。
2.建立一个缓存池,主要是为了request_list申请和释放使用的。
3.建立名为blkdev_queue的缓存池,主要是为了request_queue建立一个缓存池。用于request_queue的申请和释放。
register_blkdev(BLOCK_EXT_MAJOR, “blkext”);
主要建立bdev文件系统。bdev文件系统的作用已经在之前有所涉及,不在赘述。