当前位置:首页>Linux>Linux驱动编程块设备驱动初体验0x00

Linux驱动编程块设备驱动初体验0x00

  • 2026-09-10 20:26:18
Linux驱动编程块设备驱动初体验0x00

一、一些概念

1.Linux内核的块子系统(Block Subsystem) 是连接文件系统层和块设备驱动层的核心中间层,也常被称为 "块 I/O 子系统"。它的核心使命是:标准化、调度、优化所有块设备的 I/O 请求,向上为文件系统提供统一的扇区读写接口,向下为驱动层提供标准化的请求封装和分发机制。

2.调度层级:

  用户层 read/write → 块设备层(VFS + 通用块层) → 调度合并 → 驱动程序 → 硬件(磁盘/Flash/模拟内存)。

1)用户层

  sudo dd if=/dev/mybd of=/dev/null count=1   # 读

  sudo dd if=/dev/zero of=/dev/mybd count=1   # 写

2)VFS虚拟文件系统

  用户层调用open,内核找到并识别对应的块设备节点(例如/dev/mybd),然后进入通用块层。

3)通用块层(内核核心)

--把read/write转换成BIO;

  --把BIO合并成Request(request);

  --把Request放进调度队列;

  --把Request派发给驱动的queue_rq。

4)blk-mq多队列层(Linux5.x/6.x标准,不同内核版本可能API接口不太一样)

 内核会管理队列、分配请求最终调用驱动中的my_queue_rq()。

5)在my_queue_rq()中编写操作驱动代码

所有读写最终都会进入这个函数,这也是块驱动的唯一I/O入口。

6)返回给用户层(形成闭环)

驱动完成 → 通知块层 → 通知 VFS → 用户层完成退出。

二、关键结构体及函数接口

1.关键结构体:

1)bio:块I/O的最小单元,描述 "一次扇区读写请求"(包含起始扇区、长度、读写方向、数据缓冲区);2)request:一个读写请求,由多个连续的bio合并而成的 ”批量请求"(减少驱动操作次数);3)request_queue:驱动的 "请求队列",块子系统将bio/request放入队列,驱动从队列取请求处理;4)gendisk:块设备的 "身份标识",描述设备的主/次设备号、扇区数、请求队列等信息;5)blk_mq_ops:驱动操作集。

2.关键函数接口:

1)blk_mq_alloc_tag_set():分配blk-mq多队列标签集,必须调用,块驱动的起点;2)blk_mq_alloc_disk():分配gendisk磁盘结构 + 绑定队列;3)add_disk():注册磁盘到内核,自动生成 /dev/xxx;4)del_gendisk/put_disk():卸载磁盘;5)blk_mq_free_tag_set():释放队列资源。

三、测试

1.源码

my_blockdev.c

#include<linux/module.h>#include<linux/blkdev.h>#include<linux/blk-mq.h>#include<linux/hdreg.h>#define MYBD_SECTORS 1024static struct gendisk *mybd_disk;static struct blk_mq_tag_set *mybd_tagset;/* 读写请求处理函数 */staticblk_status_tmybd_queue_rq(struct blk_mq_hw_ctx *hctx, conststruct blk_mq_queue_data *bd){    struct request *rq = bd->rq;    pr_info("mybd_queue_rq\n");    blk_mq_start_request(rq);    blk_mq_end_request(rq, BLK_STS_OK);    return BLK_STS_OK;}static const struct blk_mq_ops mybd_mq_ops = {    .queue_rq = mybd_queue_rq,};/* 打开设备 */staticintmybd_open(struct gendisk *disk, blk_mode_t mode){    pr_info("mybd: open\n");    return 0;}/* 关闭设备 */staticvoidmybd_release(struct gendisk *disk){    pr_info("mybd: release\n");}/* 磁盘几何信息(必须实现,否则内核不认) */staticintmybd_getgeo(struct block_device *bdev, struct hd_geometry *geo){    geo->heads = 1;    geo->sectors = 32;    geo->cylinders = MYBD_SECTORS / (1 * 32);    geo->start = 0;    return 0;}static const struct block_device_operations mybd_fops = {    .owner    = THIS_MODULE,    .open     = mybd_open,    .release  = mybd_release,    .getgeo   = mybd_getgeo,  // 关键!必须有};staticint __init mybd_init(void){    int ret;    /* 分配 tag set */    mybd_tagset = kzalloc(sizeof(*mybd_tagset), GFP_KERNEL);    if (!mybd_tagset)        return -ENOMEM;    mybd_tagset->ops = &mybd_mq_ops;    mybd_tagset->nr_hw_queues = 1;    mybd_tagset->queue_depth = 64;    mybd_tagset->numa_node = NUMA_NO_NODE;    ret = blk_mq_alloc_tag_set(mybd_tagset);    if (ret)        goto free_tagset;    /* 分配磁盘 */    mybd_disk = blk_mq_alloc_disk(mybd_tagset, NULL);    if (!mybd_disk) {        ret = -ENOMEM;        goto cleanup_tags;    }    /* 设置磁盘信息 */    mybd_disk->fops = &mybd_fops;    mybd_disk->flags = GENHD_FL_NO_PART;  // 无分区    snprintf(mybd_disk->disk_name, DISK_NAME_LEN, "mybd");    set_capacity(mybd_disk, MYBD_SECTORS);    /* 注册磁盘 → 自动生成 /dev/mybd */    add_disk(mybd_disk);    pr_info("mybd: loaded\n");    return 0;cleanup_tags:    blk_mq_free_tag_set(mybd_tagset);free_tagset:    kfree(mybd_tagset);    return ret;}staticvoid __exit mybd_exit(void){    del_gendisk(mybd_disk);    put_disk(mybd_disk);    blk_mq_free_tag_set(mybd_tagset);    kfree(mybd_tagset);    pr_info("mybd: unloaded\n");}module_init(mybd_init);module_exit(mybd_exit);MODULE_AUTHOR("AXUN");MODULE_LICENSE("GPL");

2.Makefile

CC = gcc-12  # 新增:指定编译器为gcc-12obj-m += my_blockdev.o  # 要编译的模块名(对应 my_blockdev.c)KERNELDIR ?= /lib/modules/$(shell uname -r)/build  #内核源码路径PWD := $(shell pwd)  #当前目录all:$(MAKE) -C $(KERNELDIR) M=$(PWD) modules  #编译模块clean:$(MAKE) -C $(KERNELDIR) M=$(PWD) clean  #清理编译产物

3.编译与加载

#编译驱动

 make

#加载模块

 sudo insmod my_blockdev.ko

#查看设备号

 ls /dev/mybd -l

#读写磁盘

 sudo dd if=/dev/mybd of=/dev/null count=1   # 读

 sudo dd if=/dev/zero of=/dev/mybd count=1   # 写

四、测试平台及使用的Linux版本

最新文章

随机文章