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

目录

6.5 块设备操作

6.5.1 块设备的表示

6.5.2 数据结构

6.5.3 向系统添加磁盘和分区

6.5.4 打开块设备文件


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

6.5 块设备操作

特点:

        随机访问任意位置。

        固定块大小的传输。

        块设备在内存进行缓存。

扇区(sector):

        最小寻址单位。

        固定的硬件单位,常数,软件不可修改。

        常见大小:512B。

块(block):

        长度:扇区的整数倍。软件可修改。

        用于在内核和设备之间传输,受内存页限制

        常见大小:512B,1024B,2048B,4096B。最大不超过页大小。

一个文件系统内有大块,也有小块。

        优点:处理不同大小文件时分别优化性能。

块设备层工作有:

        1. 寻址块设备。

        2. 预读算法,预读块设备到内存。

6.5.1 块设备的表示

块设备的请求队列管理,包括:

        1. 重排读写块请求。

        2. 在内存中缓存读写的内容。

struct         bdev_inode {         //关联块设备与inode

        struct block_device         bdev;                 块设备

        struct inode                     vfs_inode;         块设备的inode

};

struct block_device *bdget(dev_t dev)

        根据设备号找到对应块设备。

        dev_t -> inode -> struct bdev_inode -> struct block_device

每个块设备有一个请求队列。包含了:

        读写请求

        IO调度器 :用于重排请求。

        特征数据:扇区,块长度。

上图中通用硬盘,用struct gendisk表示。

void add_disk(struct gendisk *disk);

        将通用硬盘添加到内核。

对块设备的读写请求不会立即执行,而是协同汇总一起发给设备。

所以块设备文件的file_operations没有实现读写函数。

6.5.2 数据结构

1. 块设备

一个flash或硬盘中有多个分区。

        如/dev/mtblockN, 或/dev/sdaN

struct gendisk:表示一个flash或硬盘。

struct block_device:每个分区有一个该结构的实例。

struct block_device {

        dev_t                    bd_dev;                 //设备号

        int                         bd_openers;         //打开该块设备的次数

        struct inode         *bd_inode;              //bdev伪文件系统中,该块设备的inode

        struct super_block        *bd_super;    //设备挂载的文件系统

        struct mutex                   bd_mutex;

        struct list_head              bd_inodes;

        struct block_device       *bd_contains;

        unsigned                        bd_block_size;

        struct hd_struct              *bd_part;         //该块设备上的某个分区

        unsigned                        bd_part_count;         //引用分区的次数

        int                                   bd_invalidated;

        struct gendisk                *bd_disk;         //块设备在通用磁盘层的表示。

        struct request_queue     *bd_queue;

        struct list_head               bd_list;         //连接系统所有可用的block_device

        unsigned long                 bd_private;         //私有数据

};

bd_invalidated:

        若为1,则该分区在内核中信息无效,因为磁盘分区已改变。

blkdev_open:

        打开块设备并独占使用。

2. 通用硬盘和分区

struct         gendisk {         //驱动层,表示一个已分区的硬盘。

        int                 major;                 //主设备号。

        int                 first_minor;         //第一从设备号。

        int                 minors;                 //从设备号总数。

                //每个分区有各自的从设备号。

        char                 disk_name[DISK_NAME_LEN];         // 驱动程序的名字

        char                 *(*devnode)(struct gendisk *gd, umode_t *mode);

                //用于生成设备节点。创建设备文件时调用。

        unsigned short             events;                     //磁盘事件

        unsigned int                 async_events;         //异步的磁盘事件

        struct disk_part_tbl      *part_tbl;                  //分区表

        struct hd_struct            part0;

        struct block_device_operations         *fops;

        struct request_queue                         *queue;         //管理IO请求

        void                      *private_data;         //磁盘的私有数据

        int                         flags;                       //磁盘的特性或状态

        struct kobject        *slave_dir;

};

成员part0:

        不对应于磁盘上的实际分区,而是代表整个磁盘。允许以分区的方式对整个磁盘操作。

        起始扇区:

                part0的起始扇区为是 0,表示磁盘的第一个扇区。

        大小:

                part0 的大小等于整个磁盘的大小。

        操作:

                对part0的操作实际上是对整个磁盘的操作(如格式化)

每个分区都有一个struct hd_struct实例。

struct hd_struct {

        sector_t         start_sect;         //分区在磁盘的起始扇区。

        sector_t         nr_sects;         //该分配的总扇区数。

        struct kobject         *holder_dir;

};

struct gendisk *alloc_disk(int minors);

        参数minors:从设备数目。

        作用:分配struct gendisk,包括每个分区的hd_struct指针。

void del_gendisk(struct gendisk *gp);

3. 几个结构体的联系

一个磁盘(struct gendisk)有多个分区。

        其中每个分区都有一个:

                struct         block_device(打开该分区设备文件时创建)

                struct         hd_struct

struct gendisk:一个磁盘。

struct hd_struct:磁盘中一个分区。

struct block_device:VFS层,打开一个分区的设备文件时创建该结构体实例。

struct hd_struct的kobject->parent指向struct gendisk的kobject。

4. 块设备操作

//不由VFS调用,而是被def_blk_fops调用

struct         block_device_operations {

        int         (*open) (struct block_device *, fmode_t);

        void      (*release) (struct gendisk *, fmode_t);

        int         (*media_changed) (struct gendisk *);

                //检查存储介质是否改变(磁盘是否被移除了)

        int         (*revalidate_disk) (struct gendisk *);

                //替换一个新存储介质时使用。

};

5. 请求队列

请求队列:包含对一个块设备的读写请求。

struct         gendisk {

        struct request_queue         *queue;

}

struct         block_device {

        struct request_queue         *bd_queue;

}

struct         request_queue {

        struct list_head         queue_head;

                //连接块设备的IO请求(struct request),内核会重排链表以提高性能。

        struct elevator_queue         *elevator;

        request_fn_proc                 *request_fn;

                //向队列添加新读写IO请求。

                //该函数需要驱动各自实现。

        make_request_fn                 *make_request_fn;

                //创建新请求。

        softirq_done_fn                   *softirq_done_fn;

                //异步处理IO请求时,用于通知请求已处理完毕。

        struct request_list                 rq;                       //request实例的缓存

        unsigned long                      nr_requests         //队列可管理的请求最大数目

        unsigned long                      queue_flags;        //队列标志

}

struct request_queue *blk_init_queue_node(request_fn_proc *rfn,

spinlock_t *lock, int node_id)

        作用:生成一个标准的请求队列。

6.5.3 向系统添加磁盘和分区

1. 添加分区

struct hd_struct    *add_partition(struct gendisk   *disk,    int partno,

sector_t   start,    sector_t    len,    int    flags, ,)

        作用:向通用硬盘(struct gendisk)添加一个新分区。

        内容:

                1. 分配struct hd_struct实例。并初始化分区信息。

                2. 设置p->kobj,然后kobject_add();

2. 添加硬盘

void   add_disk(struct gendisk    *disk):

        作用:向系统添加通用硬盘。

6.5.4 打开块设备文件

创建块设备的设备文件时(mknod),调用init_special_inode函数。

void    init_special_inode(struct inode    *inode,    umode_t    mode,    dev_t   rdev)

{

        inode->i_mode    =    mode;

        if (S_ISBLK(mode)) {

                inode->i_fop    =    &def_blk_fops;

        }

}

struct file_operations         def_blk_fops     =    {

        .open     =     blkdev_open,

};

所以打开块设备的设备文件时:

        VFS将调用blkdev_open(struct inode * inode, struct file * filp)

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

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

相关文章

手机网站制作软件是哪些

手机网站制作软件是一种用于设计、开发和创建适用于移动设备的网站的软件工具。随着移动互联网时代的到来,越来越多的用户开始使用手机浏览网页和进行在线交流,因此,手机网站制作软件也逐渐成为了市场上的热门工具。 1. Adobe Dreamweaver&am…

天翼云8080、80端口用不了的问题

天翼云8080、80端口用不了的问题 前言:前段时间天翼云搞了活动,原来公司用的华为云老板说太贵了也快到期了,就换了天翼云的服务器。 排查: 安全组开放 80 8080 防火墙查看 没有问题 nginx nacos dcoker等停了 查看监听端口 发现…

YOLOv10改进 | 注意力篇 | YOLOv10引入HAttention(HAT)注意力

1. HAT介绍 1.1 摘要:基于 Transformer 的方法在低级视觉任务(例如图像超分辨率)中表现出了令人印象深刻的性能。 然而,我们发现这些网络通过归因分析只能利用有限的输入信息空间范围。 这意味着 Transformer 的潜力在现有网络中仍未得到充分发挥。 为了激活更多的输入像素…

国际现货黄金的交易方式:二次入场机会识别

近期受地缘局势以及通胀因素的影响,国际现货黄金投资又重新受到市场的青睐。虽然近期金价出现大跌,但投资者反而认为这是低价买金的好机会。为了方便投资者做出决策,下面我们就介绍一些国际现货黄金的交易方式——二次入场点进场。 在国际现货…

探索高效和轻量级多模态大语言模型的奥秘

过去一年,多模态大语言模型(MLLM)在视觉问答、视觉理解和推理等任务中表现出色。然而,模型的庞大尺寸和训练推理的高成本限制了其在学术界和工业界的广泛应用。因此,研究高效和轻量级的MLLM具有重要意义,尤其是在边缘计算场景中。…

Graphviz——实现动态更新协议状态机

1、描述 为了实现动态更新协议状态机,首先需要定义类来表示协议状态机。初始化该类后,保存状态机对象。在后续更新过程中,就可以加载保存的状态机对象,添加新的状态或事件。Graphviz的安装过程参考:Graphviz——安装、…

ECharts 雷达图案例002 - 诈骗性质分析

ECharts 雷达图案例002 - 诈骗性质分析 📊 ECharts 雷达图案例002 - 诈骗性质分析 深入挖掘数据背后的故事,用可视化手段揭示诈骗行为的模式和趋势。 🔍 案例亮点 创新的数据展示方式,让复杂的诈骗数据一目了然。定制化的雷达图…

一文带你入门【论文排版】利器·LaTeX |Macos

小罗碎碎念 我在刚开始写公众号的时候,写过一期推文,详细的讲解过如何使用LaTeX快速的进行论文排版。不过当时用的是windows的系统,这一次把Mac端的教程补上。 windows系统教程 https://zhuanlan.zhihu.com/p/677481269 LaTeX是一种流行的排…

Python10 python多线程

1.什么是python多线程 Python的多线程指的是在一个Python程序中同时运行多个线程,以达到并发执行多个任务的目的。线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。 在Python中,多线程的…

昇思25天学习打卡营第1天 | 快速入门

内容介绍:通过MindSpore的API来快速实现一个简单的深度学习模型。 具体内容: 1. 导包 import mindspore from mindspore import nn from mindspore.dataset import vision, transforms from mindspore.dataset import MnistDataset 2. 处理数据 fro…

如何快速使用向量检索服务DashVector?

免费体验阿里云高性能向量检索服务:https://www.aliyun.com/product/ai/dashvector 本文将介绍如何快速上手使用向量检索服务DashVector。 前提条件 已创建Cluster:创建Cluster。 已获得API-KEY:API-KEY管理。 已安装最新版SDK&#xff1a…

【网络安全学习】漏洞扫描:-01- 漏洞数据库searchsploit的使用

漏洞数据库是收集和存储各种软件漏洞信息的资源库。 漏洞数据库通常包含漏洞的名称、编号、描述、影响范围、危害等级、解决方案等信息,有些还提供漏洞的分析报告、演示视频、利用代码等内容。 1.常用的在线漏洞库: 国家信息安全漏洞共享平台 https:/…

Unity 天空盒制作使用教程

文章目录 1.概念2.制作天空盒3.使用天空盒3.1 为场景添加3.2 为相机添加 1.概念 天空盒是包裹整个场景的环境效果。 2.制作天空盒 1、创建材质球。 2、设置材质球Shader为SkyBox/6 Sided,将六张贴图放到对应位置。 3.使用天空盒 3.1 为场景添加 方法一、直接…

STM32F103ZET6_移植uC/OS_HAL

1下载源码 网址 GitHub - weston-embedded/uC-OS2: C/OS-II is a preemptive, highly portable, and scalable real-time kernels. Designed for ease of use on a huge number of CPU architectures. 需要下载三个文件 1看你使用是ucos2还是3(第一个文件&#…

【Python】类和对象高级特性

目录 前言 类变量与实例变量 类方法 静态方法 私有属性和方法 多重继承 元类 描述符 总结 前言 在前一篇文章中,我们讨论了 Python 类和对象的基本概念。本文将深入探讨一些高级特性,这些特性可以帮助你更有效地使用 Python 进行面向对象编程。…

Next.js开发中使用useRouter实现点击返回到上一页

在使用Next.js框架做前端页面开发时,如果想返回到上一页,可以利用useRouter钩子提供的back()方法,可以这样做: import {useRouter} from "next/navigation"; import {Space} from "antd"; import {ArrowLeftOutlined} f…

Mendix 创客访谈录|医疗设备领域的数字化转型利器

本期创客 尚衍亮 爱德亚(北京)医疗科技有限公司 应用开发和数字化事业部开发经理 大家好,我叫尚衍亮。毕业于软件工程专业,有6年的软件开发经验。从2021年开始,我在爱德亚(北京)医疗科技有限公司…

智能合约开发的过程

智能合约是一种运行在区块链上的程序,可以自动执行预先设定的条款和条件。智能合约具有去中心化、透明、不可篡改等特点,因此被广泛应用于金融、供应链、物联网等领域。北京木奇移动技术有限公司,专业的软件外包开发公司,欢迎交流…

Spring Boot集成Minio插件快速入门

1 Minio介绍 MinIO 是一个基于 Apache License v2.0 开源协议的对象存储服务。它兼容亚马逊 S3 云存储服务接口,非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小&…

LSM-Tree数据结构原理

LSM-Tree树原理 什么是LSM-Tree LSM-Tree 即 Log Structrued Merge Tree,这是一种分层有序,硬盘友好的数据结构。核心思想是利用磁盘顺序写性能远高于随机写。 LSM-Tree 并不是一种严格的树结构,而是一种内存磁盘的多层存储结构。HBase、L…