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 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 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 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 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 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 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
ducomo 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 +L1necesita privilegios para ver descriptores de otros usuarios. Sinsudoobtendrá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 0en logs vivos, o configura logrotate concopytruncate.
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
- «¿Quién se está comiendo mi CPU?» — monitorización en lenguaje natural
- Barre logs y backups antiguos con una frase
- Borrar archivos de más de 30 días en Linux, con seguridad
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.