问题描述
我试图通过引用已经存在的dm-linear,dm-snapshot,dm-cache等来实现设备映射器目标.在我的实现中,我需要对特定扇区执行读/修改/写操作范围.由于设备映射器直接与块层通信,因此我不确定要使用哪些数据结构/函数来读取内存中的扇区,修改缓冲区并将其写回到另一个扇区范围.在应用程序级别,我们有syscall,在下面是vfs_read/vfs_write.设备映射器层是否有类似内容?我已经在这里呆了很长时间了.任何帮助将不胜感激.
I am trying to implement device mapper target by referring to the already existing ones dm-linear, dm-snapshot, dm-cache etc. In my implementation, I need to perform a read/modify/write operation on a certain sector range. Since the device mapper directly talks to the block layer, I am not sure what data structures/functions to use to read the sectors in the memory, modify the buffer and write it back to another sector range.At the application level, we have syscalls and below we have vfs_read/vfs_write. Is there anything similar for device mapper layer?I have been stuck here for very long. Any help will be appreciated.
推荐答案
注意:我的回答与内核版本< 3.14,因为从3.14开始,API稍有更改.
NOTE: My answer is related to kernel version < 3.14, because since 3.14 API is slightly changed.
在内核中,您使用 struct bio
.该结构用于所有块级I/O.可以在内核中 中找到完整的文档 lwn .这些是此结构中最重要的几个成员:
In kernel you read/write certain sectors with struct bio
. This struct is used for all block level I/O. Comprehensive documentation can be found in kernel and on lwn. These are the several most significant members of this structure:
-
bio->bi_sector
-块I/O请求的第一个扇区 -
bio->bi_size
-I/O请求的大小 -
bio->bi_bdev
-可以读取/写入的设备 -
bio->bi_end_io
-内核将在请求结束时调用的回调
bio->bi_sector
- first sector of block I/O requestbio->bi_size
- size of I/O requestbio->bi_bdev
- device to read/writebio->bi_end_io
- callback that kernel will call on the end of request
您在设备映射器目标中所做的是映射传入的bio
.创建设备映射器目标时,您至少提供两个回调:ctr
和map
.例如,最简单的设备映射器目标 dm-zero 声明其回调如下:
What you do in device mapper target is map incoming bio
. When you creating your device mapper target you supply at least 2 callbacks: ctr
, and map
. For example, the simplest device-mapper target dm-zero declares it's callbacks 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
的扇区均偏移预定义的偏移量.参见代码:
map
is a key callback - it's a heart of every device-mapper target. map
receive incoming bio
and it can do anything with it. For example, dm-linear just shift sector of every incoming bio
by predefined offset. See the code:
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;
}
因为地图接收到指向bio
的指针,所以它可以更改该指针下的值而已.
Because map receives pointer to bio
it can change value under that pointer and that's it.
这就是映射I/O请求的方式.如果要创建自己的请求,则必须分配bio
,填充其扇区,设备,大小,结束回调并添加缓冲区以进行读/写操作.基本上,这只是几个步骤:
That's how you map I/O requests. If you want to create your own requests then you must allocate bio
, fill it's sector, device, size, end callback and add buffers to read into/write from. Basically, it's just a few steps:
- 调用bio_alloc分配生物.
- 设置
bio->bi_bdev
,bio->bi_sector
,bio->bi_size
,bio->bi_end_io
- 通过
bio_add_page
添加页面. - 致电
submit_bio
. - 处理
bio->bi_end_io
回调中的结果和错误
- Call to bio_alloc to allocate bio.
- Set
bio->bi_bdev
,bio->bi_sector
,bio->bi_size
,bio->bi_end_io
- Add pages via
bio_add_page
. - Call
submit_bio
. - Handle results and errors in
bio->bi_end_io
callback
可以在 crypt_alloc_buffer
函数.
Example can be found in dm-crypt target in crypt_alloc_buffer
function.
这篇关于创建设备映射器目标的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!