驱动开发硬核特训 · Day 11(下篇):从 virtio_blk 看虚拟总线驱动模型的真实落地

🔍

B站相应的视屏教程
📌 内核:博文+视频 - 总线驱动模型实战全解析
敬请关注,记得标为原始粉丝。


🔧

在上篇中,我们已经从理论视角分析了“虚拟总线驱动模型”在 Linux 驱动体系中的独特定位。本篇我们聚焦实战:深入分析一个真实的内核子系统 —— virtio_blk 虚拟块设备驱动,完整讲清虚拟总线模型的运行机制、设备匹配、驱动注册、驱动结构体组织方式、probe 流程、VQ(virtqueue)使用方式等。我们将对照 platform_driver、i2c_driver,总结异同点,帮助你彻底理解这个典型的虚拟驱动模型。


1. virtio_blk 简介与实战目标

virtio_blk 是 Linux 内核中 VirtIO 虚拟设备框架的一部分,模拟了一个块设备(类似硬盘),用于 KVM 虚拟机中的磁盘访问、容器虚拟块设备等场景。它不对应具体硬件,但提供了完整的设备模型。

我们实战目标是:

  • 看懂 virtio_blk 驱动如何注册。
  • 理解它是如何匹配“虚拟设备”的。
  • 弄清 virtio 总线下设备与驱动之间的绑定机制。
  • 对比 platform_drivervirtio_driver,理解它们的核心区别。

2. virtio 驱动注册机制总览

drivers/block/virtio_blk.c 中,驱动最终通过以下结构注册:

static struct virtio_driver virtio_blk = {.feature_table = features,.feature_table_size = ARRAY_SIZE(features),.driver.name = KBUILD_MODNAME,.id_table = id_table,.probe = virtblk_probe,.remove = virtblk_remove,
};

通过:

module_virtio_driver(virtio_blk);

内核完成注册,最终宏会展开为 module_init()module_exit() 自动注册。

这非常类似于 platform_driver 的注册过程:

module_platform_driver(my_platform_driver);

区别在于总线类型不同:

  • platform_driver 注册到 platform 总线上,匹配 platform_device
  • virtio_driver 注册到 virtio 总线上,匹配 virtio_device

3. virtio 设备和驱动匹配机制

virtio 的匹配方式不基于设备树(也可以配合使用),而是通过 virtio_device_id 表完成。

static const struct virtio_device_id id_table[] = {{ VIRTIO_ID_BLOCK, VIRTIO_DEV_ANY_ID },{ 0 },
};
  • VIRTIO_ID_BLOCK 是预定义的设备类型标识,代表块设备。
  • 系统在虚拟机启动时(比如 QEMU)会注入 virtio_device,并调用驱动的 probe

匹配过程:

virtio_bus.c→ virtio_register_driver()→ __register_driver()→ bus_add_driver()→ driver_match_device() // 比较 virtio_id

platform_driverof_match_table 匹配方式略有不同,virtio_driver 更偏向于“协议栈类型匹配”。


4. 重点函数分析:virtblk_probe()

static int virtblk_probe(struct virtio_device *vdev) {// 关键:分配 virtio_blk 结构体,挂载到 vdev->privvdev->priv = vblk = kmalloc(...);// 初始化 virtqueueinit_vq(vblk);// 分配 gendisk,注册 blk-mq 调度器vblk->disk = blk_mq_alloc_disk(...);// 注册设备device_add_disk(...);
}
  • vdev->priv 与 platform_driver 中的 dev_set_drvdata() 类似,保存上下文。
  • virtqueue 是 virtio 驱动的关键数据通道。
  • 使用 blk-mq 接口建立请求调度与提交。

5. virtqueue 与传统 platform 驱动的差异

项目virtio_blkplatform_driver
总线类型virtio 总线platform 总线
匹配机制virtio_device_idof_match_table / id_table
资源传递virtqueue + virtio_config设备树 + platform_resource
probe 中行为初始化 VQ / 队列注册申请 IO 内存、中断、寄存器
特点无真实硬件,支持热插拔通常为静态资源

6. 真实代码结构分析:virtio_blk 是怎样注册块设备的?

从注册 gendiskblk_mq 调度器配置:

vblk->tag_set.ops = &virtio_mq_ops;
blk_mq_alloc_tag_set(&vblk->tag_set);
vblk->disk = blk_mq_alloc_disk(&vblk->tag_set, vblk);

重点在于:

  • virtio_mq_ops 提供了 .queue_rq.poll.map_queues 等接口。
  • 驱动注册时,通过 device_add_disk() 向 block subsystem 注册。

再看看 .queue_rq 实现:

virtio_queue_rq() {struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);virtblk_add_req(...) // 将请求挂到 virtqueue
}

即使没有真实硬件,virtqueue 就相当于“虚拟的 DMA ring”,请求通过它发送到对端。


7. 与软件工程中的“适配器”模式对比分析

设备模型是内核层次的一种“适配机制”:

  • 驱动与设备解耦(device 和 driver 通过总线进行匹配)。
  • 匹配后注册调用 probe(相当于运行时建立适配连接)。
  • 通过统一接口调用函数(如 probe()remove()suspend())。

在 virtio 中,这种适配机制更为纯粹,因为:

  • 驱动和设备都是“运行时注入”的;
  • 没有真实硬件,不需要解析物理寄存器映射;
  • 强依赖 virtqueue 来传递数据,适配的是协议数据格式。

因此,virtio 驱动更像是“运行时适配器 + 抽象接口定义”的组合,非常符合软件工程中 Adapter 模式的精髓。


8. 总结与核心问答

Q1:virtio_driver 和 platform_driver 最大区别是什么?
A:总线不同、匹配机制不同、资源获取不同。virtio 无真实硬件,匹配依赖 virtio_device_id。

Q2:virtqueue 相当于 platform 驱动中的什么?
A:类似于 platform 驱动中通过 ioremap 得到的寄存器,但更加抽象,是“通用的数据传输管道”。

Q3:是否可以将 virtio_driver 看成虚拟平台驱动?
A:从使用方式看类似,但从总线层来看,是完全不同的子系统。


小结

本篇我们通过对 virtio_blk 的深入剖析,完整讲解了虚拟总线驱动模型在 Linux 内核中的真实落地。它不是一个“子集”或“附属”模型,而是一个独立存在、拥有自己总线匹配机制与通信方式的驱动模型。

下一篇(Day 12),我们将继续拓展——深入理解 virtio_consolevirtio_net 等设备的实现方式,帮助你逐步掌握虚拟设备开发的核心技能。

如有任何问题,欢迎在评论区留言讨论!

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

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

相关文章

音视频转换器 AV 接口静电保护方案

方案简介 音视频转换器是将音视频(AV)信号转换成其他格式或信号类型的设备或软件。 它能够实现大多数视频、音频以及图像格式之间的转换,包括但不限于 RMVB、AVI、 MP4、MOV 等常见格式,同时也支持将不同采样率、位深度、声道数…

AI agents系列之全从零开始构建

在我们上一篇博客文章中,我们全面介绍了智能代理,讨论了它们的特性、组成部分、演变过程、面临的挑战以及未来的可能性。 这篇文章,咱们就来聊聊怎么用 Python 从零开始构建一个智能代理。这个智能代理能够根据用户输入做出决策,…

【Python爬虫】详细工作流程以及组成部分

目录 一、Python爬虫的详细工作流程 确定起始网页 发送 HTTP 请求 解析 HTML 处理数据 跟踪链接 递归抓取 存储数据 二、Python爬虫的组成部分 请求模块 解析模块 数据处理模块 存储模块 调度模块 反爬虫处理模块 一、Python爬虫的详细工作流程 在进行网络爬虫工…

Kotlin 集合过滤全指南:all、any、filter 及高级用法

在 Kotlin 中,集合过滤是数据处理的核心操作之一。无论是简单的条件筛选,还是复杂的多条件组合,Kotlin 都提供了丰富的 API。本文将详细介绍 filter、all、any、none 等操作符的用法,并展示如何在实际开发中灵活运用它们。 1. 基础…

爬虫:一文掌握 curl-cffi 的详细使用(支持 TLS/JA3 指纹仿真的 cURL 库)

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、curl-cffi 概述1.1 curl-cffi介绍1.2 主要特性1.3 适用场景1.4 使用 curl-cffi 的注意事项1.5 与 requests 和 pycurl 对比1.6 curl-cffi 的安装二、基本使用2.1 同步请求2.2 异步请求三、高级功能3.1 模拟浏览器指…

AllData数据中台升级发布 | 支持K8S数据平台2.0版本

🔥🔥 AllData大数据产品是可定义数据中台,以数据平台为底座,以数据中台为桥梁,以机器学习平台为中层框架,以大模型应用为上游产品,提供全链路数字化解决方案。 ✨杭州奥零数据科技官网&#xf…

dnf install openssl失败的原因和解决办法

网上有很多编译OpenSSL源码(3.x版本)为RPM包的文章,这些文章在安装RPM包时都是执行rpm -ivh openssl-xxx.rpm --nodeps --force 这个命令能在缺少依赖包的情况下能强行执行安装 其实根据Centos的文档,安装RPM包一般是执行yum install或dnf install。后者…

从入门到进阶:React 图片轮播 Carousel 的奇妙世界!

全文目录: 开篇语🖐 前言✨ 目录🎯 什么是图片轮播组件?🔨 初识 React 中的轮播实现示例代码分析 📦 基于第三方库快速实现轮播示例:用 react-slick优势局限性 🛠️ 自己动手实现一个…

2025第十六届蓝桥杯PythonB组部分题解

一、攻击次数 题目描述 小蓝操控三个英雄攻击敌人,敌人初始血量2025: 第一个英雄每回合固定攻击5点第二个英雄奇数回合攻击15点,偶数回合攻击2点第三个英雄根据回合数除以3的余数攻击:余1攻2点,余2攻10点&#xff0…

新手宝塔部署thinkphp一步到位

目录 一、下载对应配置 二、加载数据库 三、添加FTP​ 四、上传项目到宝塔​ 五、添加站点​ 六、配置伪静态 七、其他配置 开启监控 八、常见错误 一、打开宝塔页面,下载对应配置。 二、加载数据库 从本地导入数据库文件 三、添加FTP 四、上传项目到宝塔…

2025年,HarmonyOS认证学习及考试

HarmonyOS应用开发者认证考试 基础认证 通过系统化的课程学习,熟练掌握 DevEco Studio,ArkTS,ArkUI,预览器,模拟器,SDK 等 HarmonyOS 应用开发的关键概念,具备基础的应用开发能力。 高级认证…

3-1 Git分布式版本控制特性探讨

Git 的分布式版本控制特性是其核心优势之一,它使 Git 在版本管理方面具有高度的灵活性、可靠性和高效性。以下从多个方面来理解这一特性: 分布式存储 在 Git 中,每个开发者的本地机器上都拥有完整的版本库,包含了项目的所有历史记录和元数据。这与集中式版本控制系统(如…

flutter 桌面应用之右键菜单

​在 Flutter 桌面应用开发中,context_menu 和 contextual_menu 是两款常用的右键菜单插件,各有特色。以下是对它们的对比分析:​ context_menu 集成方式:​通过 ContextMenuArea 组件包裹目标组件,定义菜单项。​掘金…

Tips:用proxy解决前后端分离项目中的跨域问题

在前后端分离项目中,"跨域问题"是浏览器基于同源策略(Same-Origin Policy)对跨域请求的安全限制。当你的前端(如运行在 http://localhost:3000 )和后端(如运行在 http://localhost:8080 &#…

基于 Qt 的图片处理工具开发(一):拖拽加载与基础图像处理功能实现

一、引言 在桌面应用开发中,图片处理工具的核心挑战在于用户交互的流畅性和异常处理的健壮性。本文以 Qt为框架,深度解析如何实现一个支持拖拽加载、亮度调节、角度旋转的图片处理工具。通过严谨的文件格式校验、分层的架构设计和用户友好的交互逻辑&am…

设计模式:依赖倒转原则 - 依赖抽象,解耦具体实现

一、为什么用依赖倒转原则? 在软件开发中,类与类之间的依赖关系是架构设计中的关键。如果依赖过于紧密,系统的扩展性和维护性将受到限制。为了应对这一挑战,依赖倒转原则(Dependency Inversion Principle,…

vue+d3js+fastapi实现天气柱状图折线图饼图

说明: vued3jsfastapi实现天气柱状图折线图饼图 效果图: step0:postman 1. 生成天气数据(POST请求):URL: http://localhost:8000/generate-data/?year2024&month3&seed42 方法: POST Headers:Content-Type:…

UE5,LogPackageName黄字警报处理方法

比如这个场景,淘宝搜索,ue5 T台,转为ue5.2后,选择物体,使劲冒错。 LogPackageName: Warning: DoesPackageExist called on PackageName that will always return false. Reason: 输入“”为空。 2. 风险很大的删除法&…

量子代理签名:量子时代的数字授权革命

1. 量子代理签名的定义与核心原理 量子代理签名(Quantum Proxy Signature, QPS)是经典代理签名在量子信息领域的延伸,允许原始签名者(Original Signer)授权给代理签名者(Proxy Signer)代为签署文…

【ESP32-C6】Base on esptool commands to enable Flash Encryption and Secure Boot

Please refer to Security Guides Security Overview Flash Encryption Secure Boot v2 Security Features Enablement Workflows Vulnerabilities You can base on “esp-idf/examples/security/flash_encryption” example for testing. Partition Table setting&#…