Wie ich einen Fehler in GNU Tar gefunden habe

Gepostet von Chris Siebenmann , Unix-Systemadministrator an der Universität von Toronto

Von Zeit zu Zeit passiert in meiner Arbeit etwas Seltsames, das mich zum Nachdenken bringt. Auch wenn nicht sofort klar ist, welche Schlussfolgerungen folgen. Ich habe kürzlich erwähnt, dass wir einen Fehler in GNU Tar gefunden haben, und die Geschichte, wie dies passiert ist, ist ein solcher Fall.

Für Backup-Dateiserver verwenden wir Amanda und GNU Tar. Im Laufe der Zeit hatten wir gelegentlich ein eher seltenes Problem, bei dem Teer beim Sichern des Dateisystems mit dem Verzeichnis /var/mail verrückt wurde und eine große Menge an Ausgabe erzeugte. Normalerweise ging dieser Prozess bis ins Unendliche und musste die Müllkippe töten; In anderen Fällen wurden immer noch Terabyte an Daten ausgegeben, die perfekt komprimiert zu sein schienen. Als ich wieder auf eine so riesige TAR-Datei stieß, überprüfte ich sie - und stellte fest, dass sie teilweise aus null Bytes besteht, was das tar -t Testteam wirklich nicht mag. Danach kehrt alles zum Normalzustand zurück.

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

Wir haben kürzlich das Dateisystem von /var/mail auf die neuen Linux-Dateiserver unter Ubuntu 18.04 verschoben und daher auf eine spätere und standardisiertere Version von GNU Tar umgestellt als auf OmniOS-Computern. Wir hofften, dass dies unsere Probleme lösen würde, aber der gleiche Vorfall ereignete sich fast sofort. Dieses Mal arbeitete GNU Tar auf einem Ubuntu-Computer, auf dem ich mit allen verfügbaren Debugging-Tools sehr vertraut bin. Daher habe ich den laufenden tar Prozess überprüft. Der Test zeigte, dass tar einen endlosen Strom von 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 [...] 

lsof Dateideskriptor 6 ist das Postfach eines anderen.

Mit apt-get source tar ich den Quellcode heruntergeladen und nach read() -Systemaufrufen gesucht, die nicht auf Dateivervollständigung überprüft haben. Nachdem ich mehrere Ebenen der indirekten Adressierung untersucht hatte, fand ich einen offensichtlichen Ort, an dem eine solche Prüfung anscheinend weggelassen wurde, nämlich in der Funktion sparse_dump_region aus der Datei sparse.cs . Und dann erinnerte ich mich an etwas.

Vor einigen Monaten sind wir in Alpine auf ein NFS-Problem gestoßen . Während ich an diesem Fehler arbeitete, verfolgte ich den Alpine-Prozess und stellte unter anderem fest, dass ftruncate() zum ftruncate() der Größe von Postfächern verwendet wird. manchmal werden sie erweitert, vorübergehend ein spärlicher Abschnitt der Datei erstellt, bis sie gefüllt ist, und manchmal wird sie möglicherweise komprimiert. Dies schien mit der aktuellen Situation ftruncate() : Es werden spärliche Bereiche verbunden, und das Reduzieren der Dateigröße mit ftruncate() , dass tar unerwartet auf eine Dateivervollständigung stößt.

(Dies erklärt sogar, warum tar manchmal wiederhergestellt wird. Wenn neue E-Mails später plötzlich in der Mailbox eintreffen, wird die erwartete Größe wiederhergestellt, und tar stößt nicht mehr auf eine unerwartete Beendigung der Datei.)

Ich habe in GDB ein bisschen mit den Ubuntu-Debugging-Symbolen und dem Quellcode des Tar-Pakets herumgespielt und konnte den Fehler reproduzieren, obwohl er sich etwas von meiner ursprünglichen Theorie unterschied. Es stellte sich heraus, dass sparse_dump_region die spärlichen Bereiche der Datei nicht zurücksetzt, aber (natürlich) nicht spärliche Bereiche zurücksetzt und für alle Dateien (spärlich oder nicht) verwendet wird, wenn Sie tar mit dem Argument --sparse . Der eigentliche Fehler besteht also darin, dass tar das Ende der früher empfangenen Datei nicht korrekt verarbeiten kann , wenn Sie GNU Tar mit dem Argument --sparse und die Datei beim --sparse komprimiert wird . Wenn die Datei erneut wächst, wird tar wiederhergestellt.

(Außer wenn die Datei nur am Ende spärlich ist und nur an dieser Stelle komprimiert wird. In diesem Fall ist alles in Ordnung).

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

(Es geht nicht nur um die Tools und die Umgebung. Wir haben automatisch angenommen, dass OmniOS eine alte, nicht unterstützte Version von GNU Tar hat, deren Untersuchung keinen Sinn macht, da das Problem in der neueren Version sicherlich gelöst wurde.)

PS: Wahrscheinlich verbieten wir Amanda als schnelle Lösung einfach, beim --sparse tar --sparse . Postfächer sollten nicht spärlich sein. In diesem Fall werden die Dateisystemsicherungen weiterhin komprimiert , sodass alle diese Null-Bytes gut komprimiert sind.

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

Source: https://habr.com/ru/post/de434624/


All Articles