Trimm mit LVM und dm-crypt

21

Ich habe versucht, TRIM mit LVM und dm-crypt unter Ubuntu 13.04 einzurichten.

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

Beachten Sie die nachstehenden Hinweise zu meiner Konfiguration und meinem Testverfahren.

Fragen

  1. Gibt es einen zuverlässigen Test, ob TRIM richtig funktioniert?

  2. Ist meine Testroutine falsch oder funktioniert mein TRIM nicht?

  3. Wenn es nicht funktioniert: Was ist mit meinem Setup falsch?

  4. Wie kann ich TRIM für mein Setup debuggen und dafür sorgen, dass TRIM funktioniert?

Aufbau

Hier ist meine Konfiguration:

cat /etc/crypttab

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

und

cat /etc/lvm/lvm.conf

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

Die SSD ist ein Samsung 840 Pro.

Hier ist mein Testablauf

Um das Setup zu testen, habe ich gerade das gemacht, sudo fstrim -v /was dazu geführt hat

/: [...] bytes were trimmed

Dies erneut zu tun, ergab /: 0 bytes were trimmedeinen Sinn und zeigte an, dass TRIM zu funktionieren scheint.

Allerdings habe ich dann diesen Test gemacht:

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

Dies scheint darauf hinzudeuten, dass TRIM nicht funktioniert. Schon seit

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

Bearbeiten

Hier ist die Ausgabe von 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

Hier ist mein /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 

Bearbeiten:

Ich habe es schließlich als Fehler in https://bugs.launchpad.net/ubuntu/+source/lvm2/+bug/1213631 gemeldet

Hoffe, dass jemand dort eine Lösung findet oder zumindest das Setup testet und den Fehler überprüft.

Aktualisieren

Jetzt funktioniert es, siehe akzeptierte Antwort.

Schüler
quelle
LVM scheinen Fehlwürfe zu sein, sollte aber issue_discardsnicht sein, issue discardswenn das kein Tippfehler war. allow_discardssollte in der Dmsetup-Tabelle für die LVM-Partitionen angezeigt werden.
Frostschutz
Entschuldigung, das war ein Tippfehler. Ich habe issue_discards = 1in meiner Konfigurationsdatei.
Schüler
Wenn ich Sie wäre, würde ich versuchen, ein iSCSI-Ziel zu verwenden und dies über tcpdump / wireshark zu testen, um festzustellen, ob das Setup funktioniert, obwohl ich nicht weiß, ob das Linux-iSCSI-Ziel Trim unterstützt oder nicht. Ich glaube, dass dm-crypt die Blöcke auf der physischen Festplatte nicht leeren sollte, da dies das Ignorieren des freien Speicherplatzes auf dem Gerät erleichtert, wenn versucht wird, es zu brachialisieren (ich weiß jedoch nicht, ob dies der Fall ist oder nicht) ). Darüber hinaus müssen SSDs nach dem Austasten keine Nullen zurückgeben, da der Abnutzungsgrad den Lesevorgang zu einem anderen Block als dem ausgetasteten umleiten kann.
Didi Kohen
1
Laut bugzilla.redhat.com/show_bug.cgi?id=958096 habe ich die issue_discards = 1 falsch verstanden.
frostschutz

Antworten:

23

Ich schlage vor, eine andere Testmethode zu verwenden. hdparmDas ist etwas seltsam, da es eher Geräteadressen als Dateisystemadressen angibt und nicht angibt, auf welches Gerät sich diese Adressen beziehen (z. B. werden Partitionen aufgelöst, aber keine Gerätekarten-Ziele usw.). Es ist viel einfacher, etwas zu verwenden, das an Dateisystemadressen festhält, auf diese Weise ist es konsistent (möglicherweise mit Ausnahme nicht traditioneller Dateisysteme wie zfs / btrfs).

Erstellen Sie eine Testdatei: (nicht absichtlich zufällig)

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

Adresse, Länge und Blockgröße ermitteln: (exakter Befehl abhängig von der 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

Holen Sie sich das Gerät und den Mountpoint:

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

Damit einzurichten, müssen Sie eine Datei trim.testmit gefüllt yesauf -Muster /dev/mapper/somethingan der Adresse 34048mit einer Länge von 256Blöcken von 4096Bytes.

Wenn Sie dies direkt vom Gerät aus yeslesen, sollte das folgende Muster angezeigt werden:

# 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

Wenn TRIM aktiviert ist, sollte sich dieses Muster ändern, wenn Sie die Datei löschen. Beachten Sie, dass auch Caches gelöscht werden müssen, da sonst dddie Daten nicht erneut von der Festplatte gelesen werden.

# 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

Auf den meisten SSDs würde dies zu einem Nullmuster führen:

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

Wenn es sich um eine Verschlüsselung handelt, wird stattdessen ein zufälliges Muster angezeigt:

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..&... ~"..!|.,|

Das liegt daran, dass die Kryptoschicht physikalisch getrimmt Nullen liest und diese Nullen zu "zufälligen" Daten entschlüsselt.

Wenn das yes-Muster bestehen bleibt, wurde höchstwahrscheinlich kein Zuschnitt durchgeführt.

Frostschutz
quelle
1
@student: Es tut mir leid, dass ich das nicht früher bemerkt habe. Ich habe die Antwort bearbeitet, um Caches vorher zu löschen hexdump.
Frostschutz
1
Danke, das war der fehlende Punkt. Jetzt scheint es zu funktionieren!
Student
2
Ich bin mir immer noch nicht sicher, ob der Kernel Caches nicht von selbst löschen soll, wenn er etwas auf einer SSD zuschneidet. Caches dürfen keine falschen Daten zurückgeben. Es ist auch eine Verschwendung von Cache-Speicher, wenn es von etwas besetzt ist, das nicht mehr da ist ... na ja.
Frostschutz
1
@frostschutz Danke für diese tolle Lösung. Ich habe ein Skript erstellt, um den Prozess zu automatisieren, wenn eine faule Person hierher kommt.
Desgua
1
Neulinge sollten beachten, dass der TRIM-Befehl die Blöcke nicht immer sofort mit Null füllt. Sehen Sie hier , hier und hier . hdparm -IDies sollte jedoch in OPs Fall der Fall sein, da sein Ergebnis "Deterministic read ZEROs after TRIM" anzeigt.
Marc.2377
3

Ihre Testroutine ist falsch - Sie erhalten Sektornummern relativ zu dem Blockgerät, auf dem sich das Dateisystem befindet - in diesem Fall handelt es sich um ein logisches Volume. Das logische Volume beginnt natürlich nicht mit dem ersten Sektor des physischen Volumes (und ist möglicherweise nicht einmal zusammenhängend).

Selbst wenn der logische Datenträger bei Sektor 0 des physischen Datenträgers begann (was nicht der Fall ist), ist der physische Datenträger tatsächlich ein anderes Device-Mapper-Ziel, dieses zur Verschlüsselung. Und wahrscheinlich gibt es einen LUKS-Header davor, sodass die Sektornummern dort auch nicht übereinstimmen.

Wenn Sie die Sektornummer dem zugrunde liegenden Datenträger zuordnen möchten dmsetup tables, erhalten Sie die erforderlichen Informationen. Wenn Sie es hier einfügen, stellen Sie sicher, dass es sich bei Ihrer Version um eine Version handelt, bei der der Schlüssel in der Ausgabe nicht angezeigt wird (stattdessen sollten alle Nullen angezeigt werden)! (Es gibt keine Wiederherstellung nach der Offenlegung des Schlüssels - er kann nicht geändert werden - es ist weitaus schlimmer als die Offenlegung des Passworts).

Ich schlage vor, dass Sie zum Debuggen (sobald Sie die Sektorzuordnung erstellt haben) auf der untersten Ebene beginnen und bestätigen, dass sie dort funktioniert. TRIMMEN Sie ein Dateisystem direkt auf / dev / sdaX und stellen Sie sicher, dass es funktioniert (es ist gut möglich, dass das Gerät lügt und trim keine Nullen zurückliest). Dann dm-crypt darüber und schneide ein Dateisystem drauf und stelle sicher, dass es funktioniert. Legen Sie abschließend LVM obenauf und überprüfen Sie, ob dies funktioniert.

derobert
quelle
@student OK, das ist dann der falsche Sektor (die ersten beiden Absätze meiner Antwort). Ich bearbeite meine Antwort, um den Satz zu Sektor 6575104 zu entfernen, da er nicht mehr relevant ist.
Derobert
Ich bin nicht sicher, welches Gerät ich nehmen soll dmsetup. Ich habe gerade getan: sudo dmsetup table /dev/mapper/lubuntu--vg-rootwas gibt0 465903616 linear 252:0 2048
Schüler
@student Das bedeutet, dass Sektor 0 auf Gerät 252: 0 auf Sektor 2048 liegt. Sie müssen herausfinden, was 252: 0 ist. Ich würde raten, dass es sich um Ihr dm-Verschlüsselungsgerät handelt (das ist die Haupt- und Nebenzahl, die beispielsweise in / dev angezeigt wird). Sie müssen sich die Tabelle für dieses Gerät ansehen, um die Suche nach einem Block auf einem zugrunde liegenden Gerät fortzusetzen.
Derobert
3

Dies ist nur ein Skript, das ich gerne teilen möchte, wenn eine faule Person hierher kommt. Es wurde aus der akzeptierten Antwort von frostschutz gemacht .

#! / bin / bash
#
# Dieses Skript wird "wie besehen" ohne jegliche ausdrückliche oder stillschweigende Garantie zur Verfügung gestellt, einschließlich, aber nicht beschränkt auf die stillschweigenden Garantien der Marktgängigkeit, Eignung für einen bestimmten Zweck oder Nichtverletzung.
#
# Lizenz GPL2
#
# von desgua 29.04.2014

Funktion CLEAN {
cd "$ pasta"
[-f test-trim-by-desgua] && rm test-trim-by-desgua && echo "Temporäre Datei entfernt"
Echo "Auf Wiedersehen"
Ausfahrt 0
}

Fallenecho; Echo "Abgebrochen." ; REINIGEN; Echo; Ausfahrt 0 'INT HUP

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

read -n 1 -p 'Root werden? [J / n] 'a
    if [[$ a == "Y" || $ a == "y" || $ a == ""]]; dann
        sudo $ 0 $ 1
        Ausfahrt 0
    sonst
        echo "
        Dieses Skript benötigt Root-Rechte.
        "
        Ausfahrt 1

    fi

fi


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

echo "
Verwendung: $ name / folder / to / test /

"
Ausfahrt 1
fi

Nudeln = $ 1

read -n 1 -p 'fstrim verwenden? [J / N] 'a
if [[$ a == "Y" || $ a == "y"]]; dann
    fs = 1
fi

method =
while [["$ method"! = "1" && "$ method"! = "2"]]; machen
read -n 1 -s -p 'Wähle eine Methode:
[1] hdparm (schlägt in LUKS auf LVM fehl)
[2] Dateifragmentierung (Warnung: Möglicherweise müssen Sie das Beenden erzwingen - das Terminal schließen - in einigen Fällen, wenn der Erfolg nachlässt, wenn Sie eine Ausgabe sehen, die niemals endet) 
' Methode
getan

Funktion SDATEST {
disk = $ (fdisk -l | grep / dev / sda)
if ["$ disk" == ""]; dann
echo "
fdisk hat / dev / sda nicht gefunden 
"
Ausfahrt 1
fi
}

Funktionstest {
echo "Entrying /"; Echo
CD $ Pasta
echo "Erstellen der Datei test-trim-by-desgua bei $ pasta"; Echo
dd if = / dev / urandom von = test-trim-by-desgua count = 10 bs = 512k
Echo "Synchronisieren und 2 Sekunden schlafen." ; Echo
synchronisieren
schlaf 2

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

echo "Wie Sie sehen, wurde die Datei erstellt und ihr LBA beginnt bei $ lbab"; Echo

Echo "Synchronisieren und 2 Sekunden schlafen." ; Echo
synchronisieren
schlaf 2

echo "Entfernen der Datei test-trim-by-desgua"; Echo
rm test-trim-by-desgua

Fallenecho; Echo; Echo "Abgebrochen." ; Echo; Ausfahrt 0 'INT
Echo "Synchronisieren und 2 Sekunden schlafen." ; Echo
synchronisieren
schlaf 2

if [["$ fs" == "1"]]; dann
    echo "fstrim $ pasta && sleep 2"; Echo
    fstrim $ pasta
    schlaf 2
fi

echo "Dies wird aus dem Sektor $ lbab gelesen:"
hdparm --read-sector $ lbab / dev / sda

pass = $ (hdparm --read-sector $ lbab / dev / sda | grep "0000 0000 0000 0000")

if [[$ pass == ""]]; dann
    echo "
Zuschneiden fehlgeschlagen ... 
Sie sollten nur 0000 0000 0000 0000 sehen ...
"
sonst
    Echo "Erfolg !!!"
fi
Ausfahrt 0

}

Funktion LUKSTEST {
# Referenz: /unix/85865/trim-with-lvm-and-dm-crypt#
echo 1> / proc / sys / vm / drop_caches
CD $ Pasta
echo "Erstellen einer" Ja "-Datei."
ja | dd iflag = fullblock bs = 1M count = 1 von = 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 's | g; s |. * 255: || ; s | \. \ .. * || '`
[["$ position" == ""]] && echo "Konnte die Position der Datei nicht finden. Sind Sie auf einem LUKS in LVM?" && REINIGEN;

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

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

echo "In der nächsten Zeile solltest du ein Muster sehen wie: 
00000000 79 0a 79 0a 79 0a 79 0a 79 0a 79 0a 79 0a 79 0a | jjjjjjj |
$ ja
"

if [["` echo "$ yes" | grep "yyy" `" == ""]]; dann
    echo "Das Muster konnte nicht überprüft werden. Es ist ein Fehler aufgetreten. Verlassen."
    REINIGEN;
sonst
    Echo "Muster bestätigt."
fi

echo "Temporäre Datei entfernen." 
rm test-trim-by-desgua

Echo "Synchronisierung"
synchronisieren
schlaf 1

if [["$ fs" == "1"]]; dann
    echo "fstrim -v $ pasta && sleep 2"; Echo
    fstrim -v $ pasta
    schlaf 2
fi

# Cache löschen
echo 1> / proc / sys / vm / drop_caches

echo "In der nächsten Zeile solltest du ** NICHT ** ein Ja Muster sehen wie: 
00000000 79 0a 79 0a 79 0a 79 0a 79 0a 79 0a 79 0a 79 0a | jjjjjjj | 
Wenn Sie sehen, funktioniert der Zuschnitt nicht:
`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" `"! = ""]]; dann
    echo "TRIM funktioniert nicht."
sonst
    echo "TRIM funktioniert!"
fi
REINIGEN;
}

if [["$ method" == "1"]]; dann
    SDATEST;
    PRÜFUNG;
elif [["$ method" == "2"]]; dann
    LUKSTEST;
fi
Ausfahrt 0

desgua
quelle