SSD Nodes Learn Hosting plans →
Guias Matt ConnorPor Matt Connor · Atualizado 2026-08-24

df cheio e du diferente: onde está o espaço?

Veja por que df indica disco cheio e du não encontra o espaço: localize ficheiros apagados ainda abertos por processos e verifique inodes, mounts e blocos reservados.

Verified Every command ran end-to-end on a fresh Ubuntu 24.04 server, August 15, 2026.

Por que df indica disco cheio e du mostra outra coisa

df indica que o disco está cheio, enquanto du não encontra o espaço porque um processo ainda mantém aberto um ficheiro que foi eliminado. Eliminar um ficheiro remove o respetivo nome do diretório. Os blocos de dados só são libertados quando o último descritor de ficheiro aberto que aponta para esse inode é fechado. du percorre os nomes, por isso não contabiliza esse ficheiro. df consulta ao sistema de ficheiros quantos blocos estão alocados, por isso continua a contabilizar o ficheiro que já não tem nome.

Este guia reproduz o problema numa VPS Ubuntu simples, com ferramentas que já estão instaladas, identifica o processo que mantém o ficheiro aberto através de /proc e liberta o espaço sem reiniciar o sistema. Também são abordadas as outras causas do mesmo sintoma: uma tabela de inodes sem entradas livres, ficheiros ocultos sob um ponto de montagem e blocos reservados para root.

Execute cada comando e leia o resultado apresentado no seu sistema. Os valores dependem do seu disco. Compare o estado antes e depois na sua própria máquina, em vez de o comparar com um valor apresentado num guia.

O que df contabiliza e o que du contabiliza

df (disk free) consulta cada sistema de ficheiros montado para obter os próprios dados contabilísticos: quantos blocos existem, quantos estão alocados e quantos estão livres. Nunca abre um diretório. A resposta inclui todos os blocos alocados, incluindo os blocos pertencentes a um ficheiro para o qual nenhuma entrada de diretório aponta.

du (disk usage) faz o oposto. Começa no caminho que indicar, lê os diretórios, obtém os dados de cada entrada encontrada e soma os blocos. Um ficheiro sem nome fica invisível para o comando. O mesmo acontece com qualquer diretório que não tenha permissão para ler, razão pela qual um utilizador normal obtém um total inferior ao de root. Execute du com sudo antes de tirar conclusões da comparação.

Duas opções são importantes sempre que compara os dois comandos.

  • -x mantém du num único sistema de ficheiros. Sem esta opção, du / entra em todos os sistemas de ficheiros montados abaixo de / e produz um total que df / nunca estava a contabilizar.
  • -s imprime uma linha de resumo por argumento, em vez de uma linha por diretório.

Assim, pode executar o par lado a lado no sistema de ficheiros que pretende analisar.

df -h /
sudo du -xhs / 2>/dev/null

df responde imediatamente. du demora minutos num sistema de ficheiros grande, porque obtém os dados de cada ficheiro durante o percurso. Quando os dois totais são muito diferentes e du foi executado como root com -x, o espaço em falta está alocado a algo que não tem nome.

Reproduza a discrepância de propósito

Faça isto numa VPS de teste. Tudo o que se segue usa bash e coreutils, por isso não é instalado nada.

Registe o estado inicial do sistema de ficheiros que contém /var/tmp.

cd /var/tmp
df -h .
df --output=used -B1 .

O segundo comando apresenta os bytes utilizados sem arredondamento. Isto torna a verificação final exata.

Agora crie um ficheiro. O tamanho é calculado a partir do espaço livre indicado pela própria máquina. Assim, a demonstração adapta-se ao disco que tiver.

free=$(df --output=avail -B1 . | tail -n 1)
fallocate -l $((free / 10)) ghost.bin
ls -l ghost.bin
df -h .

$(...) é substituição de comandos: a shell executa o comando dentro dela e o resultado passa a ser o valor de free. Se esta sintaxe for nova para si, a substituição de comandos em bash explica-a corretamente. fallocate reserva blocos reais sem os escrever, razão pela qual termina imediatamente. Num sistema de ficheiros que não suporte esta operação, o comando falha. head -c $((free / 10)) /dev/zero > ghost.bin faz o mesmo trabalho ao escrever os bytes.

Compare este df -h . com o que registou. A coluna de espaço utilizado aumentou e a coluna de espaço disponível diminuiu.

Agora mantenha o ficheiro aberto por outro processo e elimine-o.

sleep infinity < ghost.bin &
holder=$!
rm ghost.bin
ls -l ghost.bin
df -h .
sudo du -xhs . 2>/dev/null

O redirecionamento é todo o mecanismo. sleep infinity < ghost.bin & inicia um processo em segundo plano cuja entrada padrão é esse ficheiro. A shell abre o ficheiro e entrega o descritor a sleep, que o mantém aberto. $! contém o ID do processo dessa tarefa em segundo plano. rm remove então o nome enquanto o descritor continua aberto.

Leia o resultado. ls não encontra o ficheiro porque o nome desapareceu. du volta para perto do valor inicial porque percorre os nomes. df não mudou porque os blocos continuam alocados. O sistema de ficheiros e a árvore de diretórios estão agora em desacordo. A diferença entre ambos é o ficheiro que acabou de eliminar.

Localizar o processo que mantém o ficheiro eliminado aberto

Cada descritor de ficheiro aberto aparece em /proc/<pid>/fd/ como uma ligação simbólica para o ficheiro a que se refere. Quando o ficheiro é desvinculado, o kernel marca o destino dessa ligação como eliminado. Portanto, para localizar o processo, é necessário encontrar uma ligação cujo destino contenha essa marca.

sudo find /proc/[0-9]*/fd -lname '*(deleted)' -printf '%p -> %l\n' 2>/dev/null

-lname corresponde ao destino de uma ligação simbólica, e não ao seu nome. %p mostra o caminho do descritor, e %l mostra para onde aponta. O ID do processo é o segundo elemento do caminho apresentado. Execute o comando com sudo, porque, caso contrário, só poderá ler /proc/<pid>/fd nos seus próprios processos. O redirecionamento de stderr elimina as mensagens dos processos que terminam enquanto find percorre o sistema de ficheiros.

Um servidor ocupado mantém vários ficheiros eliminados abertos a qualquer momento, e a maioria é pequena e inofensiva. Ordene-os por tamanho para manter no topo apenas os que são relevantes.

sudo bash -c 'for fd in /proc/[0-9]*/fd/*; do
  target=$(readlink "$fd" 2>/dev/null) || continue
  case "$target" in
    *"(deleted)") echo "$(stat -Lc %s "$fd" 2>/dev/null) $fd $target" ;;
  esac
done' | sort -rn | head

stat -L segue a ligação até ao próprio inode, por isso %s apresenta o tamanho do ficheiro que já não tem um nome. Ordenar por esse número coloca o maior ficheiro em primeiro lugar.

Em seguida, identifique o processo associado ao descritor encontrado. O caminho no topo da lista contém os dois números necessários. Atribua-os primeiro a variáveis, substituindo PID e N pelos valores apresentados na sua própria listagem.

pid=PID
n=N
ps -o pid,user,etime,args -p "$pid"
sudo stat -L "/proc/$pid/fd/$n"

ps identifica o programa e mostra há quanto tempo está em execução. stat -L apresenta o tamanho e o número de blocos alocados do inode eliminado. Em conjunto, estes dados respondem à pergunta importante: qual é o serviço que mantém este ficheiro aberto.

Se a máquina já tiver lsof, sudo lsof +L1 lista os ficheiros abertos cujo número de ligações caiu para zero e mostra os tamanhos numa única tabela. Esta ferramenta não está presente numa imagem mínima do Ubuntu, e instalar um pacote num sistema de ficheiros sem espaço livre também pode falhar. Por isso, a pesquisa com /proc é a versão que funciona sempre.

Liberar espaço sem reiniciar

Um reboot resolve o problema, mas é a primeira medida errada: interrompe o serviço e destrói as evidências. Existem quatro opções menos intrusivas, pela ordem em que deve experimentá-las.

Primeiro, copie os dados para outro local se ainda precisar deles. Ler o caminho do descritor lê o inode ativo.

sudo cp /proc/<pid>/fd/<n> /root/recovered.log

Este é o único caso em que é fácil recuperar um ficheiro eliminado. Por isso, recuperar ficheiros eliminados com rm -rf começa por perguntar se um processo ainda mantém o ficheiro aberto. Depois de o último descritor ser fechado, essa possibilidade desaparece.

Segundo, esvazie o ficheiro através do descritor. O caminho /proc aponta para o mesmo inode. Truncá-lo liberta os blocos enquanto o processo continua em execução.

sudo truncate -s 0 "/proc/$pid/fd/$n"
df -h /

Isto funciona corretamente quando o processo que escreve abriu o ficheiro em modo append, porque cada escrita é feita no fim atual do ficheiro. Quando isso não acontece, o processo mantém a posição de escrita antiga. A escrita seguinte ocorre muito depois do início do ficheiro e recria-o com um hole no início. Um hole não é alocado, por isso os blocos continuam livres e df mantém o espaço que acabou de devolver. O que volta a aparecer é apenas o tamanho: execute sudo stat -L "/proc/$pid/fd/$n" novamente depois de o processo escrever. O comando mostra o tamanho antigo junto de uma contagem de blocos que já não corresponde a esse tamanho. Reinicie o processo quando também quiser que o tamanho volte a começar em zero.

Terceiro, peça ao serviço para reabrir os logs. Um daemon cujo ficheiro de log foi eliminado enquanto continuava aberto é a versão real mais comum deste problema. Muitos daemons reabrem os ficheiros de log depois de receberem um sinal: nginx usa SIGUSR1 e rsyslog usa SIGHUP. Consulte a documentação do daemon em causa em vez de adivinhar, porque enviar o sinal errado para o daemon errado pode interrompê-lo.

sudo systemctl kill -s USR1 nginx

Isto envia o sinal para o processo que systemd regista como principal da unidade. Assim, uma unidade que declara o Type= errado para a forma como o daemon realmente arranca pode enviar o seu sinal para um processo que nunca manteve o ficheiro eliminado aberto, e o espaço continua ocupado.

Quarto, reinicie a unidade. sudo systemctl restart <unit> fecha todos os descritores mantidos pelo processo antigo, por isso os blocos são certamente libertados. Na demonstração anterior, o processo que mantém o ficheiro aberto é um sleep iniciado por si. Por isso, terminá-lo é suficiente.

kill $holder
df -h .
df --output=used -B1 .
sudo find /proc/[0-9]*/fd -lname '*(deleted)' -printf '%p -> %l\n' 2>/dev/null

Compare os bytes utilizados com o valor registado antes de criar o ficheiro. Os valores voltam a coincidir, e find já não mostra o seu descritor. Verificar com o mesmo comando que encontrou o problema é o hábito que deve manter.

É mais fácil observar essa alteração do que executar df manualmente repetidamente. watch repete um comando em intervalos fixos e volta a mostrar o resultado no mesmo local. Assim, watch df -h / mostra a alteração da coluna de espaço utilizado à medida que o espaço é libertado.

Quando os totais coincidem e o disco continua cheio

Se df e um du -x root coincidirem, não há nenhum ficheiro eliminado envolvido. As causas restantes são de outro tipo, e cada uma tem a sua própria verificação.

Sem inodes, não sem blocos

Um inode contém os metadados de um ficheiro. O ext4 cria um número fixo de inodes quando o sistema de ficheiros é criado, pelo que um sistema de ficheiros pode ficar sem inodes enquanto ainda tem blocos livres. A criação de novos ficheiros falha, mesmo que df -h mostre espaço disponível.

df -h /
df -i /

O primeiro comando conta blocos e o segundo conta inodes. Compare a coluna de utilização de cada um. Uma utilização baixa de blocos e uma utilização de inodes no limite indicam um número muito elevado de ficheiros muito pequenos.

df rejeita -i e --output na mesma invocação. Por isso, quando quiser obter as contagens brutas para as ler ou as fornecer a outro comando, selecione os campos de inodes pelo nome e não use -i.

df --output=itotal,iused,iavail,ipcent /

Essas colunas apresentam os mesmos dados de contabilização que df -i imprime, num formato que pode analisar.

Encontre os ficheiros contando entradas em vez de bytes.

sudo du --inodes -x -d 1 / 2>/dev/null | sort -rn | head

Repita o mesmo comando um nível abaixo, no diretório que ficou no topo, até chegar à árvore que está a criar os ficheiros. Se o seu du não suportar --inodes, então sudo find /var -xdev -type f | wc -l conta uma subárvore de forma mais lenta.

A solução é eliminar ou mover esses ficheiros. Não pode adicionar inodes a um sistema de ficheiros ext4 existente, porque a quantidade é definida no momento mkfs. Para a aumentar, teria de recriar o sistema de ficheiros e restaurar a partir de uma cópia de segurança. O XFS aloca inodes conforme necessário, pelo que não fica sujeito a um limite fixo da mesma forma. Uma máquina que execute contentores atinge ambos os limites mais depressa do que a maioria, porque as camadas das imagens contêm muitos ficheiros pequenos. Nessa máquina, libertar espaço usado pelo Docker num VPS é a solução específica e recupera muito mais espaço do que uma limpeza geral do sistema de ficheiros.

Espaço oculto sob um ponto de montagem

Um diretório pode conter ficheiros antes de qualquer montagem ser feita sobre ele. Monte um sistema de ficheiros nesse diretório e os ficheiros subjacentes permanecem exatamente onde estavam: continuam alocados, continuam contabilizados por df e deixam de estar acessíveis pelo nome. du não os consegue ver porque a montagem os encobre.

Mostre este comportamento com tmpfs, que não precisa de espaço livre em disco. Esta parte requer uma máquina onde tenha autorização para fazer montagens, por isso funciona numa KVM VPS.

sudo mkdir -p /srv/covered
sudo cp /etc/services /srv/covered/
ls /srv/covered
sudo mount -t tmpfs tmpfs /srv/covered
ls /srv/covered
sudo umount /srv/covered
ls /srv/covered

O ls intermédio mostra um diretório vazio. A cópia não desapareceu: continua no sistema de ficheiros raiz e volta a aparecer assim que desmontar. Agora imagine um serviço que gravou logs nesse caminho durante um mês antes de alguém montar um volume sobre ele.

Para encontrar os ficheiros reais num servidor em execução, monte novamente o sistema de ficheiros raiz noutro local. Uma montagem bind mostra um sistema de ficheiros sem os sistemas de ficheiros montados dentro dele.

sudo mkdir -p /mnt/rootcheck
sudo mount --bind / /mnt/rootcheck
sudo du -xhs /mnt/rootcheck/* 2>/dev/null | sort -h
sudo umount /mnt/rootcheck

Tudo o que aparecer nessa listagem, mas não no caminho normal, está oculto sob um ponto de montagem. Desmonte a montagem bind quando terminar; caso contrário, um du posterior sem -x contabiliza os mesmos ficheiros duas vezes.

Blocos reservados para root

O ext4 reserva uma parte dos seus blocos para o utilizador root. Assim, um disco cheio não impede o root de iniciar sessão e reparar a máquina. Um processo executado por um utilizador normal atinge esse limite primeiro, enquanto df ainda mostra algum espaço disponível. Consulte a configuração no seu próprio sistema de ficheiros em vez de assumir o valor predefinido.

dev=$(df --output=source / | tail -n 1)
sudo tune2fs -l "$dev" | grep -i 'block count'

Isto apresenta o número total de blocos e o número de blocos reservados nas mesmas unidades, pelo que a proporção entre ambos é direta. df apresenta a coluna disponível como o espaço que um utilizador normal ainda pode utilizar. Por isso, o espaço usado mais o disponível é inferior ao tamanho total. A diferença corresponde à reserva.

Altere este valor com sudo tune2fs -m <percent> "$dev". A alteração aplica-se imediatamente e não requer a remontagem do sistema de ficheiros. Reduzir a reserva num sistema de ficheiros separado para dados é razoável. No sistema de ficheiros raiz, mantenha espaço suficiente para que o root ainda possa escrever. Um sistema de ficheiros raiz sem espaço livre é muito mais difícil de reparar. A reserva também evita que fique sem acesso ao sistema: uma chave adicionada a authorized_keys num sistema de ficheiros sem espaço pode ser gravada de forma incompleta ou não ser gravada, e o início de sessão seguinte responde com Permission denied (publickey) por uma razão que não está relacionada com a própria chave. tune2fs funciona em ext2, ext3 e ext4. O XFS não tem uma configuração equivalente.

Quando du engana se for usado isoladamente

Quatro comportamentos de du produzem totais que parecem errados.

  • Hard links: du conta um inode uma só vez, mesmo quando vários nomes apontam para ele. Por isso, uma árvore cheia de hard links mostra menos do que a soma dos seus ficheiros.
  • Ficheiros esparsos: du mostra os blocos efetivamente alocados, enquanto ls -l mostra o tamanho aparente. Adicione --apparent-size para ver o outro valor.
  • Permissões: quando é executado como utilizador normal, du ignora o que não consegue ler e apresenta um valor inferior ao real. Os erros que imprime são os que as pessoas redirecionam para /dev/null e deixam de consultar.
  • Limites do sistema de ficheiros: sem -x, du / conta todos os sistemas de ficheiros montados abaixo de /, por isso o total pode exceder o valor apresentado por df /.

df também tem um comportamento importante. Apresenta cada sistema de ficheiros separadamente. Por isso, execute-o sobre o caminho exato usado pela operação de escrita que falha. Um sistema de ficheiros /boot separado enche segundo o seu próprio ritmo, à medida que se acumulam pacotes do kernel, e remover kernels antigos no Ubuntu é uma tarefa diferente de libertar espaço em /.

Uma sequência de trabalho para um incidente real

  1. Execute df -h <path> e df -i <path> no sistema de ficheiros onde a escrita falhou, e não em / por reflexo.
  2. Execute sudo du -xh -d 1 <mountpoint> 2>/dev/null | sort -h e, em seguida, avance para o diretório maior.
  3. Se du não conseguir justificar o espaço que df indica como utilizado, procure em /proc ficheiros eliminados que ainda estejam abertos.
  4. Se os dois valores coincidirem, monte o sistema de ficheiros noutro local com bind e procure ficheiros localizados sob um ponto de montagem.
  5. Se a utilização de inodes estiver no limite, conte ficheiros em vez de bytes.

Cada passo inclui um comando cujo resultado pode ser analisado. Essa é a diferença entre corrigir o problema e tentar adivinhar a causa.

FAQ

Por que df mostra o disco cheio quando du encontra muito menos?

A causa mais comum é um ficheiro que foi eliminado enquanto um processo ainda o tinha aberto. Remover o ficheiro elimina a sua entrada no diretório, por isso du deixa de ter um nome para percorrer e deixa de o contabilizar. O inode e os respetivos blocos continuam alocados até ao último descritor ser fechado, e df contabiliza os blocos alocados. Pesquise em /proc/<pid>/fd por ligações simbólicas cujo destino esteja marcado como eliminado para encontrar o ficheiro e o processo que o mantém aberto. Antes de confiar na comparação, confirme que executou du como root e com -x, porque um utilizador normal ignora silenciosamente os diretórios que não consegue ler.

Como encontro um ficheiro eliminado que ainda está aberto sem usar lsof?

Use o registo próprio do kernel dos descritores abertos. sudo find /proc/[0-9]*/fd -lname '*(deleted)' -printf '%p -> %l\n' 2>/dev/null lista todos os descritores que apontam para um ficheiro sem nome, e o ID do processo aparece no caminho apresentado. sudo stat -Lc %s num desses caminhos de descritor mostra o respetivo tamanho, para que possa ordená-los e escolher o que é relevante. Isto não requer qualquer pacote, o que é importante porque a instalação de um pacote num sistema de ficheiros sem espaço livre pode falhar.

Posso libertar o espaço sem terminar o processo?

Por vezes. sudo truncate -s 0 /proc/<pid>/fd/<n> acede ao mesmo inode através do descritor e liberta os respetivos blocos enquanto o processo continua em execução. Esta é a opção mais limpa quando o processo abriu o ficheiro em modo de anexação, porque as escritas são sempre feitas no fim atual. Caso contrário, o deslocamento de escrita mantém-se na posição anterior e a escrita seguinte recria o ficheiro com um intervalo vazio no início. Assim, o tamanho apresentado volta a aumentar, enquanto os blocos sob esse intervalo continuam livres. Reiniciar a unidade ou enviar-lhe o sinal indicado na respetiva documentação para reabrir os logs é a correção que não deixa um ficheiro esparso.

df mostra espaço livre, mas as escritas continuam a falhar. O que mais pode ser?

Verifique os inodes com df -i no mesmo caminho, porque um sistema de ficheiros com blocos livres mas sem inodes disponíveis rejeita ficheiros novos. Verifique se a escrita é executada por um utilizador que não seja root num sistema de ficheiros ext4 onde apenas restam os blocos reservados. sudo tune2fs -l no dispositivo mostra essa situação. Confirme que está a consultar o sistema de ficheiros que a escrita realmente utiliza, porque um /boot ou /var separado pode ficar cheio independentemente de /.

Por que du apresenta um total maior do que df?

du sem -x entra em todos os sistemas de ficheiros montados sob o caminho indicado, somando vários sistemas de ficheiros, enquanto df descreve apenas um. Os bind mounts agravam o problema, porque os mesmos ficheiros são contabilizados uma vez por cada caminho em que aparecem. Adicione -x para manter du num único sistema de ficheiros e indique a df o mesmo caminho, para que ambos os comandos descrevam a mesma coisa.