A série de patches que entra no ciclo do Linux 6.19 finalmente coloca NUMA e mempolicy no mesmo plano que guest_memfd, a base de memória “privada” usada por VMs de confidential computing como TDX e SEV-SNP. O efeito prático é simples de descrever e difícil de exagerar: em servidores grandes, com múltiplos sockets, o hipervisor passa a conseguir forçar as páginas de memória do convidado a nascerem “perto” do CPU que vai acessá-las, em vez de cair no comportamento padrão do kernel e torcer pelo melhor.
Por que NUMA importa para VMs (e por que isso dói mais em confidential computing)
Se você precisa de uma analogia rápida: imagine um servidor como uma biblioteca com duas alas (nós NUMA). Sentado na ala oeste, pegar um livro na estante do lado é rápido; pedir um livro da ala leste envolve atravessar corredores, filas e portas. Em hardware real, esse “corredor” é o interconnect entre sockets, e a latência extra vira penalidade constante em cargas com muita pressão de memória, típicas de HPC, bancos em memória, analytics e microserviços densos.
Em VMs tradicionais, o VMM costuma ter maneiras razoáveis de guiar a alocação. Já em confidential computing, o caminho de memória é mais rígido: a “memória privada” do guest precisa seguir regras de isolamento e frequentemente é tratada como não migrável, o que torna ainda mais importante acertar a localidade desde o primeiro fault.
O problema: guest_memfd alocava páginas sem obedecer política NUMA do VMM
O guest_memfd existe justamente para ser o backend de memória do guest em cenários que exigem separação forte entre memória “privada” e “compartilhada” (por exemplo, o que um host consegue mapear e o que não consegue). Só que, até aqui, ele era uma peça meio “surda” para NUMA: faltava um mecanismo fino para garantir de qual nó sairia a página física quando o guest provocasse a alocação.
O resultado em sistemas multi-socket era previsível: parte relevante das páginas acabava no nó errado, e o guest pagava latência remota de forma silenciosa. Em workloads sensíveis à localidade, isso pode ser a diferença entre “parece bare metal” e “por que esse p99 está esquisito?”.
A solução: aplicar mempolicy às alocações do guest_memfd
Os patches para 6.19 acrescentam suporte para que políticas de mempolicy (por exemplo, MPOL_BIND para amarrar a um nó específico, ou interleave/preferred) sejam aplicadas às alocações feitas via guest_memfd. A ideia é que o VMM consiga configurar a política e, quando o kernel precisar alocar um folio/páginas para um determinado offset do arquivo, a decisão de “onde alocar” respeite essa política.
Aqui há um detalhe importante de engenharia: para isso funcionar de verdade, não basta mudar KVM. A série também encosta na camada de mm/filemap, adicionando suporte para que rotas como filemap_alloc_folio() e __filemap_get_folio() recebam e apliquem políticas NUMA no momento em que o folio nasce. Em outras palavras, o kernel ganha um caminho “mempolicy-aware” para file-backed memory.
“Shared policy”: a peça que faz a regra valer no offset certo
O ponto técnico mais interessante é o uso de “shared policy” para impor as regras. A intuição é: em vez de depender de uma política por thread ou por processo (que pode mudar conforme quem está faultando), o guest_memfd passa a manter a política associada ao mapeamento/arquivo, de forma compartilhada, e consultá-la com granularidade por offset (por pgoff). Assim, quando um fault pede a página X do backend, o kernel consegue recuperar “qual política vale para este offset” e alocar no nó correto.
Esse modelo é particularmente adequado para VMs, porque a autoria da política é do VMM (por exemplo via mbind() sobre um mmap() do fd), mas o consumo real das páginas acontece no contexto de execução do guest e do KVM. “Shared policy” evita que a intenção se perca no caminho.
Higiene de código: CLASS(gmem_get_file) e menos chance de vazamento de referência
Além do ganho de performance, a série também tem um componente claro de robustez: o novo CLASS(gmem_get_file) encapsula o padrão “get+put” ao pegar o arquivo guest_memfd a partir de um memslot. Na prática, é uma forma de RAII em C do kernel, reduzindo a chance de esquecer um fput() em paths de erro e prevenindo vazamentos de referência em código que frequentemente é cheio de early returns.
Há também uma limpeza conceitual útil: renomear estruturas para refletir melhor o que é “instância” e o que é “arquivo” por trás do gmem, o que ajuda revisão e reduz ambiguidade.
Impacto: VMs mais previsíveis e rápidas em servidores grandes
Em hosts com muitos nós NUMA, essa mudança tende a reduzir acesso remoto e estabilizar latência, especialmente em VMs de confidential computing que dependem de guest_memfd. Em ambientes de nuvem privada e HPC, onde topologia e pinning já são tratados como instrumentos de performance, finalmente dá para alinhar “CPU placement” e “mem placement” também para a memória privada do guest, com o kernel aplicando a intenção do VMM no ponto certo do fast path de alocação.
