【Linux驱动】块设备驱动(三)—— 块设备读写(不使用请求队列)

并非每种块设备都会用到请求队列,从上节可以知道,请求队列的作用是管理和调用IO请求,那么反过来想,如果IO请求较少,那就可以无需使用请求队列。在以下情况中,可以不使用请求队列。

  • 单任务环境: 当系统中只有单个任务(线程或进程)需要对存储设备进行读写操作时,IO操作可以直接被发起,而无需经过请求队列进行调度。

  • IO操作不频繁: 当系统中的IO操作非常稀少并且不频繁时,IO操作可以被直接发起,并由底层设备来处理,而无需经过请求队列进行处理。

  • 闪存设备:闪存设备通常由多个存储单元(通常是存储芯片)组成,每个存储单元可以存储大量的数据,通常以块(页)为单位进行读写,每个块的大小通常为几十到几百KB,因此,闪存设备可以直接以块为单位进行读写,无需像传统设备那样以扇区为单位进行读写。

本篇的重点是在不使用请求队列的情况下读写块设备,依然需要用到请求处理函数,只不过内部的逻辑与之前有所不同。


目录

一、制造请求

1、API 介绍

2、代码实现

二、请求处理函数

1、遍历 bio 结构退数组

2、获取扇区起始地址

3、获取内存页起始地址及页偏移

4、获取数据长度

5、读写操作实现

6、关闭 bio 操作

7、完整示例


一、制造请求

1、API 介绍

现在不使用请求队列,所以下面要换一个请求处理函数的原型,使用 blk_queue_make_request 来注册一个新的请求处理函数。函数声明如下,这里虽然还注册了一个请求队列,但是我们后续不会用到这个请求队列。

/*** @param q     请求队列* @param hanle 请求处理函数指针*/
void blk_queue_make_request(struct request_queue * q, make_request_fn * handle);

make_request_fn 函数指针的原型如下,q 为请求队列,bio 为 bio 结构体数组,bio 是一种描述块设备IO操作的数据结构,如起始地址、操作的数据长度、目的地址等信息都在这个结构体中。

ps:上一节在介绍每个请求的结构提到过。(详情参考上一篇的第三部分内容)

/*** @param q     请求队列* @param hanle 请求处理函数指针*/
void (* make_request_fn)(struct request_queue *q, struct bio *bio);

注意:后续测试不会使用这个请求队列,这个请求队列只是以备不时之需。 

2、代码实现

这里就直接在之前的基础上进行修改,修改的地方只有一处,将原本的 “申请请求队列” 替换为 “制造请求”即可。其中 blk_alloc_queue 用于动态创建并初始化一个请求队列。

// 请求处理函数
void make_request_hanlde(struct request_queue *q, struct bio *bio)
{
}// 驱动入口函数
static int __init blkdriver_init(void)
{// ... ... /*制造请求*/blkdev.queue = blk_alloc_queue(GFP_KERNEL);if(blkdev.queue == NULL){del_gendisk(blkdev.gendisk); unregister_blkdev(blkdev.major, blkdev_NAME);return -1;}blk_queue_make_request(blkdev.queue, make_request_hanlde);// ... ...
}

二、请求处理函数

bio 中包含了两个重要结构体对象,一个是 bio_vec 结构体对象 bi_io_vec,保存了内存页的相关信息,如页地址、页偏移;另一个是 bvec_iter 结构体对象 bi_iter,保存了块设备扇区相关信息,如扇区地址。

1、遍历 bio 结构退数组

遍历 bio 数组使用的是宏 bio_for_each_segment,本质是一个for 循环,bvec、bio 和 iter 都是 for 循环中的循环项,该宏的声明如下。

/** @param bvec: bio_vec结构体对象 (保存的是内存页信息)* @param bio: bio 结构体指针* @param iter: bvec_iter结构体对象 (保存的是扇区信息)*/
#define bio_for_each_segment(bvec, bio, iter)

传入的 bvec、bio 和 iter 之间关系如下,随着循环的推进,bio 指针也会跟着变化。

iter = bio->bi_iter;
bvec = bio->bi_io_vec;
bio = bio + sizeof(bio);

2、获取扇区起始地址

因为这里是将虚拟内存 diskbuf 模拟成一个块设备,所以这里无需手动获取扇区地址。若是在使用真实块设备时,可以使用传入的 iter 循环项来获取扇区起始地址。

sector_t start = iter.bi_sector;    // sector_t 本质是unsigned long 类型

3、获取内存页起始地址及页偏移

获取页偏移可以直接通过 bvec 循环项获取。

int offset = bvec.bv_offset;

获取内存页起始地址有两种方法:

① bio_data 一步到位

bio_data 是内核提供的API,能够获取内存中数据页的地址,在上一篇也用到了,函数声明如下:

/*** @param bio 指向bio结构体的指针* @return    成功返回指向指定数据页的地址*/
void *bio_data(struct bio *bio);

② 逐步获取

这种方法其实就是根据 bvec 循环项先获取到 page 结构体成员,然后将 page 转换成数据页地址

struct page* pagestruct = bvec.bv_page;        // 先获取到与数据页相关的数据类型
void* buffer = page_address(pagestruct);       // 从 page 结构体获取到页地址

4、获取数据长度

在遍历 bio 数组时,bio_vec 的 bv_len 代表当前数据段的长度;bvec_iter 的 bi_size 是当前迭代器所指向的数据段的字节数,这两者是一致的。一般使用 bv_len

int len = bvec.bv_len;

5、读写操作实现

这里的读写操作和上一篇基本一致,使用 bio_data_dir 来判断读写方向

if (bio_data_dir(bio) == WRITE)memcpy(blkdev.diskbuf, buffer + offset, len);
else if (bio_data_dir(bio) == READ)memcpy(buffer + offset, blkdev.diskbuf, len);

6、关闭 bio 操作

和上一篇 blk_end_request 一样,每次请求处理结束,需要做一些收尾工作,如释放用于 I/O 操作的资源、更新状态信息、通知上层文件系统或者块层,还可以处理错误情况。使用的API原型如下:

/*** @param bio     指向bio结构体的指针* @param error   I/O操作的错误码*/
void bio_endio(struct bio *bio, int error);

7、完整示例

void make_request_hanlde(struct request_queue *q, struct bio *bio)
{int offset = 0;int len = 0;struct bio_vec bvec;            // 内存页信息struct bvec_iter iter;          // 块设备扇区信息printk("请求处理函数被触发!\n");bio_for_each_segment(bvec, bio, iter) {// 扇区起始地址// 内存页起始地址void* buffer = page_address(pageAddr);// 内存偏移offset = bvec.bv_offset;// 涉及的数据长度len = bvec.bv_len;if (bio_data_dir(bio) == WRITE){memcpy(blkdev.diskbuf, buffer + offset, len);}else if (bio_data_dir(bio) == READ){memcpy(buffer + offset, blkdev.diskbuf, len);}}bio_endio(bio, 0);
}

替换请求处理函数以后,将块设备注册到内核无异常,输入 fdisk -l 可以看到我们注册的块设备 

此外,fdisk -l 会触发请求处理函数,所以会打印预设的内容。

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

HarmonyOS class类对象基础使用

按我们之前的写法 就是 Entry Component struct Dom {p:Object {name: "小猫猫",age: 21,gf: {name: "小小猫猫",age: 18,}}build() {Row() {Column() {// ts-ignoreText(this.p.gf.name)}.width(100%)}.height(100%)} }直接用 Object 一层一层往里套 这…

机器学习——有监督学习和无监督学习

有监督学习 简单来说,就是人教会计算机学会做一件事。 给算法一个数据集,其中数据集中包含了正确答案,根据这个数据集,可以对额外的数据希望得到一个正确判断(详见下面的例子) 回归问题 例如现在有一个…

基于单片机的造纸纸浆液位控制系统结构设计

摘要:为适应无人化与高效化制浆造纸生产体系,造纸企业趋于以嵌入式技术优化造纸过 程中的纸浆液位控制系统,以单片机与传感器相互耦合实现纸浆液位控制。本文基于单片机 设计了造纸纸浆液位控制系统,其结构由控制模块、信息采集模块、物联网模…

图数据库 之 Neo4j - Browser 介绍(3)

Neo4j Browser 介绍 Neo4j Browser 中有 3 个模块,侧边栏,Cypher 编辑器与结果栏,在进入 Neo4j Browser 时结果栏会展示欢迎界面。 Cypher 编辑器 Cypher 是一种图形查询语言,用于查询和操作图形数据库。它是 Neo4j 图形数据库的…

uniapp+uView 【详解】录音,自制音频播放器

效果预览 代码实现 <template><view class"btnListBox"><view class"audioBox" v-if"audioLength"><u-row><u-col span"2"><u--text aligncenter :text"currentTime"></u--text>…

[Vulnhub靶机] DriftingBlues: 4

[Vulnhub靶机] DriftingBlues: 4靶机渗透思路及方法&#xff08;个人分享&#xff09; 靶机下载地址&#xff1a; https://download.vulnhub.com/driftingblues/driftingblues4_vh.ova 靶机地址&#xff1a;192.168.67.23 攻击机地址&#xff1a;192.168.67.3 一、信息收集 …

使用secure+xming通过x11访问ubuntu可视化程序

windows使用securexming通过x11访问ubuntu可视化程序 windows机器IP&#xff1a;192.168.9.133 ubuntu-desktop20.04机器IP&#xff1a;192.168.9.190 windows下载xming并安装 按照图修改xming配置 开始->xming->Xlaunch 完成xming会在右下角后台运行 windows在sec…

20240203在WIN10下使用GTX1080配置stable-diffusion-webui.git不支持float16精度出错的处理

20240203在WIN10下使用GTX1080配置stable-diffusion-webui.git不支持float16精度出错的处理 2024/2/3 21:23 缘起&#xff1a;最近学习stable-diffusion-webui.git&#xff0c;在Ubuntu20.04.6下配置SD成功。 不搞精简版本&#xff1a;Miniconda了。直接上Anacoda&#xff01; …

SpringBoot之事务源码解析

首先事务是基于aop的&#xff0c;如果不了解aop的&#xff0c;建议先去看下我关于aop的文章: Spring之aop源码解析  先说结论&#xff0c;带着结论看源码。首先&#xff0c;在bean的生命周期中&#xff0c; 执行实例化前置增强&#xff0c;会加载所有切面并放入缓存&#xff0…

汉字拼音桥接交流与传承的关键

汉字拼音&#xff0c;一种基于拉丁字母为汉字标注读音的发音指导系统&#xff0c;自20世纪50年代推广以来便成为学习汉语的基石。这种独特的拼写系统不仅在汉语的教育与学习领域起到不可替代的作用&#xff0c;而且对文化的传承、科技的进步以及国际交流都产生了深远的影响。 汉…

MFC实现遍历系统进程

今天我们来枚举系统中的进程和结束系统中进程。 认识几个API 1&#xff09;CreateToolhelp32Snapshot 用于创建系统快照 HANDLE WINAPI CreateToolhelp32Snapshot( __in DWORD dwFlags, //指定快照中包含的系统内容__in DWORD th32P…

如何使用CLZero对HTTP1.1的请求走私攻击向量进行模糊测试

关于CLZero CLZero是一款功能强大的模糊测试工具&#xff0c;该工具可以帮助广大研究人员针对HTTP/1.1 CL.0的请求走私攻击向量进行模糊测试。 工具结构 clzero.py - 工具主脚本&#xff1b; default.py - 包含了大多数标准攻击测试方法和字符&#xff1b; exhaustive.py - 包…

微信公众号接入智能聊天机器人

微信公众号免费接入智能聊天机器人 准备物料操作步骤1.准备1个域名2.讯飞星火认知大模型3.github帐号4.vercel1.登录[vercel](https://vercel.com/login),使用github帐号登录2.创建一个新应用&#xff0c;通过github导入(它会自动拉取github仓库的项目)3.添加domains 5.微信公众…

【MySQL】学习和总结DCL的权限控制

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-Bl9kYeLf8GfpdQgL {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

k8s-项目部署案例

一、容器交付流程 在k8s平台部署项目流程 在K8s部署Java网站项目 DockerFile 如果是http访问&#xff0c;需要在镜像仓库配置可信任IP 三、使用工作负载控制器部署镜像 建议至少配置两个标签 一个是声明项目类型的 一个是项目名称的 继续配置属性 资源配额 健康检查 五、使…

堆排序-Python实现

简述 堆排序&#xff08;Heap Sort&#xff09;是一种基于比较的排序算法&#xff0c;它利用堆这种数据结构所设计的一种排序算法。堆排序是一种选择排序&#xff0c;它的最坏&#xff0c;最好&#xff0c;平均时间复杂度均为O(nlogn)&#xff0c;它也是不稳定排序。 堆 堆排…

JCIM | MD揭示PTP1B磷酸酶激活RtcB连接酶的机制

Background 内质网应激反应&#xff08;UPR&#xff09; 中的一个重要过程。UPR是由内质网中的三种跨膜传感器&#xff08;IRE1、PERK和ATF6&#xff09;控制的细胞应激反应&#xff0c;当内质网中的蛋白质折叠能力受到压力时&#xff0c;UPR通过减少蛋白质合成和增加未折叠或错…

零基础学Python(8)— 流程控制语句(上)

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。流程控制语句是编程语言中用于控制程序执行流程的语句&#xff0c;本节课就带大家认识下Python语言中常见的流程控制语句&#xff01;~&#x1f308; 目录 &#x1f680;1.程序结构 &#x1f680;2.最简单的if语句 &a…

论 Scratch 版“愤怒的小鸟”的资源(10000 余块代码)

资源链接 “愤怒的小鸟”资源&#xff1a;https://download.csdn.net/download/leyang0910/88820527 游戏 SJA 分析及&#xff1a;角色数量&#xff1a;12&#xff0c;素材数量&#xff1a;214&#xff0c;积木数量&#xff1a;1442&#xff0c;音频数量&#xff1a;11 “愤怒…

【复现】万户 ezOFFICE SQL注入漏洞_42

目录 一.概述 二 .漏洞影响 三.漏洞复现 1. 漏洞一&#xff1a; 四.修复建议&#xff1a; 五. 搜索语法&#xff1a; 六.免责声明 一.概述 万户ezOFFICE协同管理平台分为企业版和政务版。 解决方案由五大应用、两个支撑平台组成&#xff0c;分别为知识管理、工作流程、沟…