从内核模块访问块设备

发布于 2024-10-07 00:18:27 字数 592 浏览 6 评论 0原文

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

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

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

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

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

I am interested in developing kernel module that binds two block devices into a new block device in such manner that first block device contains data at mount time, and the other is considered empty. Every write is being made to second partition, so on next mount the base filesystem remains unchanged. I know of solutions like UnionFS, but those are filesystem-based, while i want to develop it a layer lower, block-based.

Can anyone tell me how could i open ad read/write block device from kernel module? Possibly without using userspace program for reading/writing merged block devices. I found similar topic here, but the answer was rather unsatysfying because filp_* functions are rather for reading small config files, not for (large) block device I/O.

Since interface for creating block devices is standarized i was thinking of direct (or almost direct) acces to functions implementing source devices, as i will be requested to export similar functions anyway. If i could do that i would simply create some proxy-functions calling appropriate functions on source devices. Can i somehow obtain pointer to a gendisk structure that belongs to different driver?

This serves only my own purposes (satisfying quriosity being main of them) so i am not worried about messing my kernel up seriously.

Or does somebody know if module like that already exists?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

饭团 2024-10-14 00:18:27

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

您不需要访问其他设备的 gendisk 结构,而是访问其请求队列。您可以准备 I/O 请求并将其推送到其他设备的队列中,然后它会自行完成剩下的工作。

我已经实现了一个简单的块设备,可以打开另一个块设备。看看我的帖子描述它:
stackbd:堆叠块设备覆盖另一个块设备

以下是访问另一个设备的 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);
}

The source code in the device mapper driver will suit your needs. Look at the code in the Linux source in Linux/drivers/md/dm-*.

You don't need to access the other device's gendisk structure, but rather its request queue. You can prepare I/O requests and push it down the other device's queue, and it will do the rest itself.

I have implemented a simple block device that opens another block device. Take a look in my post describing it:
stackbd: Stacking a block device over another block device

Here are some examples of functions that you need for accessing another device's gendisk.
The way to open another block device using its path ("/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;
}

The simplest example of passing an I/O request from one device to another is by remapping it without modifying it. Notice in the following code that the bi_bdev entry is modified with a different device. One can also modify the block address (*bi_sector) and the data itself.

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);
}
¢蛋碎的人ぎ生 2024-10-14 00:18:27

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

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

Consider examining the code for the dm / md block devices in drivers/md - these existing drivers create a block device that stores data on other block devices.

In fact, you could probably implement your idea as another "RAID personality" in md, and thereby make use of the existing userspace tools for setting up the devices.

回忆那么伤 2024-10-14 00:18:27

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

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

You know, if you're a GPL'd kernel module you can just call open(), read(), write(), etc. from kernel mode right?

Of course this way has certain caveats including requiring forking from kernel mode to create a space for your handle to live.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文