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 rm
ing, 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.
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"
Où $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", ....)
.
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
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.