Create device target map

I am trying to realize the purpose of the mapper device, referring to already existing dm-linear, dm-snapshot, dm-cache, etc. In my implementation, I need to perform a read / modify / write operation in a specific assortment sector. Since the mapper directly talks to the block layer, I'm not sure which data structures / functions to use to read sectors in memory, change the buffer, and write it back to a different sector range. At the application level, we have system calls, and below we have vfs_read / vfs_write. Is there something similar for the device display level? I have been stuck here for a very long time. Any help would be appreciated.

+6
source share
1 answer

NOTE. My answer is related to kernel version <3.14, because since API 3.14 is slightly modified.

In the kernel, you read / write specific sectors with struct bio . This structure is used for all block-level I / O. Comprehensive documentation can be found in the kernel and lwn . These are some of the most significant members of this structure:

  • bio->bi_sector - the first sector of the block I / O request
  • bio->bi_size - I / O request size
  • bio->bi_bdev - reader / writer
  • bio->bi_end_io - callback that calls the kernel at the end of the request

What you do on the target device map is display incoming bio . When you create a target device map, you provide at least two callbacks: ctr and map . For example, the simplest target, dm-zero device-mapper, declares callbacks as follows :

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

map is a key callback - it is the heart of every goal of a mapmaker. map receives the incoming bio , and it can do something with it. For example, a dm-linear sector of shift shift for each incoming bio at a predefined offset. See 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; } 

Since map receives a pointer to bio , it can change the value under that pointer and that it is.

The way you map I / O requests. If you want to create your own queries, you must select bio , fill in its sector, device, size, end of the callback and add read / write buffers. Basically, these are just a few steps:

  • Call bio_alloc to highlight biographies.
  • Set bio->bi_bdev , bio->bi_sector , bio->bi_size , bio->bi_end_io
  • Add pages via bio_add_page .
  • Call submit_bio .
  • Handling results and errors in the bio->bi_end_io

An example can be found in the dm-crypt target in crypt_alloc_buffer .

+9
source

Source: https://habr.com/ru/post/970819/


All Articles