目录
1. 前言
本专题文章是对多队列部分学习的笔记。主要以null_dev为例来研究多队列的工作机制, 为了能够凸显多队列的工作流程,只对block层做重点分析说明,对其它代码只做注释性说明。本文主要通过分析null blk块设备的初始化流程,来理解多队列的初始化,流程。
kernel版本:5.10
平台:arm64
注:
为方便阅读,正文标题采用分级结构标识,每一级用一个"-“表示,如:两级为”|- -", 三级为”|- - -“
2. null_init
static int __init null_init(void)
|--struct nullb *nullb;
| struct nullb_device *dev;
|--config_group_init(&nullb_subsys.su_group)
|--configfs_register_subsystem(&nullb_subsys)
|--register_blkdev(0, "nullb")
\--for (i = 0; i < nr_devices; i++)
dev = null_alloc_dev();
null_add_dev(dev);
null_init为null dev创建gendisk并注册进系统,创建软硬件队列及其映射关系,期间也会为null设备创建派发队列request_queue并初始化
-
config_group_init 初始化cofigfs group以供使用
-
configfs_register_subsystem: 将config group注册进configfs
-
null_alloc_dev 分配nullb_device,并初始化nullb_device的成员
-
register_blkdev完成了nullb块设备的注册,实际是添加到全局major_names数组中
-
null_add_dev为null设备创建gendisk并注册进系统,同时也创建了软硬队列的映射关系
static int null_add_dev(struct nullb_device *dev)
|--struct nullb *nullb;
|--null_validate_conf(dev)
| //tag_set嵌入nullb,因此分配nullb时连同nullb->tag_set一起分配
|--nullb = kzalloc_node(sizeof(*nullb), GFP_KERNEL, dev->home_node);
| nullb->dev = dev;
| dev->nullb = nullb
|
|--setup_queues(nullb)
|--if (dev->queue_mode == NULL_Q_MQ)
| null_init_tag_set(nullb, nullb->tag_set)
| nullb->q = blk_mq_init_queue_data(nullb->tag_set, nullb);
| else if (dev->queue_mode == NULL_Q_BIO)
| nullb->q = blk_alloc_queue(dev->home_node);
| rv = init_driver_queues(nullb);
|--nullb->q->queuedata = nullb;
|--blk_queue_logical_block_size(nullb->q, dev->blocksize)
|--blk_queue_physical_block_size(nullb->q, dev->blocksize)
|--null_config_discard(nullb);
\--null_gendisk_register(nullb)
|--struct gendisk *disk;
|--disk = nullb->disk = alloc_disk_node(1, nullb->dev->home_node);
|--set_capacity(disk, size);
|--if (queue_is_mq(nullb->q))
| disk->fops = &null_rq_ops;
| else
| disk->fops = &null_bio_ops;
\--add_disk(disk)
null_add_dev创建tag set并初始化,创建软硬件队列及其映射关系,为null设备创建request_queue并初始化,为null设备创建gendisk并注册进系统
-
setup_queues:主要为nullb_queue分配空间,个数由nr_cpu_ids来定义,同时也设置了队列深度
nullb->queue_depth = nullb->dev->hw_queue_depth -
null_init_tag_set:对nullb的内嵌blk_mq_tag_set进行初始化,为set->mq_map分配空间,用于保存软硬队列的映射关系建立软硬件队列的映射关系,set->mq_map数组下标为cpu编号,数组元素为硬队列号。根据队列深度为每个硬件队列分配bitmap,创建request。
-
blk_mq_init_queue_data创建request_queue并对其进行初始化,这里只考虑了多队列的情况
-
null_gendisk_register注册nullb磁盘设备。首先alloc_disk_node分配gendisk,add_disk 将gendisk注册进系统
|- -blk_mq_alloc_tag_set
static int null_init_tag_set(struct nullb *nullb, struct blk_mq_tag_set *set)
| //对nullb的内嵌blk_mq_tag_set进行初始化
|--set->ops = &null_mq_ops;
| set->nr_hw_queues = nullb ? nullb->dev->submit_queues : g_submit_queues;//初始化硬队列个数
| set->queue_depth = nullb ? nullb->dev->hw_queue_depth : g_hw_queue_depth;//初始化硬队列深度
| set->numa_node = nullb ? nullb->dev->home_node : g_home_node;
| set->cmd_size = sizeof(struct nullb_cmd);
| set->flags = BLK_MQ_F_SHOULD_MERGE;
| if (g_no_sched)
| set->flags |= BLK_MQ_F_NO_SCHED;
| if (g_shared_tag_bitmap)
| set->flags |= BLK_MQ_F_TAG_HCTX_SHARED;
| if ((nullb && nullb->dev->blocking) || g_blocking)
| set->flags |= BLK_MQ_F_BLOCKING;
\--blk_mq_alloc_tag_set(set)
| //分配set->nr_hw_queues个struct blk_mq_tags
|--blk_mq_realloc_tag_set_tags

本文解析了null_device的初始化过程,深入剖析了null_init函数中的null_b_add_dev,重点关注了blk_mq_tag_set的初始化、request_queue的创建与blk_mq_tag_set与request_queue的关系。介绍了如何通过blk_mq_alloc_tag_set和blk_mq_init_queue_data构建软硬件队列映射,以及elevator初始化的重要步骤。
最低0.47元/天 解锁文章
2894

被折叠的 条评论
为什么被折叠?



