Disco cheio mas df mostra espaço: Handles de arquivos deletados e exaustão de inodes

Disco cheio mas df mostra espaço: Handles de arquivos deletados e exaustão de inodes

O que você vai aprender

  • Por que você recebe No space left on device mesmo quando df mostra espaço livre
  • Por que df reporta disco cheio mas o total do du é muito menor (ocupação por arquivo deletado)
  • Como dividir as duas direções da discrepância com lsof e df -i, e recuperar espaço com segurança

Resumo rápido

  • df -h cheio mas du é pequeno -> um processo mantém um arquivo deletado aberto. Encontre com lsof +L1, depois reinicie o serviço ou trunque o fd
  • df -h mostra espaço mas escritas falham -> exaustão de inodes (verifique df -i) ou blocos reservados (não-root não consegue escrever)

Premissas (ambiente alvo)

  • SO: Ubuntu / família Debian (ext4 assumido para tune2fs)
  • Shell: bash
  • Privilégios: sudo disponível

Por que df discorda do espaço real livre?

Conclusão: df apenas lê os contadores agregados no superbloco do filesystem, então um inode deletado-mas-aberto ou uma tabela de inodes esgotada nunca aparece na porcentagem de capacidade.

df não percorre diretórios; ele lê os contadores que o filesystem mantém (blocos livres, inodes livres). du em vez disso percorre caminhos reais e soma seus tamanhos. Essa diferença de implementação é a raiz da discrepância, e aparece em três padrões típicos.

Sintoma Causa raiz Comando
df cheio, du pequeno Processo mantém arquivo deletado aberto lsof +L1
df tem espaço, escritas falham Exaustão de inodes df -i
df mostra ~5% livre, não-root não escreve Blocos reservados tune2fs -l

A ideia chave: capacidade (blocos) e inodes são contadores separados. Esgote qualquer um deles e você recebe No space left on device.

Como verificar se um arquivo deletado está ocupando espaço?

Conclusão: lsof +L1 lista arquivos que ainda estão abertos mas têm link count de 0 (deletados); um SIZE grande em uma dessas linhas é exatamente o que causa a discrepância entre df e du.

Executar rm não libera um inode enquanto um processo ainda tem o arquivo aberto, então seus blocos nunca são recuperados. O caso clássico: um log foi deletado com rm, mas o serviço continua escrevendo nele.

$ sudo lsof +L1

+L1 mostra apenas arquivos abertos cujo link count está abaixo de 1 (ou seja, 0, deletado). Procure linhas onde NLINK é 0 e SIZE é grande.

Você também pode fazer grep pelo marcador deleted:

$ sudo lsof -nP / 2>/dev/null | grep '(deleted)'
COMMAND   PID  USER   FD   TYPE DEVICE     SIZE/OFF NODE NAME
nginx    1234  root    5w  REG  259,1   8589934592  131 /var/log/nginx/access.log (deleted)

Aqui o nginx ainda mantém um log deletado de 8 GB aberto. O resultado: df está cheio, mas du /var/log parece pequeno.

Anote o PID e FD (aqui PID 1234 / FD 5). Você vai precisar deles no passo de liberação abaixo.

Como liberar o espaço mantido?

Conclusão: a correção limpa é reiniciar (ou recarregar) o processo ofensor. Se você precisa de espaço imediatamente, trunque /proc/PID/fd/N para zero bytes para recuperar sem reiniciar.

Opção A: reiniciar / recarregar o processo (recomendado)

Uma vez que o fd aberto é fechado, o inode é liberado e os blocos retornam instantaneamente.

$ sudo systemctl restart nginx

Para arquivos de log, muitos serviços reabrem seus arquivos no reload (systemctl reload nginx) em vez de um reinicio completo.

Opção B: truncar o fd quando não pode reiniciar

Se o serviço deve permanecer ativo, trunque o arquivo ainda aberto via /proc/<PID>/fd/<FD>.

$ sudo truncate -s 0 /proc/1234/fd/5

: > /proc/1234/fd/5 faz o mesmo. Os dados são perdidos, mas o processo continua rodando e o espaço é recuperado imediatamente.

Como verificar exaustão de inodes?

Conclusão: Quando df -i mostra IUse% em 100%, escritas falham mesmo com capacidade livre; localize o diretório com muitos arquivos pequenos usando find e faça limpeza.

Se df -h mostra espaço mas escritas ainda falham, suspeite de inodes.

$ df -i
Filesystem      Inodes  IUsed   IFree IUse% Mounted on
/dev/sda1      6553600 6553600     0  100% /

IUse% em 100% significa exaustão de inodes. Encontre onde os muitos arquivos pequenos estão:

$ sudo find / -xdev -type f 2>/dev/null | cut -d/ -f1-3 | sort | uniq -c | sort -n | tail

Culpados comuns são arquivos de sessão, filas de email e fragmentos de cache (/var/lib/php/sessions, /var/spool, grandes quantidades de arquivos pequenos). Para limpeza detalhada, veja Corrigindo exaustão de inodes.

Por que df mostra ~5% livre mas escritas ainda falham?

Conclusão: ext4 reserva 5% dos blocos para root por padrão, então processos não-root recebem ENOSPC mesmo quando df mostra espaço livre; verifique e ajuste a reserva com tune2fs.

ext4 reserva 5% do filesystem para root por padrão (para manter o sistema recuperável). Aplicações não-root recebem ENOSPC mesmo quando df mostra espaço.

$ sudo tune2fs -l /dev/sda1 | grep -i 'reserved block'
Reserved block count:     6553600

Em uma partição somente de dados você pode reduzir a reserva para recuperá-la (não reduza muito no filesystem raiz):

$ sudo tune2fs -m 1 /dev/sda1

-m 1 define a reserva para 1%. Mantenha o padrão de 5% em /.

Como prevenir recorrência?

Conclusão: Rotacione logs com logrotate copytruncate ou um hook de reload correto para que arquivos sejam reabertos, e monitore inodes; adicione df -i e lsof +L1 as suas verificações de rotina, não apenas df.

  • Logs inchados: configure logrotate com copytruncate, ou sinalize o serviço corretamente após rotação (nunca apenas rm no log ativo)
  • Monitoramento de inodes: adicione df -i ao monitoramento. Observar apenas capacidade (%) não detecta exaustão de inodes
  • Verificar antes de deletar: execute lsof <arquivo> antes de remover um arquivo grande para ver quem o tem aberto

A rotina confiável é sempre olhar os três: df -h para capacidade, df -i para inodes, e lsof +L1 para ocupação por arquivo deletado.

Próximas leituras