[LINUX] Device mapper learning notes

What is device mapper

See the links below to find out what the device mapper is http://lc.linux.or.jp/lc2009/slide/T-02-slide.pdf https://en.wikipedia.org/wiki/Device_mapper

Personally, I understand that in Linux, where Filesystem is more diverse than other Unixes, it was necessary to cut out and provide functions that should be integrated into Filesystem, such as ZFS.

Let's build a device mapper target stray

I started by picking up a simple device mapper target code, building it, and using it.

The environment is as follows CentOS Linux release 7.7.1908 (Core)  A virtual machine on VirtualBox built with Vagrant. git clone https://github.com/huwan/dm-target

$ git clone https://github.com/huwan/dm-target.git

Go to the cloned folder

$ make 
make -C /lib/modules/3.10.0-957.12.2.el7.x86_64/build M=/home/vagrant/dm-target modules
make[1]:directory`/usr/src/kernels/3.10.0-957.12.2.el7.x86_64'Enter
  CC [M]  /home/vagrant/dm-target/mapper.o
(Omission)
include/linux/device-mapper.h:160:5:Remarks: expected ‘struct dm_dev **’ but argument is of type ‘sector_t’
 int dm_get_device(struct dm_target *ti, const char *path, fmode_t mode,
     ^
/home/vagrant/dm-target/mapper.c:85:13:error:Function ‘dm_get_Too many arguments to device ’
             dm_table_get_mode(target->table), &mdt->dev)) {
             ^
In file included from /home/vagrant/dm-target/mapper.c:15:0:
include/linux/device-mapper.h:160:5:Remarks:Declared here
 int dm_get_device(struct dm_target *ti, const char *path, fmode_t mode,
     ^
(Omitted)

With that feeling, the trouble is that an error occurs on line 85 and the build does not pass. The applicable part is

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

The dm_get_device in the if statement is called, but I'm angry when there are too many arguments.

Check device-mapper.h. (Is it easier to see the code online?)

First, check the kernel version

$ uname -a 
Linux localhost.localdomain 3.10.0-957.12.2.el7.x86_64 #1 SMP Tue May 14 21:24:32 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

Search device-mapper.h

$ sudo find / -name  device-mapper.h
/usr/src/kernels/3.10.0-957.12.2.el7.x86_64/include/linux/device-mapper.h
/usr/src/kernels/3.10.0-1062.18.1.el7.x86_64/include/linux/device-mapper.h

It seems that it refers to the header of 3.10.0-957. Check the contents of the header

[device-mapper.h]

/*                                                                                                                                                                      
 * Constructors should call these functions to ensure destination devices                                                                                               
 * are opened/closed correctly.                                                                                                                                         
 */
int dm_get_device(struct dm_target *ti, const char *path, fmode_t mode,
                  struct dm_dev **result);
void dm_put_device(struct dm_target *ti, struct dm_dev *d);

The comment says it's a constructor. I read the implementation below (it's easier on the net) https://elixir.bootlin.com/linux/v3.10.95/source/drivers/md/dm-table.c#L462

/*
 * Add a device to the list, or just increment the usage count if
 * it's already present.
 */
int dm_get_device(struct dm_target *ti, const char *path, fmode_t mode,
		  struct dm_dev **result)

Apparently, it adds a new block device to the list of target block devices (and allows duplicates ??). Well I do not know. If it fails, it will return a non-zero value and enter the if statement in mapper.c.

The build failed probably because start and target-> len were extra arguments when dm_get_device was called. Since start is a long long type and target-> len is a sector_t type, it is not in the function declaration. target is the dm_target structure, which is declared in device-mapper.h.

Modify mapper.c

/*
 * Add a device to the list, or just increment the usage count if
 * it's already present.
 */
int dm_get_device(struct dm_target *ti, const char *path, fmode_t mode,
		  struct dm_dev **result)

Make again

$ make
make -C /lib/modules/3.10.0-957.12.2.el7.x86_64/build M=/home/vagrant/dm-target modules
 make [1]: Enter the directory `/usr/src/kernels/3.10.0-957.12.2.el7.x86_64'
  CC [M]  /home/vagrant/dm-target/mapper.o
 /home/vagrant/dm-target/mapper.c:122:5: WARNING: Initialization from incompatible pointer type [Enabled by default]
     .map = hello_target_map,
     ^
 /home/vagrant/dm-target/mapper.c:122:5: WARNING: (near initialization for ‘hello_target.map’) [enabled by default]
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/vagrant/dm-target/mapper.mod.o
  LD [M]  /home/vagrant/dm-target/mapper.ko
 make [1]: Exit from the directory `/usr/src/kernels/3.10.0-957.12.2.el7.x86_64'
$ ls
mapper.c#  Makefile  Module.symvers  README.md  mapper.c  mapper.ko  mapper.mod.c  mapper.mod.o  mapper.o  modules.order  run-dmtarget.sh

The build passed.

A shell script for setup is enclosed, so try using it.

$ sudo ./run-dmtarget.sh -s
128+0 records in
128+0 records out
134217728 bytes (134 MB) copied, 0.1957 s, 686 MB/s
 /home/vagrant/dm-target/mapper.c:122:5: WARNING: Initialization from incompatible pointer type [Enabled by default]
     .map = hello_target_map,
     ^
 /home/vagrant/dm-target/mapper.c:122:5: WARNING: (near initialization for ‘hello_target.map’) [enabled by default]
$ sudo dmsetup targets
 hello_target v1.0.0 <-this
striped          v1.6.0
linear           v1.3.0
error            v1.5.0
$ lsblk 
NAME               MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda                  8:0    0   40G  0 disk 
└─sda1               8:1    0   40G  0 part /
loop0                7:0    0  128M  0 loop 
 └─my_device_mapper 253: 0 0 128M 0 dm <-this

It would be helpful for beginners to have a shell script for such experiments. Looking at the contents, ...

dd if=/dev/zero of=/tmp/mydisk bs=1M count=128 # 128MB file                                                                                             
losetup /dev/loop0 /tmp/mydisk # losetup -f                                                                                                             
make -s
insmod ./mapper.ko
 echo <starting logical sector number> <logical size of device in terms of sector> <target name> <device path> <unsed paramter> | dmsetup create <mapper  name>                                                                                                                                                               
echo 0 262144 hello_target /dev/loop0 0 | dmsetup create my_device_mapper
  1. Create an image file with dd
  2. Create a loopback device (although I don't know what it is) and assign it to the image file / tmp / mydisk
  3. make
  4. Module installation (insmod)
  5. Create my_device_mapper with hello_target with dmsetup

Next, try a writing test with dd

sudo ./run-dmtarget.sh -d
16+0 records in
16+0 records out
16384 bytes (16 kB) copied, 0.0399802 s, 410 kB/s

What the process here is doing

dd if=/dev/urandom of=/dev/mapper/my_device_mapper  bs=1K count=16

It seems that 16KB of random data is being written.

Next, try formatting the created block device with ext4.

$ sudo ./run-dmtarget.sh -f 
copy.txt  lost+found  test.txt

So what are you doing here?

if [ ! -d /mnt/mapper ]
then
   mkdir -p /mnt/mapper
fi
modprobe ext4
mkfs.ext4 -q /dev/mapper/my_device_mapper
mount /dev/mapper/my_device_mapper /mnt/mapper
cd /mnt/mapper
touch test.txt
cp test.txt copy.txt
ls

Check if it is mounted

$ lsblk 
NAME               MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda                  8:0    0   40G  0 disk 
└─sda1               8:1    0   40G  0 part /
loop0                7:0    0  128M  0 loop 
 └─ my_device_mapper 253: 0 0 128M 0 dm / mnt / mapper <-Mounted on / mnt / mapper
$ ls /mnt/mapper/
copy.txt  lost+found  test.txt
$ cd /mnt/mapper/
$ du -sh 
 du: cannot read directory ‘./lost+found’: No permission
15K	.
$ sudo touch hoge
$ ls
copy.txt  hoge  lost+found  test.txt

It can be used normally as a 16KB folder.

Try code reading for the device mapper target

It's a very simple device mapper target, so it's simple.

The members of the instance hello_target of the target_type structure are initialized as follows.

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,
};

The definition of this structure is declared in device-mapper.h. The function pointer for handling block I / O (bio) is assigned to the map member variable, and the constructor and destructor are assigned to ctr and dtr, respectively. that's all.

The results of the following code reading will be added.

Recommended Posts

Device mapper learning notes
Python learning notes
python learning notes
O'Reilly python3 Primer Learning Notes
go language learning miscellaneous notes 1
Python data analysis learning notes
Notes on PyQ machine learning python grammar
Learning notes from the beginning of Python 1
Notes on running Azure Machine Learning locally
Personal notes and links about machine learning ① (Machine learning)
Learning notes from the beginning of Python 2