Tem hora que o Linux dá aquela travada “do nada” em ARM64 — e foi exatamente isso que uma bateria pesada de testes expôs. Durante stress tests com stress-ng, um bug raro virou hard lockup: a máquina congelava por completo. O que parecia um caso isolado acabou revelando uma lição importante sobre o que não fazer em caminhos críticos do kernel: chamar printk() no lugar errado.
O que estava acontecendo nos bastidores
O roteiro do problema é quase um dominó. O stress-ng chamava a interface de debugfs clear_warn_once
, que zera a seção de memória responsável por mensagens do tipo pr_info_once() — aquelas que deveriam aparecer só uma vez. Com isso, toda nova rodada de teste “rearmava” o aviso. Se, por azar, isso coincidia com o teste pty06 do LTP usando o serial, a impressão de log acontecia no pior momento possível: no caminho de troca de tarefas do escalonador, onde rq_lock
já estava segurado.

E aí vem a queda: printk() precisa destravar o console (console_unlock()
), que por sua vez acorda tarefas e tenta re-adquirir o mesmo lock do escalonador (via try_to_wake_up()
→ ttwu_queue()
→ rq_lock
) — um A–A deadlock clássico. Resultado: hard lockup e queda geral. Em linguagem direta: um aviso de console, repetido por causa do reset de clear_warn_once, trombou com locks do escalonador e derrubou o sistema.
O patch inicial… e o diagnóstico de raiz
A primeira reação foi trocar o pr_info_once() por um controle local com atomic_cmpxchg() — uma forma de garantir que o aviso apareça de fato só uma vez, mesmo que clear_warn_once
tente “resetar” tudo. Ajuda? Ajuda. Mas os mantenedores de ARM64 foram além: Catalin Marinas e Mark Rutland apontaram que o problema verdadeiro não é “quantas vezes” a gente imprime, e sim onde a gente imprime. printk() em caminho sensível do escalonador (debaixo de locks) é pedir para sofrer. A orientação deles foi cirúrgica: remover a impressão desse caminho (no caso, relacionado à mitigação da Spectre v4) e mover o log para um ponto seguro do boot — por exemplo, via um initcall junto de setup_system_capabilities()
.
Por que isso importa (e muito)
Esse é o tipo de Linux ARM64 bug que não aparece em toda máquina, todo dia — mas quando aparece, dói. E ensina. A moral da história é que printk() pode encadear wakeups, semáforos e outras interações que não combinam com locks do escalonador. Evitar logs em accessors de estado ou em caminhos que seguram rq_lock
é higiene de código que paga dividendos em estabilidade e segurança (especialmente perto de mitigação de Spectre).
O que esperar nas próximas versões
A limpeza dessas impressões nos caminhos sensíveis deve chegar em breve ao mainline — possivelmente a partir do 6.18 — junto de ajustes mais amplos para que mecanismos do tipo *_ONCE não voltem a ser rearmados de maneira perigosa por clear_warn_once
. Se você mantém distros, kernels customizados ou infra de testes, vale acompanhar os próximos pulls da arquitetura ARM64 e dos subsistemas de scheduler e printk.