1. 前言
本专题我们开始学习通用block层的相关内容。本专题主要参考了《存储技术原理分析》、ULA、ULK的相关内容。本文为概述部分
kernel版本:5.10
FS: minix
平台:arm64
注:
为方便阅读,正文标题采用分级结构标识,每一级用一个"-“表示,如:两级为”|- -", 三级为”|- - -“
2. I/O子系统总体结构
-
通用块层:为各种类型的设备建立了一个统一的模型,通用块层的主要工作是接受上层(FS)发出的磁盘请求,并最终发出IO请求,该层隐藏了底层硬件设备的特性,为块设备提供了一个通用的抽象视图
-
IO调度层:接受通用块层发出的IO请求,缓存请求并试图合并相邻的请求,根据设置好的调度算法,回调驱动层提供的请求处理函数
-
块设备驱动层:具体IO交给块设备驱动层处理,它可能是纯粹的软件层不跟硬件打交道,而是跟某类块设备子系统打交道
注:在5.10中已经去除了传统单队列,因此对应的IO但队列调度器也一起删除,取而代之的多队列调度器dead line
3. genhd_device_init
static void __init do_basic_setup(void)
|....
|--driver_init();
| |......
| |--devices_init();
| | |--devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
| | |--dev_kobj = kobject_create_and_add("dev", NULL);
| | |--sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
| | |--sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
| \......
|--do_initcalls();
\....
在说明genhd_device_init之前先来介绍下devices_init, 在start_kernel的do_basic_setup->driver_init->devices_init,会在sys下创建deivces目录,在根目录/创建dev目录, 在/dev下创建block和char目录
<block/genhd.c>
struct class block_class = {
.name = "block",
};
static int __init genhd_device_init(void)
{
int error;
//此sysfs_dev_block_kobj对应/dev/block
block_class.dev_kobj = sysfs_dev_block_kobj;
//注册block_class,这样会创建/sys/class/block目录
error = class_register(&block_class);
if (unlikely(error))
return error;
//分配kobj_map结构体,保存在全局bdev_map,用于磁盘设备gendisk与设备号的映射
bdev_map = kobj_map_init(base_probe, &block_class_lock);
blk_dev_init();
register_blkdev(BLOCK_EXT_MAJOR, "blkext");
/* create top-level block dir */
if (!sysfs_deprecated)
block_depr = kobject_create_and_add("block", NULL);
return 0;
}
subsys_initcall(genhd_device_init);
do_initcalls中会执行genhd_device_init
kobj_map_init:分配kobj_map结构体,保存在全局bdev_map,用于磁盘设备gendisk与设备号的映射,在添加磁盘设备一节可以看到注册磁盘设备就是在bdev_map建立设备号与gendisk的映射
参考文档
《存储技术原理分析》