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.
The device mapper is a framework provided by the Linux kernel for mapping physical block devices onto higher-level virtual block devices. It forms the foundation of the logical volume manager (LVM), software RAIDs and dm-crypt disk encryption, and offers additional features such as file system snapshots.
dmsetup manages logical devices that use the device-mapper driver. Devices are created by loading a table that specifies a target for each sector (512 bytes) in the logical device. The first argument to dmsetup is a command.
Typing xfs_growfs /var OR resize2fs /dev/mapper/vg00-var (depending on which filesystem is used on your system) will extend the file system to the 10 gigabyte limit of the logical volume. Type df -h to display the disk free space to confirm that the file system has been extended.
The remove command deactivates a device mapper device. It removes it from /dev/mapper. Syntax is dmsetup remove [-f] <device name> Note is not possible to remove a device that's in use. The -f option may be passed the replace the target with one that fails all I/O, hopefully allowing the reference count to drop to 0.
NOTE: My answer is related to kernel version < 3.14, because since 3.14 API is slightly changed.
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
- 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 requestWhat 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
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;
}
Because map receives pointer to bio
it can change value under that pointer and that's it.
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->bi_bdev
, bio->bi_sector
, bio->bi_size
, bio->bi_end_io
bio_add_page
.submit_bio
.bio->bi_end_io
callbackExample can be found in dm-crypt target in crypt_alloc_buffer
function.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With