Saturday 15 March 2014

Device mapper

                                                                Device Mapper 

It is generic framework which provide required functionality to underlying block devices, by creating a virtual layer of block device and map the request. These functionality can be
1. Snapshotting
2. Mirroring
3. Concatenation
4. Striping
5. Encryption
6. Raid

A device mapper target implements particular functionality. For example if you want to write a device mapper for "zeroing"  then target code would make sure that for every read it returns zeroed data and write operation can be dropped silently. Device mapper target may or may not modify original data, it depends on functionality to be implemented. Data can be modify for encryption functionality.
Device mapper creates a virtual layer of block device and maps all the IO requests on this logical layer to underlying device. Mapping table has information about mapping of sectors on virtual layer to sectors on underlying device.
Whenever you want to implement a functionality on a block device, you need to write device mapper target for same. Device mapper is a modular kernel driver which provide generic framework for volume management. LVM is good application of device mapper.






Now, lets see demo for linear device mapper.
-------------------------------------------------------------------------------------------------------------------
Prerequisite : Basics of Linux kernel module
                      (please refer http://www.tldp.org/LDP/lkmpg/2.6/lkmpg.pdf)
-------------------------------------------------------------------------------------------------------------------
Writing target for linear device mapper.
mapper.c
/*
 *  This module creates target for linear device mapper which maps a linear range of the device-mapper 
* device onto a linear range of another device
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/bio.h>
#include <linux/device-mapper.h>
#include <linux/slab.h>

/* For underlying device */
struct my_dm_target {
        struct dm_dev *dev;
        sector_t start;
};

/ * Map function , called whenever target gets a bio request.  */

static int hello_target_map(struct dm_target *target, struct bio *bio,union map_info *map_context)
{
        struct my_dm_target *mdt = (struct my_dm_target *) target->private;
     
printk("\nEntry %s",__func__);

/*  bio should perform on our underlying device   */
        bio->bi_bdev = mdt->dev->bdev;                                              

if ((bio->bi_rw & WRITE) == WRITE)
                printk("\nbio is a write request");
        else
                printk("\nbio is a read request");
     
submit_bio(bio->bi_rw,bio);


        printk("\nExit : %s",__func__);    
        return DM_MAPIO_SUBMITTED;
}

/*
 * This is constructor function of target gets called when we create some device of type 'hello_target'.
 * i.e on execution of command 'dmsetup create'. It gets called per device.
 */
static int hello_target_ctr(struct dm_target *target,unsigned int argc,char **argv)
{
        struct my_dm_target *mdt;
        unsigned long long start;
int ret = 0;
        printk("\nEntry : %s",__func__);

        if (argc != 2) {
                printk("\n Invalid no.of arguments.\n");
                target->error = "Invalid argument count";
                ret =  -EINVAL;
        }

        mdt = kmalloc(sizeof(struct my_dm_target), GFP_KERNEL);

        if (mdt==NULL)
        {
                printk("\n Error in kmalloc\n");
                target->error = "Cannot allocate linear context";
                ret = -ENOMEM;
        }    

        if (sscanf(argv[1], "%llu", &start)!=1)
        {
                target->error = "Invalid device sector";
kfree(mdt);
                ret = -EINVAL;
        }
        mdt->start=(sector_t)start;

/* To add device in target's table and increment in device count */

        if (dm_get_device(target, argv[0], dm_table_get_mode(target->table), &mdt->dev)) {
                target->error = "Device lookup failed";
                goto out;
       }

      target->private = mdt;

printk("\nExit : %s ",__func__);
return ret;

  out:
        printk("\nExit : %s with ERROR",__func__);        
        return ret;
}

/*
 * This is destruction function, gets called per device.
 * It removes device and decrement device count.
 */
static void hello_target_dtr(struct dm_target *ti)
{
        struct my_dm_target *mdt = (struct my_dm_target *) ti->private;
        printk("\nEntry : %s",__func__);      
        dm_put_device(ti, mdt->dev);
        kfree(mdt);
        printk("\nExit : %s",__func__);            
}
/*  This structure is fops for hello target */
static struct target_type hello_target = {
     
        .name = "hello_target",
        .version = {1,0,0},
        .module = THIS_MODULE,
        .ctr = hello_target_ctr,
        .dtr = hello_target_dtr,
        .map = hello_target_map,
};
     
/*---------Module Functions -----------------*/

static int init_hello_target(void)
{
        int result;
        printk("\nEntry : %s",__func__);
result = dm_register_target(&hello_target);
        if (result < 0) {
                printk("\nError in registering target");
} else {
printk("\nTarget registered");
}
printk("\nExit : %s",__func__);
        return 0;
}


static void cleanup_hello_target(void)
{
        printk("\nEntry : %s",__func__);
dm_unregister_target(&hello_target);
printk("\nTarget unregistered");
printk("\nExit : %s",__func__);
}

module_init(init_hello_target);
module_exit(cleanup_hello_target);
MODULE_LICENSE("GPL");

MODULE_AUTHOR("Narendra Pal Singh");


-------------------------------------------------------------------------------------------------------------------

Makefile

obj-m+=mapper.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

-------------------------------------------------------------------------------------------------------------------

Steps for creating device mapper :

1. Make a file of 1Gb using dd command.
   #dd if=/dev/zero of=/tmp/mydisk bs=1M count=1024

2. Find first free loop device and attach it to created file
   # losetup -f
   #losetup /dev/loop0 /tmp/mydisk

->check man page of losetup.

3. Compile code
   #make

4.Insert your kernel module.
   #insmod mapper.ko

5.create mapper
   use echo <starting logical sector number> <logical size of device in terms of sactor> <target name> <device path> <unsed paramter> | dmsetup create <mapper  name>

     For this case:
      #echo 0 2097152 hello_target /dev/loop0 0 | dmsetup create my_device_mapper
               
->Try #man dmsetup

6. Perform io operation to your new device

Method-1  Using dd
   #dd if=/dev/urandom of=/dev/mapper/my_device_mapper  bs=1K count=16

Method-2  Using file system level commands
   #mkfs.ext3 /dev/mapper/my_device_mapper
   #mount /dev/mapper/my_device_mapper  /mnt
   Now use cp, mv, touch, rm etc.

7. To clear above set up
  #dmsetup remove my_device_mapper
  #losetup -d /drv/loop0
  #rmmod

----------------------------------------------------------------------------------------------------------------
Flow can be summarized as :

                                                             Read / Write request
                                                                       (dd )
                                                                          |
                                                                          |
                                                                 device mapper  
                                                   (/dev/mapper/my_device_mapper)
                                                                          |
                                                                          |
                                                                 Target code
                                                                 (hello_target)
                                                                          |
                                                                          |                                                                      
                                                                 loop device
                                                                 (/dev/loop0)
                                                                          |
                                                                          |
                                                               Actual device
                                                               (/tmp/mydisk)

----------------------------------------------------------------------------------------------------------------

No comments:

Post a Comment