Wie ich einen Fehler in GNU Tar gefunden habe

Published on December 27, 2018

Wie ich einen Fehler in GNU Tar gefunden habe

Originalautor: Chris Siebenmann
  • Übersetzung
Der Autor des Artikels ist Chris Siebenmann , Unix-Systemadministrator an der University of Toronto.

Von Zeit zu Zeit passiert etwas Merkwürdiges in meiner Arbeit, das mich zum Nachdenken anregt. Auch wenn nicht sofort klar ist, worauf die Schlussfolgerungen folgen. Kürzlich erwähnte ich, dass wir einen Fehler in GNU Tar gefunden haben, und die Geschichte, wie dies geschah, ist ein solcher Fall.

Für Backup-Dateiserver verwenden wir Amanda und GNU Tar. Lange Zeit hatten wir gelegentlich ein eher seltenes Problem, als tar beim Sichern des Dateisystems mit einem Verzeichnis verrückt wurde/var/mail, eine riesige Menge an Output zu produzieren. Normalerweise ging dieser Prozess bis ins Unendliche und musste die Müllhalde töten; In anderen Fällen endete es mit einem Terabyte an Daten, die perfekt komprimiert zu sein schienen. Als ich wieder eine solche riesige Teerdatei bekam, überprüfte ich sie - und stellte fest, dass sie teilweise aus null Bytes besteht, was das Testteam nicht besonders mag. tar -tDanach kehrt alles zum Normalzustand zurück.

(Aus diesem Grund habe ich mich gefragt, ob Personen in Postfächern natürlich in Null-Bytes erscheinen. Es stellte sich heraus, dass das Suchen nach Null-Bytes in Textdateien nicht so einfach ist und ja, sie sind da).

Wir haben kürzlich das Dateisystem /var/mailunter Ubuntu 18.04 von auf neue Linux-Dateiserver umgestellt und daher auf eine neuere und standardisiertere Version von GNU Tar umgestellt, als dies auf OmniOS-Computern der Fall ist. Wir hofften, dass dies unsere Probleme lösen würde, aber fast sofort ereignete sich der gleiche Vorfall. Dieses Mal arbeitete GNU Tar auf dem Ubuntu-Rechner, wo ich mit allen verfügbaren Debugging-Tools vertraut war, und überprüfte den laufenden Prozess tar. Der Test hat gezeigt, dass er tareinen unendlichen Stream erzeugt read(), der 0 Bytes zurückgibt:

read(6, "", 512)   = 0
read(6, "", 512)   = 0
[...]
read(6, "", 512)   = 0
write(1, "\0\0\0\0\0"..., 10240) = 10240
read(6, "", 512)   = 0
[...]

lsofbesagter Dateideskriptor 6 ist die Mailbox von jemandem.

Mit der Hilfe habe apt-get source tarich den Quellcode heruntergeladen und nach Systemaufrufen gesucht read(), die nicht auf Dateivervollständigung prüfen. Nachdem ich mehrere Ebenen der indirekten Adressierung untersucht hatte, fand ich eine offensichtliche Stelle, an der eine solche Prüfung offenbar weggelassen wurde, nämlich in der Funktion sparse_dump_regionaus der Datei sparse.cs . Und dann fiel mir etwas ein.

Vor ein paar Monaten stießen wir in Alpine auf ein NFS-Problem . Während ich an diesem Fehler arbeitete, verfolgte ich den alpinen Prozess und bemerkte unter anderem, dass er die Größe von Postfächern veränderteftruncate(); Manchmal werden sie erweitert und vorübergehend ein Teil der Datei erstellt, bis sie ausgefüllt und möglicherweise manchmal komprimiert wird. Dies schien mit der aktuellen Situation übereinzustimmen: Die spärlichen Bereiche sind miteinander verbunden, und das Verringern der Dateigröße mit der Hilfe führt zu ftruncate()einer Situation, in der tar unerwartet auf die Vervollständigung der Datei stößt.

(Dies erklärt sogar, warum Teer manchmal wiederhergestellt wird. Wenn später plötzlich eine neue E-Mail in der Box eintrifft, wird die erwartete Größe wiederhergestellt und Teer sieht sich nicht länger einer unerwarteten Vervollständigung der Datei gegenüber.)

Ich habe ein bisschen mit GDB an den Ubuntu-Debugging-Symbolen und dem erhaltenen Tar-Quellcode herumgespielt und konnte den Fehler reproduzieren, obwohl er sich etwas von meiner ursprünglichen Theorie unterschied. Es stellte sich heraus, dasssparse_dump_regionsetzt keine spärlichen Bereiche der Datei zurück, aber setzt nicht spärlich zurück (naja, natürlich) und wird für alle Dateien verwendet (spärlich oder nicht), wenn Sie tar mit einem Argument ausführen --sparse. Der eigentliche Fehler ist also, dass wenn Sie GNU Tar mit einem Argument ausführen --sparseund die Datei während des Lesens komprimiert wird, tar das Ende der Datei, die früher als erwartet empfangen wurde, nicht korrekt verarbeiten kann . Wenn die Datei erneut wächst, wird tar wiederhergestellt.

(Außer in Fällen, in denen die Datei nur am Ende dünn ist und nur an dieser Stelle komprimiert wird. In diesem Fall ist alles in Ordnung).

Ich dachte, ich könnte es trotzdem vor vielen Jahren auf unseren OmniOS-Dateiservern überprüfen. Es gibt Möglichkeiten, die Systemaufrufe des Programms und der Analoga zu verfolgenlsof, und ich konnte den Quellcode meiner Version von GNU Tar finden und sehen und ihn mit dem OmniOS-Debugger ausführen (obwohl GDB dort nicht installiert ist) und so weiter. Das habe ich aber nicht getan. Stattdessen zuckten wir die Achseln und gingen weiter. Ich musste das Dateisystem unter Ubuntu verschieben, damit ich einen Finger rühren und das Problem herausfinden konnte.

(Es geht nicht nur um die Tools und die Umgebung. Wir gingen auch automatisch davon aus, dass eine alte, nicht unterstützte Version von GNU Tar unter OmniOS verfügbar war. Eine Untersuchung ist daher nicht sinnvoll, da das Problem natürlich in einer neueren Version entschieden wurde.)

PS: Als schnelle Lösung haben wir Amanda wahrscheinlich einfach verboten, den Parameter tar --sparsebeim Sichern zu verwenden. Postfächer sollten nicht spärlich sein, und wenn dies passiert,Wir komprimieren weiterhin Dateisystem-Backups , sodass alle diese Null-Bytes gut komprimiert werden.

PPS: Ich habe nicht versucht, den Entwicklern von GNU Tar einen Fehler zu melden, da ich ihn erst am Freitag entdeckt habe und die Universität jetzt in den Winterferien ist. Fühlen Sie sich frei, dies vor mir zu tun.