创建设备映射器目标

Ras*_*ikh 5 linux-device-driver linux-kernel device-mapper

我试图通过引用已有的dm-linear,dm-snapshot,dm-cache等来实现设备映射器目标.在我的实现中,我需要对某个扇区范围执行读/修改/写操作.由于器件映射器直接与块层对话,我不确定用什么数据结构/函数来读取存储器中的扇区,修改缓冲区并将其写回另一个扇区范围.在应用程序级别,我们有系统调用,下面我们有vfs_read/vfs_write.设备映射器层有什么类似的东西吗?我被困在这里很久了.任何帮助将不胜感激.

Ale*_*oba 9

注意:我的答案与内核版本<3.14有关,因为3.14 API略有改变.

在内核中,您可以读取/写入某些扇区struct bio.此结构用于所有块级I/O. 可以在内核lwn中找到全面的文档.这些是该结构中几个最重要的成员:

  • bio->bi_sector - 块I/O请求的第一个扇区
  • bio->bi_size - I/O请求的大小
  • bio->bi_bdev - 读/写设备
  • bio->bi_end_io - 内核将在请求结束时调用的回调

您在设备映射器目标中执行的操作是映射传入bio.在创建设备映射器目标时,您至少提供2个回调:ctrmap.例如,最简单的device-mapper目标dm-zero声明它的回调如下:

static struct target_type zero_target = {
         .name   = "zero",
         .version = {1, 1, 0},
         .module = THIS_MODULE,
         .ctr    = zero_ctr,
         .map    = zero_map,
};
Run Code Online (Sandbox Code Playgroud)

map是一个关键的回调 - 它是每个设备映射器目标的核心.map收到来电bio,它可以做任何事情.例如,dm-linear只是将每个输入bio的扇区移位预定义的偏移量.看代码:

static sector_t linear_map_sector(struct dm_target *ti, sector_t bi_sector)
{
        struct linear_c *lc = ti->private;

        return lc->start + dm_target_offset(ti, bi_sector);
}

static void linear_map_bio(struct dm_target *ti, struct bio *bio)
{
        struct linear_c *lc = ti->private;

        bio->bi_bdev = lc->dev->bdev;
        if (bio_sectors(bio))
                bio->bi_sector = linear_map_sector(ti, bio->bi_sector);
}

static int linear_map(struct dm_target *ti, struct bio *bio)
{
        linear_map_bio(ti, bio);

        return DM_MAPIO_REMAPPED;
}
Run Code Online (Sandbox Code Playgroud)

因为map接收指向bio它的指针可以改变该指针下的值,就是这样.

这就是你映射I/O请求的方式.如果要创建自己的请求,则必须分配bio,填充扇区,设备,大小,结束回调并添加缓冲区以读取/写入.基本上,它只是几个步骤:

  • 调用bio_alloc来分配bio.
  • bio->bi_bdev,bio->bi_sector,bio->bi_size,bio->bi_end_io
  • 通过添加页面bio_add_page.
  • 打电话submit_bio.
  • 处理bio->bi_end_io回调中的结果和错误

示例可以在函数中的dm-crypt目标中找到crypt_alloc_buffer.

  • 谢谢@avd,这真的很有帮助.你认为我可以使用[dm-bufio.c](http://lxr.free-electrons.com/source/drivers/md/dm-bufio.c)进行相同的rmw操作.我想读取一系列扇区,修改其中一些扇区并将数据写入新范围.它类似于我们在循环缓冲区中所做的. (2认同)
  • dm-bufio是内部设备映射器头.它不是通过include/linux目录导出的.我可以看到使用它的唯一方法是在内核树中创建自己的dm目标 - 在drivers/md/dm-ours-target.c下并在内核中编译它.在那里你可以像`#include"dm-bufio.h"那样包含它. (2认同)