blk_mq_init_queue函数学习记录

blk-mq编程,主要要调用两个函数进行初始化工作,blk_mq_init_queue这是第二个。该函数先是申请了struct request_queue结构,这个请求队列后面用于赋值给磁盘那个结构体的相应成员。

struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set)
{struct request_queue *uninit_q, *q;//分配struct request_queue并初始化uninit_q = blk_alloc_queue_node(GFP_KERNEL, set->numa_node, NULL);if (!uninit_q)return ERR_PTR(-ENOMEM);/*1:分配每个cpu专属的软件队列并初始化2:分配硬件队列,并初始化3:建立软件队列和硬件队列的联系*/q = blk_mq_init_allocated_queue(set, uninit_q);if (IS_ERR(q))blk_cleanup_queue(uninit_q);return q;
}
EXPORT_SYMBOL(blk_mq_init_queue);

blk_mq_init_allocated_queue函数分析

一眼望过去,确实有点复杂,不过,多看几遍就好了,
这里面,主要就是给struct request_queue *q结构体里面的成员变量赋值的,简单的变量赋值就不分析了,看看它调用的函数进行分析。

struct request_queue *blk_mq_init_allocated_queue(struct blk_mq_tag_set *set, struct request_queue *q)
{/* mark the queue as mq asap */q->mq_ops = set->ops;q->poll_cb = blk_stat_alloc_callback(blk_mq_poll_stats_fn, blk_mq_poll_stats_bkt, BLK_MQ_POLL_STATS_BKTS, q);if (!q->poll_cb)goto err_exit;q->queue_ctx = alloc_percpu(struct blk_mq_ctx);//percpu变量 软件队列if (!q->queue_ctx)goto err_exit;/* init q->mq_kobj and sw queues' kobjects */blk_mq_sysfs_init(q); //主要是初始化kobject变量//二级指针 硬件队列q->queue_hw_ctx = kcalloc_node(nr_cpu_ids, sizeof(*(q->queue_hw_ctx)), GFP_KERNEL, set->numa_node);if (!q->queue_hw_ctx)goto err_percpu;//赋值q->mq_map,这个数组保存了每个CPU对应的硬件队列编号q->mq_map = set->mq_map;blk_mq_realloc_hw_ctxs(set, q);if (!q->nr_hw_queues)goto err_hctxs;/*定时器初始化,设置超时时间*/INIT_WORK(&q->timeout_work, blk_mq_timeout_work);blk_queue_rq_timeout(q, set->timeout ? set->timeout : 30 * HZ);q->nr_queues = nr_cpu_ids;q->queue_flags |= QUEUE_FLAG_MQ_DEFAULT;if (!(set->flags & BLK_MQ_F_SG_MERGE))queue_flag_set_unlocked(QUEUE_FLAG_NO_SG_MERGE, q);q->sg_reserved_size = INT_MAX;INIT_DELAYED_WORK(&q->requeue_work, blk_mq_requeue_work);INIT_LIST_HEAD(&q->requeue_list);spin_lock_init(&q->requeue_lock);blk_queue_make_request(q, blk_mq_make_request);if (q->mq_ops->poll)q->poll_fn = blk_mq_poll;/** Do this after blk_queue_make_request() overrides it...*/q->nr_requests = set->queue_depth; //防止被覆盖/** Default to classic polling*/q->poll_nsec = -1;if (set->ops->complete)blk_queue_softirq_done(q, set->ops->complete);blk_mq_init_cpu_queues(q, set->nr_hw_queues);blk_mq_add_queue_tag_set(set, q);blk_mq_map_swqueue(q);if (!(set->flags & BLK_MQ_F_NO_SCHED)) {int ret;ret = elevator_init_mq(q);if (ret)return ERR_PTR(ret);}return q;
err_hctxs:kfree(q->queue_hw_ctx);
err_percpu:free_percpu(q->queue_ctx);
err_exit:q->mq_ops = NULL;return ERR_PTR(-ENOMEM);
}
EXPORT_SYMBOL(blk_mq_init_allocated_queue);

blk_stat_alloc_callback

这个函数一看也没什么分析的,主要也是给poll_cb进行赋值,采用了很多的默认函数进行赋值。

struct blk_stat_callback *
blk_stat_alloc_callback(void (*timer_fn)(struct blk_stat_callback *),int (*bucket_fn)(const struct request *), unsigned int buckets, void *data)
{struct blk_stat_callback *cb;cb = kmalloc(sizeof(*cb), GFP_KERNEL);if (!cb)return NULL;cb->stat = kmalloc_array(buckets, sizeof(struct blk_rq_stat), GFP_KERNEL);if (!cb->stat) {kfree(cb);return NULL;}cb->cpu_stat = __alloc_percpu(buckets * sizeof(struct blk_rq_stat), __alignof__(struct blk_rq_stat));if (!cb->cpu_stat) {kfree(cb->stat);kfree(cb);return NULL;}cb->timer_fn = timer_fn;cb->bucket_fn = bucket_fn;cb->data = data;cb->buckets = buckets;timer_setup(&cb->timer, blk_stat_timer_fn, 0);return cb;
}
EXPORT_SYMBOL_GPL(blk_stat_alloc_callback);

blk_mq_sysfs_init

接着到这个函数,也是变量的初始化工作,struct request_queue队列里面的kobject变量初始化,以及取出在每一个cpu上q->queue_ctx结构体,然后对齐成员kobject变量进行初始化。

void blk_mq_sysfs_init(struct request_queue *q)
{struct blk_mq_ctx *ctx;int cpu;kobject_init(&q->mq_kobj, &blk_mq_ktype);for_each_possible_cpu(cpu) {ctx = per_cpu_ptr(q->queue_ctx, cpu);//返回每个cpu上的q->queue_ctx变量的首地址kobject_init(&ctx->kobj, &blk_mq_ctx_ktype);}
}

blk_mq_realloc_hw_ctxs

这个函数相对来说比较重要。后面再补充。

在这里插入代码片

blk_queue_make_request

这个函数也是给q的其成员赋值的,先大概熟悉一下,如果有实际的调试分析,需要了解某个参数的值,到时再回来看吧。

void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn)
{/** set defaults*/q->nr_requests = BLKDEV_MAX_RQ; //这个值后面会重新赋值进行覆盖q->make_request_fn = mfn;blk_queue_dma_alignment(q, 511);blk_queue_congestion_threshold(q);q->nr_batching = BLK_BATCH_REQ;blk_set_default_limits(&q->limits);
}
EXPORT_SYMBOL(blk_queue_make_request);

blk_queue_softirq_done

也是赋值,IO操作完成时,会调用这个回调函数。

void blk_queue_softirq_done(struct request_queue *q, softirq_done_fn *fn)
{q->softirq_done_fn = fn;
}
EXPORT_SYMBOL(blk_queue_softirq_done);

blk_mq_init_cpu_queues

static void blk_mq_init_cpu_queues(struct request_queue *q, unsigned int nr_hw_queues)
{unsigned int i;for_each_possible_cpu(i) { //硬件队列数/*返回这个变量在编号为i的cpu上的起始地址*/struct blk_mq_ctx *__ctx = per_cpu_ptr(q->queue_ctx, i);struct blk_mq_hw_ctx *hctx;//其成员做一些赋值操作__ctx->cpu = i;spin_lock_init(&__ctx->lock);INIT_LIST_HEAD(&__ctx->rq_list);__ctx->queue = q;/** Set local node, IFF we have more than one hw queue. If* not, we remain on the home node of the device*/hctx = blk_mq_map_queue(q, i); //取出每个cpu上的硬件队列if (nr_hw_queues > 1 && hctx->numa_node == NUMA_NO_NODE)hctx->numa_node = local_memory_node(cpu_to_node(i));}
}

blk_mq_add_queue_tag_set


blk_mq_map_swqueue


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/166200.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python3到文件的读取以及输出

excel表格的读取和输入输出 python中txt的读取和输入输出 txt输出报错👇 UnicodeEncodeError: ascii codec cant encode characters in position 154-157: ordinal not in range(128)解决方法

Tomcat 配置

1: 打开 2:选择版本号,我这边是 1.7 3:添加 web 4: 添加jar包 5:添加 6:添加 Tomcat

【每日一题】1410. HTML实体解析器-2023.11.23

题目: 1410. HTML 实体解析器 「HTML 实体解析器」 是一种特殊的解析器,它将 HTML 代码作为输入,并用字符本身替换掉所有这些特殊的字符实体。 HTML 里这些特殊字符和它们对应的字符实体包括: 双引号:字符实体为 &…

vim翻页快捷键

Vim翻页 整页 Ctrlf向下翻页,下一页,相当于Page DownCtrlb向上翻页,上一页,相当于Page Up 半页 Ctrld向下半页,下一半页,光标下移Ctrlu向上半页,上衣半页,光标上移 按行 Ctrle…

vue2【组件的构成】

目录 1:什么是组件化开发 2:vue中的组件化开发 3:vue组件的三个组成部分 4:组件中定义方法,监听器,过滤器,计算属性节点。 5:template中只允许唯一根节点,style默认…

OpenMLDB SQL 开发调试神器 - OpenMLDB SQL Emulator

今天为大家介绍一款来自 OpenMLDB 社区的优秀独立工具 - OpenMLDB SQL Simulator(https://github.com/vagetablechicken/OpenMLDBSQLEmulator) ,可以让你更加高效方便的开发、调试 OpenMLDB SQL。 为了高效的实现时序特征计算,Op…

高质量短效SOCKS5代理IP是什么意思?作为技术你了解吗

小张是一位网络安全技术测试员,最近他接到了一个头疼的任务,那就是评估公司系统的安全性,因此他前来咨询,在得知SOCKS5代理IP可以帮他之后,他不禁产生疑问,这是什么原理?其实和小张一样的朋友不…

命令查询职责分离 (CQRS)

CQRS 的最初需求 多年来,传统的 CRUD(创建、读取、更新、删除)模式一直是系统架构的支柱。在 CRUD 中,读取和写入操作通常由相同的数据模型和相同的数据库模式处理。虽然这种方法简单直观,但随着系统规模的扩大和需求…

第99步 深度学习图像目标检测:SSDlite建模

基于WIN10的64位系统演示 一、写在前面 本期,我们继续学习深度学习图像目标检测系列,SSD(Single Shot MultiBox Detector)模型的后续版本,SSDlite模型。 二、SSDlite简介 SSDLite 是 SSD 模型的一个变种&#xff0c…

竹云参编《公共数据授权运营平台技术要求》团体标准正式发布

2023年11月23日,第二届全球数字贸易博览会“数据要素治理与市场化论坛”于杭州成功召开,国家数据局党组书记、局长刘烈宏,浙江省委常委、常务副省长徐文光出席会议并致辞。会上,国家工业信息安全发展研究中心发布并解读了我国首部…

[Linux] 冯诺依曼体系结构 与 操作系统

文章目录 1、冯诺依曼体系结构2、操作系统 1、冯诺依曼体系结构 冯诺依曼结构也称普林斯顿结构,是一种将程序指令存储器和数据存储器合并在一起的存储器结构。程序指令存储地址和数据存储地址指向同一个存储器的不同物理位置,因此程序指令和数据的宽度相…

【鸿蒙应用ArkTS开发系列】- 云开发入门实战二 实现省市地区三级联动地址选择器组件(下)

文章目录 概述端云调用流程端侧集成AGC SDK端侧省市地区联动的地址选择器组件开发创建省市数据模型创建省市地区视图UI子组件创建页面UI视图Page文件 打包测试总结 概述 我们在前面的课程,对云开发的入门做了介绍,以及使用一个省市地区联动的地址选择器…

三次输错密码后,系统是怎么做到不让我继续尝试的?

1故事背景 忘记密码这件事,相信绝大多数人都遇到过,输一次错一次,错到几次以上,就不允许你继续尝试了。 但当你尝试重置密码,又发现新密码不能和原密码重复: 图片 相信此刻心情只能用一张图形容&#xf…

Mobaxterm 使用lrzsz传输文件(rz/sz)

Mobaxterm 使用lrzsz传输文件报错 1. 现象 最近从xshell切换到Mobaxterm其他一切正常,就是使用rz传输文件时会出现错误,比较苦恼. 会出现以下错误 [rootcentos7 rpmbuild]# rz ▒CCCCCCCCCCC23be50ive.**B0100000023be502. 解决方法 去官网(https://mobaxterm.mobatek.net…

2021年03月 Scratch(三级)真题解析#中国电子学会#全国青少年软件编程等级考试

Scratch等级考试(1~4级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 在《采矿》游戏中,当角色捡到黄金时财富值加1分,捡到钻石时财富值加2分,下面哪个程序实现这个功能? A: B: C: D: 答案:D A将变量值固定,BC为双重判断

练习七-在Verilog中使用任务task

在Verilog中使用任务task 1,任务目的2,RTL代码,交换3,测试代码4,波形显示 1,任务目的 (1)掌握任务在verilog模块设计中的应用; (2)学会在电平敏感…

Android Studio记录一个错误:Execution failed for task ‘:app:lintVitalRelease‘.

Android出现Execution failed for task :app:lintVitalRelease.> Lint found fatal errors while assembling a release target. Execution failed for task :app:lintVitalRelease解决方法 Execution failed for task ‘:app:lintVitalRelease’ build project 可以正常执…

〖大前端 - 基础入门三大核心之JS篇㊷〗- DOM事件对象及它的属性

说明:该文属于 大前端全栈架构白宝书专栏,目前阶段免费,如需要项目实战或者是体系化资源,文末名片加V!作者:不渴望力量的哈士奇(哈哥),十余年工作经验, 从事过全栈研发、产品经理等工作&#xf…

进程已结束,退出代码-1073741571 (0xC00000FD)

今天遇到了一个很邪门的问题,没有报错,只是提示“进程已结束,退出代码-1073741571 (0xC00000FD)”。后来查资料说是栈溢出。 出问题的应该是上面这段代码。 这里我想把一个128*128的矩阵进行剪枝操作。 传入的128*128的矩阵太大了,两组for循…

介绍GLFW库和OpenGL和GLEW库三者之间的关系

具体来说,OpenGL是一个开放的图形库,它规定了每个函数应该如何执行,以及它们的输出值,但没有具体实现。它提供了渲染2D和3D图形的标准或规范。 GLEW,全称OpenGL Extension Wrangler Library,是一个用于管理…