我正在尝试通过引用已经存在的 dm-linear、dm-snapshot、dm-cache 等来实现设备映射器目标。在我的实现中,我需要在某个扇区范围内执行读/修改/写操作。由于设备映射器直接与块层对话,我不确定使用什么数据结构/函数来读取内存中的扇区、修改缓冲区并将其写回另一个扇区范围。在应用程序级别,我们有系统调用,下面我们有 vfs_read/vfs_write。设备映射器层有类似的东西吗?我被困在这里很长时间了。任何帮助将不胜感激。
2371 次
1 回答
10
注意:我的回答与内核版本 < 3.14 有关,因为从 3.14 API 开始略有更改。
在内核中,您使用struct bio. 该结构用于所有块级 I/O。综合文档可以在 kernel和lwn中找到。以下是该结构中最重要的几个成员:
bio->bi_sector- 块 I/O 请求的第一个扇区bio->bi_size- I/O 请求的大小bio->bi_bdev- 读/写设备bio->bi_end_io- 内核将在请求结束时调用的回调
您在设备映射器目标中所做的是映射传入bio。创建设备映射器目标时,您至少提供 2 个回调:ctr和map. 例如,最简单的设备映射器目标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 回答