Suchen und entfernen Sie große Dateien, die geöffnet, aber gelöscht wurden

120

Wie findet man große Dateien, die gelöscht wurden, aber noch in einer Anwendung geöffnet sind? Wie kann man eine solche Datei entfernen, obwohl ein Prozess sie geöffnet hat?

Die Situation ist, dass wir einen Prozess ausführen, der eine Protokolldatei mit einer hervorragenden Geschwindigkeit füllt. Ich kenne den Grund und kann ihn beheben. Bis dahin möchte ich die Protokolldatei speichern oder leeren, ohne den Prozess zu beenden.

Durch einfaches Ausführen werden rm output.lognur Verweise auf die Datei entfernt, der Speicherplatz auf der Festplatte wird jedoch weiterhin belegt, bis der Vorgang beendet wird. Schlimmer noch: rmIch habe jetzt keine Möglichkeit herauszufinden, wo sich die Datei befindet oder wie groß sie ist! Gibt es eine Möglichkeit, die Datei zu finden und möglicherweise zu leeren, obwohl sie in einem anderen Prozess noch geöffnet ist?

Ich beziehe mich speziell auf Linux-basierte Betriebssysteme wie Debian oder RHEL.

dotancohen
quelle
2
Wenn Sie die PID kennen, können Sie die lsof -p <pid>geöffneten Dateien und deren Größe auflisten. (deleted)Neben der gelöschten Datei befindet sich ein . Die gelöschte Datei wird /proc/<pid>/fd/1wahrscheinlich um verlinkt . Ich weiß nicht, wie ich einen Prozess stoppen kann, ohne ihn zu beenden. Ich würde denken, dass das vom Prozess abhängen würde.
donothingsuccessfully
Vielen Dank. Wie kann man die PIDs aller rmnoch geöffneten ed-Dateien erhalten?
Dotancohen
@donothingsuccessfully Das von lsof gemeldete "Deleted" -Tag ist spezifisch für Solaris, in der Tat nur für Solaris 10 oder höher. Das OP hat nicht angegeben, welches Betriebssystem er verwendet. @dotancohen Unter Solaris können Sie die Ausgabe von lsof weiterleiten, um nach gelöschten Dateien zu suchen, z lsof | grep "(deleted)". Wenn keine Prozesse mehr vorhanden sind, bei denen eine gelöschte Datei geöffnet ist, gibt der Kernel die Inode- und Festplattenblöcke frei. Prozesse haben keine "Handler", mit denen sie benachrichtigt werden können, dass eine offene, im Wesentlichen gesperrte Datei von der Festplatte entfernt wurde.
Johan
2
@Johan, das lsof | grep '(deleted)'funktioniert auch unter Linux. Unter Linux können Sie Löschen von Dateien benachrichtigt werden (auch Dateien , die bereits keinen Eintrag andere in einem beliebigen Verzeichnis haben als / proc / some-pid / fd mehr) mit dem inotify Mechanismus (IN_DELETE_SELF Ereignis)
Stéphane Chazelas
Ich habe somefilees in VIM erstellt und geöffnet und es dann rmin einem anderen Bash-Prozess bearbeitet. Ich laufe dann lsof | grep somefileund es ist nicht drin, obwohl die Datei in VIM geöffnet ist.
Dotancohen

Antworten:

141

Wenn Sie Ihre Anwendung nicht beenden können, können Sie die Protokolldatei abschneiden, anstatt sie zu löschen, um den Speicherplatz freizugeben. Wenn die Datei nicht im Anfügemodus (mit O_APPEND) geöffnet war , wird die Datei beim nächsten Schreiben so groß wie zuvor angezeigt (obwohl der führende Teil spärlich ist und so aussieht, als ob er NUL-Bytes enthält), aber der Speicherplatz wird zurückgefordert (dies gilt jedoch nicht für HFS + -Dateisysteme unter Apple OS / X, die keine Sparse-Dateien unterstützen).

So kürzen Sie es:

: > /path/to/the/file.log

Wenn es unter Linux bereits gelöscht wurde, können Sie es dennoch abschneiden, indem Sie folgende Schritte ausführen:

: > "/proc/$pid/fd/$fd"

Wo $pidist die Prozess - ID des Prozesses, der die Datei geöffnet hat, und $fdein Dateideskriptor hat es unter geöffnet (die Sie überprüfen mit kann lsof -p "$pid".

Wenn Sie die PID nicht kennen und nach gelöschten Dateien suchen, können Sie Folgendes tun:

lsof -nP | grep '(deleted)'

lsof -nP +L1, wie von @ user75021 erwähnt, ist eine noch bessere (zuverlässigere und portablere) Option (Dateien mit weniger als 1 Link auflisten ).

Oder (unter Linux):

find /proc/*/fd -ls | grep  '(deleted)'

Oder um die Großen zu finden mit zsh:

ls -ld /proc/*/fd/*(-.LM+1l0)

Eine Alternative, wenn die Anwendung dynamisch verknüpft ist, besteht darin, einen Debugger an sie anzuhängen und ihn aufzurufen, close(fd)gefolgt von einem neuen open("the-file", ....).

Stéphane Chazelas
quelle
1
Es gibt auch einen truncateBefehl, der dasselbe expliziter ausführt.
Tobu
1
@dotancohen Stephane bearbeitet, um Informationen darüber, wie dies zu tun ist, wenn die PID nicht bekannt ist, aufzunehmen.
Didi Kohen
1
@OlivierDulac lsofist wahrscheinlich die Lösung, die einer portablen Lösung am nächsten kommt, mit der Sie offene Dateien auflisten können. Der Debugger-Ansatz zum Schließen des fd unter den Anwendungsfüßen sollte ebenfalls portabel sein.
Stéphane Chazelas
2
@StephaneChazelas: danke. Ich habe eine Möglichkeit gefunden, alle PIDs aufzulisten, bei denen auf jeder Partition eine Datei geöffnet ist: df -k | awk 'NR>1 { print $NF }' | xargs fuser -Vud (und dann einfach Signale an die Täter zu senden, um sie zur Freigabe des fd zu zwingen)
Olivier Dulac
6
Sie können auch verwenden lsof +L1. Auf der lsof-Manpage: "Eine Spezifikation des Formulars +L1wählt offene Dateien aus, die nicht verknüpft wurden. Eine Spezifikation des Formulars +aL1 <file_system>wählt nicht verknüpfte offene Dateien im angegebenen Dateisystem aus." Das sollte ein bisschen zuverlässiger sein als Greifen.
Synchro
31

Überprüfen Sie die Schnellstart - out hier: lsofQuickstart

Ich bin überrascht, dass niemand die lsof-Schnellstartdatei erwähnt hat (in lsof enthalten). Abschnitt "3.a" zeigt, wie offene, nicht verknüpfte Dateien gefunden werden:

lsof -a +L1 *mountpoint*

Z.B:

[root@enterprise ~]# lsof -a +L1 /tmp
COMMAND   PID   USER   FD   TYPE DEVICE    SIZE NLINK  NODE NAME
httpd    2357 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
mysqld   2588  mysql    4u   REG 253,17      52     0  1495 /tmp/ibY0cXCd (deleted)
mysqld   2588  mysql    5u   REG 253,17    1048     0  1496 /tmp/ibOrELhG (deleted)
mysqld   2588  mysql    6u   REG 253,17       0     0  1497 /tmp/ibmDFAW8 (deleted)
mysqld   2588  mysql    7u   REG 253,17       0     0 11387 /tmp/ib2CSACB (deleted)
mysqld   2588  mysql   11u   REG 253,17       0     0 11388 /tmp/ibQpoZ94 (deleted)
httpd    3457   root   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8437 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8438 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8439 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8440 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8441 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8442 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8443 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd    8444 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd   16990 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd   19595 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd   27495 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd   28142 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)
httpd   31478 apache   29u   REG 253,17 3926560     0  1499 /tmp/.NSPR-AFM-3457-9820130.0 (deleted)

Auf Red Hat-Systemen gehe ich normalerweise folgendermaßen vor, um die lokale Kopie der Schnellstartdatei zu finden:

[root@enterprise ~]# locate -i quickstart |grep lsof
/usr/share/doc/lsof-4.78/00QUICKSTART

... oder dieses:

[root@enterprise ~]# rpm -qd lsof
/usr/share/doc/lsof-4.78/00.README.FIRST
/usr/share/doc/lsof-4.78/00CREDITS
/usr/share/doc/lsof-4.78/00DCACHE
/usr/share/doc/lsof-4.78/00DIALECTS
/usr/share/doc/lsof-4.78/00DIST
/usr/share/doc/lsof-4.78/00FAQ
/usr/share/doc/lsof-4.78/00LSOF-L
/usr/share/doc/lsof-4.78/00MANIFEST
/usr/share/doc/lsof-4.78/00PORTING
/usr/share/doc/lsof-4.78/00QUICKSTART
/usr/share/doc/lsof-4.78/00README
/usr/share/doc/lsof-4.78/00TEST
/usr/share/doc/lsof-4.78/00XCONFIG
/usr/share/man/man8/lsof.8.gz
user75021
quelle
1

Es liegt Fahrer auf das Dateisystem tatsächlich befreien den zugewiesenen Speicherplatz, und das wird in der Regel nur einmal passiert alle Dateideskriptoren auf diese Datei beziehen freigegeben werden. Sie können den Speicherplatz also nicht wirklich zurückfordern, es sei denn, Sie veranlassen die Anwendung, die Datei zu schließen. Was bedeutet, dass Sie es entweder beenden oder "ein bisschen" in einem Debugger damit spielen (z. B. die Datei schließen und sicherstellen, dass sie nicht erneut geöffnet / beschrieben wird, oder /dev/nullstattdessen öffnen ). Oder Sie könnten den Kernel hacken, aber ich würde davon abraten.

Das Kürzen der Datei, wie von Stephane vorgeschlagen, kann hilfreich sein, das tatsächliche Ergebnis hängt jedoch auch von Ihrem Dateisystem ab (z. B. werden vorab zugewiesene Blöcke wahrscheinlich erst freigegeben, nachdem Sie die Datei in jedem Fall geschlossen haben).

Der Grund für dieses Verhalten ist, dass der Kernel nicht weiß, was mit Datenanforderungen (Lesen und Schreiben, aber Lesen ist tatsächlich kritischer) zu tun ist, die auf eine solche Datei abzielen.

peterph
quelle
2
Da Linux auf den meisten Dateisystemen Dateien mit geringer Dichte unterstützt, ist das Verhalten genau definiert und der Festplattentreiber kann wirklich Speicherplatz freigeben. Ich habe es für ext3 und ext4 getestet und es funktioniert so, wie Stephane es geschrieben hat.
Jofel
1
Was lässt Sie sagen, dass beim Abschneiden einer Datei vorab zugewiesene Blöcke nicht wiederhergestellt werden? Abschneiden ist dazu gedacht, die Zuordnung von Daten aufzuheben. Ich glaube nicht, dass dies eine Unklarheit darstellt.
Stéphane Chazelas
1
Das Dateisystem behält möglicherweise die zugewiesenen Blöcke bei, um später Zeit zu sparen (insbesondere, wenn die Datei noch geöffnet ist), insbesondere, wenn sie vor dem Abschneiden groß genug war. Zumindest scheint XFS dies zu tun.
Peterph
Vielen Dank, Peter. Ich freue mich, dass Sie in diesem Beitrag das "Warum" ansprechen.
Dotancohen
2
Soweit ich das beurteilen kann, beansprucht das Abschneiden offener Dateien auch Speicherplatz in XFS. Getestet mit normalen Dateien und Dateien, die unter fallocateLinux 4.9 zugewiesen wurden . Können Sie bitte klären, unter welchen Dateisystemen und Bedingungen das Abschneiden einer Datei keinen Speicherplatz beansprucht?
Stéphane Chazelas