我正在尝试通过引用已经存在的 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 回答