You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux 5.15下如何基于blk_mq正确注册、创建和操作块设备?

Linux内核5.15+ blk_mq块设备注册框架及问题排查

正确的blk_mq块设备注册步骤

  • 分配并初始化struct blk_mq_tag_set,配置队列深度、硬件队列数、请求处理函数等核心参数
  • 分配struct gendisk,设置设备容量、扇区大小、操作函数集等属性
  • 分配设备号(动态/静态均可),关联到gendisk
  • 初始化blk_mq队列,将tag_set与gendisk的队列绑定
  • 调用add_disk()将设备注册到系统(这是设备出现在/dev目录的关键步骤)
  • 模块卸载时反向清理:删除gendisk、销毁队列、释放tag_set、注销设备号

常见问题点

  • 遗漏add_disk():这是设备被系统识别并生成/dev节点的核心操作,很多人会忽略
  • 设备号分配失败:动态分配需检查返回值,静态分配要确保设备号未被占用
  • blk_mq_tag_set参数配置错误:如nr_hw_queues、queue_depth设置不合理导致队列初始化失败
  • 未设置gendisk的fops:块设备需提供基础操作函数(至少要指定owner)

完整框架代码

#include <linux/module.h>
#include <linux/blk-mq.h>
#include <linux/fs.h>
#include <linux/genhd.h>
#include <linux/slab.h>

#define DEVICE_NAME "myblkdev"
#define DEVICE_SECTORS (1024 * 1024)  // 512MB(默认扇区大小512字节)
#define QUEUE_DEPTH 128
#define NR_HW_QUEUES 1

static struct blk_mq_tag_set my_tag_set;
static struct gendisk *my_disk;
static dev_t my_dev;

// 块设备请求处理示例(实际需根据存储介质实现读写逻辑)
static blk_status_t myblk_queue_rq(struct blk_mq_hw_ctx *hctx, const struct blk_mq_queue_data *bd)
{
    struct request *rq = bd->rq;
    blk_mq_end_request(rq, BLK_STS_OK);
    return BLK_STS_OK;
}

// 块设备操作函数集
static const struct block_device_operations myblk_fops = {
    .owner = THIS_MODULE,
    // 可按需添加open、release等函数
};

// blk_mq操作函数集
static const struct blk_mq_ops myblk_mq_ops = {
    .queue_rq = myblk_queue_rq,
};

static int __init myblk_init(void)
{
    int ret;

    // 初始化blk_mq_tag_set
    my_tag_set.ops = &myblk_mq_ops;
    my_tag_set.nr_hw_queues = NR_HW_QUEUES;
    my_tag_set.queue_depth = QUEUE_DEPTH;
    my_tag_set.numa_node = NUMA_NO_NODE;
    ret = blk_mq_alloc_tag_set(&my_tag_set);
    if (ret) {
        pr_err("blk_mq_alloc_tag_set failed: %d\n", ret);
        goto err_tag_set;
    }

    // 分配gendisk
    my_disk = alloc_disk(1);  // 支持1个分区
    if (!my_disk) {
        pr_err("alloc_disk failed\n");
        ret = -ENOMEM;
        goto err_disk;
    }

    // 动态分配设备号
    ret = alloc_chrdev_region(&my_dev, 0, 1, DEVICE_NAME);
    if (ret) {
        pr_err("alloc_chrdev_region failed: %d\n", ret);
        goto err_dev;
    }

    // 配置gendisk参数
    my_disk->major = MAJOR(my_dev);
    my_disk->first_minor = MINOR(my_dev);
    my_disk->fops = &myblk_fops;
    my_disk->queue = blk_mq_init_queue(&my_tag_set);
    if (!my_disk->queue) {
        pr_err("blk_mq_init_queue failed\n");
        ret = -ENOMEM;
        goto err_queue;
    }
    set_capacity(my_disk, DEVICE_SECTORS);
    strscpy(my_disk->disk_name, DEVICE_NAME, DISK_NAME_LEN);

    // 注册设备到系统(关键步骤)
    add_disk(my_disk);

    pr_info("myblkdev registered successfully\n");
    return 0;

err_queue:
    unregister_chrdev_region(my_dev, 1);
err_dev:
    put_disk(my_disk);
err_disk:
    blk_mq_free_tag_set(&my_tag_set);
err_tag_set:
    return ret;
}

static void __exit myblk_exit(void)
{
    del_gendisk(my_disk);
    blk_mq_destroy_queue(my_disk->queue);
    put_disk(my_disk);
    blk_mq_free_tag_set(&my_tag_set);
    unregister_chrdev_region(my_dev, 1);
    pr_info("myblkdev unregistered\n");
}

module_init(myblk_init);
module_exit(myblk_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Simple blk_mq block device for Linux 5.15+");

验证说明

  • 加载模块后,可通过ls /dev/myblkdev查看设备是否存在
  • 若设备未出现,检查dmesg日志排查初始化错误
  • 示例配置的512MB容量足够使用fdisk进行分区操作

内容的提问来源于stack exchange,提问作者Hank Nie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 16:57:19