6

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

4

1 回答 1

10

注意:我的回答与内核版本 < 3.14 有关,因为从 3.14 API 开始略有更改。

在内核中,您使用struct bio. 该结构用于所有块级 I/O。综合文档可以在 kernellwn中找到。以下是该结构中最重要的几个成员:

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

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

static struct target_type zero_target = {
         .name   = "zero",
         .version = {1, 1, 0},
         .module = THIS_MODULE,
         .ctr    = zero_ctr,
         .map    = zero_map,
};

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;
}

因为 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

于 2014-06-16T08:18:57.490 回答