我试图通过引用现有的dm-linear,dm-snapshot,dm-cache等来实现设备映射器目标。在我的实现中,我需要对某个扇区执行读/修改/写操作范围。由于器件映射器直接与块层对话,我不确定用什么数据结构/函数来读取存储器中的扇区,修改缓冲区并将其写回另一个扇区范围。 在应用程序级别,我们有系统调用,下面我们有vfs_read / vfs_write。设备映射器层有什么类似的东西吗? 我被困在这里很久了。任何帮助将不胜感激。
答案 0 :(得分:9)
注意:我的答案与内核版本< 3.14,因为自3.14以来API略有变化。
在内核中,您使用struct bio
读/写某些扇区。此结构用于所有块级I / O.可以在in 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 声明它的回调as following:
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->bi_bdev
,bio->bi_sector
,bio->bi_size
,bio->bi_end_io
bio_add_page
添加网页。submit_bio
。bio->bi_end_io
回调示例可以在crypt_alloc_buffer
函数的 dm-crypt 目标中找到。