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

块设备的操作函数并没有类似于字符驱动中的read 和write函数,要实现读写操作,只能在请求处理函数中实现。这就分为两种,是否要使用请求队列,请求队列的主要作用是管理和调度IO请求。在以下情况中,一般需要用到请求队队列:

  • 多任务环境:多个任务同时对存储设备进行读写,请求队列可以对IO请求进行排序和调度
  • 磁盘优化:磁盘是一种机械设备,其IO操作需要进行磁盘寻道等操作,非常耗时,请求队列可以将多个IO请求进行合并,可以减少磁盘的寻道次数,提高磁盘的吞吐量。

因此,本篇的重点便是使用请求队列来实现块设备的读写操作。


目录

一、请求处理函数的触发条件

二、从请求队列获取请求

三、开始进行读写操作

1、请求的结构

2、相关API

四、关闭请求

五、完整代码


一、请求处理函数的触发条件

若要对块设备进行读写操作,需要触发请求处理函数,随后块设备驱动才会调度并处理请求。那么在什么情况下会触发请求处理函数?以下是读写操作的常见触发条件。

读操作

一般涉及到访问文件内容、文件属性、文件权限的时候,会触发请求处理函数中的读操作。

① 读取数据

当应用程序执行文件读取操作(如 read 函数)时,它会向文件系统发送读取请求,并触发请求处理函数中的读操作。每一个请求内包含源数据(块设备扇区地址、读取字节数)以及目的地址(内存页地址、页偏移)。文件系统从块设备读取相应的文件块数据,并将其返回给应用程序。

② 目录遍历

当应用程序执行目录遍历操作(如 opendir、readdir 函数等)时,文件系统会在磁盘上读取目录的元数据,并返回给应用程序。

③打开文件

当应用程序打开一个文件时,文件系统需要读取磁盘上的文件元数据信息,如文件大小、访问权限等,以供应用程序使用。

写操作

一般涉及到文件内容的更新、文件创建等操作时,会触发请求处理函数中的写操作。

① 文件内容写入(追加、更新)

文件内容的写入(write)和追加(append)会向文件系统发送写入请求,并触发请求触发函数中的写操作。每一个请求内包含源数据(内存页地址、页偏移)以及目的地址(块设备扇区地址),文件系统会将应用程序提供的数据写入到指定扇区。

此外,除了文件内容的更新,文件属性(如访问权限)的更新也会触发请求处理函数。

② 文件创建

当应用程序创建一个新文件时,它会向文件系统发送创建文件的请求,并触发请求处理函数中的写操作。文件系统在磁盘上为新文件分配空间,并更新文件的元数据信息。

二、从请求队列获取请求

接下来便是正式开始实现请求处理函数,函数的形参为请求队列,对此,下面的第一步便是从请求队列中获取请求。涉及的API 在 <linux/blkdev.h>

void request_handle(struct request_queue *q);

① 方式一:获取 + 开启请求

正常来说,获取请求包含两步,第一步是获取请求,使用的API为 blk_peek_request

/**
 * @param q 请求队列
 * @return 成功返回获取到的请求结构体地址,失败返回 NULL
 */
struct request *blk_peek_request(struct request_queue *q);

获取到请求以后,还没结束,需要开启请求,目的是将通知硬件设备开始处理当前请求,同时将当前请求标记为启动状态,以确保请求在处理的过程中不会被打断。其他还有数据预处理、设备准备等原因。

/**
 * @param rq 获取到的请求
 */
void blk_start_request(struct request *rq);

② 方式二:一步到位

Linux内核提供了获取 + 开启一步到位的方式,使用的API为 blk_fetch_request,该函数其实就是对上述两个函数的使用做了一层封装。

/**
 * @param q 请求队列
 * @return 成功返回获取到的请求结构体地址,失败返回 NULL
 */
struct request *blk_fetch_request(struct request_queue *q);
/*
struct request *blk_fetch_request(struct request_queue *q)
{
    struct request *rq;

    rq = blk_peek_request(q);
    if (rq)
        blk_start_request(rq);
    return rq;
}
*/

三、开始进行读写操作

在开始读写操作之前,需要先了解每一个请求的结构,因为既然要进行读写操作,我们需要知道源数据地址、目的地址、操作的字节数等信息。

1、请求的结构

每个request 中保存了多个 bio,bio保存着最终要读写的数据、地址等信息。bio 中的 bvec_iter 保存了块设备扇区起始地址、扇区大小等信息,bio 中的 bio_vec 保存了 RAM 页地址、剩余页长度以及页偏移等信息。

下面是 biobio_iter bio_vec 三者之间的关系

2、相关API

获得扇区起始地址

/**
 * @param rq 指向请求结构体的指针
 * @return   成功返回获取到的扇区起始地址
 */
sector_t blk_rq_pos(const struct request *rq);

 获取请求所涉及的数据长度

/**
 * @param rq 指向请求结构体的指针
 * @return   成功返回数据长度,单位:字节
 */
unsigned int blk_rq_bytes(const struct request *rq);

获取指定数据页的线性地址,即 RAM 中的起始页地址

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

获取当前请求的数据传输方向(读操作、写操作)

/**
 * @param rq 指向请求结构体的指针
 * @return   返回数据传输方向。可以是 READ / WRITE
 */
int rq_data_dir(struct request *rq);

四、关闭请求

与前面开启请求相对应,开启请求后将当前请求标记为开启状态,以确保在处理请求的过程中不会被打断;关闭请求意味着该请求的数据传输和相关操作已经完成,主要目的有两点:

  • 通知请求完成:通知相关的应用程序或调用者操作已经结束,允许继续执行后续的操作
  • 资源释放:在请求处理完成后,需要释放请求所占用的内存和其他资源,以便系统能够重新利用这些资源。

这里可以使用 __blk_end_request_cur 或者 blk_end_request_cur,两个函数的使用方法完全一样,他们之间的区别在于

① __blk_end_request_cur

__blk_end_request_cur是一个异步函数,它会立即结束当前的 I/O 请求,并触发相应的回调函数(例如,end_io)来进行后续处理。这意味着调用 __blk_end_request_cur 并不会等待请求的处理完成,而是立即返回,将请求的处理交给后续的回调函数来处理。

② blk_end_request_cur

blk_end_request_cur 与上面相反,是一个同步函数,它会等待当前的 I/O 请求的处理完成,并在处理完成后返回。它会等待直到请求的 end_io 回调函数执行完毕,或者出现超时或错误等情况。因此,在调用 blk_end_request_cur 的过程中,它会阻塞当前的执行线程,直到请求处理完成。

/**
 * @param rq     指向请求结构体的指针
 * @param error  代表请求处理结果,
 *               - 若请求处理成功,应该将 error 设置为 0
 *               - 若请求处理失败,则可以设置为其他非零值。
 */
bool __blk_end_request_cur(struct request *rq, int error);

五、完整代码

将驱动代码重新编译并加入到内核,输入 fdisk -l,我们会发现请求处理函数被触发了,因为 fdisk -l 用于列出当前系统中所有的磁盘分区信息,在扫描设备的过程中,会涉及块设备的访问和信息读取,这就导致了请求处理函数被触发。

void request_handle(struct request_queue *q)
{
    printk("请求处理函数被触发!\n");

    struct request* req;                // 处理请求
    int errors = 0;                     // 请求处理状态
    sector_t start = 0;                 // 操作扇区的起始地址
    int len = 0;

    while ((req = blk_fetch_request(q)) != NULL)
    {
        // 获得扇区起始地址
        start = blk_rq_pos(req);
        // 当前请求所涉及的字节数
        len = blk_rq_cur_bytes(req);
        // 获得bio结构体中的缓冲区指针
        void* buffer = bio_data(req->bio);
        
        // 判断是读操作还是写操作
        if (rq_data_dir(req) == READ)
        {
            memcpy((uint8_t*)buffer, blkdev.diskbuf, len);
            printk("从块设备读数据\n");
        }
        else if(rq_data_dir(req) == WRITE)
        {
            memcpy(blkdev.diskbuf, (uint8_t*)buffer, len);
            printk("向块设备写数据\n");
        }
        
        // 结束当前请求
        __blk_end_request_cur(req, errors);
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于SSM的便民自行车管理系统的开发与实现(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的便民自行车管理系统的开发与实现&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0…

基于单片机的智能寻光小车设计

摘 要&#xff1a;随着物联网技术的飞速发展和逐渐成熟&#xff0c;以单片机为主的智能小车在巡查、仓储、探险及国防等领域得到广泛应用。本文设计了一种基于单片机的智能寻光小车&#xff0c;该小车以STC89C52RC 芯片为设计核心&#xff0c;结合光敏传感器和超声波传感器等多…

FCIS 2023:洞悉网络安全新态势,引领创新防护未来

随着网络技术的飞速发展&#xff0c;网络安全问题日益凸显&#xff0c;成为全球共同关注的焦点。在这样的背景下&#xff0c;FCIS 2023网络安全创新大会应运而生&#xff0c;旨在汇聚业界精英&#xff0c;共同探讨网络安全领域的最新动态、创新技术和解决方案。 本文将从大会的…

【Java 数据结构】反射

反射 1 定义2 用途(了解)3 反射基本信息4 反射相关的类&#xff08;重要&#xff09;4.1 Class类(反射机制的起源 )4.1.1 Class类中的相关方法(方法的使用方法在后边的示例当中) 4.2 反射示例4.2.1 获得Class对象的三种方式4.2.2 反射的使用 5、反射优点和缺点 1 定义 Java的反…

python统计分析——卡方检验

参考资料&#xff1a;用python动手学统计学 1、导入库 # 导入库 # 用于数值计算的库 import numpy as np import pandas as pd import scipy as sp from scipy import stats # 用于绘图的库 from matplotlib import pyplot as plt import seaborn as sns sns.set() 2、数据准…

转融通业务是什么?好处和弊端是什么?

转融通业务是指证券金融公司借入证券、筹得资金后&#xff0c;再转借给证券公司&#xff0c;为证券公司开展融资融券业务提供资金和证券来源&#xff0c;包括转融券业务和转融资业务两部分。从证券金融公司角度看&#xff0c;向证券公司提供资金和证券供其开展融资融券业务&…

主动网络安全:成本效率和危机管理的战略方法

如何面对复杂网络攻击的进攻策略以及零信任模型的作用。攻击后反应性网络安全策略的基本步骤&#xff0c;透明度和准备工作。 讨论采用主动网络安全方法的好处&#xff0c;特别是在成本效率和危机管理方面&#xff0c;进攻性安全测试对合规性和零日响应的影响。 组织应该更多…

【证书管理】实验报告

证书管理实验 【实验环境】 ISES客户端 【实验步骤】 查看证书 查看证书详细信息 选择任意证书状态&#xff0c;在下方“证书列表”中出现符合要求的所有证书。在“证书列表”中点击要查看证书&#xff0c;在右侧“证书详细信息”栏出现被选证书信息。 上述操作如图1.2.…

JAVA原型模式详解

原型模式 1 原型模式介绍 定义: 原型模式(Prototype Design Pattern)用一个已经创建的实例作为原型&#xff0c;通过复制该原型对象来创建一个和原型对象相同的新对象。 西游记中的孙悟空 拔毛变小猴,孙悟空这种根据自己的形状复制出多个身外化身的技巧,在面向对象软件设计领…

ROS笔记一:工作空间和功能包

目录 工作空间 如何创建工作空间&#xff1a; 编译工作空间 设置环境变量 功能包 创建功能包 CMakeLists.txt package.xml 工作空间 ROS的工作空间是用来存放工程文件代码的文件夹 ROS的开发依赖于工作空间&#xff0c;包括编写代码、编译等都是在工作空间下进行的 工作空…

SQLite database实现加密

注意&#xff1a;以下操作以VS2022为开发工具&#xff0c;以C#为开发语言。 数据加密原因 软件在使用的各个场景&#xff0c;很多都需要数据具有保密性&#xff0c;于是对于数据库就需要加密。特别是在某些特定领域或存储敏感数据尤其如此。 SQLite加密实现 SQLite加密有两种…

防范恶意勒索攻击!亚信安全发布《勒索家族和勒索事件监控报告》

本周态势快速感知 本周全球共监测到勒索事件81起&#xff0c;事件数量有所下降&#xff0c;比上月降低20%。 lockbit3.0仍然是影响最严重的勒索家族&#xff1b;akira和incransom也是两个活动频繁的恶意家族&#xff0c;需要注意防范。 本周alphv勒索组织窃取MBC法律专业公司…

【动态规划】【图论】【C++算法】1928规定时间内到达终点的最小花费

作者推荐 【动态规划】【状态压缩】【2次选择】【广度搜索】1494. 并行课程 II 本文涉及知识点 动态规划汇总 LeetCode1928. 规定时间内到达终点的最小花费 一个国家有 n 个城市&#xff0c;城市编号为 0 到 n - 1 &#xff0c;题目保证 所有城市 都由双向道路 连接在一起…

Java设计模式大全:23种常见的设计模式详解(一)

本系列文章简介&#xff1a; 设计模式是在软件开发过程中&#xff0c;经过实践和总结得到的一套解决特定问题的可复用的模板。它是一种在特定情境中经过验证的经验和技巧的集合&#xff0c;可以帮助开发人员设计出高效、可维护、可扩展和可复用的软件系统。设计模式提供了一种在…

VS编译器对scanf函数不安全报错的解决办法(详细步骤)

&#x1f4da;博客主页&#xff1a;爱敲代码的小杨. ✨专栏&#xff1a;《Java SE语法》 | 《数据结构与算法》 | 《C生万物》 ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更新的动力❤️ &#x1f64f;小杨水平有…

第5节、S曲线加减速转动【51单片机+L298N步进电机系列教程】

↑↑↑点击上方【目录】&#xff0c;查看本系列全部文章 摘要&#xff1a;本节介绍步进电机S曲线相关内容&#xff0c;总共分四个小节讨论步进电机S曲线相关内容 5-1、S曲线加减速简介   根据上节内容&#xff0c;步进电机每一段的速度可以任意设置&#xff0c;但是每一段的…

【教程】ESP32-CAM使用WiFi和MQTT

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] 连接MQTT 1、先安装库 2、默认你已有MQTT服务器 3、编写代码(跳过WiFi连接部分) #include <PubSubClient.h>// MQTT server details const char* mqtt_server "xxxxx.cn"; const int mqtt_po…

Spring Boot整合MyBatis Plus实现基本CRUD与高级功能

文章目录 1. 引言2. 项目搭建与依赖配置2.1 添加MyBatis Plus依赖2.2 配置数据源与MyBatis Plus 3. 实现基本CRUD功能3.1 创建实体类3.2 创建Mapper接口3.3 实现Service层3.4 控制器实现 4. 高级功能实现4.1 自动填充功能4.2 乐观锁功能4.3 逻辑删除功能 5. 拓展&#xff1a;My…

Kafka SASL_SSL双重认证

文章目录 1. 背景2. 环境3. 操作步骤3.1 生成SSL证书3.2 配置zookeeper认证3.3 配置kafka安全认证3.4 使用kafka客户端进行验证3.5 使用Java端代码进行认证 1. 背景 kafka提供了多种安全认证机制&#xff0c;主要分为SASL和SSL两大类。 SASL&#xff1a; 是一种身份验证机制&…

计算机网络——新型网络架构:SDN/NFV

1. 传统节点与SDN节点 1.1 传统节点(Traditional Node) 这幅图展示了传统网络节点的结构。在这种设置中&#xff0c;控制层和数据层是集成在同一个设备内。 以太网交换机&#xff1a;在传统网络中&#xff0c;交换机包括控制层和数据层&#xff0c;它不仅负责数据包的传输&…