¿Cómo se encuentran los archivos grandes que se han eliminado pero que todavía están abiertos en una aplicación? ¿Cómo se puede eliminar dicho archivo, a pesar de que un proceso lo tiene abierto?
La situación es que estamos ejecutando un proceso que está llenando un archivo de registro a una velocidad excelente. Sé el motivo y puedo solucionarlo. Hasta entonces, me gustaría rm o vaciar el archivo de registro sin cerrar el proceso.
Simplemente haciendo rm output.log
elimina solo las referencias al archivo, pero continúa ocupando espacio en el disco hasta que finaliza el proceso. Peor: después de rm
ing ahora no tengo forma de encontrar dónde está el archivo o qué tan grande es. ¿Hay alguna forma de encontrar el archivo y posiblemente vaciarlo, aunque todavía esté abierto en otro proceso?
Me refiero específicamente a los sistemas operativos basados en Linux como Debian o RHEL.
Si no puede eliminar su aplicación, puede truncar en lugar de eliminar el archivo de registro para recuperar el espacio. Si el archivo no estaba abierto en modo de agregado (con O_APPEND
), El archivo aparecerá tan grande como antes la próxima vez que la aplicación lo escriba (aunque con la parte inicial escasa y pareciendo que contenía NUL bytes), pero el espacio habrá sido reclamado (eso no se aplica a los sistemas de archivos HFS + en Apple OS/X que no admiten archivos dispersos).
Para truncarlo:
: > /path/to/the/file.log
Si ya se eliminó, en Linux, aún puede truncarlo haciendo:
: > "/proc/$pid/fd/$fd"
Donde $pid
Es la identificación del proceso que tiene el archivo abierto, y $fd
Un descriptor de archivo en el que lo tiene abierto (¡que puede verificar con lsof -p "$pid"
.
Si no conoce el pid y está buscando archivos eliminados, puede hacer lo siguiente:
lsof -nP | grep '(deleted)'
lsof -nP +L1
, como lo menciona @ user75021 es una opción aún mejor (más confiable y más portátil) (lista de archivos que tienen menos de 1 enlace).
O (en Linux):
find /proc/*/fd -ls | grep '(deleted)'
O para encontrar los grandes con zsh
:
ls -ld /proc/*/fd/*(-.LM+1l0)
Una alternativa, si la aplicación está vinculada dinámicamente es adjuntarle un depurador y hacer que llame a close(fd)
seguido de un nuevo open("the-file", ....)
.
Vea el inicio rápido aquí: lsof
Quickstart
Me sorprende que nadie haya mencionado el archivo de inicio rápido lsof (incluido con lsof). La sección "3.a" muestra cómo encontrar archivos abiertos no vinculados:
lsof -a +L1 *mountpoint*
P.ej.:
[[email protected] ~]# 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)
En los sistemas Red Hat para encontrar la copia local del archivo de inicio rápido, generalmente hago esto:
[[email protected] ~]# locate -i quickstart |grep lsof
/usr/share/doc/lsof-4.78/00QUICKSTART
... o esto:
[[email protected] ~]# 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
Depende del controlador del sistema de archivos en realidad libre el espacio asignado, y eso generalmente sucederá solo una vez todos los descriptores de archivo que se refieren a ese archivo se liberan. Por lo tanto, realmente no puede reclamar el espacio, a menos que haga que la aplicación cierre el archivo. Lo que significa terminarlo o jugar con él "un poco" en un depurador (por ejemplo, cerrar el archivo y asegurarse de que no se abre/escribe de nuevo, o abrir /dev/null
en su lugar). O podrías hackear el kernel, pero te aconsejaría que no.
Truncar el archivo como sugiere Stephane podría ayudar, pero el resultado real también dependerá de su sistema de archivos (por ejemplo, los bloques preasignados probablemente se liberarán solo después de cerrar el archivo en cualquier caso).
La razón detrás de este comportamiento es que el núcleo no sabría qué hacer con las solicitudes de datos (tanto de lectura como de escritura, pero la lectura es realmente más crítica) dirigida a dicho archivo.