CLI AI

df dice que el disco está lleno y du dice que no

2026-05-20

Los dos. df pregunta al sistema de archivos cuántos bloques están asignados; du recorre el árbol de directorios y suma lo que ve. Cuando esos dos no coinciden, algo retiene espacio que ya no tiene nombre. Así se encuentra.

1. Confirmar la discrepancia

clai
$ clai compara lo que df dice de / con lo que du encuentra realmente ahí→ df -h / && du -shx / 2>/dev/nullFilesystem      Size  Used Avail Use% Mounted on/dev/nvme1n1p2  915G  871G   44G  96% /348G	/

871 GB ocupados, 348 GB encontrados. Esa diferencia es todo el problema. -x evita que du se meta en otros sistemas de archivos montados e infle su propia respuesta.

2. Mira los inodos antes de perseguir bytes

clai
$ clai comprueba si al sistema de archivos le faltan inodos en vez de espacio→ df -i /Filesystem        Inodes   IUsed      IFree IUse% Mounted on/dev/nvme1n1p2 124960768 3634368  121326400    3% /

Si IUse% está al 100% y Use% no, tienes millones de archivos diminutos y ningún inodo libre. Es otro problema: hay sitio en el disco, pero el sistema de archivos no tiene dónde anotar otro archivo.

3. Encontrar los archivos borrados que siguen abiertos

clai
$ clai muestra archivos que fueron borrados pero un proceso sigue teniendo abiertos→ sudo lsof +L1COMMAND    PID USER   FD   TYPE DEVICE   SIZE/OFF NLINK  NODE NAMEpython3  23435 app     3u   REG  259,2 1000000000     0 41231 /var/log/app/debug.log (deleted)

NLINK 0 es la firma: ninguna entrada de directorio apunta ya a ese archivo, así que du no lo ve, pero los bloques siguen asignados hasta que se cierre el último descriptor. Casi siempre es un log que alguien borró sin reiniciar el servicio que escribe en él.

4. Recuperar el espacio

clai
$ clai reinicia el servicio que retiene ese archivo borrado→ sudo systemctl restart app.service

Reiniciar el proceso cierra el descriptor y el kernel libera los bloques al instante. df baja en el momento — sin desmontar y sin reiniciar la máquina.

5. Si ahora mismo no puedes reiniciarlo

clai
$ clai vacía el archivo borrado que el pid 23435 mantiene en el descriptor 3→ sudo truncate -s 0 /proc/23435/fd/3

Escribir a través de /proc/<pid>/fd/<n> vacía el archivo en el que el proceso sigue escribiendo, sin matarlo. El proceso conserva su descriptor y sigue registrando; tú recuperas el espacio ya.

6. El otro clásico: un punto de montaje que tapa archivos

clai
$ clai comprueba si hay algo montado sobre un directorio que aún tiene archivos debajo→ sudo mount --bind / /mnt/root && du -shx /mnt/root/var14G	/mnt/root/var

Si se escribió en /var/data antes de montar un disco ahí, esos archivos siguen en el sistema de archivos raíz, ocupando espacio que nadie ve a través del montaje. Un bind mount de / los saca a la luz.

Trampas

  • Ejecuta du como root. Como usuario normal se salta en silencio los directorios que no puede leer, y culparás a un fantasma de lo que en realidad son permisos.
  • lsof +L1 necesita privilegios para ver descriptores de otros usuarios. Sin sudo obtendrás una lista corta y engañosamente limpia.
  • No vuelvas a borrar un log activo. Eso es lo que creó esta situación. Usa truncate -s 0 en logs vivos, o configura logrotate con copytruncate.

Preguntas relacionadas

¿Por qué no vuelve el espacio tras un rm? En Unix, desenlazar borra el nombre, no los datos. Los bloques se liberan cuando se cierra el último descriptor abierto, lo que para un servicio en marcha significa nunca, hasta que reinicie.

du y df difieren en un pequeño porcentaje, ¿es un problema? No. Son los bloques reservados (5% para root por defecto en ext4) más los metadatos. Solo merecen investigación las diferencias grandes.

¿Puedo encontrarlo sin lsof? Sí: sudo ls -l /proc/*/fd 2>/dev/null | grep deleted muestra lo mismo a través de la tabla de procesos.

Ver también

Deja de buscar flags de lsof a las 3 de la mañana: describe el problema y CliAI escribe el comando. Instálalo en una línea.