Volver al inicio

df du difieren: buscar archivos eliminados Linux

En Linux la discrepancia de df y du ocurre debido a archivos eliminados mantenidos por descriptores de procesos abiertos. El artículo explica mecánicas de inode, búsqueda vía lsof +L1 y liberación de espacio con > /proc/PID/fd/FD sin reinicio. Recomendaciones sobre logrotate copytruncate y monitoreo.

¿df miente? No, buscar archivos eliminados en lsof
Advertisement 728x90

Por qué df y du no coinciden: Encontrando gigabytes ocultos en Linux

El comando df -h muestra un uso del disco del 95%, mientras que du -sh /* suma solo el 20%. El 75% restante es invisible para du pero ocupa bloques del disco. La razón son los descriptores de archivos abiertos por procesos que apuntan a archivos eliminados. df lee el superbloque del sistema de archivos directamente, du recorre el árbol de directorios e ignora los archivos sin entradas en él.

Un inodo almacena metadatos del archivo, incluida la lista de bloques de datos. rm solo elimina la entrada del directorio (enlace físico), el contador de enlaces del inodo disminuye, pero si un proceso mantiene un descriptor, los bloques permanecen asignados.

Diagrama:

Google AdInline article slot
Antes de rm:
directorio        inodo          bloques
/var/log/  --> app.log  -->  [bloque1][bloque2]
               ^
               descriptor de nginx (pid 1234, fd 7)

Después de rm:
directorio        inodo          bloques
/var/log/  --> (eliminado) -->  [bloque1][bloque2]
               ^
               descriptor de nginx

du no ve el archivo en /var/log/, df registra los bloques ocupados.

Casos clásicos del problema

Rotación de logs: logrotate ejecuta rm en un archivo antiguo, pero nginx o java mantienen un descriptor desde el inicio. El proceso escribe en el archivo eliminado, df registra un mayor uso, du no.

Otros escenarios:

Google AdInline article slot
  • Demonios de larga duración con logs abiertos.
  • Errores en scripts de limpieza donde rm precede al cierre del descriptor.
  • Contenedores Docker donde procesos internos mantienen archivos del host.

El problema se acumula: los gigabytes desaparecen sin ser notados hasta que el disco se llena.

Encontrar procesos con archivos eliminados

Usa lsof +L1 para archivos con NLINK < 1 (eliminados del sistema de archivos pero abiertos):

COMANDO  PID  USUARIO  FD  TIPO  DISPOSITIVO  TAMAÑO/OFF  NLINK  NODO  NOMBRE
nginx   1234  www   7w  REG   8,1  2147483648  0  12345  /var/log/app.log (eliminado)
java    5678  app   3w  REG   8,1   536870912  0  67890  /var/log/service.log (eliminado)

Campos clave:

Google AdInline article slot
  • COMANDO/PID: proceso e ID.
  • FD: descriptor (7w — escritura, número 7).
  • TAMAÑO/OFF: tamaño — fuente de los GB perdidos.
  • NLINK=0: confirmación de eliminación.
  • NOMBRE (eliminado): ruta antes de rm.

Filtro por tamaño: lsof +L1 | awk '$7 > 104857600 {print}' (archivos >100MB).

Liberar espacio sin reiniciar

Para proceso PID 1234, FD 7:

$ > /proc/1234/fd/7

/proc es procfs en memoria. El comando pone a cero el archivo a través del descriptor, el kernel libera bloques al instante. df se actualiza, el proceso continúa escribiendo en fd 7.

Verificar: lsof +L1 | grep 1234 — TAMAÑO/OFF=0 o vacío.

Automatización con script:

#!/bin/bash
lsof +L1 | awk '$7 > 104857600 && $9 ~ /eliminado/ {print $2, $8}' | while read pid fd; do
  echo "Poniendo a cero $pid/$fd"
  > /proc/$pid/fd/$fd
  echo "Espacio liberado"
done

Prevenir el problema en logrotate

Evitar rm en la rotación. En /etc/logrotate.d/app:

/var/log/app.log {
    daily
    rotate 7
    compress
    copytruncate
}

copytruncate copia el log, luego trunca el original (mecanismo >). El descriptor no cambia.

Desventaja: micro-retraso en la copia — posible pérdida de líneas.

Alternativa sin pérdidas:

  • logrotate: mv antiguo → nuevo archivo.
  • kill -HUP <pid> (SIGHUP para reabrir log).

nginx: nginx -s reopen. systemd: systemctl reload nginx.

Monitoreo y alertas

Script de verificación:

lsof +L1 -F s | awk '/^s/ && substr($0,2)+0 > 104857600 {count++} END {print count+0}'

Devuelve el conteo de archivos eliminados >100MB.

Integración con Prometheus:

  • node_filefd_allocated — crecimiento de fd abiertos.
  • Comparar df/disk_used vs suma de du.

Cron cada 5 min: alertar si discrepancia >10%.

Conclusiones clave

  • df muestra bloques asignados desde el superbloque, du muestra archivos visibles en el directorio.
  • lsof +L1 encuentra procesos con archivos (eliminados) por NLINK=0.
  • Liberar espacio: > /proc/PID/fd/FD — poner a cero sin reiniciar.
  • copytruncate de logrotate previene el problema sin HUP.
  • Monitoreo: scripts con lsof o métricas de node_exporter.

— Editorial Team

Advertisement 728x90

Leer después