Linux如何编写块设备驱动_LinuxBlockDriver开发教程
发布时间 - 2025-11-25 00:00:00 点击率:次首先实现块设备驱动需理解gendisk与request_queue的作用,1. gendisk描述设备信息并注册到系统;2. request_queue管理I/O请求并通过make_request处理bio;3. 每个bio包含多个段,驱动需遍历并完成数据拷贝;4. 模块卸载时按顺序释放资源;5. 编译后通过insmod加载并用mkfs、mount测试。
编写Linux块设备驱动需要理解内核中块I/O子系统的基本架构和数据流。块设备与字符设备不同,它以固定大小的数据块为单位进行读写,并支持随机访问。典型的块设备包括硬盘、SSD、U盘等。本文将带你一步步实现一个简单的内存模拟块设备驱动(RAM Disk),帮助你掌握Linux块设备驱动开发的核心要点。
1. 理解块设备驱动的基本结构
Linux块设备驱动主要依赖于struct gendisk和struct request_queue两个核心结构体:
- gendisk:描述一个逻辑块设备,包含设备名、主次设备号、分区信息等。
- request_queue:管理来自文件系统的I/O请求,驱动需为其注册请求处理函数。
块设备不直接处理read/write系统调用,而是通过请求队列接收bio(block I/O)结构,由驱动完成数据搬运。
2. 创建请求队列与gendisk实例
在模块初始化函数中,需分配并初始化请求队列和gendisk:
static struct request_queue *queue; static struct gendisk *disk;static int __init my_blk_init(void) { // 分配请求队列 queue = blk_alloc_queue(GFP_KERNEL); if (!queue) return -ENOMEM;
// 设置请求处理函数 blk_queue_make_request(queue, my_make_request); // 分配gendisk结构(1个分区) disk = alloc_disk(1); if (!disk) { blk_cleanup_queue(queue); return -ENOMEM; } disk->major = MY_BLK_MAJOR; // 主设备号 disk->first_minor = 0; disk->fops = &my_blk_fops; // 文件操作(通常为空或仅占位) disk->queue = queue; strcpy(disk->disk_name, "myblk"); // 设置容量(以512字节扇区为单位) set_capacity(disk, MY_BLK_SIZE / 512); // 注册设备 add_disk(disk); return 0;
}
3. 实现make_request函数处理I/O
传统方式使用make_request函数逐个处理bio。每个bio代表一次I/O操作,可能包含多个段(segment):
static int my_make_request(struct request_queue *q, struct bio *bio)
{
struct bio_vec bvec;
sector_t sector = bio->bi_iter.bi_sector;
void *mem = myblk_data + (sector * 512); // 内存偏移
bool is_write = op_is_write(bio_op(&bio));
if (sector * 512 + bio->bi_iter.bi_size > MY_BLK_SIZE) {
bio_endio(bio, -EIO);
return 0;
}
bio_for_each_segment(bvec, bio, iter) {
char *bdata = kmap_atomic(bvec.bv_page) + bvec.bv_offset;
if (is_write)
memcpy(mem, bdata, bvec.bv_len);
else
memcpy(bdata, mem, bvec.bv_len);
kunmap_atomic(bdata - bvec.bv_offset);
mem += bvec.bv_len;
}
bio_endio(bio, 0);
return 0;}
注意:现代内核推荐使用blk_mq_make_request配合多队列机制,但简单驱动仍可用传统方式。
4. 清理资源与模块卸载
模块卸载时必须释放申请的资源,顺序不能错:
static void __exit my_blk_exit(void)
{
del_gendisk(disk);
put_disk(disk);
blk_cleanup_queue(queue);
}
确保在del_gendisk后不再有新的I/O进入,避免空指针访问。
5. 编译与测试
编写Makefile:
obj-m += myblk.oKDIR := /lib/modules/$(shell uname -r)/build
all: $(MAKE) -C $(KDIR) M=$(PWD) modules
clean: $(MAKE) -C $(KDIR) M=$(PWD) clean
编译后加载模块:
sudo insmod myblk.ko dmesg | tail # 查看设备号 lsblk # 应看到 myblk 设备 sudo mkfs.ext4 /dev/myblk sudo mount /dev/myblk /mnt echo "hello" > /mnt/test.txt
基本上就这些。从零写块设备驱动的关键是理解bio的处理流程和内存映射方式。虽然真实硬件驱动还需处理DMA、中断等,但内存模拟设备是学习的良好起点。调试时多用dmesg观察内核输出,逐步验证读写正确性。
# linux
# 字节
# u盘
# 硬盘
# ai
# 架构
# 结构体
# 指针
# Struct
# 空指针
# 多个
# 加载
# 遍历
# 推荐使用
# 为其
# 带你
# 还需
# 文件系统
# 它以
# 为空
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
如何用西部建站助手快速创建专业网站?
如何快速重置建站主机并恢复默认配置?
Linux后台任务运行方法_nohup与&使用技巧【技巧】
javascript中对象的定义、使用以及对象和原型链操作小结
在centOS 7安装mysql 5.7的详细教程
米侠浏览器网页背景异常怎么办 米侠显示修复
VIVO手机上del键无效OnKeyListener不响应的原因及解决方法
laravel怎么实现图片的压缩和裁剪_laravel图片压缩与裁剪方法
Laravel如何实现文件上传和存储?(本地与S3配置)
php485函数参数是什么意思_php485各参数详细说明【介绍】
Laravel Seeder填充数据教程_Laravel模型工厂Factory使用
网站图片在线制作软件,怎么在图片上做链接?
Laravel如何实现模型的全局作用域?(Global Scope示例)
Laravel如何配置和使用队列处理异步任务_Laravel队列驱动与任务分发实例
个人网站制作流程图片大全,个人网站如何注销?
如何在浏览器中启用Flash_2025年继续使用Flash Player的方法【过时】
简历没回改:利用AI润色让你的文字更专业
如何在景安服务器上快速搭建个人网站?
Firefox Developer Edition开发者版本入口
laravel怎么在请求结束后执行任务(Terminable Middleware)_laravel Terminable Middleware请求结束任务执行方法
高端建站三要素:定制模板、企业官网与响应式设计优化
如何在自有机房高效搭建专业网站?
厦门模型网站设计制作公司,厦门航空飞机模型掉色怎么办?
Windows驱动无法加载错误解决方法_驱动签名验证失败处理步骤
Laravel如何使用Seeder填充数据_Laravel模型工厂Factory批量生成测试数据【方法】
如何挑选高效建站主机与优质域名?
如何用AI一键生成爆款短视频文案?小红书AI文案写作指令【教程】
Laravel用户认证怎么做_Laravel Breeze脚手架快速实现登录注册功能
香港服务器租用每月最低只需15元?
标准网站视频模板制作软件,现在有哪个网站的视频编辑素材最齐全的,背景音乐、音效等?
Python函数文档自动校验_规范解析【教程】
Laravel如何安装Breeze扩展包_Laravel用户注册登录功能快速实现【流程】
做企业网站制作流程,企业网站制作基本流程有哪些?
清除minerd进程的简单方法
SQL查询语句优化的实用方法总结
如何在IIS中配置站点IP、端口及主机头?
Laravel请求验证怎么写_Laravel Validator自定义表单验证规则教程
googleplay官方入口在哪里_Google Play官方商店快速入口指南
Win10如何卸载预装Edge扩展_Win10卸载Edge扩展教程【方法】
成都品牌网站制作公司,成都营业执照年报网上怎么办理?
悟空浏览器如何设置小说背景色_悟空浏览器背景色设置【方法】
Laravel如何使用API Resources格式化JSON响应_Laravel数据资源封装与格式化输出
Laravel如何实现API版本控制_Laravel版本化API设计方案
如何使用 Go 正则表达式精准提取括号内首个纯字母标识符(忽略数字与嵌套)
网站优化排名时,需要考虑哪些问题呢?
Laravel的辅助函数有哪些_Laravel常用Helpers函数提高开发效率
Laravel怎么使用Blade模板引擎_Laravel模板继承与Component组件复用【手册】
如何在Ubuntu系统下快速搭建WordPress个人网站?
如何用PHP快速搭建CMS系统?
百度浏览器ai对话怎么关 百度浏览器ai聊天窗口隐藏


disk) {
blk_cleanup_queue(queue);
return -ENOMEM;
}
disk->major = MY_BLK_MAJOR; // 主设备号
disk->first_minor = 0;
disk->fops = &my_blk_fops; // 文件操作(通常为空或仅占位)
disk->queue = queue;
strcpy(disk->disk_name, "myblk");
// 设置容量(以512字节扇区为单位)
set_capacity(disk, MY_BLK_SIZE / 512);
// 注册设备
add_disk(disk);
return 0;