web-dev-qa-db-fra.com

Rechercher et supprimer des fichiers volumineux qui sont ouverts mais qui ont été supprimés

Comment trouve-t-on des fichiers volumineux qui ont été supprimés mais qui sont toujours ouverts dans une application? Comment peut-on supprimer un tel fichier, même si un processus l'a ouvert?

La situation est que nous exécutons un processus qui remplit un fichier journal à un rythme formidable. Je connais la raison et je peux la réparer. Jusque-là, je voudrais rm ou vider le fichier journal sans arrêter le processus.

Faire simplement rm output.log supprime uniquement les références au fichier, mais il continue d'occuper de l'espace sur le disque jusqu'à la fin du processus. Pire: après rming, je n'ai plus aucun moyen de trouver où se trouve le fichier ou sa taille! Existe-t-il un moyen de trouver le fichier, et éventuellement de le vider, même s'il est toujours ouvert dans un autre processus?

Je me réfère spécifiquement aux systèmes d'exploitation basés sur Linux tels que Debian ou RHEL.

124
dotancohen

Si vous ne pouvez pas tuer votre application, vous pouvez tronquer au lieu de supprimer le fichier journal pour récupérer l'espace. Si le fichier n'était pas ouvert en mode ajout (avec O_APPEND), Le fichier apparaîtra comme avant la prochaine fois que l'application y écrit (mais avec la partie principale clairsemée et semblant contenir NUL octets), mais l'espace aura été récupéré (cela ne s'applique pas aux systèmes de fichiers HFS + sur Apple OS/X qui ne prend pas en charge les fichiers rares cependant).

Pour le tronquer:

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

S'il a déjà été supprimé, sous Linux, vous pouvez toujours le tronquer en faisant:

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

$pid Est l'ID de processus du processus qui a ouvert le fichier, et $fd Un descripteur de fichier sous lequel il est ouvert (que vous pouvez vérifier avec lsof -p "$pid".

Si vous ne connaissez pas le pid et que vous recherchez des fichiers supprimés, vous pouvez faire:

lsof -nP | grep '(deleted)'

lsof -nP +L1, comme mentionné par @ user75021 est une option encore meilleure (plus fiable et plus portable) (liste des fichiers qui ont moins de 1 lien).

Ou (sous Linux):

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

Ou pour trouver les grands avec zsh:

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

Une alternative, si l'application est liée dynamiquement, est d'y attacher un débogueur et de le faire appeler close(fd) suivi d'un nouveau open("the-file", ....).

146
Stéphane Chazelas

Consultez le démarrage rapide ici: lsof Démarrage rapide

Je suis surpris que personne n'ait mentionné le fichier de démarrage rapide lsof (inclus avec lsof). La section "3.a" montre comment trouver des fichiers ouverts non liés:

lsof -a +L1 *mountpoint*

Par exemple.:

[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)

Sur les systèmes Red Hat pour trouver la copie locale du fichier de démarrage rapide, je fais généralement ceci:

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

... ou ca:

[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
36
user75021

Il appartient au pilote du système de fichiers de --- gratuit l'espace alloué, et cela ne se produit généralement qu'une seule fois tous les descripteurs de fichiers faisant référence à ce fichier sont publiés. Vous ne pouvez donc pas vraiment récupérer l'espace, sauf si vous fermez l'application le fichier. Ce qui signifie soit le terminer ou jouer avec lui "un peu" dans un débogueur (par exemple, fermer le fichier et s'assurer qu'il n'est pas ouvert/réécrit, ou ouvrir /dev/null au lieu). Ou vous pouvez pirater le noyau, mais je déconseille cela.

Tronquer le fichier comme le suggère Stéphane pourrait aider, mais le résultat réel dépendra également de votre système de fichiers (par exemple, les blocs pré-alloués ne seront probablement libérés qu'après avoir fermé le fichier dans tous les cas).

La raison derrière ce comportement est que le noyau ne sait pas quoi faire des demandes de données (à la fois en lecture et en écriture, mais la lecture est en fait plus critique) ciblant un tel fichier.

1
peterph