Trim avec LVM et dm-crypt

21

J'ai essayé de configurer TRIM avec LVM et dm-crypt sur Ubuntu 13.04 en suivant ce tutoriel:

http://blog.neutrino.es/2013/howto-properly-activate-trim-for-your-ssd-on-linux-fstrim-lvm-and-dmcrypt/

Voir les notes sur ma configuration et ma procédure de test ci-dessous.

Des questions

  1. Existe-t-il un test fiable si TRIM fonctionne correctement?

  2. Ma routine de test est-elle incorrecte ou mon TRIM ne fonctionne-t-il pas?

  3. Si cela ne fonctionne pas: quel est le problème avec ma configuration?

  4. Comment puis-je déboguer TRIM pour ma configuration et faire fonctionner TRIM?

Configuration

Voici ma configuration:

cat /etc/crypttab

sda3_crypt UUID=[...] none luks,discard

et

cat /etc/lvm/lvm.conf

# [...]
devices  {
      # [ ... ]
      issue_discards = 1
      # [ ... ]
   }
# [...]

Le SSD est un Samsung 840 Pro.

Voici ma procédure de test

Pour tester la configuration que je viens de faire ce sudo fstrim -v /qui a entraîné

/: [...] bytes were trimmed

Refaire cela a eu pour résultat /: 0 bytes were trimmedce qui semble logique et a indiqué que TRIM semble fonctionner.

Cependant, j'ai fait ce test:

dd if=/dev/urandom of=tempfile count=100 bs=512k oflag=direct

sudo hdparm --fibmap tempfile                                 

tempfile:
 filesystem blocksize 4096, begins at LBA 0; assuming 512 byte sectors.
 byte_offset  begin_LBA    end_LBA    sectors
           0    5520384    5521407       1024
      524288    5528576    5529599       1024
     1048576    5523456    5525503       2048
     2097152    5607424    5619711      12288
     8388608    5570560    5603327      32768
    25165824    5963776    5980159      16384
    33554432    6012928    6029311      16384
    41943040    6275072    6291455      16384
    50331648    6635520    6639615       4096

sync

sudo hdparm --read-sector 5520384 /dev/sda                    

/dev/sda:
reading sector 5520384: succeeded
7746 4e11 bf42 0c93 25d3 2825 19fd 8eda
bd93 8ec6 9942 bb98 ed55 87eb 53e1 01d5
c61a 3f52 19a1 0ae5 0798 c6e2 39d9 771a
b89f 3fc5 e786 9b1d 3452 d5d7 9479 a80d
114a 7528 a79f f475 57dc aeaf 25f4 998c
3dd5 b44d 23bf 77f3 0ad9 8688 6518 28ee
81db 1473 08b5 befe 8f2e 5b86 c84e c7d2
1bdd 1065 6a23 fd0f 2951 d879 e823 021b
fa84 b9c1 eadd 9154 c9f4 2ebe cd70 64ec
75a8 4d93 c8fa 3174 7277 1ffb e858 5eca
7586 8b2e 9dbc ab12 40ab eb17 8187 e67d
5e0d 0005 5867 b924 5cfd 6723 9e4a 6f5f
99a4 a3b0 eeac 454a 83b6 c528 1106 6682
ca77 4edf 2180 bf0c b175 fabb 3d4b 37e2
b834 9e3e 82f2 2fdd 2c6a c6ca 873f e71e
f979 160f 5778 356f 2aea 6176 46b6 72b9
f76e ee51 979c 326b 1436 7cfe f677 bfcd
4c3c 9e11 4747 45c1 4bb2 4137 03a1 e4c8
e9dd 43b4 a3b4 ce1b d218 4161 bf64 727b
75d8 dcc2 e14c ebec 2126 25da 0300 12bd
6b1a 28b3 824f 3911 c960 527d 97cd de1b
9f08 9a8e dcdc e65f 1875 58ca be65 82bf
e844 50b8 cc1b 7466 58b8 e708 bd3d c01f
64fb 9317 a77a e43b 671f e1fb e328 93a9
c9c7 291c 56e0 c6c1 f011 b94d 9dc7 71e6
c8b1 5720 b8c9 b1a6 14f1 7299 9122 912b
312a 0f2f a31a 8bf9 9f8c 54e6 96f3 60b8
04a7 7dc9 3caa db0a a837 e5d7 2752 b477
c22d 7598 44e1 84e9 25d4 5db5 9f19 f73b
85a0 c656 373a ec34 55fb e1fc 124e 4674
1ba8 1a84 6aa4 7cb5 455e f416 adc6 a125
c4d4 8323 4eee 2493 2920 4e38 524c 1981

sudo rm tempfile

sync

sudo fstrim /

sync

sudo hdparm --read-sector 5520384 /dev/sda

/dev/sda:
reading sector 5520384: succeeded
7746 4e11 bf42 0c93 25d3 2825 19fd 8eda
bd93 8ec6 9942 bb98 ed55 87eb 53e1 01d5
c61a 3f52 19a1 0ae5 0798 c6e2 39d9 771a
b89f 3fc5 e786 9b1d 3452 d5d7 9479 a80d
114a 7528 a79f f475 57dc aeaf 25f4 998c
3dd5 b44d 23bf 77f3 0ad9 8688 6518 28ee
81db 1473 08b5 befe 8f2e 5b86 c84e c7d2
1bdd 1065 6a23 fd0f 2951 d879 e823 021b
fa84 b9c1 eadd 9154 c9f4 2ebe cd70 64ec
75a8 4d93 c8fa 3174 7277 1ffb e858 5eca
7586 8b2e 9dbc ab12 40ab eb17 8187 e67d
5e0d 0005 5867 b924 5cfd 6723 9e4a 6f5f
99a4 a3b0 eeac 454a 83b6 c528 1106 6682
ca77 4edf 2180 bf0c b175 fabb 3d4b 37e2
b834 9e3e 82f2 2fdd 2c6a c6ca 873f e71e
f979 160f 5778 356f 2aea 6176 46b6 72b9
f76e ee51 979c 326b 1436 7cfe f677 bfcd
4c3c 9e11 4747 45c1 4bb2 4137 03a1 e4c8
e9dd 43b4 a3b4 ce1b d218 4161 bf64 727b
75d8 dcc2 e14c ebec 2126 25da 0300 12bd
6b1a 28b3 824f 3911 c960 527d 97cd de1b
9f08 9a8e dcdc e65f 1875 58ca be65 82bf
e844 50b8 cc1b 7466 58b8 e708 bd3d c01f
64fb 9317 a77a e43b 671f e1fb e328 93a9
c9c7 291c 56e0 c6c1 f011 b94d 9dc7 71e6
c8b1 5720 b8c9 b1a6 14f1 7299 9122 912b
312a 0f2f a31a 8bf9 9f8c 54e6 96f3 60b8
04a7 7dc9 3caa db0a a837 e5d7 2752 b477
c22d 7598 44e1 84e9 25d4 5db5 9f19 f73b
85a0 c656 373a ec34 55fb e1fc 124e 4674
1ba8 1a84 6aa4 7cb5 455e f416 adc6 a125
c4d4 8323 4eee 2493 2920 4e38 524c 1981

Cela semble indiquer que TRIM ne fonctionne pas. Puisque

sudo hdparm -I /dev/sda | grep -i TRIM                        
       *    Data Set Management TRIM supported (limit 8 blocks)
       *    Deterministic read ZEROs after TRIM

modifier

Voici la sortie de sudo dmsetup table

lubuntu--vg-root: 0 465903616 linear 252:0 2048
lubuntu--vg-swap_1: 0 33308672 linear 252:0 465905664
sda3_crypt: 0 499222528 crypt aes-xts-plain64 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0 8:3 4096 1 allow_discards

Voici mon /etc/fstab:

# <file system> <mount point>   <type>  <options>       <dump>  <pass>
/dev/mapper/lubuntu--vg-root /               ext4    errors=remount-ro 0       1
# /boot was on /dev/sda2 during installation
UUID=f700d855-96d0-495e-a480-81f52b965bda /boot           ext2    defaults        0       2
# /boot/efi was on /dev/sda1 during installation
UUID=2296-2E49  /boot/efi       vfat    defaults        0       1
/dev/mapper/lubuntu--vg-swap_1 none            swap    sw              0       0
# tmp
tmpfs /tmp tmpfs nodev,nosuid,noexec,mode=1777          0       0 

Éditer:

Je l'ai finalement signalé comme bogue dans https://bugs.launchpad.net/ubuntu/+source/lvm2/+bug/1213631

J'espère que quelqu'un y trouvera une solution ou du moins testera la configuration et vérifiera le bogue.

Mise à jour

Maintenant cela fonctionne, voir la réponse acceptée.

étudiant
la source
LVM semble manquer de rejets, ce ne devrait issue_discardspas être le issue discardscas si ce n'était pas une faute de frappe. allow_discardsdevrait apparaître dans la table dmsetup pour les partitions LVM.
frostschutz
Désolé, c'était une faute de frappe. J'ai issue_discards = 1dans mon fichier de configuration.
étudiant
Si j'étais vous, j'essaierais d'utiliser une cible iSCSI et de tester cela via tcpdump / cableshark pour voir si la configuration fonctionne, bien que je ne sache pas si la cible iSCSI Linux prend en charge le trim ou non. Je crois que dm-crypt ne doit pas effacer les blocs sur le disque physique car cela facilite l'ignorance de l'espace libre sur l'appareil lorsque vous essayez de le forcer par brute (je ne sais pas s'il le fait ou non, cependant ). De plus, les disques SSD ne sont pas tenus de renvoyer des zéros après la suppression, car le niveau d'usure peut rediriger la lecture vers un bloc différent de celui masqué.
Didi Kohen
1
Selon bugzilla.redhat.com/show_bug.cgi?id=958096 j'ai mal compris le issue_discards = 1.
frostschutz

Réponses:

23

Je suggère d'utiliser une méthode de test différente. hdparmest un peu bizarre car il donne des adresses de périphérique plutôt que des adresses de système de fichiers, et il ne dit pas à quel périphérique ces adresses se rapportent (par exemple, il résout les partitions, mais pas les cibles de devicemapper, etc.). Il est beaucoup plus facile d'utiliser quelque chose qui colle aux adresses des systèmes de fichiers, de cette façon il est cohérent (peut-être à l'exception des systèmes de fichiers non traditionnels comme zfs / btrfs).

Créer un fichier de test: (non aléatoire exprès)

# yes | dd iflag=fullblock bs=1M count=1 of=trim.test 

Obtenez l'adresse, la longueur et la taille du bloc: (la commande exacte dépend de la filefragversion)

# filefrag -s -v trim.test
File size of trim.test is 1048576 (256 blocks, blocksize 4096)
 ext logical physical expected length flags
   0       0    34048             256 eof
trim.test: 1 extent found

Obtenez l'appareil et le point de montage:

# df trim.test
/dev/mapper/something  32896880 11722824  20838512   37% /mount/point

Avec cette configuration, vous avez un fichier trim.testrempli de yes-pattern sur /dev/mapper/somethingà l'adresse 34048avec une longueur de 256blocs d' 4096octets.

La lecture directe du périphérique devrait produire le yesmodèle:

# dd bs=4096 skip=34048 count=256 if=/dev/mapper/something | hexdump -C
00000000  79 0a 79 0a 79 0a 79 0a  79 0a 79 0a 79 0a 79 0a  |y.y.y.y.y.y.y.y.|
*
00100000

Si TRIM est activé, ce modèle doit changer lorsque vous supprimez le fichier. Notez que les caches doivent également être supprimés, sinon ddils ne reliront pas les données du disque.

# rm trim.test
# sync
# fstrim -v /mount/point/ # when not using 'discard' mount option
# echo 1 > /proc/sys/vm/drop_caches
# dd bs=4096 skip=34048 count=256 if=/dev/mapper/something | hexdump -C

Sur la plupart des SSD, cela entraînerait un motif nul:

00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00100000

Si le cryptage est impliqué, vous verrez un modèle aléatoire à la place:

00000000  1f c9 55 7d 07 15 00 d1  4a 1c 41 1a 43 84 15 c0  |..U}....J.A.C...|
00000010  24 35 37 fe 05 f7 43 93  1e f4 3c cc d8 83 44 ad  |$57...C...<...D.|
00000020  46 80 c2 26 13 06 dc 20  7e 22 e4 94 21 7c 8b 2c  |F..&... ~"..!|.,|

En effet, la couche cryptographique lit physiquement les zéros et les déchiffre en données "aléatoires".

Si le yesmotif persiste, aucun rognage n'a probablement été effectué.

frostschutz
la source
1
@ étudiant: Je me sens mal de ne pas l'avoir remarqué plus tôt, j'ai modifié la réponse pour supprimer les caches avant hexdump.
frostschutz
1
Merci, c'était le point manquant. Maintenant, cela semble fonctionner!
étudiant
2
Je ne sais toujours pas si le noyau ne devrait pas supprimer les caches par lui-même chaque fois qu'il coupe quelque chose sur un SSD. Les caches ne sont pas censés renvoyer des données erronées. C'est aussi un gaspillage de mémoire cache si elle est occupée par quelque chose qui n'est plus là ... eh bien.
frostschutz
1
@frostschutz Merci pour cette excellente solution. J'ai fait un script pour automatiser le processus si une personne paresseuse vient ici.
desgua
1
Les nouveaux arrivants , notez que la commande TRIM ne remplira pas toujours les blocs immédiatement. Voyez ici , ici et ici . Bien que ce soit le cas, dans le cas de OP, puisque son hdparm -Irésultat indique "Lecture déterministe des ZÉROS après TRIM".
Marc.2377
3

Votre routine de test est incorrecte - vous obtenez des numéros de secteur par rapport au périphérique de bloc sur lequel se trouve le système de fichiers - qui, dans ce cas, est un volume logique. Bien entendu, le volume logique ne démarre pas au premier secteur du volume physique (et peut même ne pas être contigu).

Même si le volume logique a commencé au secteur 0 du volume physique (ce qui n'est pas le cas), le volume physique est en fait une autre cible de mappeur de périphérique, celle-ci pour le chiffrement. Et il y a probablement un en-tête LUKS devant, donc les numéros de secteur ne correspondent pas non plus.

Si vous souhaitez travailler en mappant le numéro de secteur sur le disque sous-jacent, vous dmsetup tablesobtiendrez les informations dont vous avez besoin. Si vous le collez ici, assurez-vous que la vôtre est une version qui n'affiche pas la clé dans la sortie (elle devrait afficher tous les 0 à la place)! (Il n'y a pas de récupération après la divulgation de la clé - elle ne peut pas être modifiée - c'est bien pire que la divulgation du mot de passe).

Je suggère que pour déboguer (une fois que la cartographie du secteur est établie), vous commencez au niveau le plus bas et confirmez que cela fonctionne là-bas. TRIM un système de fichiers directement sur / dev / sdaX et assurez-vous que cela fonctionne (il est tout à fait possible que le périphérique repose et que le trim ne relise pas les zéros). Ensuite, dm-crypt en plus de cela, et coupez un système de fichiers là-dessus, et assurez-vous que cela fonctionne. Enfin, mettez LVM sur le dessus et vérifiez que cela fonctionne.

derobert
la source
@ étudiant OK, ce n'est donc pas le bon secteur (les deux premiers paragraphes de ma réponse). Je vais modifier ma réponse pour supprimer cette phrase sur le secteur 6575104, car elle n'est plus pertinente.
derobert
Je ne sais pas pour quel appareil je dois prendre dmsetup. Je viens de le faire: sudo dmsetup table /dev/mapper/lubuntu--vg-rootce qui donne0 465903616 linear 252:0 2048
étudiant
@student Cela signifie que le secteur 0 est au secteur 2048 sur le périphérique 252: 0. Vous devrez comprendre ce qu'est 252: 0, je suppose que c'est votre appareil de cryptage dm (c'est le nombre majeur et mineur, apparaîtra dans / dev par exemple). Et vous devrez consulter le tableau de cet appareil, pour continuer à le rechercher dans un bloc sur un appareil sous-jacent.
derobert
3

Ceci est juste un script que je voudrais partager si une personne paresseuse vient ici. Il a été fait à partir de la réponse acceptée de frostschutz .

#! / bin / bash
#
# Ce script est fourni "en l'état" sans garantie d'aucune sorte, expresse ou implicite, y compris, mais sans s'y limiter, les garanties implicites de qualité marchande, d'adéquation à un usage particulier ou de non-contrefaçon.
#
# Licence GPL2
#
# par desgua 29/04/2014

fonction CLEAN {
cd "$ pasta"
[-f test-trim-by-desgua] && rm test-trim-by-desgua && echo "Fichier Temp supprimé"
écho "Au revoir"
sortie 0
}

écho de piège; écho "abandonné". ; NETTOYER; écho ; sortie 0 'INT HUP

if [["$ (echo $ USER)"! = "root"]]; ensuite

read -n 1 -p 'Devenir root? [O / n] 'a
    si [[$ a == "Y" || $ a == "y" || $ a == ""]]; ensuite
        sudo $ 0 $ 1
        sortie 0
    autre
        écho "
        Ce script a besoin du privilège root.
        "
        sortie 1

    Fi

Fi


name = $ (echo $ 0 | sed 's /.*\///')
si [$ # -ne 1]; ensuite

écho "
Utilisation: $ nom / dossier / vers / test /

"
sortie 1
Fi

pâtes = 1 $

read -n 1 -p 'Utiliser fstrim? [o / N] 'a
si [[$ a == "Y" || $ a == "y"]]; ensuite
    fs = 1
Fi

méthode =
while [["$ method"! = "1" && "$ method"! = "2"]]; faire
read -n 1 -s -p 'Choisissez une méthode:
[1] hdparm (échouera dans LUKS sur LVM)
[2] filefrag (avertissement: vous devrez peut-être forcer la fermeture - fermer le terminal - dans certains cas de réussite si vous voyez une sortie qui ne se termine jamais) 
' méthode
terminé

fonction SDATEST {
disque = $ (fdisk -l | grep / dev / sda)
if ["$ disk" == ""]; ensuite
écho "
fdisk n'a pas trouvé / dev / sda 
"
sortie 1
Fi
}

test de fonctionnalité {
echo "Entrée /"; écho
cd $ pasta
echo "Création du fichier test-trim-by-desgua sur $ pasta"; écho
dd if = / dev / urandom of = test-trim-by-desgua count = 10 bs = 512k
echo "Synchronisation et sommeil 2 secondes." ; écho
synchroniser
dormir 2

hdparm --fibmap test-trim-by-desgua
lbab = $ (hdparm --fibmap test-trim-by-desgua | tail -n1 | awk '{print $ 2}')

echo "Comme vous pouvez le voir, le fichier a été créé et son LBA commence à $ lbab"; écho

echo "Synchronisation et sommeil 2 secondes." ; écho
synchroniser
dormir 2

echo "Suppression du fichier test-trim-by-desgua"; écho
rm test-trim-by-desgua

écho de piège; écho ; écho "abandonné". ; écho ; sortie 0 'INT
echo "Synchronisation et sommeil 2 secondes." ; écho
synchroniser
dormir 2

if [["$ fs" == "1"]]; ensuite
    echo "fstrim $ pasta && sleep 2"; écho
    fstrim $ pasta
    dormir 2
Fi

echo "Ceci est lu à partir du secteur $ lbab:"
hdparm - secteur de lecture $ lbab / dev / sda

pass = $ (hdparm - secteur de lecture $ lbab / dev / sda | grep "0000 0000 0000 0000")

if [[$ pass == ""]]; ensuite
    écho "
Échec de l'ajustement ... 
Vous ne devriez voir que 0000 0000 0000 0000 ...
"
autre
    écho "Succès !!!"
Fi
sortie 0

}

fonction LUKSTEST {
# Référence: /unix/85865/trim-with-lvm-and-dm-crypt#
echo 1> / proc / sys / vm / drop_caches
cd $ pasta
echo "Création d'un fichier \" oui \ "."
oui | dd iflag = fullblock bs = 1M count = 1 of = test-trim-by-desgua

# position = `filefrag -s -v test-trim-by-desgua | grep "eof" | awk '{print $ 3}' '
position = `filefrag -s -v test-trim-by-desgua | grep "eof" | sed | || g; s |. * 255: || ; s | \. \ .. * || ''
[["$ position" == ""]] && echo "Impossible de trouver la position du fichier. Êtes-vous sur un LUKS sur LVM?" && NETTOYER;

device = `df test-trim-by-desgua | grep "dev /" | awk '{print $ 1}' '

yes = `dd bs = 4096 skip = $ position count = 256 if = $ device | hexdump -C`

echo "Dans la ligne suivante, vous devriez voir un modèle comme: 
00000000 79 0a 79 0a 79 0a 79 0a 79 0a 79 0a 79 0a 79 0a | yyyyyyyy |
$ oui
"

if [["` echo "$ yes" | grep "yyy" `" == ""]]; ensuite
    echo "Le motif n'a pas pu être vérifié. Quelque chose s'est mal passé. Sortie."
    NETTOYER;
autre
    echo "Motif confirmé."
Fi

echo "Suppression du fichier temporaire." 
rm test-trim-by-desgua

écho "Synchronisation".
synchroniser
dormir 1

if [["$ fs" == "1"]]; ensuite
    echo "fstrim -v $ pasta && sleep 2"; écho
    fstrim -v $ pasta
    dormir 2
Fi

# Supprimer le cache
echo 1> / proc / sys / vm / drop_caches

echo "Dans la ligne suivante, vous devriez ** PAS ** voir un motif oui comme: 
00000000 79 0a 79 0a 79 0a 79 0a 79 0a 79 0a 79 0a 79 0a | yyyyyyyy | 
Si vous voyez, alors le trim ne fonctionne pas:
`dd bs = 4096 skip = $ position count = 256 if = $ device | hexdump -C` "

yes = `dd bs = 4096 skip = $ position count = 256 if = $ device | hexdump -C`
if [["` echo "$ yes" | grep "yyy" `"! = ""]]; ensuite
    echo "TRIM ne fonctionne pas."
autre
    echo "TRIM fonctionne!"
Fi
NETTOYER;
}

if [["$ method" == "1"]]; ensuite
    SDATEST;
    TESTER;
elif [["$ method" == "2"]]; ensuite
    LUKSTEST;
Fi
sortie 0

desgua
la source