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

Linux内核6.2块驱动的数据持久化实现方法问询

Linux 6.2块设备驱动数据持久化及submit_bio递归问题解答

内存块持久化核心逻辑

要实现内存块到存储设备的持久化,核心是将处理后的读写请求提交给底层真实存储设备,而非停留在内存中,具体步骤如下:

  1. 持有底层设备引用:驱动初始化阶段,通过blk_get_dev()打开目标物理块设备(比如存储数据的/dev/sdb、存储奇偶块的/dev/sdc),获取struct block_device *句柄,保存到驱动私有数据结构中。
  2. 请求处理与转换:在驱动的请求处理函数中(内核6.2推荐使用make_request_fn,偏向bio级别的高效处理),对收到的bio做XOR冗余处理:
    • 写操作:计算生成奇偶块的bio,将原始数据bio和奇偶块bio分别指向对应的底层设备;
    • 读操作:校验数据完整性,若损坏则用奇偶块恢复后再返回给上层。
  3. 提交到底层设备:修改处理后bio的bi_bdev字段为底层设备的struct block_device,提交该bio完成持久化。

避免submit_bio递归的关键

递归的根源是将处理后的bio提交回了自己的驱动设备,只要确保提交目标是底层真实设备,就不会触发递归:

  • 绝对不能将bio的bi_bdev设置为自己驱动创建的gendisk对应的bdev;
  • 必须指向初始化阶段获取的底层物理块设备的bdev。

代码示例片段

// 驱动私有数据结构
struct my_raid_data {
    struct block_device *data_bdev;    // 存储数据的底层设备
    struct block_device *parity_bio;   // 存储奇偶块的底层设备
    struct gendisk *disk;
};

static void my_make_request(struct request_queue *q, struct bio *bio)
{
    struct my_raid_data *raid_data = q->queuedata;
    struct bio *parity_bio = NULL;

    // 处理写请求:生成奇偶块
    if (bio_op(bio) == REQ_OP_WRITE) {
        // 自定义函数:基于原始bio生成奇偶块的bio
        parity_bio = create_parity_bio(bio, raid_data);
        if (!parity_bio) {
            bio_io_error(bio);
            return;
        }
        // 设置奇偶块bio的目标设备并提交
        parity_bio->bi_bdev = raid_data->parity_bdev;
        submit_bio(parity_bio);
    }

    // 修改原始bio的目标设备为底层数据设备,提交到底层
    bio->bi_bdev = raid_data->data_bdev;
    submit_bio(bio);
}

// 驱动probe函数中打开底层设备示例
static int my_raid_probe(struct platform_device *pdev)
{
    struct my_raid_data *raid_data = devm_kzalloc(&pdev->dev, sizeof(*raid_data), GFP_KERNEL);
    // 打开数据设备(示例路径,实际需根据配置获取)
    raid_data->data_bdev = blk_get_dev("/dev/sdb", FMODE_READ | FMODE_WRITE);
    if (IS_ERR(raid_data->data_bdev))
        return PTR_ERR(raid_data->data_bdev);
    // 打开奇偶块设备
    raid_data->parity_bdev = blk_get_dev("/dev/sdc", FMODE_READ | FMODE_WRITE);
    if (IS_ERR(raid_data->parity_bdev)) {
        blk_put_dev(raid_data->data_bdev);
        return PTR_ERR(raid_data->parity_bdev);
    }

    // 初始化gendisk和请求队列,设置make_request_fn
    raid_data->disk = alloc_disk(1);
    raid_data->disk->fops = &my_disk_fops;
    raid_data->disk->queue = blk_alloc_queue(GFP_KERNEL);
    blk_queue_make_request(raid_data->disk->queue, my_make_request);
    raid_data->disk->queue->queuedata = raid_data;
    // 其他gendisk初始化操作...
    add_disk(raid_data->disk);
    return 0;
}

额外注意事项

  • bio生命周期管理:生成的奇偶块bio需在end_io回调中释放,避免内存泄漏;
  • IO完成跟踪:若需要保证原始数据和奇偶块的写入原子性,可通过bio_set_end_io设置回调,在所有关联bio完成后再通知上层;
  • 内核版本适配:Linux 6.2中,bio操作需使用bio_op()、bio_for_each_segment()等现代接口,避免使用已废弃的函数;
  • 错误处理:底层设备IO失败时,需在回调中触发奇偶块修复逻辑,保证数据可用性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 14:55:33