create device mapper target

后端 未结 1 1035
太阳男子
太阳男子 2021-02-09 20:40

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/modi

1条回答
  •  长情又很酷
    2021-02-09 21:26

    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 request
    • bio->bi_size - size of I/O request
    • bio->bi_bdev - device to read/write
    • bio->bi_end_io - callback that kernel will call on the end of request

    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 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:

    • 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

    Example can be found in dm-crypt target in crypt_alloc_buffer function.

    0 讨论(0)
提交回复
热议问题