第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)

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

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

相关文章

MySQL进阶——索引【核心】

目录 1索引概述 2索引结构 2.1 B-Tree(多路平衡查找树) 2.2 BTree 2.3 hash 3索引分类 3.1MySQL中分4类 3.2 InnoDB存储引擎分两类(SQL优化中重要) 4索引语法 4.1创建和查看索引 4.2删除索引 5 SQL性能分析 5.1 查看执…

Ubuntu安装docker 详细教程

Ubuntu安装docker,以及docker compose踩了一步一步的坑,真的特别抓马!!! 因此分享我的安装教程和踩坑,希望给大家一些帮助吧 安装详细教程 卸载docker停止 docker 运行使用以下命令来卸载 Docker 软件包及其…

国产数据库中读写分离实现机制

在数据库高可用架构下会存在1主多备的部署,备节点可以根据业务场景分发一部分流量以充分利用资源,并减轻主库的压力,因此在数据库的功能上需要读写分离来实现。 充分利用备节点的资源,提升业务的吞吐量;防止运维等非业…

助力低空经济-eVTOL/无人机ADS-B航管应答机选型指南

一、低空经济概述 “低空经济”在今年全国两会首次写入政府工作报告。近日,工业和信息化部、科学技术部、财政部、中国民用航空局印发《通用航空装备创新应用实施方案(2024—2030年)》,提出到2030年,推动低空经济形成…

c语言回顾-结构体(2)

前言 前面讲了结构体的概念,定义,赋值,访问等知识,本节内容小编将讲解结构体的内存大小的计算以及通过结构体实现位段,话不多说,直接上干货!!! 1.结构体内存对齐 说到计…

自建消息推送工具 Gotify 实现消息私有化通知

本文首发于只抄博客,欢迎点击原文链接了解更多内容。 前言 之前分享了如何通过 Webhook 将 VPS 与 NAS 上部署的应用消息推送到钉钉、飞书、企业微信,但是对于部分用户来说,可能因为以下种种原因,不方便使用常见的办公 IM 软件来进行消息推送: 消息涉及隐私敏感信息,不希…

11.6.k8s实战-节点扩缩容

目录 一,需求描述 二、集群缩容-节点下线 1,节点下线案例说明 2,查看现有节点 3,查看所有名称空间下的pod ​编辑4,驱逐下线节点的pod 5,驱逐后再次查看pod 6,驱逐pod后再次查看节点信息…

新书速览|Ubuntu Linux运维从零开始学

《Ubuntu Linux运维从零开始学》 本书内容 Ubuntu Linux是目前最流行的Linux操作系统之一。Ubuntu的目标在于为一般用户提供一个最新的、相当稳定的、主要由自由软件构建而成的操作系统。Ubuntu具有庞大的社区力量,用户可以方便地从社区获得帮助。《Ubuntu Linux运…

熟练一种编程语言再学另一种语言时,叠的是buff还是debuff?

在大多数情况下,尤其是对于广泛使用的高级编程语言,它们之间存在正向的相互促进作用,熟练使用一种语言后再去学习另一种语言,大概率能叠个buff。 首先,学习编程语言的基础是通用的,比如软硬件和网络基础、算…

iOS原生APP开发的技术难点

iOS原生APP开发的技术难点主要体现在以下几个方面,总而言之,iOS原生APP开发是一项技术难度较高的工作,需要开发者具备扎实的编程基础、丰富的开发经验和良好的学习能力。北京木奇移动技术有限公司,专业的软件外包开发公司&#xf…

shell中的条件判断

在Linux操作系统中如何是用条件判断语句, 如上图所示,先定义一个变量变量值,再使用test $a hello来判断式子的正确与否,当结果正确的时候返回0,当结果错误时候结果返回1,可以是用echo $? 来获取并打印输出…

AI大模型会如何颠覆手机?

导语:大模型在手机端的落地,不仅仅是AI进入人类生活的开始,也是行业发生颠覆,新老巨头进行更替的时刻。 将大模型变小,再塞进手机,会给人们的生活带来怎样的影响? 最近,荣耀成为了…

数据结构历年考研真题对应知识点(单链表、双链表、循环链表)

目录 2.3线性表的链式表示 2.3.1单链表的定义 【单链表的应用(2009、2012、2013、2015、2016、2019)】 2.3.2单链表上基本操作的实现 【单链表插入操作后地址或指针的变化(2016)】 2.3.3双链表 【双链表中插入操作的实现(2023)】 【循环双链表中删除操作的实现(2016)】 …

Ubuntu20.04部署Qwen2.openvino流程

下载代码 里面包含依赖 git clone https://github.com/OpenVINO-dev-contest/Qwen2.openvino.gitpython环境配置 创建虚拟环境 conda create -name qwen2openvino python3.10 conda activate qwen2openvino安装依赖 pip install wheel setuptools pip install -r requirem…

C# OCCT Winform 选中模型改变状态

选中状态设置 _context new AIS_InteractiveContext(_viewer);var selectionDrawer new Prs3d_Drawer();selectionDrawer.SetColor(Colors.Selection);selectionDrawer.SetDisplayMode(1);selectionDrawer.SetTransparency(0.1f);_context.SetSelectionStyle(selectionDrawe…

基于PHP的民宿管理系统

有需要请加文章底部Q哦 可远程调试 基于PHP的民宿管理系统 一 介绍 此民宿管理系统基于原生PHP开发,数据库mysql,前端jquery.js和echarts.js。系统角色分为用户和管理员。用户可以在线浏览和预订民宿,管理员登录后台进行相关管理等。(在系统…

【TB作品】MSP430G2553,单片机,口袋板, 单相交流电压、电流计设计

题5 单相交流电压、电流计设计 设计基于MSP430的单相工频交流电参数检测仪。交流有效值0-220V,电流有效值0-40A。电压、电流值经电压、电流传感器输出有效值为0-5V的交流信号,传感器输出的电压、电流信号与被测电压、电流同相位。 基本要求如下 &#xf…

前端网站(二)-- 菜单页面【附源码直接可用】

菜单页面 开篇(请大家看完):此网站写给挚爱,后续页面还会慢慢更新,大家敬请期待~ ~ ~ 轻舟所编写这个前端框架的设计初衷,纯粹是为了哄对象开心。除此之外,并无其它任何用途或目的。 此前端框…

基于Java的二手手机回收平台系统

开头语: 你好呀,我是计算机学长猫哥!如果有相关需求,文末可以找到我的联系方式。 开发语言:Java 数据库:MySQL 技术:JavaJSPServlet 工具:IDEA/Eclipse、Navicat、Maven 系统展…

【C++提高编程-10】----C++ STL常用拷贝和替换算法

🎩 欢迎来到技术探索的奇幻世界👨‍💻 📜 个人主页:一伦明悦-CSDN博客 ✍🏻 作者简介: C软件开发、Python机器学习爱好者 🗣️ 互动与支持:💬评论 &…