Voltar ao Blog
Disponível em:
14 de jul. de 20263 min read

Depurando um RCU Stall no Proxmox: A Causa Não Era a Placa de Rede

O servidor ficava inacessível de forma intermitente e precisava de reboot físico para voltar. Eu tinha acabado de trocar a placa de rede, então obviamente a culpa era da NIC.

Não era. Essa suposição me custou um dia.

A falsa correlação

A troca da placa e os crashes eram eventos independentes que por acaso ficaram próximos no tempo. Os logs eram inequívocos assim que eu de fato os li: a interface estava UP, sem erros, durante toda a janela do stall.

Essa é a armadilha que vale nomear. Quando duas coisas mudam por volta do mesmo momento, a mudança deliberada mais recente absorve toda a suspeita. É um prior razoável — e é exatamente por isso que você checa os logs antes de agir sobre ele.

O que estava realmente acontecendo

O pvestatd, daemon de estatísticas do Proxmox, estava dando segfault em Perl com general protection fault. Ao morrer, deixou um spinlock preso.

A cadeia a partir daí:

pvestatd[1193] segfault em Perl
  → sai com preempt_count=1 (spinlock nunca liberado)
  → BUG: scheduling while atomic: pvestatd/1193
  → "Fixing recursive fault but reboot is needed!"
  → RCU stalls a cada 3 minutos por ~42 horas
  → UI completamente inacessível

O RCU stall era o sintoma, não a causa. Quando um processo em contexto de kernel morre segurando um spinlock, o Read-Copy-Update não consegue avançar. O kernel detecta isso e reporta em alto e bom som — mas não se recupera sozinho.

Passei horas lendo sobre RCU stalls. O RCU era quem reclamava, não quem estava quebrado.

O agravante

O pvestatd.service vem com Restart=no.

Essa única linha transformou um crash recuperável em 42 horas de indisponibilidade. Com Restart=on-failure, o systemd teria reiniciado o daemon em dez segundos e o stall nunca teria persistido tempo suficiente para eu notar.

O daemon crashar esporadicamente é um bug conhecido e não resolvido — há vários relatos contra essa versão do Proxmox. Isso eu não consigo consertar. O que consigo consertar é como o sistema reage a isso.

Como diagnosticar esse padrão

O movimento-chave é ler o boot anterior, já que a evidência é destruída pelo reboot que restaura o serviço:

# 1. Listar boots anteriores
journalctl --list-boots

# 2. Inspecionar o boot antes do reboot
journalctl -b -1 -k | grep -E "BUG|segfault|general protection|panic" | head -20

# 3. Confirmar a ordem: o crash veio antes do primeiro RCU stall?
journalctl -b -1 -k | grep -E "rcu.*stall" | head -3

# 4. Identificar o processo
journalctl -b -1 -k | grep "segfault" | head -5

O passo três é a técnica inteira. Se o segfault aparece antes do primeiro stall, o processo que crashou é a sua causa raiz e o RCU é ruído. A causa precede o sintoma no log; você só precisa olhar mais cedo que a mensagem alarmante que chamou sua atenção.

O que eu mudei

A correção real foi um drop-in do systemd sobrescrevendo o default do upstream:

# /etc/systemd/system/pvestatd.service.d/restart.conf
[Service]
Restart=on-failure
RestartSec=10

Também instalei o kdump-tools com crashkernel=256M reservado, para que o próximo crash sério capture um vmcore em vez de me deixar inferir tudo a partir do journal.

A lição

A parte mais cara desse incidente não foi a indisponibilidade. Foram as horas investigando um componente que estava funcionando corretamente, porque confiei numa coincidência em vez dos logs.

Leia o boot anterior. Procure a primeira coisa que quebrou, não a coisa mais barulhenta que está reclamando.

HomelabProxmoxLinuxDebugging