从内核模块访问块设备

时间:2010-12-13 04:27:06

标签: linux-kernel block device

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

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

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

这仅仅是出于我自己的目的(满足quriosity为主要目的)所以我并不担心会严重搞乱我的内核。

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

3 个答案:

答案 0 :(得分:4)

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

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

答案 1 :(得分:3)

设备映射器驱动程序中的源代码将满足您的需求。查看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);
}

答案 2 :(得分:0)

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

当然,这种方式有一些注意事项,包括要求从内核模式分叉以创建一个让你的句柄生存的空间。