block多队列分析 - 2. block多队列的初始化

本文解析了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初始化的重要步骤。

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并初始化

  1. config_group_init 初始化cofigfs group以供使用

  2. configfs_register_subsystem: 将config group注册进configfs

  3. null_alloc_dev 分配nullb_device,并初始化nullb_device的成员

  4. register_blkdev完成了nullb块设备的注册,实际是添加到全局major_names数组中

  5. 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并注册进系统

  1. setup_queues:主要为nullb_queue分配空间,个数由nr_cpu_ids来定义,同时也设置了队列深度
    nullb->queue_depth = nullb->dev->hw_queue_depth

  2. null_init_tag_set:对nullb的内嵌blk_mq_tag_set进行初始化,为set->mq_map分配空间,用于保存软硬队列的映射关系建立软硬件队列的映射关系,set->mq_map数组下标为cpu编号,数组元素为硬队列号。根据队列深度为每个硬件队列分配bitmap,创建request。

  3. blk_mq_init_queue_data创建request_queue并对其进行初始化,这里只考虑了多队列的情况

  4. 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
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值