[LINUX] Die Geschichte des "Lochs" in der Akte

Die Geschichte des "Lochs" in der Akte

$ dd if=/dev/zero of=testfile1 bs=1 seek=104857599 count=1 ; ls -ls testfile1
1+0 records in
1+0 records out
1 bytes transferred in 0.000114 secs (8775 bytes/sec)
8 -rw-r--r--  1 user  staff  104857600  5 25 13:24 testfile
$ 

Sie können eine Datei mit einer Dateigröße von 100 MB erstellen, die jedoch nur 8 Blöcke belegt. Ähnliches können Sie mit dem Linux-Befehl (coreutils) truncate oder dem qemu-Verwaltungsbefehl qemu-img tun.

$ truncate -s 100M testfile2
$ qemu-img create -f raw testfile3 100M
$ 

dd verwendet zwei Systemaufrufe, lseek (2) und write (2), und truncate und qemu-img verwenden einen Systemaufruf namens ftruncate (2), aber die Ergebnisse sind fast gleich [^ 1].

[^ 1]: Da am Ende von dd 1 Byte geschrieben wird, wird der Plattenblock dieses Teils zugewiesen. Auf der anderen Seite werden Truncate und Qemu-Img möglicherweise überhaupt nicht zugewiesen. Wie viel es tatsächlich zugewiesen wird, hängt von der Implementierung des Dateisystems ab.

Wenn diese Dateien gelesen werden, werden die mit "0" gefüllten Daten gelesen, und beim Schreiben wird der Plattenblock an diesem Punkt zugewiesen und die geschriebenen Informationen werden gespeichert. Der Teil, dem der Plattenblock nicht zugeordnet ist, wird als "Loch" oder "Loch" bezeichnet, und die Datei mit einem solchen Teil wird als "perforierte Datei" oder "Datei mit geringer Dichte" bezeichnet. Seit jeher wurden buchstäblich spärliche Dateien (große Dateien im Vergleich zur Informationsmenge) wie DB-Dateien häufig perforiert, und in letzter Zeit wurde das Image der virtuellen Festplatte der virtuellen Qemu / KVM-Maschine perforiert. Vielleicht.

Locherkennung und Bohren

Die Lücke in dieser Datei bezieht sich auf die Verwendung des Speicherplatzes im Dateisystem und wurde traditionell nicht in der API angezeigt. Zusätzlich zur normalen POSIX-API gab es auch eine DMAPI, die jedoch anscheinend nicht sehr beliebt war.

Seit jeher kann Linux Lücken in Dateien erkennen, indem es die Datei öffnet und ioctl (2) ausgibt. Ein ioctl namens FIBMAP gibt die Nummer des Plattenblocks zurück, in dem die Dateidaten gespeichert sind. Der Lochteil gibt 0 als Plattenblocknummer zurück, damit er erkannt werden kann. Das Problem ist, dass Sie Root-Rechte benötigen, um dieses ioctl auszuführen, und dass Sie ioctl (2) einmal ausgeben müssen, um einen Block nachzuschlagen.

Linux hat auch ein ioctl (2) namens FS_IOC_FIEMAP. Dies ist eine erweiterte Version von FIBM AP, mit der Sie Informationen zu einem bestimmten Dateibereich gleichzeitig abrufen können und für die keine Root-Rechte erforderlich sind. FIEMAP Oktober 2008, in Entwicklung von 2.6.28 Eingeführt in.

Sowohl FIBMAP als auch FS_IOC_FIEMAP waren Methoden, um den spezifischen Speicherort auf der Festplatte zu ermitteln, an dem die Dateidaten gespeichert wurden, und das Loch wurde als Nebeneffekt festgestellt. Als dedizierte API zum Erkennen von Löchern gibt es im Systemaufruf lseek (2) die Optionen SEEK_HOLE und SEEK_DATA. Es wurde ursprünglich unter Solaris und später unter FreeBSD und [Linux] implementiert (https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=982d816581eeeacfe5b2b7c6d47d13a157616eff) ) Da es implementiert ist, scheint es gut zu denken, dass es nicht Standard ist, aber eine gewisse Portabilität aufweist.

SEEK_HOLE bewegt sich zum ersten Loch nach dem angegebenen Versatz. SEEK_DATA wird nach dem angegebenen Versatz in ein nicht erstes Loch verschoben. Mit der richtigen Kombination können Sie die Löcher in der gesamten Datei korrekt auflisten.

Wie wäre es andererseits mit einem Loch? Die am Anfang erwähnten Methoden lseek (2) + write (2) und ftruncate (2) können nur am Ende der Datei ein Loch hinzufügen. Mit anderen Worten, es ist nicht möglich, ein Loch in den Teil zu bohren, in dem der Datenblock bereits zugewiesen wurde.

Wiederum geht Solaris voran und ein Befehl namens F_FREESP wird zu fcntl (2) hinzugefügt. Sie können ein Loch in einen bestimmten Bereich der Datei bohren. Dieser API folgen keine anderen Betriebssysteme [^ 2], und unter Linux wurde ein Systemaufruf namens fallocate (2) als FALLOC_FL_PUNCH_HOLE gekennzeichnet. scm / linux / kernel / git / torvalds / linux.git / commit /? id = 79124f18b335172e1916075c633745e12dae1dac) können Sie auch ein Loch in den angegebenen Bereich bohren. In beiden Implementierungen gehen die im angegebenen Bereich aufgezeichneten Daten verloren (beim Lesen werden mit Nullen aufgefüllte Daten zurückgegeben).

[^ 2]: XFS hat jedoch lange Zeit ein Ioctl namens XFS_IOC_FREESP und kann dasselbe wie fcntl (F_FREESP) tun.

Löcher speichern und kopieren

Noch vor dem Hinzufügen von APIs, die zum Erkennen von Löchern (ohne Root-Berechtigungen) verwendet werden konnten, konnten der Befehl coreutils cp und GNU tar perforierte Dateien erkennen und diese effizient kopieren und archivieren. Wie wurde dies festgestellt?

Gemäß dem Update-Verlauf von coreutils wurde die Locherkennung durch FS_IOC_FIEMAP in Mai 2010 implementiert. //git.savannah.gnu.org/gitweb/?p=coreutils.git; a = commit; h = dff2b95e4fb22f3e6f3360da0774c784d2f50ff9). Siehe vorherigen [Code](https://git.savannah.gnu.org/gitweb/?p=coreutils.git;a=blob;f=src/copy.c;h=9a014ad5aa672c78b7e3cd69de1e684c73563e1f;hb= Probier es einfach.

Eine Kopie einer regulären Datei ist ungefähr copy_reg () 9a014ad5aa672c78b7e3cd69de1e684c73563e1f; hb = e1aaf8903db97f3240b1551fd6936ccdc652dfc8 # l458). [Zeile 707](https://git.savannah.gnu.org/gitweb/?p=coreutils.git;a=blob;f=src/copy.c;h=9a014ad5aa672c78b7e3cd69de1e684c73563e1f;hb= Die Kopie wird in der while-Schleife von ausgeführt.

Aufmerksamkeit ist Zeile 746, Zähle die Anzahl der Nullen und suche so viel. Mit anderen Worten, wenn die Kopierquelldaten 0 sind, wird nicht 0 in das Kopierziel geschrieben, sondern nur gesucht, sodass es zu einer Lücke werden kann.

Selbst mit den neuesten Coreutils werden Löcher auf diese Weise verarbeitet, wenn FIEMAP nicht verwendet werden kann.

Dateilöcher und TRIM (UNMAP) -Befehle

In einem anderen Sinne wurde der Begriff TRIM-Befehl einige Jahre vor der Verbreitung von SSDs zu einem heißen Thema. TRIM löst das Problem, dass das Schreiben von Daten relativ langsam ist, da der NAND-Flash-Speicher, der das Speichermedium der SSD ist, vor dem erneuten Schreiben gelöscht werden muss. Durch Benachrichtigen der SSD über nicht verwendete oder freigegebene Blöcke vom Betriebssystem (Dateisystem) kann die SSD im Voraus gelöscht werden. Darüber hinaus ist es auch beim Verschleißnivellieren vorteilhaft, die Schreibfrequenz für jeden Block von NAND-Flash auszugleichen, der eine Obergrenze für die Anzahl von Schreibvorgängen aufweist.

TRIM ist ein SATA-Befehl, aber SCSI hat auch einen ähnlichen Befehl namens UNMAP. Es gibt SSDs mit SCSI-Verbindung, aber es ist auch für Thin Provisioning mit SAN effektiv. Da der zugewiesene Bereich beim Löschen einer Datei in den Speicher zurückgegeben werden kann, erhöht sich der verwendete Bereich nicht nur monoton wie in der Vergangenheit.

Apropos Thin Provisioning: Virtuelle Festplatten für virtuelle Maschinen können durch Thin Provisioning bereitgestellt werden. Die Qcow2-Datei von Qemu ist beispielsweise ein Thin-Provisioning-Format. Wenn Sie ein Rohbild als perforierte Datei erstellen, wird es Thin-Provisioning-Datei. Also kam ich zurück zum Loch.

Qemu- und TRIM / UNMAP-Befehle

Die emulierten SATA- und SCSI-Festplatten von Qemu verstehen den Befehl TRIM (UNMAP), um das Backend-Festplatten-Image (optional) ordnungsgemäß zu bearbeiten.

Zunächst begann SATA, TRIM in [Commit im Mai 2011] zu interpretieren (https://git.qemu.org/?p=qemu.git;a=commitdiff;h=d353fb72f59cd0e1f67baf773e74719cda761a89). Die SCSI-Festplatte ist August 2012. Das VirtIO-Blockgerät ist viel neuer Februar 2019. In Bezug auf Qemu-Versionen entsprechen sie den Veröffentlichungszyklen von 0,15, 1,2,0 bzw. 4,0.

Auf der anderen Seite ist Qcow2 unter den Treibern für virtuelle Back-End-Image-Dateien Januar 2011, TRIM (UNMAP) Lassen Sie nun das Teil los. Die Dateigröße wird jedoch nicht reduziert, und der freigegebene Bereich kann durch Fallocate gestanzt werden. Im Rohformat wird der Bereich TRIM (UNMAP) von fallocate () zu [Januar 2013] hinzugefügt (https://git.qemu.org/?p=qemu.git;a=commitdiff;h=3d4fa43e648f3b169e7ab5dd4e21312e510805d7). Es wurde offen. Es scheint, dass XFS zuvor von ioctl () veröffentlicht wurde.

Wenn Sie nun tatsächlich eine virtuelle Maschine in der Umgebung von Ubuntu 20.04 LTS (Fokus, Linux-5.4-Serie, Qemu-4.2-Serie) erstellen, ist die virtuelle Festplatte (alle VirtIO SCSI-Beispiele) ein Gastbetriebssystem als "Thin Provisionable" -Diskette. Es ist sichtbar von. Wenn Sie beispielsweise den Linux-Gast starten, werden die Dateien thin_provisioning und Bereitstellungsmodus im folgenden sysfs-Festplatteneintrag wie folgt erstellt.

$ cat /sys/bus/scsi/devices/0\:0\:0\:0/scsi_disk/0\:0\:0\:0/thin_provisioning
1
$ cat /sys/bus/scsi/devices/0\:0\:0\:0/scsi_disk/0\:0\:0\:0/provisioning_mode
unmap
$ 

Wenn Sie sich für Windows-Gäste das Tool "Laufwerkdefragmentierung und -optimierung" (Start-> Unter Windows-Verwaltung) ansehen, lautet der Abschnitt "Medientyp" "Kompatibles Laufwerk mit virtueller Bereitstellung" und wählen Sie "Optimieren". Und TRIM werden ausgeführt (Z: in der Abbildung ist eine iSCSI-Festplatte).

スクリーンショット 2020-05-29 16.39.54.png

Wenn Sie sich auf der Hostseite mit einer normalen Festplatte dieselbe Datei ansehen, die Sie im Linux-Gast gesehen haben,

$ cat /sys/bus/scsi/devices/0\:0\:0\:0/scsi_disk/0\:0\:0\:0/thin_provisioning
0
$ cat /sys/bus/scsi/devices/0\:0\:0\:0/scsi_disk/0\:0\:0\:0/provisioning_mode
full
$ 

Es ist ersichtlich, dass es sich nicht um Thin Provisioning (Thick Provisioning) handelt.

Wenn ein Gast einen UNMAP-Befehl ausgibt (weil es sich um SCSI handelt), verfügt das Blockgerät über eine Option zum Verwerfen. In diesem Fall gibt Fallocate (2) Speicherplatz frei. Wenn Sie einen Kernel mit Linux 4.9 oder höher wie Ubuntu 20.04 verwenden, funktioniert [fallocate (2)] nicht nur, wenn es sich bei der virtuellen Festplatte um eine Datei handelt, sondern auch, wenn es sich um ein Hostgerät handelt (z. B. ein LVM-Volume) (https :: //git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=25f4c41415e513f0e9fb1f3fce2ce98fcba8d263), TRIM (UNMAP) wird weitergeleitet.

Ich habe tatsächlich mit einem Rohbild experimentiert.

host# qemu-img create -f raw vol.img 20G
Formatting 'vol.img', fmt=raw size=21474836480
host# qemu-img info vol.img ; ls -lsh vol.img
image: vol.img
file format: raw
virtual size: 20 GiB (21474836480 bytes)
disk size: 4 KiB
4.0K -rw-r--r-- 1 libvirt-qemu kvm 20G May 30 13:42 vol.img
host# 

Hängen Sie diese Festplatte an die Gast-SDB an. Mit libvirt die Option zum Verwerfen hinzufügen

      <driver name='qemu' type='raw'/>

Wo es aussieht

      <driver name='qemu' type='raw' discard='unmap'/>

Machen. Formatieren Sie den Gast, nachdem Sie ihn gestartet und identifiziert haben. Ich habe hier XFS gewählt.

guest:~# mkfs.xfs /dev/sdb
meta-data=/dev/sdb               isize=512    agcount=4, agsize=1310720 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=0, rmapbt=0, reflink=0
data     =                       bsize=4096   blocks=5242880, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=1
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
guest:~# 

Wenn Sie das Bild auf der Hostseite untersuchen, können Sie feststellen, dass es um die Menge der Metadaten größer ist.

host# qemu-img info vol.img ; ls -lsh vol.img
image: vol.img
file format: raw
virtual size: 20 GiB (21474836480 bytes)
disk size: 10.3 MiB
11M -rw-r--r-- 1 libvirt-qemu kvm 20G May 30 13:51 vol.img
host# 

Hängen Sie dies ein und erstellen Sie eine 512-MB-Datei.

guest:~# mount /dev/sdb /mnt
guest:~# dd if=/dev/urandom of=/mnt/randomfile bs=1M count=512
512+0 records in
512+0 records out
536870912 bytes (537 MB, 512 MiB) copied, 2.95154 s, 182 MB/s
guest:~# 

Die Untersuchung des Bildes auf der Hostseite zeigt, dass es etwa 512 MB größer ist.

host# qemu-img info vol.img ; ls -lsh vol.img
image: vol.img
file format: raw
virtual size: 20 GiB (21474836480 bytes)
disk size: 522 MiB
523M -rw-r--r-- 1 libvirt-qemu kvm 20G May 30 13:52 vol.img
host# 

Versuchen Sie als Nächstes, diese Datei zu löschen. TRIM wird ausgegeben, wenn der Mount-Option Discard hinzugefügt wird oder wenn fstrim (8) ausgeführt wird. Führen Sie daher fstrim aus (-v ist ausführlich).

guest:~# rm /mnt/randomfile 
guest:~# fstrim -v /mnt
/mnt: 20 GiB (21464170496 bytes) trimmed
guest:~# 

Wenn Sie das Bild untersuchen, können Sie feststellen, dass es ungefähr dieselbe Größe wie unmittelbar nach mkfs hat.

host# qemu-img info vol.img ; ls -lsh vol.img
image: vol.img
file format: raw
virtual size: 20 GiB (21474836480 bytes)
disk size: 10.1 MiB
11M -rw-r--r-- 1 libvirt-qemu kvm 20G May 30 13:53 vol.img
host# 

Neuere Debian und Ubuntu haben einen Befehl namens zerofree, der den freien Speicherplatz von ext3 und ext4 auf Null zu füllen scheint. Wenn Sie dies mit der Option [erkenne-Nullen = Unmap] von qemu (https://www.qemu.org/docs/master/system/invocation.html#hxtool-1) kombinieren, wird ein zugewiesener Bereich des Disk-Images erstellt. Es kann möglich sein, es zu reduzieren.

Recommended Posts

Die Geschichte des "Lochs" in der Akte
Die Geschichte der Teilnahme an AtCoder
Die Geschichte eines Fehlers in PyOCR
Die Geschichte von sys.path.append ()
Die Geschichte des Lesens von HSPICE-Daten in Python
Die Geschichte der Anzeige von Mediendateien in Django
Die Geschichte des Baus von Zabbix 4.4
Die Geschichte von FileNotFound im Python open () -Modus = 'w'
Die Geschichte von Python und die Geschichte von NaN
Speichern Sie die Binärdatei in Python
Google sucht mit Python nach der Zeichenfolge in der letzten Zeile der Datei
Die Geschichte des erneuten Bereitstellens des Anwendungsservers
Die Geschichte des Exportierens eines Programms
Die Geschichte der Herabstufung der Version von Tensorflow in der Demo von Mask R-CNN.
Verarbeiten Sie den Inhalt der Datei der Reihe nach mit einem Shell-Skript
Die Geschichte der Ausgabe des Planetarium-Meisters im PDF-Format mit Pycairo
Verwendung der in Pip 7.1 hinzugefügten Einschränkungsdatei
Die Geschichte des Versuchs, den Client wieder zu verbinden
[Verständnis in 3 Minuten] Der Beginn von Linux
Überprüfen Sie das Verhalten des Zerstörers in Python
Umgang mit Zeichencodes von Dateien in IronPython
Die Geschichte, MeCab in Ubuntu 16.04 zu setzen
Implementieren Sie einen Teil des Prozesses in C ++
Überprüfen Sie die Existenz der Datei mit Python
Die Geschichte einer unveränderlichen Form
Das Ergebnis der Installation von Python auf Anaconda
Lesen Sie die Datei Zeile für Zeile mit Python
Lesen Sie die Datei Zeile für Zeile mit Python
Die Geschichte der Manipulation globaler Python-Variablen
Grundlagen zum Ausführen von NoxPlayer in Python
Die Geschichte, deep3d auszuprobieren und zu verlieren
Dekodierung von Keras 'LSTM model.predict
Auf der Suche nach dem schnellsten FizzBuzz in Python
[Python] Ruft den Zeichencode der Datei ab
Die Geschichte der Verarbeitung A von Blackjack (Python)
Die Geschichte von pep8 wechselt zu pycodestyle
[Python] Lesen Sie die angegebene Zeile in der Datei
[Python3] Grundlegendes zu Dateivorgängen
Die Geschichte eines Parksensors in 10 Minuten mit dem GrovePi + Starter Kit
Zeigen Sie den vollständigen Pfad (absoluten Pfad) einer Datei in einem Verzeichnis in Linux Bash an
Öffnen Sie eine Excel-Datei in Python und färben Sie die Karte von Japan
Ich habe ein Programm erstellt, um die Größe einer Datei mit Python zu überprüfen
Geben Sie die Anzahl der CPU-Kerne in Python aus
Die Geschichte des tiefen Lernens mit TPU
Bedeutung von {Versionsnummer} im MySQL-RPM-Paket
Die Geschichte, dass die Lernkosten von Python niedrig sind
[Python] Sortieren Sie die Liste von pathlib.Path in natürlicher Reihenfolge
Extrahieren Sie nur den Dateinamen mit Ausnahme des Verzeichnisses im Verzeichnis
Ändern Sie die Schriftgröße der Legende in df.plot
Holen Sie sich den Aufrufer einer Funktion in Python
Passen Sie die Verteilung jeder Gruppe in Python an
Zeigen Sie das Ergebnis der Geometrieverarbeitung in Python an
Die Geschichte der Herstellung des Mel Icon Generator Version 2
Kopieren Sie die Liste in Python