3

我有兴趣开发内核模块,将两个块设备绑定到一个新的块设备中,这样第一个块设备在挂载时包含数据,另一个被认为是空的。每次写入都会写入第二个分区,因此在下一次挂载时基本文件系统保持不变。我知道像 UnionFS 这样的解决方案,但它们是基于文件系统的,而我想开发一个更低的层,基于块。

谁能告诉我如何从内核模块打开广告读/写块设备?可能不使用用户空间程序来读取/写入合并的块设备。我在这里找到了类似的主题,但答案相当不令人满意,因为 filp_* 函数是用于读取小型配置文件,而不是用于(大型)块设备 I/O。

由于创建块设备的接口是标准化的,我正在考虑直接(或几乎直接)访问实现源设备的功能,因为无论如何我都会被要求导出类似的功能。如果我能做到这一点,我只需在源设备上创建一些调用适当函数的代理函数。我可以以某种方式获得指向属于不同驱动程序的 gendisk 结构的指针吗?

这仅用于我自己的目的(满足好奇心是其中的主要目的),所以我不担心会严重搞乱我的内核。

或者有人知道这样的模块是否已经存在?

4

3 回答 3

4

设备映射器驱动程序中的源代码将满足您的需要。在 Linux/drivers/md/dm-* 中查看 Linux 源码中的代码。

您不需要访问其他设备的 gendisk 结构,而是访问它的请求队列。您可以准备 I/O 请求并将其推送到其他设备的队列中,其余的将自己完成。

我已经实现了一个简单的块设备,可以打开另一个块设备。看看我描述它的帖子: stackbd: Stacking a block device over another block device

以下是访问其他设备的 gendisk 所需的一些功能示例。使用路径(“/dev/”)打开另一个块设备的方法:

struct block_device *bdev_raw = lookup_bdev(dev_path);
printk("Opened %s\n", dev_path);
if (IS_ERR(bdev_raw))
{
    printk("stackbd: error opening raw device <%lu>\n", PTR_ERR(bdev_raw));
    return NULL;
}
if (!bdget(bdev_raw->bd_dev))
{
    printk("stackbd: error bdget()\n");
    return NULL;
}
if (blkdev_get(bdev_raw, STACKBD_BDEV_MODE, &stackbd))
{
    printk("stackbd: error blkdev_get()\n");
    bdput(bdev_raw);
    return NULL;
}

将 I/O 请求从一台设备传递到另一台设备的最简单示例是在不修改的情况下重新映射它。请注意,在以下代码中,bi_bdev条目已使用不同的设备进行了修改。还可以修改块地址(*bi_sector)和数据本身。

static void stackbd_io_fn(struct bio *bio)
{
    bio->bi_bdev = stackbd.bdev_raw;

    trace_block_bio_remap(bdev_get_queue(stackbd.bdev_raw), bio,
            bio->bi_bdev->bd_dev, bio->bi_sector);

    /* No need to call bio_endio() */
    generic_make_request(bio);
}
于 2014-11-01T07:18:20.470 回答
4

考虑检查dm/md块设备的代码drivers/md- 这些现有驱动程序创建一个块设备,将数据存储在其他块设备上。

事实上,您可以将您的想法实现为另一个“RAID 个性” md,从而利用现有的用户空间工具来设置设备。

于 2010-12-13T11:42:35.570 回答
0

你知道,如果你是一个 GPL 内核模块,你可以从内核模式调用open()、read()、write() 等,对吗?

当然,这种方式有一些注意事项,包括需要从内核模式分叉来为您的句柄创建空间。

于 2010-12-13T04:38:12.580 回答