SSD Nodes Learn 🎉 VPS ab $5.50/Monat
Anleitungen Matt ConnorVon Matt Connor

df voll, du nicht: Gelöschte Dateien finden

Bei „df voll, du findet nichts“ hält oft ein Prozess eine gelöschte Datei offen. Finden Sie sie mit lsof, geben Sie Speicher ohne Neustart frei und prüfen Sie weitere Ursachen.

Warum df „voll“ meldet und du etwas anderes anzeigt

df meldet, dass der Datenträger voll ist, während du den belegten Speicher nicht findet, weil ein Prozess weiterhin eine gelöschte Datei geöffnet hält. Beim Löschen einer Datei wird ihr Name aus einem Verzeichnis entfernt. Die Datenblöcke werden erst freigegeben, wenn der letzte offene Dateideskriptor, der auf diesen Inode verweist, geschlossen wird. du verarbeitet Dateinamen und zählt die Datei daher nicht. df fragt das Dateisystem ab, wie viele Blöcke belegt sind, und zählt deshalb weiterhin die Datei, die keinen Namen mehr hat.

Diese Anleitung reproduziert das Verhalten auf einem einfachen Ubuntu-VPS mit bereits installierten Werkzeugen, ermittelt den Prozess über /proc und gibt den Speicherplatz ohne Neustart frei. Anschließend werden weitere Ursachen für dasselbe Symptom behandelt: eine Inode-Tabelle ohne freie Einträge, Dateien unterhalb eines Mount-Punkts und für root reservierte Blöcke.

Führen Sie jeden Befehl aus und prüfen Sie die eigene Ausgabe. Die Werte hängen von Ihrem Datenträger ab. Vergleichen Sie daher die Werte vor und nach der Änderung auf Ihrem eigenen System, nicht mit einem Wert aus dieser Anleitung.

Was df zählt und was du zählt

df (disk free) fragt jedes eingehängte Dateisystem nach seiner eigenen Buchführung: wie viele Blöcke vorhanden, wie viele belegt und wie viele frei sind. Es öffnet kein Verzeichnis. Das Ergebnis umfasst jeden belegten Block, einschließlich der Blöcke einer Datei, auf die kein Verzeichniseintrag verweist.

du (disk usage) arbeitet umgekehrt. Es beginnt bei einem angegebenen Pfad, liest Verzeichnisse, ermittelt die Metadaten jedes gefundenen Eintrags und summiert die Blöcke. Eine Datei ohne Namen ist für das Programm unsichtbar. Das gilt auch für Verzeichnisse, die es nicht lesen darf. Deshalb erhält ein normaler Benutzer eine kleinere Summe als root. Führen Sie du unter sudo aus, bevor Sie aus dem Vergleich Schlussfolgerungen ziehen.

Beim Vergleich der beiden Befehle sind immer zwei Optionen relevant.

  • -x beschränkt du auf ein Dateisystem. Ohne diese Option durchläuft du / jedes Dateisystem, das unterhalb von / eingehängt ist, und erzeugt eine Summe, die df / überhaupt nicht erfasst hat.
  • -s gibt eine Zusammenfassungszeile pro Argument statt einer Zeile pro Verzeichnis aus.

Damit ergibt sich das Befehlspaar, das Sie für das betreffende Dateisystem nebeneinander ausführen sollten.

df -h /
sudo du -xhs / 2>/dev/null

df liefert sofort ein Ergebnis. du benötigt auf einem großen Dateisystem Minuten, weil es jede Datei auf dem Weg prüft. Wenn die beiden Summen stark voneinander abweichen und du mit root-Rechten und -x ausgeführt wurde, ist der fehlende Speicherplatz etwas zugeordnet, das keinen Namen hat.

Die Abweichung absichtlich reproduzieren

Führen Sie dies auf einem Test-VPS aus. Alles Folgende verwendet bash und coreutils. Es wird nichts installiert.

Erfassen Sie den Ausgangszustand des Dateisystems, auf dem sich /var/tmp befindet.

cd /var/tmp
df -h .
df --output=used -B1 .

Der zweite Befehl gibt die belegten Bytes ohne Rundung aus. Dadurch ist die Prüfung am Ende exakt.

Erstellen Sie nun eine Datei. Ihre Größe ergibt sich aus dem freien Speicherplatz, den das System selbst meldet. Die Demonstration funktioniert daher unabhängig von der Größe Ihrer Festplatte.

free=$(df --output=avail -B1 . | tail -n 1)
fallocate -l $((free / 10)) ghost.bin
ls -l ghost.bin
df -h .

$(...) ist eine Befehlsersetzung: Die Shell führt den darin enthaltenen Befehl aus. Dessen Ausgabe wird zum Wert von free. Wenn diese Syntax für Sie neu ist, wird sie unter Befehlsersetzung in bash ausführlich erklärt. fallocate reserviert reale Blöcke, ohne Daten hineinzuschreiben. Deshalb wird der Befehl sofort abgeschlossen. Auf einem Dateisystem ohne Unterstützung dafür schlägt der Befehl fehl. head -c $((free / 10)) /dev/zero > ghost.bin erfüllt dann dieselbe Aufgabe, indem es die Bytes schreibt.

Vergleichen Sie diesen df -h . mit dem zuvor erfassten Wert. Die Spalte für den belegten Speicherplatz ist gewachsen. Die Spalte für den verfügbaren Speicherplatz ist kleiner geworden.

Halten Sie die Datei nun von einem anderen Prozess geöffnet und löschen Sie sie anschließend.

sleep infinity < ghost.bin &
holder=$!
rm ghost.bin
ls -l ghost.bin
df -h .
sudo du -xhs . 2>/dev/null

Die Umleitung ist der entscheidende Teil. sleep infinity < ghost.bin & startet einen Hintergrundprozess, dessen Standardeingabe diese Datei ist. Dadurch öffnet die Shell die Datei und übergibt den Dateideskriptor an sleep, das ihn geöffnet hält. $! enthält die Prozess-ID dieses Hintergrundprozesses. rm entfernt anschließend den Dateinamen, während der Dateideskriptor weiterhin geöffnet ist.

Lesen Sie die Ausgabe. ls findet die Datei nicht, weil der Dateiname entfernt wurde. du liegt wieder ungefähr auf dem Ausgangswert, weil es die Dateinamen durchsucht. df hat sich nicht verändert, weil die Blöcke weiterhin belegt sind. Das Dateisystem und der Verzeichnisbaum stimmen jetzt nicht mehr überein. Die Differenz zwischen beiden ist die Datei, die Sie gerade gelöscht haben.

Prozess ermitteln, der die gelöschte Datei geöffnet hält

Jeder geöffnete Dateideskriptor erscheint unter /proc/<pid>/fd/ als symbolischer Link auf die Datei, auf die er verweist. Wurde die Datei entlinkt, markiert der Kernel das Ziel dieses Links als gelöscht. Den Prozess zu ermitteln bedeutet daher, einen Link zu finden, dessen Ziel diese Markierung trägt.

sudo find /proc/[0-9]*/fd -lname '*(deleted)' -printf '%p -> %l\n' 2>/dev/null

-lname vergleicht das Ziel eines symbolischen Links und nicht dessen Namen. %p gibt den Pfad des Deskriptors aus, und %l zeigt, worauf er verweist. Die Prozess-ID ist das zweite Element des ausgegebenen Pfads. Führen Sie den Befehl mit sudo aus, da Sie andernfalls nur /proc/<pid>/fd Ihrer eigenen Prozesse lesen können. Die Umleitung von stderr unterdrückt Meldungen von Prozessen, die beendet werden, während find das Dateisystem durchsucht.

Ein ausgelasteter Server hält jederzeit mehrere gelöschte Dateien geöffnet. Die meisten davon sind klein und unkritisch. Sortieren Sie sie nach Größe, damit nur die relevanten Dateien oben stehen.

sudo bash -c 'for fd in /proc/[0-9]*/fd/*; do
  target=$(readlink "$fd" 2>/dev/null) || continue
  case "$target" in
    *"(deleted)") echo "$(stat -Lc %s "$fd" 2>/dev/null) $fd $target" ;;
  esac
done' | sort -rn | head

stat -L folgt dem Link bis zum Inode selbst. Dadurch gibt %s die Größe der Datei aus, die keinen Namen mehr besitzt. Durch die Sortierung nach dieser Zahl steht die größte Datei an erster Stelle.

Ermitteln Sie anschließend den Prozess hinter dem betreffenden Deskriptor. Der oberste Pfad in dieser Liste enthält beide benötigten Zahlen. Übernehmen Sie sie daher zunächst in Variablen und ersetzen Sie PID und N durch die Werte aus Ihrer eigenen Ausgabe.

pid=PID
n=N
ps -o pid,user,etime,args -p "$pid"
sudo stat -L "/proc/$pid/fd/$n"

ps nennt das Programm und zeigt, wie lange es bereits läuft. stat -L gibt die Größe und die Anzahl der belegten Blöcke des gelöschten Inodes aus. Zusammen beantworten diese Angaben die entscheidende Frage: Welcher Dienst hält diese Datei geöffnet?

Wenn lsof bereits auf dem System vorhanden ist, listet sudo lsof +L1 geöffnete Dateien auf, deren Link-Zähler auf null gesunken ist, und zeigt die Größen in einer Tabelle. Auf einem minimalen Ubuntu-Image ist das Programm nicht vorhanden. Die Installation eines Pakets kann auf einem Dateisystem ohne freien Speicherplatz selbst fehlschlagen. Deshalb ist der Suchlauf mit /proc die Variante, die immer funktioniert.

Speicherplatz ohne Neustart freigeben

Ein Reboot behebt das Problem zwar, ist aber der falsche erste Schritt: Er nimmt den Dienst außer Betrieb und zerstört die Beweise. Es gibt vier schonendere Optionen. Probieren Sie sie in dieser Reihenfolge aus.

Kopieren Sie die Daten zunächst heraus, wenn Sie sie noch benötigen. Das Lesen des Descriptor-Pfads liest den aktiven Inode.

sudo cp /proc/<pid>/fd/<n> /root/recovered.log

Dies ist der eine Fall, in dem sich eine gelöschte Datei leicht wiederherstellen lässt. Deshalb beginnt Dateien wiederherstellen, die mit rm -rf gelöscht wurden mit der Frage, ob ein Prozess die Datei noch geöffnet hält. Sobald der letzte Descriptor geschlossen wird, ist dieser Weg nicht mehr verfügbar.

Leeren Sie die Datei zweitens über den Descriptor. Der Pfad /proc führt zum selben Inode. Durch das Kürzen werden die Blöcke freigegeben, während der Prozess weiterläuft.

sudo truncate -s 0 "/proc/$pid/fd/$n"
df -h /

Das funktioniert zuverlässig, wenn der Writer die Datei im Append-Modus geöffnet hat. Dann wird jeder Schreibvorgang an das aktuelle Dateiende angehängt. War das nicht der Fall, behält der Prozess seinen alten Schreiboffset. Der nächste Schreibvorgang landet dann weit innerhalb der Datei und erstellt sie mit einem Hole am Anfang neu. Ein Hole wird nicht alloziert. Die Blöcke bleiben daher frei, und df behält den Speicherplatz, den es gerade freigegeben hat. Nur die Größe springt zurück: Führen Sie sudo stat -L "/proc/$pid/fd/$n" erneut aus, nachdem der Prozess geschrieben hat. Der alte Größenwert wird dann neben einer Blockanzahl ausgegeben, die nicht mehr dazu passt. Starten Sie den Prozess neu, wenn die Größe ebenfalls bei null beginnen soll.

Bitten Sie den Dienst drittens, seine Logs erneut zu öffnen. Ein Daemon, dessen Logdatei unterhalb des laufenden Prozesses gelöscht wurde, ist die häufigste praktische Variante dieses Problems. Viele Daemons öffnen ihre Logdateien nach einem Signal erneut: nginx verwendet SIGUSR1, rsyslog verwendet SIGHUP. Prüfen Sie die Dokumentation des jeweiligen Daemons, statt zu raten. Ein falsches Signal an den falschen Daemon beendet ihn.

sudo systemctl kill -s USR1 nginx

Starten Sie viertens die Unit neu. sudo systemctl restart <unit> schließt jeden Descriptor, den der alte Prozess geöffnet hatte. Dadurch kommen die Blöcke sicher zurück. In der obigen Demonstration ist der Halter ein sleep, den Sie selbst gestartet haben. Es reicht daher, ihn zu beenden.

kill $holder
df -h .
df --output=used -B1 .
sudo find /proc/[0-9]*/fd -lname '*(deleted)' -printf '%p -> %l\n' 2>/dev/null

Vergleichen Sie die belegten Bytes mit dem Wert, den Sie vor dem Erstellen der Datei aufgezeichnet haben. Die Werte stimmen wieder überein, und find meldet Ihren Descriptor nicht mehr. Die Überprüfung mit demselben Befehl, der das Problem gefunden hat, ist eine nützliche Gewohnheit.

Es ist einfacher, diese Änderung mitzuverfolgen, als df immer wieder manuell auszuführen. watch wiederholt einen Befehl in einem festen Intervall und gibt die Ausgabe an derselben Stelle erneut aus. Dadurch zeigt watch df -h /, wie sich die belegte Spalte ändert, während der Speicherplatz zurückkommt.

Wenn die Summen übereinstimmen, aber der Datenträger weiterhin voll ist

Wenn df und ein root-du -x miteinander übereinstimmen, ist keine gelöschte Datei beteiligt. Die verbleibenden Ursachen sind anderer Art und müssen jeweils separat geprüft werden.

Keine Inodes mehr, obwohl noch Blöcke frei sind

Ein Inode enthält die Metadaten für eine Datei. ext4 erstellt beim Anlegen des Dateisystems eine feste Anzahl von Inodes. Daher können einem Dateisystem die Inodes ausgehen, obwohl noch freie Blöcke vorhanden sind. Neue Dateien können dann nicht erstellt werden, obwohl df -h noch freien Speicherplatz anzeigt.

df -h /
df -i /

Der erste Befehl zählt Blöcke, der zweite Inodes. Vergleichen Sie jeweils die Spalte use. Eine geringe Blockauslastung bei einer Inode-Auslastung am Limit bedeutet, dass sehr viele sehr kleine Dateien vorhanden sind.

df lehnt -i und --output im selben Aufruf ab. Wenn Sie die Rohwerte auslesen oder an einen anderen Befehl übergeben möchten, wählen Sie die Inode-Felder daher nach Namen aus und lassen Sie -i weg.

df --output=itotal,iused,iavail,ipcent /

Diese Spalten enthalten dieselben Abrechnungswerte, die df -i ausgibt, jedoch in einer Form, die Sie gezielt weiterverarbeiten können.

Finden Sie die Dateien, indem Sie Einträge statt Bytes zählen.

sudo du --inodes -x -d 1 / 2>/dev/null | sort -rn | head

Führen Sie denselben Befehl auf der Verzeichnisebene aus, die im vorherigen Schritt an erster Stelle stand. Wiederholen Sie dies, bis Sie den Verzeichnisbaum erreichen, in dem die Dateien erstellt werden. Wenn Ihr du --inodes nicht unterstützt, zählt sudo find /var -xdev -type f | wc -l einen Teilbaum auf die langsamere Weise.

Die Lösung besteht darin, diese Dateien zu löschen oder zu verschieben. Sie können einem vorhandenen ext4-Dateisystem keine Inodes hinzufügen, weil ihre Anzahl beim mkfs festgelegt wird. Eine Erhöhung der Anzahl erfordert daher, das Dateisystem neu zu erstellen und aus einer Sicherung wiederherzustellen. XFS weist Inodes bei Bedarf zu und hat daher nicht dieselbe feste Obergrenze. Ein Rechner, auf dem Container ausgeführt werden, erreicht beide Grenzen früher als die meisten anderen Systeme, weil Image-Layer viele kleine Dateien enthalten. Auf diesem Rechner ist die Bereinigung der Docker-Festplattenbelegung auf einem VPS die konkrete Lösung. Sie gibt deutlich mehr Speicherplatz frei als eine allgemeine Suche im Dateisystem.

Unter einem Mountpoint verborgener Speicher

Ein Verzeichnis kann Dateien enthalten, bevor etwas darauf eingehängt wird. Hängen Sie ein Dateisystem über diesem Verzeichnis ein, bleiben die darunterliegenden Dateien genau dort: Sie belegen weiterhin Speicherplatz, werden weiterhin von df gezählt und sind nicht mehr über ihren Namen erreichbar. du kann sie nicht sehen, weil der Mount die Dateien verdeckt.

Zeigen Sie dies mit tmpfs, das keinen zusätzlichen Festplattenspeicher benötigt. Für diesen Teil benötigen Sie eine Maschine, auf der Sie Mounts durchführen dürfen. Das funktioniert daher auf einem KVM-VPS.

sudo mkdir -p /srv/covered
sudo cp /etc/services /srv/covered/
ls /srv/covered
sudo mount -t tmpfs tmpfs /srv/covered
ls /srv/covered
sudo umount /srv/covered
ls /srv/covered

Der mittlere ls zeigt ein leeres Verzeichnis. Die Kopie wurde nirgendwohin verschoben: Sie befindet sich weiterhin im Root-Dateisystem und erscheint wieder, sobald Sie den Mount aushängen. Stellen Sie sich nun einen Dienst vor, der einen Monat lang in diesen Pfad geschrieben hat, bevor jemand ein Volume darüber eingehängt hat.

Um das auf einem laufenden Server zu finden, hängen Sie das Root-Dateisystem ein zweites Mal an einer anderen Stelle ein. Ein Bind-Mount zeigt ein Dateisystem ohne die darin eingehängten Dateisysteme.

sudo mkdir -p /mnt/rootcheck
sudo mount --bind / /mnt/rootcheck
sudo du -xhs /mnt/rootcheck/* 2>/dev/null | sort -h
sudo umount /mnt/rootcheck

Alles, was in dieser Auflistung erscheint, aber nicht unter dem normalen Pfad, ist unter einem Mountpoint verborgen. Hängen Sie den Bind-Mount anschließend aus. Andernfalls zählt ein späteres du ohne -x dieselben Dateien doppelt.

Für root reservierte Blöcke

ext4 reserviert einen Teil seiner Blöcke für den Benutzer root. Dadurch verhindert das Dateisystem, dass ein volles Laufwerk root an der Anmeldung und der Reparatur des Systems hindert. Ein Prozess eines normalen Benutzers erreicht diese Grenze zuerst, während df weiterhin etwas freien Speicher anzeigt. Lesen Sie die Einstellung für Ihr eigenes Dateisystem aus, anstatt den Standardwert anzunehmen.

dev=$(df --output=source / | tail -n 1)
sudo tune2fs -l "$dev" | grep -i 'block count'

Dieser Befehl gibt die Gesamtzahl der Blöcke und die Anzahl der reservierten Blöcke in denselben Einheiten aus. Das Verhältnis lässt sich daher direkt berechnen. df gibt in der Spalte für verfügbaren Speicher den Platz an, den ein normaler Benutzer noch verwenden darf. Deshalb ergibt die Summe aus belegtem und verfügbarem Speicher einen kleineren Wert als die Größe. Die Differenz ist die Reserve.

Ändern Sie den Wert mit sudo tune2fs -m <percent> "$dev". Die Änderung wird sofort wirksam und erfordert kein erneutes Einhängen. Auf einem separaten Daten-Dateisystem ist es sinnvoll, die Reserve zu verringern. Lassen Sie auf dem Root-Dateisystem genügend freien Speicher, damit root weiterhin schreiben kann. Ein Root-Dateisystem ohne jeglichen freien Speicher ist deutlich schwieriger zu reparieren. tune2fs funktioniert mit ext2, ext3 und ext4. XFS bietet keine entsprechende Einstellung.

Where Sie in Eigenregie irreführt

Vier Eigenschaften von du führen zu Summen, die falsch aussehen.

  • Hardlinks: du zählt einen Inode nur einmal, selbst wenn mehrere Namen auf ihn verweisen. Daher meldet ein Verzeichnisbaum voller Hardlinks weniger als die Summe seiner Dateien.
  • Sparse-Dateien: du meldet die tatsächlich belegten Blöcke, während ls -l die scheinbare Größe meldet. Fügen Sie --apparent-size hinzu, um den jeweils anderen Wert anzuzeigen.
  • Berechtigungen: Wenn Sie den Befehl als normaler Benutzer ausführen, überspringt du alles, was der Benutzer nicht lesen kann, und meldet dadurch einen zu niedrigen Wert. Die ausgegebenen Fehler leiten viele Benutzer nach /dev/null um und lesen sie anschließend nicht mehr.
  • Dateisystemgrenzen: Ohne -x zählt du / jedes unterhalb von / eingehängte Dateisystem mit. Daher kann die Summe höher sein als der von df / gemeldete Wert.

df hat ebenfalls eine wichtige Eigenschaft. Das Programm meldet jedes Dateisystem separat. Führen Sie es daher für den genauen Pfad aus, auf den der fehlschlagende Schreibvorgang zugreift. Ein separates /boot füllt sich nach einem eigenen Zeitplan, während sich Kernelpakete ansammeln. Alte Kernel unter Ubuntu entfernen ist daher eine andere Aufgabe als Speicherplatz auf / freizugeben.

Ein praktikabler Ablauf für einen echten Vorfall

  1. Führen Sie df -h <path> und df -i <path> auf dem Dateisystem aus, auf das der fehlgeschlagene Schreibvorgang zugreifen sollte, und nicht reflexartig auf /.
  2. Führen Sie sudo du -xh -d 1 <mountpoint> 2>/dev/null | sort -h aus und gehen Sie anschließend in das größte Verzeichnis.
  3. Wenn du nicht erklären kann, warum df den belegten Speicherplatz meldet, durchsuchen Sie /proc nach gelöschten Dateien, die noch geöffnet sind.
  4. Wenn beide Ergebnisse übereinstimmen, binden Sie das Dateisystem an einer anderen Stelle ein und suchen Sie nach Dateien unterhalb eines Mount-Punkts.
  5. Wenn die Inode-Nutzung das Limit erreicht, zählen Sie Dateien statt Bytes.

Jeder Schritt verwendet einen Befehl, dessen Ausgabe Sie auswerten können. Das unterscheidet die Fehlerbehebung vom bloßen Raten.

FAQ

Warum zeigt df den Datenträger als voll an, obwohl du deutlich weniger findet?

Der häufigste Grund ist eine Datei, die gelöscht wurde, während ein Prozess sie noch geöffnet hatte. Durch das Löschen wird der Verzeichniseintrag entfernt. Deshalb kann du die Datei nicht mehr über ihren Namen erreichen und zählt sie nicht. Der Inode und seine Blöcke bleiben belegt, bis der letzte Deskriptor geschlossen wird. df zählt belegte Blöcke. Durchsuche /proc/<pid>/fd nach symbolischen Links, deren Ziel als gelöscht markiert ist. Dann findest du sowohl die Datei als auch den Prozess, der sie geöffnet hält. Bevor Sie den Vergleich bewerten, bestätigen Sie, dass Sie du als root und mit -x ausgeführt haben. Ein normaler Benutzer überspringt Verzeichnisse, für die ihm die Leseberechtigung fehlt, ohne Fehlermeldung.

Wie finde ich eine gelöschte, aber noch geöffnete Datei ohne lsof?

Verwenden Sie die eigene Aufzeichnung des Kernels über geöffnete Deskriptoren. sudo find /proc/[0-9]*/fd -lname '*(deleted)' -printf '%p -> %l\n' 2>/dev/null listet jeden Deskriptor auf, der auf eine Datei ohne Namen verweist. Die Prozess-ID steht im ausgegebenen Pfad. sudo stat -Lc %s auf einem dieser Deskriptorpfade gibt deren Größe aus. Sie können die Einträge danach sortieren und den relevanten auswählen. Dafür ist kein Paket erforderlich. Das ist wichtig, weil die Installation eines Pakets auf einem Dateisystem ohne freien Speicherplatz fehlschlagen kann.

Kann ich den Speicherplatz freigeben, ohne den Prozess zu beenden?

Manchmal. sudo truncate -s 0 /proc/<pid>/fd/<n> erreicht denselben Inode über den Deskriptor und gibt seine Blöcke frei, während der Prozess weiterläuft. Das ist am saubersten, wenn der Prozess die Datei im Anhängemodus geöffnet hat, weil seine Schreibvorgänge immer an das aktuelle Ende gehen. Andernfalls bleibt der Schreiboffset an seiner bisherigen Position. Der nächste Schreibvorgang erstellt die Datei dann mit einem Loch am Anfang neu. Dadurch springt die gemeldete Größe wieder nach oben, während die Blöcke unter dem Loch frei bleiben. Ein Neustart der Unit oder ein Signal zum erneuten Öffnen der Logs, wie es in der Dokumentation des Dienstes angegeben ist, behebt das Problem ohne eine Sparse-Datei zu hinterlassen.

df zeigt freien Speicherplatz an, aber Schreibvorgänge schlagen weiterhin fehl. Woran kann es noch liegen?

Prüfen Sie die Inodes mit df -i auf demselben Pfad. Ein Dateisystem mit freien Blöcken, aber ohne freie Inodes lehnt neue Dateien ab. Prüfen Sie, ob der Schreibvorgang als Nicht-root-Benutzer auf einem ext4-Dateisystem ausgeführt wird, auf dem nur noch reservierte Blöcke verfügbar sind. sudo tune2fs -l auf dem Gerät zeigt dies an. Prüfen Sie außerdem, ob Sie das Dateisystem lesen, auf das der Schreibvorgang tatsächlich zugreift. Ein separates /boot oder /var kann unabhängig von / voll laufen.

Warum meldet du eine größere Gesamtsumme als df?

du ohne -x wechselt in jedes Dateisystem, das unter dem angegebenen Pfad eingehängt ist. Dadurch addiert es mehrere Dateisysteme, während df nur eines beschreibt. Bind-Mounts verschärfen das Problem, weil dieselben Dateien unter jedem Pfad gezählt werden, unter dem sie erscheinen. Fügen Sie -x hinzu, damit du auf einem einzelnen Dateisystem bleibt, und übergeben Sie df denselben Pfad. So beschreiben beide Befehle denselben Bereich.