Disco cheio mas df mostra espaco: Handles de arquivos deletados e exaustao de inodes

Disco cheio mas df mostra espaco: Handles de arquivos deletados e exaustao de inodes

O que voce vai aprender

  • Por que voce recebe No space left on device mesmo quando df mostra espaco livre
  • Por que df reporta disco cheio mas o total do du e muito menor (ocupacao por arquivo deletado)
  • Como dividir as duas direcoes da discrepancia com lsof e df -i, e recuperar espaco com seguranca

Resumo rapido

  • df -h cheio mas du e pequeno -> um processo mantem um arquivo deletado aberto. Encontre com lsof +L1, depois reinicie o servico ou trunque o fd
  • df -h mostra espaco mas escritas falham -> exaustao de inodes (verifique df -i) ou blocos reservados (nao-root nao consegue escrever)

Premissas (ambiente alvo)

  • SO: Ubuntu / familia Debian (ext4 assumido para tune2fs)
  • Shell: bash
  • Privilegios: sudo disponivel

Por que df discorda do espaco real livre?

Conclusao: df apenas le os contadores agregados no superbloco do filesystem, entao um inode deletado-mas-aberto ou uma tabela de inodes esgotada nunca aparece na porcentagem de capacidade.

df nao percorre diretorios; ele le os contadores que o filesystem mantem (blocos livres, inodes livres). du em vez disso percorre caminhos reais e soma seus tamanhos. Essa diferenca de implementacao e a raiz da discrepancia, e aparece em tres padroes tipicos.

Sintoma Causa raiz Comando
df cheio, du pequeno Processo mantem arquivo deletado aberto lsof +L1
df tem espaco, escritas falham Exaustao de inodes df -i
df mostra ~5% livre, nao-root nao escreve Blocos reservados tune2fs -l

A ideia chave: capacidade (blocos) e inodes sao contadores separados. Esgote qualquer um deles e voce recebe No space left on device.

Como verificar se um arquivo deletado esta ocupando espaco?

Conclusao: lsof +L1 lista arquivos que ainda estao abertos mas tem link count de 0 (deletados); um SIZE grande em uma dessas linhas e exatamente o que causa a discrepancia entre df e du.

Executar rm nao libera um inode enquanto um processo ainda tem o arquivo aberto, entao seus blocos nunca sao recuperados. O caso classico: um log foi deletado com rm, mas o servico continua escrevendo nele.

$ sudo lsof +L1

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

Voce tambem 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 mantem um log deletado de 8 GB aberto. O resultado: df esta cheio, mas du /var/log parece pequeno.

Anote o PID e FD (aqui PID 1234 / FD 5). Voce vai precisar deles no passo de liberacao abaixo.

Como liberar o espaco mantido?

Conclusao: a correcao limpa e reiniciar (ou recarregar) o processo ofensor. Se voce precisa de espaco imediatamente, trunque /proc/PID/fd/N para zero bytes para recuperar sem reiniciar.

Opcao A: reiniciar / recarregar o processo (recomendado)

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

$ sudo systemctl restart nginx

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

Opcao B: truncar o fd quando nao pode reiniciar

Se o servico 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 sao perdidos, mas o processo continua rodando e o espaco e recuperado imediatamente.

Como verificar exaustao de inodes?

Conclusao: Quando df -i mostra IUse% em 100%, escritas falham mesmo com capacidade livre; localize o diretorio com muitos arquivos pequenos usando find e faca limpeza.

Se df -h mostra espaco 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 exaustao de inodes. Encontre onde os muitos arquivos pequenos estao:

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

Culpados comuns sao arquivos de sessao, filas de email e fragmentos de cache (/var/lib/php/sessions, /var/spool, grandes quantidades de arquivos pequenos). Para limpeza detalhada, veja Corrigindo exaustao de inodes.

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

Conclusao: ext4 reserva 5% dos blocos para root por padrao, entao processos nao-root recebem ENOSPC mesmo quando df mostra espaco livre; verifique e ajuste a reserva com tune2fs.

ext4 reserva 5% do filesystem para root por padrao (para manter o sistema recuperavel). Aplicacoes nao-root recebem ENOSPC mesmo quando df mostra espaco.

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

Em uma particao somente de dados voce pode reduzir a reserva para recupera-la (nao reduza muito no filesystem raiz):

$ sudo tune2fs -m 1 /dev/sda1

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

Como prevenir recorrencia?

Conclusao: 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 verificacoes de rotina, nao apenas df.

  • Logs inchados: configure logrotate com copytruncate, ou sinalize o servico corretamente apos rotacao (nunca apenas rm no log ativo)
  • Monitoramento de inodes: adicione df -i ao monitoramento. Observar apenas capacidade (%) nao detecta exaustao de inodes
  • Verificar antes de deletar: execute lsof <arquivo> antes de remover um arquivo grande para ver quem o tem aberto

A rotina confiavel e sempre olhar os tres: df -h para capacidade, df -i para inodes, e lsof +L1 para ocupacao por arquivo deletado.

Proximas leituras