Linux, les devices mappers

· Read in about 15 min · (3065 words)

Dans les environnements Linux, il existe une technologie qui permet d’avoir un disque dur virtuel qui est composé de plusieurs blocs de disques durs: device-mapper, ou carte de périphérique. Dans ce tutoriel, nous allons voir comment créer des devices-mappers en utilisant les outils dmsetup et lvm.

Les devices-mappers

Avant de commencer la création d’un device-mapper, nous allons faire un petit rappel sur les disques durs. Sous Linux, lorsque nous connectons un nouveau périphérique sur le système, ce dernier va apparaître dans le chemin /dev et sera nommé de la façon suivante:

  • /dev/fd pour les disquettes
  • /dev/sd pour les disques dur
  • /dev/sr pour les lecteurs de CD

Cependant, comment fait Linux pour identifier plusieurs périphériques de même nature ? Prenons l’exemple de deux disques durs puisque c’est l’objet de ce tutoriel. Lorsque nos deux disques durs sont connectés sur le système, Linux va les identifier de la manière suivante:

  • /dev/sda pour le premier disque dur
  • /dev/sdb pour le second disque dur

Si vous faites attention, vous remarquerez /dev/sd[a-z] est souvent suffixé d’un identifiant numérique. Cette valeur permet d’identifier la partition. Par exemple, sur le premier disque dur, vous avez 3 partitions ils seront identifiés de cette manière:

  • /dev/sda1 pour la première partition
  • /dev/sda2 pour la seconde partition
  • /dev/sda3 pour la troisième partition

Une autre chose importante à savoir est le terme secteur ou sector. Un secteur est une partie dans un disque dur qui contient la plus petite donnée stockée sur un disque dur. Cette taille est souvent 512 octets.

Pour illustrer le principe de secteur, utilisons la commande fdisk -l:

Disk /dev/sda: 698.7 GiB, 750156374016 bytes, 1465149168 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: dos
Disk identifier: 0xbd64ab85

Device     Boot     Start       End   Sectors  Size Id Type
/dev/sda1            2048 348129279 348127232  166G 83 Linux
/dev/sda2       348129280 767559679 419430400  200G 83 Linux
/dev/sda3       767559680 775948287   8388608    4G 82 Linux swap / Solaris
/dev/sda4       775948288 796919807  20971520   10G 83 Linux

Dans l’exemple ci-dessus, vous pouvez voir que mon disque dur /dev/sda a une taille de 698Go (750156374016 octets) et possède 4 partitions. Par ailleurs, on peut voir que mon disque dur possède 1465149168 secteurs et que chaque secteur à une taille de 512 octets. Multiplions le nombre de secteurs par 512 et nous obtenons la taille de notre disque dur en octets: 1465149168*512 = 750156374016. Ce nombre est bien indiqué en première ligne de l’exemple ci-dessus (juste à côté de la taille de notre disque dur). Si vous divisez ce nombre par 1024, vous obtiendrez la taille en Go de mon disque dur: 750156374016/1024/1024/1024 = 698,6 Go.

Voilà, nous avons réussi à trouver la taille de notre disque dur grâce aux secteurs.

Retournons maintenant aux devices-mappers. Comme nous l’avons vu en début de ce tutoriel, un device-mapper est un disque dur virtuel composé de plusieurs blocs d’un disque dur. C’est très pratique pour construire un disque dur virtuel qui est composé de plusieurs disques dur.

La figure ci-dessous illustre le fonctionnement des devices-mappers, nous pouvons voir un disque dur virtuel de 15Go de données. Ce disque dur est composé d’une partition situé sur le premier disque dur et une autre partition d’un second disque dur:

Présentation des devices-mappers

Création d’un device-mapper via dmsetup

Nous allons maintenant entrer dans le vif du sujet: créer un device-mapper en utilisant l’utilitaire dmsetup. Cet utilitaire qui est installé par défaut sur tous les systèmes Linux permet de gérer (créer/supprimer et même renommer) les devices-mappers.

Nous allons maintenant créer un device-mapper d’une taille de 100Mo. Pour permettre de créer nos 100Mo, nous devons avoir 204800 secteurs de 512o de données chacunes. Comment j’ai calculé cette valeur ? Tout d’abord, je calcule le nombre d’octet 100*1024 ce qui me donne 102400 et que je remultiplie par 1024 pour obtenir mes 100M, ce qui me donne 104857600. A ce stade là, je divise par 512 pour obtenir le nombre de secteurs: 104857600/512=204800.

Pour mon disque dur virtuel, je vais me baser sur la partition /dev/sda4 de mon système:

dmsetup create test --table '0 204800 linear /dev/sda4 0'

Tout d’abord, notre disque dur virtuel sera nommé test, puis, nous fournissons quelques options. Tout d’abord, la valeur 0 indique le numéro de secteur de début, puis la valeur 204800 correspond au nombre de secteurs pour obtenir nos 100Mo de données.

Ensuite, viennent les options linear /dev/sda4 0. Cela indique d’avoir une plage de secteur continue situé sur la partition 4 du disque dur /dev/sda et le secteur de démarrage est 0.

Voilà. Notre disque dur virtuel est créé. Nous allons vérifier via l’utilitaire fdisk et ont peut voir que nous avons bien un disque dur avec une taille de 100M ainsi que de nos 204800 secteurs:

Disk /dev/mapper/test: 100 MiB, 104857600 bytes, 204800 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes

Si vous regardez attentivement l’exemple ci-dessus, vous remarquez que mon disque dur virtuel est situé dans le répertoire /dev/mapper. C’est dans ce répertoire que tous les disques durs virtuels sont montés, mais ce n’est qu’un lien symbolique:

$ ls -l /dev/mapper/test
lrwxrwxrwx 1 root root 7 Aug 12 20:59 /dev/mapper/test -> ../dm-0
$ ls -l /dev/dm-0 
brw-rw---- 1 root disk 254, 0 Aug 12 20:59 /dev/dm-0

Comme le montre l’exemple ci-dessus, ont peut voir que le disque dur /dev/mapper/test pointe sur le disque dur /dev/dm-0 qui représente le disque dur virtuel.

Le noyau Linux identifie le disque dur au moyen de deux numéros: le majeur et le mineur. Le premier correspond à la valeur 254 pour notre disque dur /dev/dm-0 et le mineur possède la valeur 0. Nous reviendrons sur ces valeurs, mais je vous invite à lire le fichier devices.txt situé sur votre système pour obtenir des informations, mais vous pouvez le trouver via ce lien:

Fichier devices.txt

Mais voilà, cet exemple ne présente pas vraiment le fonctionnement de device-mapper, puisque notre disque dur virtuel est composé que d’un seul disque dur.

Nous allons maintenant créer un disque dur virtuel qui s’appuie sur les disques dur /dev/sda5 et /dev/sda6:

/dev/sda4       775948288 880805887 104857600   50G  5 Extended
/dev/sda5       775950336 828379135  52428800   25G 83 Linux
/dev/sda6       828381184 880805887  52424704   25G 83 Linux

Nous allons créer un disque dur d’une taille de 10G et sur nos deux disques durs /dev/sda[5-6], nous prendrons 5Go, ce qui nous fait 5368709120 octets et 10485760 secteurs:

$ sudo dmsetup create test
0 10485760 linear /dev/sda5 0
10485760 10485760 linear /dev/sda6 20971520

Un peu d’explication. Tout d’abord, lorsque nous saisissons la commande dmsetup create test, nous entrons dans une sorte de mode pour saisir différents paramètres. Lorsque nous avons fini, il faut appuyer sur CTRL+D pour quitter et créer le disque dur virtuel.

Dans la seconde ligne, on peut voir que nous partons du secteur 0 jusqu’au secteur 10485760 qui va correspondre à nos 5Go de données, puis les paramètres linear /dev/sda5 0, indiquent d’avoir un bloc continue sur le disque /dev/sda5 et il démarre au secteur 0.

Dans la dernière ligne, nous indiquons que nous commencons notre secteur depuis le secteur 10485760 et ce jusqu’au secteur 10485760 pour faire nos 5Go restants. Puis, les paramètres linear /dev/sda6 20971520 indiquent d’utiliser le disque dur /dev/sda6 et nous commençons depuis le secteur 20971520, en supposant que les secteurs avants sont utilisés, c’est-à-dire les 10 premiers Go de données.

Pour mieux comprendre ce que nous avons fait, une petite figure pour illustrer tout ça:

Schéma de notre device-mapper

Nous allons maintenant vérifier que notre disque dur est bien monté:

Disk /dev/mapper/test: 10 GiB, 10737418240 bytes, 20971520 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes

Maintenant que notre disque dur virtuel est créé, nous pouvons formater cette partition et la monter sur notre racine:

$ sudo mkfs.ext4 /dev/mapper/test 
mke2fs 1.43.4 (31-Jan-2017)
Creating filesystem with 2621440 4k blocks and 655360 inodes
Filesystem UUID: f26457df-9b2f-4506-915d-85a1fb807343
Superblock backups stored on blocks: 
	32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (16384 blocks): done
Writing superblocks and filesystem accounting information: done

$ sudo dmsetup table
test: 0 10485760 linear 8:5 0
test: 10485760 10485760 linear 8:6 20971520
$ sudo mount /dev/mapper/test /mnt/test

Comme le montre le résultat de la commande dmsetup table, nous voyons bien nos deux partitions, ainsi que les valeurs du majeur (8) et du mineur de nos disques, qui sont 5 et 6. La valeur 8 indique que c’est un périphérique de disque SCSCI. Je vous invite à lire le fichier /proc/device et à consulter le site:

http://www.makelinux.net/ldd3/chp-3-sect-2

Les valeurs 5 et 6 correspondent tout simplement au numéro de la partition 5 pour /dev/sda5 et 6 pour /dev/sda6.

Si on regarde le résultat de la commande ls -l /dev/dm-0 qui est notre disque virtuel:

$ ls -l /dev/dm-0 
brw-rw---- 1 root disk 254, 0 Aug 13 10:07 /dev/dm-0

On remarque que le majeur prend la valeur 254, qui correspond à un device-mapper (Cf. Fichier /proc/device).

Et voilà. Nous avons maintenant créé notre premier disque dur virtuel. Pour supprimer le disque dur virtuel, il suffit de saisir la commande dmsetup remove test.

Je vous invite à lire le manuel de dmsetup qui fournit tous les éléments nécessaires pour la gestion des devices-mappers, puisqu’il est même possible de créer des snapshots.

Création d’un device-mapper via LVM

Nous allons maintenant passer à une autre technologie pour gérer des disques dur virtuels: LVM (Logical Volume Manager). LVM est une technologie qui permet de combiner plusieurs partitions que nous appelons Physical Volume (PV) en un groupe de volume (Volume Group, VG) pour ensuite découper notre VG en plusieurs partitions que nous appelons Logical Volume (LV). Lorsqu’un LV est créé, il est possible de le formater et de le monter sur le système. LVM permet de gérer facilement les LV, en les créant, les réduisant ou les supprimant. La figure ci-dessous, illustre le fonctionnement de LVM:

Fonctionnement de LVM

La figure ci-dessous montre que nous combinons nos différents Physical Volume en 1 seul Volume Group. Par exemple, nos 4 PV ont une taille de 100Go. En fusionnant en un seul VG, nous obtenons un espace de 400Go. Ces 400Go de données peuvent être découpés en plusieurs LV de même taille ou de taille différentes.

Pour gérer nos LV, il faut respecter différentes étapes:

  1. Formatage d’une partition dans le système LVM
  2. Création d’un Physical Volume
  3. Création de Volume Groupe
  4. Création de nos LV

Nous allons voir ces 4 étapes dans les sections ci-dessous.

Gestion de nos Physical Volume

Pour gérer LVM, il faut d’abord installer le paquet lvm2. A l’issue de cette étape, nous allons créer deux partitions, qui vont chacunes simuler un PV. La première partition à une taille de 25G et la seconde de 20G. Lorsque ces partitions sont crées, il faut utiliser le système de fichier Linux LVM. Pour créer mes partitions, j’utilise l’utilitaire fdisk et mes deux partitions sont /dev/sda5 et /dev/sda6. Voici le résulat:

Device     Boot     Start       End   Sectors  Size Id Type
/dev/sda1            2048 348129279 348127232  166G 83 Linux
/dev/sda2       348129280 767559679 419430400  200G 83 Linux
/dev/sda3       767559680 775948287   8388608    4G 82 Linux swap / Solaris
/dev/sda4       775948288 880805887 104857600   50G  5 Extended
/dev/sda5       775950336 828379135  52428800   25G 8e Linux LVM
/dev/sda6       828381184 870324223  41943040   20G 8e Linux LVM

Maintenant que nos partitions sont prêtes, nous allons créer nos Physical Volume. Pour cela, il faut utiliser l’utilitaire pvcreate:

$ sudo pvcreate /dev/sda5
  Physical volume "/dev/sda5" successfully created.
$ sudo pvcreate /dev/sda6
  Physical volume "/dev/sda6" successfully created.
$ sudo pvs
  PV         VG Fmt  Attr PSize  PFree 
  /dev/sda5     lvm2 ---  25.00g 25.00g
  /dev/sda6     lvm2 ---  20.00g 20.00g

On peut voir que j’utilise la commande pvcreate sur nos deux partitions. Puis, la commande pvs affiche toutes les Physical Volumes. Il existe aussi la commande pvdisplay qui fournit plus de détails.

Création de notre Volume Group

Maintenant que nous avons créés nos Physical Volume, nous pouvons créer notre Volume Group:

$ sudo vgcreate gr1 /dev/sda5 /dev/sda6
  Volume group "gr1" successfully created
$ sudo vgs
  VG  #PV #LV #SN Attr   VSize  VFree 
  gr1   2   0   0 wz--n- 44.99g 44.99g

Grâce à l’utilitaire vgcreate, j’indique le nom de notre Volume Group, car oui, il peut en avoir plusieurs sur le système, puis je spécifie les différents PV, qui sont /dev/sda5 et /dev/sda6. On peut voir via la commande vgs, que nous avons bien un VG d’une taille de 45Go, qui correspondent à la taille de nos deux PV. Il existe aussi l’utilitaire vgdisplay qui fournit des informations plus détaillées.

Si vous souhaitez supprimer un VG, il suffit de saisir la commande vgremove <nom vg>.

Création de nos LV

Nous pouvons maintenant créer nos LVs. Pour cela, nous allons utiliser l’utilitaire lvcreate. Dans l’exemple ci-dessous, je créé deux LVs de 20Go chacunes:

$ sudo lvcreate -n lv1 -L 20G gr1
  Logical volume "lv1" created.
$ sudo lvcreate -n lv2 -L 20G gr1
  Logical volume "lv2" created
$ sudo lvs 
  LV   VG  Attr       LSize  Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  lv1  gr1 -wi-a----- 20.00g                                                    
  lv2  gr1 -wi-a----- 20.00g

Dans la commande lvcreate, on indique le nom du LV via la paramètre -n, puis la taille de notre LV grâce au paramètre -L. On va ensuite spécifier le VG qui va contenir notre LV. Grâce à la commande lvs, on peut voir nos deux LV.

Mais où se trouvent nos LVs ? Lorsque nous avons créés nos LVs, ils se trouvent dans différents répertoires:

$ ls -l /dev/gr1/
total 0
lrwxrwxrwx 1 root root 7 Aug 13 13:54 lv1 -> ../dm-0
lrwxrwxrwx 1 root root 7 Aug 13 13:54 lv2 -> ../dm-1
$ ls -l /dev/mapper
total 0
crw------- 1 root root 10, 236 Aug 13 13:54 control
lrwxrwxrwx 1 root root       7 Aug 13 13:54 gr1-lv1 -> ../dm-0
lrwxrwxrwx 1 root root       7 Aug 13 13:54 gr1-lv2 -> ../dm-1
$ ls -l /dev/dm-[0-1]
brw-rw---- 1 root disk 254, 0 Aug 13 13:54 /dev/dm-0
brw-rw---- 1 root disk 254, 1 Aug 13 13:54 /dev/dm-1

Tout d’abord, on peut voir que dans le répertoire /dev, se trouve un répertoire qui porte le nom de notre VG, ici c’est gr1. Dans ce répertoire, se trouvent nos deux LVs, mais ce sont des liens symboliques qui pointent sur nos dm-x. En l’occurrence, lorsqu’il s’agit de devices-mappers, puisque Linux nomme les devices-mapper de la manière suivante: dm-x, où x est le numéro du device-mapper. Par ailleurs, on peut voir que dans le résultat de la commande ls -l /dev/dm-[0-1], que nos devices-mappers sont considérés comme des blocs grâce au premier caractère de chaque ligne, qui correspond à b.

Mais voilà, Linux crée aussi deux liens symboliques qui pointent sur dm-[0-1] dans le répertoire /dev/mapper, qui contient tous les devices-mappers.

Comment sont réparties les données sur les différents partitons (/dev/sda5 et /dev/sda6) ? Regardez l’exemple ci-dessous:

$ sudo dmsetup table
gr1-lv2: 0 41934848 linear 8:6 2048
gr1-lv2: 41934848 8192 linear 8:5 41945088
gr1-lv1: 0 41943040 linear 8:5 2048

On peut voir que le LV1, utilise 41943040 secteurs (ce qui correspond à nos 20Go de données), puis on voit que la valeur du mineur correspond à 5 et qui est donc notre partition /dev/sda5. Mais voilà, si on regarde bien pour la LV2, on remarque qu’il utilise 41934848 secteurs sur /dev/sda6 mais aussi 8192 secteurs sur /dev/sda5. Si on additionnes 41934848+ 8192, ont obtient 41943040, qui correspond aux nombres de secteurs pour nos 20Go de données.

Pour vérifier si 41943040 correspond bien au nombres de secteurs nécessaires pour nos LVs, on peut utiliser l’utilitaire fdisk:

Disk /dev/mapper/gr1-lv1: 20 GiB, 21474836480 bytes, 41943040 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes

Disk /dev/mapper/gr1-lv2: 20 GiB, 21474836480 bytes, 41943040 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes

Maintenant que nos LVs sont créés, nous allons les formater puis les monter dans un répertoire:

$ mkdir /mnt/{lv1,lv2}
$ sudo mkfs.ext4 /dev/mapper/gr1-lv1
[...] 

$ sudo mkfs.ext4 /dev/mapper/gr1-lv2
[...]
$ sudo mount /dev/mapper/gr1-lv1 /mnt/lv1
$ sudo mount /dev/mapper/gr1-lv2 /mnt/lv2

Voilà, nous avons créés nos LVs. Nous allons maintenant voir pour créer des snapshots. Un snapshot est une image à l’instant T d’un système. Un snapshot n’est pas une copie complètement, mais simplements des pointeurs qui poitent sur des blocs de l’image d’origine. La figure ci-dessous, illustre le principe des snapshots:

Les snapshots sous LVM

Comme vous l’avez compris, nous allons créer une snapshot qui sera une image d’un LV. Ici, nous allons nous appuyer sur la lv2 qui nous servira de test. Tout d’abord, nous allons créer notre répertoires qui vont servir de point de montage pour notre snapshot, puis on monte la lv2:

$ sudo mkdir /mnt/lv-snap
$ sudo mount /dev/gr1/lv2 /mnt/lv2
$ touch /mnt/lv2/test1.txt
$ ls /mnt/lv2
lost+found  test1.txt

Maintenant, on va créer notre snapshot:

$ sudo lvcreate -s -n lv-snap -L 5G /dev/gr1/lv2

Comme le montre l’exemple ci-dessus, on spécifie simplement le paramètre -s pour indiquer de créer une snapshot et là, on spécifie tout le chemin complet de notre LV qui servira d’image, ici /dev/gr1/lv2. On vérifie si notre snapshot est bien créé:

$ sudo lvs
[sudo] password for geoffrey: 
  LV      VG  Attr       LSize  Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  lv-snap gr1 swi-aos---  5.00g      lv2    0.47                                   
  lv1     gr1 -wi-a----- 20.00g                                                    
  lv2     gr1 owi-aos---  5.00g

Comme le montre l’exemple ci-dessus, on voit bien que notre snapshot est bien créé, mais on remarque aussi que l’image d’origine est lv2.

Nous allons maintenant monter notre snapshot sur le système:

$ sudo mount /dev/gr1/lv-snap /mnt/lv-snap/
$ ls /mnt/lv-snap/
lost+found  test1.txt

Comme le montre l’exemple ci-dessus, nous voyons bien le fichier test1.txt qui a été sur lv2. Notre snapshot est bien une image de lv2. Nous pouvons maintenant créer un fichier sur nos deux répertoires, c’est-à-dire /mnt/lv2 et /mnt/lv-snap et cela n’aura aucun impacte sur les LV.

Nous avons terminé avec cet article, et comme nous l’avons vu, nous pouvons faire plein de choses intéressantes avec les devices-mappers. Nous verrons d’ailleurs dans un autre article, l’utilité des LVM pour monter des machines virtuelles dessus.

Mes sources

Je vous invite à lire les articles ci-dessous, qui sont plus détaillés que certains aspects de mon article:

  1. Les secteurs sous Linux
  2. Gestion des disques sous Linux
  3. Création du device-mapper
  4. Device-mapper’s linear