第6章 设备驱动程序(4)

目录

6.5 块设备操作

6.5.5 请求结构

6.5.6 BIO

6.5.7 提交请求

6.5.8 I/O调度

6.5.9 ioctl实现


本专栏文章将有70篇左右,欢迎+关注,查看后续文章。

6.5 块设备操作

6.5.5 请求结构

struct         request {         //放在请求队列上,请求完成放到donelist链表上。

        struct request_queue         *q;

        struct list_head                  queuelist;            //用于挂载到请求队列中。

        struct gendisk                    *rq_disk;

        struct hd_struct                 *part;

        sector_t                             sector;                 //请求的起始扇区。

        unsigned long                   nr_sectors;          //请求包含的的扇区数。

        unsigned int                     current_nr_sectors;

        struct bio                         *bio;                         //表示底层的I/O 请求。

        struct bio                         *biotail;                   //一个请求可包含多个bio,指向最后一个bio。

        void                                 *elevator_private;         //IO调度器设置。

        void                                 *elevator_private2;

        unsigned short                         nr_phys_segments;        //请求涉及连续物理区域数。

        unsigned short                         nr_hw_segments;           //重排序的请求中连续物理区域数。

        enum rq_cmd_type_bits         cmd_type;                        //如:REQ_TYPE_FS。

        unsigned int                        cmd_flags;                          //如:_REQ_RW表示数据传输方向。

        unsigned int                        cmd_len;

}

BIO:用于内核和设备间传输数据。下节讲。

struct request在更高层次表示块设备的整体I/O请求,包含多个struct bio

6.5.6 BIO

bio:描述单个IO读写请求。

struct         bio {

        struct bio                         *bi_next;

        struct block_device         *bi_bdev;         // 对应块设备。

        sector_t                           bi_sector;        // 请求传输的开始扇区号。

        unsigned int                    bi_size;           // 请求数据的长度。

        unsigned short               bi_vcnt;           // bi_io_vec数组元素个数,即数据缓冲区数量。

        unsigned short              bi_idx;              // 作为数组bi_io_vec的索引。

        struct bio_vec               *bi_io_vec;

}

struct         bio_vec {

        struct page          *bv_page;         // 缓冲区所在页。

        unsigned int         bv_len;             // 缓冲区长度。

        unsigned int         bv_offset;         // 缓存区在页内的偏移。

};

6.5.7 提交请求

内核将IO请求提交给设备,步骤:

        1. 创建一个bio以描述请求 ,并嵌入到request中,放到request_queue中。

        2. 内核处理请求队列,并执行bio中的请求。

bio创建后,调用struct request_queue中make_request_fn函数指针,将新请求加入请求队列。

而request_fn用于提交请求。

1. 创建IO请求

submit_bio:

        根据bio创建一个新request。

        使用make_request_fn将request加入到request_queue中。

2. 队列插入

为提高IO性能,尽可能重排或合并各个请求。

队列空闲时:处理队列中请求。否则只添加请求到队列,而不处理。

请求插入队列后,后续何时处理请求?

       1. 定时器。
        2. 请求超过阈值。

3. 执行请求

执行请求:

        struct request_queue->request_fn()函数指针。

struct request_queue    *blk_init_queue(request_fn_proc     *rfn,     spinlock_t     *lock)

        用于设置request_fn()函数指针。

        不同设备驱动中调用该函数设为不同函数。

6.5.8 I/O调度

I/O调度器:也叫电梯。

        用于调度和重排磁盘IO读写操作请求。以优化磁盘访问的顺序和效率。

一个调度器包含的操作:

struct elevator_ops {

        elevator_merge_fn                 *elevator_merge_fn;

                //检查新请求是否可以和现有请求合并。

        elevator_merged_fn                 *elevator_merged_fn;

                //合并后调用。

        elevator_merge_req_fn         *elevator_merge_req_fn;

                //执行请求合并。

        elevator_allow_merge_fn         *elevator_allow_merge_fn;

                //是否可以将当前请求与现有请求合并。

        elevator_bio_merged_fn         *elevator_bio_merged_fn;

                //当一个bio被合并到一个请求中时调用。

        elevator_dispatch_fn                 *elevator_dispatch_fn;

                //从指定队列中选择下一个调度的请求给设备驱动。

        elevator_add_req_fn                 *elevator_add_req_fn;

                //向队列添加请求。

        elevator_activate_req_fn                 *elevator_activate_req_fn;

        elevator_deactivate_req_fn             *elevator_deactivate_req_fn;

                //当请求变为活动/非活动时调用。

        elevator_completed_req_fn         *elevator_completed_req_fn;

                //当一个请求完成时调用。

        elevator_init_icq_fn                 *elevator_init_icq_fn;

        elevator_exit_icq_fn                 *elevator_exit_icq_fn;

                //初始化/清理 I/O上下文队列。

        elevator_set_req_fn                 *elevator_set_req_fn;

        elevator_put_req_fn                 *elevator_put_req_fn;

        elevator_may_queue_fn         *elevator_may_queue_fn;

                //是否可将请求添加到请求队列。

        elevator_init_fn                 *elevator_init_fn;

        elevator_exit_fn                 *elevator_exit_fn;

                //调度器初始化时、退出时调用。

}

请求上下文(I/O Context Queue, ICQ):

        ICQ 存储与请求相关上下文,如文件系统元数据、锁状态等。

表示一个调度器:

struct         elevator_type

{

        struct kmem_cache         *icq_cache;

        struct elevator_ops         ops;

        size_t                             icq_size;

        size_t                             icq_align;

        struct elv_fs_entry         *elevator_attrs;         //sysfs中的属性。

        char                                 elevator_name[ELV_NAME_MAX];         //调度器名称。

        struct module                 *elevator_owner;

        struct list_head                 list;         //连接所有IO调度器。

};

内核的IO调度器有:

        1. elevator_noop:

                简单,先来先服务。可合并请求,但不能重排。

                使用场景:

                        1. 可自行重排的智能硬件。

                        2. 不用寻道的设备, 如闪存。

        2. iosched_deadline:

                目的:

                        最小化寻道次数。

                        尽可能在一定时间内完成。

        3. iosched_cfq:

                完全公平队列。默认调度器。

                每个进程有一个队列,轮询调度多个队列。

拓展

常见I/O调度算法:

        完全公平队列(CFQ):

                为每个进程提供公平访问磁盘机会。将磁盘带宽分配给不同进程。

                适用于多任务公平共享磁盘资源环境。

        Deadline:

                适用于低延迟应用,如实时应用,数据库。

        Noop:

                不重排序不优化。

                适用不需要额外调度开销的情况,如SSD设备。

        电梯算法:

                优化了磁盘访问顺序,减少寻道时间。

                模拟电梯上下移动,根据磁头当前位置和移动方向,调度最近请求 。

                对于磁盘访问密集型且随机的I/O,显著提高性能。

                缺点:

                        当磁头频繁改变方向时,一些请求可能长时间等待。

                        因此需要根据实际应用的特点和需求权衡。

6.5.9 ioctl实现

系统调用 - > sys_ioctl -> vfs_ioctl

blkdef_ioctl:实现了某些ioctl,对于所有块设备都可用。

        如:读取设备分区信息,设备总长度。

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

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

相关文章

Go Gin框架

一、Gin介绍 Gin是一个用Go编写的HTTPweb框架。它是一个类似于martini但拥有更好性能的API框架, 优于httprouter,速度提高了近 40 倍。点击此处访问Gin官方中文文档。 二、安装 1、安装Gin go get -u github.com/gin-gonic/gin 2、代码中引入 import "githu…

【Docker】——安装镜像和创建容器,详解镜像和Dockerfile

前言 在此记录一下docker的镜像和容器的相关注意事项 前提条件:已安装Docker、显卡驱动等基础配置 1. 安装镜像 网上有太多的教程,但是都没说如何下载官方的镜像,在这里记录一下,使用docker安装官方的镜像 Docker Hub的官方链…

进阶篇05——存储过程、存储函数、触发器

存储过程 简介 基本语法 创建和调用 -- 创建名为p1的存储过程,小括号里可以跟参数 -- 存储过程个人觉得就是SQL里的函数 create procedure p1() begin-- begin 和 end 之间是封装的SQL语句-- 可以是一条SQL也可以是多条SQLselect * from student; end;-- 调用存储…

【FreeRTOS】估算栈的大小

参考《FreeRTOS入门与工程实践(基于DshanMCU-103).pdf》 目录 估算栈的大小回顾简介计算说明估计函数用到的栈有多大合计 估算栈的大小 回顾 上一篇文章链接:http://t.csdnimg.cn/Cc8b4 传送门: 上一篇文章 上一篇文章创建的三个任务 /* 创建任务:声 *…

vivado SITE

描述 SITE是一个设备对象,表示许多不同类型的逻辑资源之一 可在目标Xilinx FPGA上获得。 SITE包括SLICE/CLB,它们是基本逻辑元件(BEL)的集合,如 查找表(LUT)、触发器、多路复用器,携…

网页钓鱼-克隆修改--劫持口令下载后门

免责声明:本文仅做技术交流与学习... 目录 1-右键另存为 2-goblin项目(不推荐) 修改goblin.yaml文件 运行exe ​编辑 3-Setoolkit (kali自带) 网页克隆---> 1-右键另存为 --不行就再定位元素进行修改. 2-goblin项目(不推荐) GitHub - xiecat/goblin: 一款适用于红蓝…

力扣每日一题 6/19 排序+动态规划

博客主页:誓则盟约系列专栏:IT竞赛 专栏关注博主,后期持续更新系列文章如果有错误感谢请大家批评指出,及时修改感谢大家点赞👍收藏⭐评论✍ 2713.矩阵中严格递增的单元格数【困难】 题目: 给你一个下标从…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 部门组队编程(200分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 &#x1f…

项目3:从0开始的RPC框架(扩展版)-3

七. 负载均衡 1. 需求分析 目前我们的RPC框架仅允许消费者读取第一个服务提供者的服务节点,但在实际应用中,同一个服务会有多个服务提供者上传节点信息。如果消费者只读取第一个,势必会增大单个节点的压力,并且也浪费了其它节点…

文件扫描工具都有哪些?职场大佬都在用的文本提取工具大盘点~

回想起刚毕业初入职场那阵子,领导让帮忙把纸质文件扫描提取为文本时,还只会傻乎乎地一点点操作,属实是费劲得很! 好在后面受朋友安利,找到了4个能够快速实现文件扫描文字提取的方法,这才让我的办公效率蹭蹭…

GD32如何设计晶振电路

关于晶振电路真的简单吗?如何可靠的设计好GD32晶振电路,我们需要知道这些: 1、GD32可以选择哪些范围大小晶振? 以GD32F303为例,查询DATASHEET外部时钟电气特性小节可以看到晶振支持范围是4—32M范围均可选择 2、需不…

JupyterLab使用指南(六):JupyterLab的 Widget 控件

1. 什么是 Widget 控件 JupyterLab 中的 Widget 控件是一种交互式的小部件,可以用于创建动态的、响应用户输入的界面。通过使用 ipywidgets 库,用户可以在 Jupyter notebook 中创建滑块、按钮、文本框、选择器等控件,从而实现数据的交互式展…

51单片机STC89C52RC——3.1 数码管静态展示

目的 让数码管在指定位置显示指定数字 一,STC单片机模块 二,数码管 2.1 数码管位置 2.2 生活中用到的数目管 红绿灯 LED数码管在生活中随处可见,洗衣机、电饭煲、热水器、微波炉、冰箱、这些最基本的家用电器上基本都用到了这种7段LED数…

js语法---理解反射Reflect对象和代理Proxy对象

Reflect 基本要点 反射:reflect是一个内置的全局对象,它的作用就是提供了一些对象实例的拦截方法,它的用法和Math对象相似,都只有静态方法和属性,同时reflect也没有构造器,无法通过new运算符构建实例对象&…

WiFi/BLE芯片(1):英飞凌

英飞凌AIROC蓝牙芯片的应用场景:

error: ‘LocalParameterization’ is not a member of ‘ceres

一、错误提示: 对于以下报错: error: ‘LocalParameterization’ is not a member of ‘ceres’ error: ‘quatParam’ was not declared in this scope error: expected type-specifier 二、背景: 我是在Ubuntu20.04下,运行…

数据库 | 试卷五试卷六试卷七

1. 主码不相同!相同的话就不能唯一标识非主属性了 2.从关系规范化理论的角度讲,一个只满足 1NF 的关系可能存在的四方面问题 是: 数据冗余度大,插入异常,修改异常,删除异常 3.数据模型的三大要素是什么&…

DDMA信号处理以及数据处理的流程---距离速度测量

Hello,大家好,我是Xiaojie,好久不见,欢迎大家能够和Xiaojie一起学习毫米波雷达知识,Xiaojie准备连载一个系列的文章—DDMA信号处理以及数据处理的流程,本系列文章将从目标生成、信号仿真、测距、测速、cfar检测、测角、目标聚类、目标跟踪这几个模块逐步介绍,这个系列的…

华为---OSPF单区域配置(一)

09、OSPF 9.1 OSPF单区域配置 9.1.1 原理概述 为了弥补距离矢量路由协议的不足,IETF组织开发了一种基于链路状态的内部网关协议——OSPF(Open Shortest Path First,开放式最短路径优先)。 OSPF作为基于链路状态的协议&#xf…

多态性(Java)

本篇学习面向对象语言的第三个特性——多态。 目录 1、多态的概念 2、继承多态实现条件 3、重写 4、重新与重载的区别: 5、向上转移和向下转型 5、1向上转型: 5、2 向下转型 1、多态的概念 多态的概念:通俗来说,就是多种形态…