Sistemas de arquivos NVM em userspace seguros e de alto desempenho com a arquitetura Trio
Título original: Enabling High-Performance and Secure Userspace NVM File Systems with the Trio Architecture
PublicadoProceedings of the 29th Symposium on Operating Systems Principles
Saiu em uma revista, congresso ou livro, que normalmente avaliam o trabalho antes de aceitar. Mesmo assim, um único estudo nunca é a palavra final.
Resumo
Este paper não tem resumo disponível.
Análise de pesquisa
Escrita pelo Kurz, não pelos autores do paper. O resumo acima é dos próprios autores.
- Última revisão
- Versão
- 1.0
Visão geral
A memória não volátil (NVM), como a memória persistente Intel Optane, é acessível com instruções comuns de load e store, e a MMU consegue impor permissões sobre suas páginas. Isso convida a sistemas de arquivos em biblioteca no userspace (LibFSes), que são ligados a cada aplicação, dispensam o kernel no caminho dos dados e podem ser customizados por carga de trabalho sem privilégios. O problema é a integridade dos metadados: com acesso direto, uma aplicação maliciosa ou com bugs pode corromper metadados em que outras aplicações confiam. Uma entidade confiável poderia validá-los, mas cada LibFS customizada organiza seus dados de um jeito, e a entidade não consegue entendê-los.
Os desenhos anteriores escolhem um lado. Alguns intermedeiam toda atualização de metadados por um kernel ou processo confiável (Aerie, Strata, SplitFS, KucoFS), o que, segundo os autores, custa desempenho, embute o desenho do sistema de arquivos na entidade confiável e faz a customização exigir privilégios. Outros (ZoFS, ctFS, MadFS) atualizam os metadados diretamente e abrem mão da integridade, no todo ou em parte, o que deixa ataques como reescrever um ponteiro de índice para que uma vítima, ao copiar um arquivo, grave no destino o conteúdo da sua própria DRAM, segurar um lock para sempre ou remover um diretório não vazio.
Este artigo do SOSP 2023 (Koblenz), da EPFL e da Rutgers University, propõe o Trio, uma arquitetura que pretende manter ao mesmo tempo acesso direto, customização privada sem privilégios e integridade dos metadados. Termos que convém separar: core state é o que um sistema de arquivos não consegue regenerar (conteúdo dos arquivos, nomes, permissões, hierarquia de diretórios), e estado auxiliar é tudo o que pode ser reconstruído a partir dele (file descriptors, locks, caches, bitmaps). O kernel controller concede páginas e inodes da NVM por meio da MMU, e o integrity verifier é um processo confiável no userspace. Um trust group é um conjunto de processos de um mesmo usuário que confiam uns nos outros. O ArckFS é o sistema de arquivos estilo POSIX construído sobre o Trio, e o KVFS e o FPFS são dois sistemas customizados.
Vale conhecer antes: como funciona o acesso de memória persistente no estilo DAX, as permissões de tabela de páginas e o básico de sistemas de arquivos (inodes, entradas de diretório, journaling, verificações no estilo fsck). O artigo toma o acesso direto seguro com customização no nível da aplicação do Exokernel e do Arrakis, que não estão nesta biblioteca. Três pareamentos meus, nenhum citado pelo artigo: o Demikernel aplica a ideia de library OS ao networking de datacenter, o Oxbow (OSDI 2026) revisita o mesmo dilema entre sistema de arquivos no userspace e no kernel, mas mantém o page cache e a proteção do kernel, e o cache_ext deixa cada cgroup carregar sua própria política de page cache, outro caso de customização por aplicação que não atrapalha as demais.
Contribuição
- Separação de estado. Os autores tratam o core state como estado duro (hard state) e o estado auxiliar como estado mole (soft state). O Trio fixa o layout de um único core state e o compartilha entre todas as LibFSes e as entidades confiáveis. Uma LibFS não pode mudar esse layout, mas pode redesenhar livremente seu estado auxiliar privado.
- Componentes e compartilhamento. Cada aplicação tem sua própria LibFS. O controller no kernel programa a MMU para conceder acesso, e o verifier inspeciona o core state. O compartilhamento é por arquivo, com leitores concorrentes ou um único escritor exclusivo. Quando um escritor libera um arquivo, o controller o desmapeia e o envia ao verifier, e só se ele passar o arquivo é mapeado para a próxima LibFS, que reconstrói seu estado auxiliar a partir do core state. A garantia é que a corrupção fica confinada à aplicação que a causou. Os trust groups evitam esses custos compartilhando uma única LibFS, e a fronteira de confiança padrão é o processo.
- Core state do ArckFS e invariantes. O core state é mínimo: um superbloco, uma shadow inode table mantida pelo controller e as páginas dos arquivos. Arquivos e diretórios são páginas de índice que apontam para páginas de dados, e o inode fica junto da sua entrada de diretório, então create, stat e delete precisam apenas da permissão do diretório pai. A shadow inode table guarda as permissões verdadeiras, então chmod e chown passam pelo controller. O verifier, adaptado das checagens do e2fsck mas executado online sobre um único arquivo, impõe quatro invariantes: campos válidos nos inodes e entradas de diretório (tipo de arquivo, sem nomes duplicados, sem
/nos nomes), inodes e páginas válidos e sem referência dupla (conferidos contra os registros do controller), uma árvore de diretórios conexa (hard links não são suportados, então ciclos já estão excluídos) e permissões corretas. - Corrupção e falhas. Antes de conceder acesso de escrita, o controller faz um checkpoint dos metadados do arquivo. Se a verificação falha, o escritor ganha um prazo para consertar, e do contrário o controller mantém o arquivo corrompido privado a esse escritor para evitar perda de dados e reverte uma cópia para o checkpoint. Uma chamada commit permite a uma LibFS substituir o checkpoint depois de uma checagem aprovada. O core state não fixa mecanismo de crash, então cada LibFS registra um programa de recuperação, e como ele não é confiável o verifier roda depois da recuperação em todo arquivo que estava gravável no momento da falha. O ArckFS torna as operações de metadados síncronas e atômicas, em geral com atualizações atômicas de 16 bytes e undo logs para o rename, e as operações de dados síncronas mas não atômicas. Como as operações persistem na hora, o
fsyncé ignorado. - Caminho de dados do ArckFS. Uma radix tree por arquivo, com um lock de leitura e escrita no inode e um range lock, permite que threads escrevam regiões disjuntas em paralelo. Os diretórios usam uma hash table encadeada redimensionável, um logging tail por página de dados não cheia (estendendo o log por inode do NOVA) e um index tail, com alocadores e journal por CPU. Para o Optane, adota a delegação oportunista do OdinFS: threads do kernel em cada nó NUMA fazem os acessos à NVM por ring buffers por aplicação, exceto os pequenos (leituras abaixo de 32KB, escritas abaixo de 256 bytes). O kernel controller é um módulo do Linux 5.13.13 de 3.791 linhas, a LibFS tem 7.586 e o verifier 457.
- Customização. O KVFS acrescenta chamadas get e set sem file descriptors, guarda arquivos de até 32KB em um array fixo em vez de uma radix tree e usa um spinlock. O FPFS mantém uma hash table global do caminho completo para a entrada de diretório, o que elimina a travessia de diretórios. Os dois ficam sobre o core state do ArckFS, então nenhum componente confiável muda. A customização se limita ao estado auxiliar, e um desenho que muda o core state, como um sistema de arquivos log-structured convencional, exige privilégios.
Metodologia
Os autores usam uma máquina de oito sockets e 224 cores (Xeon Platinum 8276L) com 6.144 GB de Optane PM, rodando Ubuntu 20.04 e Linux 5.13.13. As bases de comparação são cinco sistemas de arquivos no kernel (ext4 com DAX, PMFS, NOVA, OdinFS, WineFS) e dois no userspace, o SplitFS (metadados pelo ext4) e o Strata (metadados por um processo privilegiado), que roda apenas com uma thread. O ArckFS roda com os oito nós NUMA e 12 threads de delegação em cada um, ou como ArckFS-no-dele em um nó sem delegação, e o ext4 também roda sobre um RAID0 dos nós.
Os microbenchmarks são o fio (um arquivo privado de 1GB por thread) e o FxMark. Os macrobenchmarks são quatro cargas do Filebench e o db_bench do LevelDB com uma thread, valores de 100 bytes e um milhão de objetos. Para a integridade, os autores montam à mão onze ataques, escrevem um script de corrupção para cada checagem do verifier e combinam scripts, chegando a 134 cenários no total. O custo de compartilhamento usa duas aplicações gravando 4KB em um arquivo de 2MB ou 1GB, ou criando arquivos em um diretório de 10 ou 100 arquivos. A customização roda oito threads no Webproxy estendido com uma interface chave-valor (KVFS) e no Varmail com diretórios de 20 níveis de profundidade (FPFS).
Resultados
Estes são os resultados relatados pelos autores.
- Uma thread. Com 4KB, o ArckFS-no-dele e o SplitFS ficam de 9% a 31% acima do NOVA graças ao acesso direto, enquanto a delegação deixa o ArckFS 21% mais lento que o ArckFS-no-dele, mas ainda cerca de 6% à frente do NOVA. Com 2MB o ArckFS lidera por 3,1× a 25× nas leituras e 2,0× a 15× nas escritas. Em open, create e delete lidera por 1,6× a 5,6×, 3,3× a 5,3× e 7,4× a 9,4×. No create, o NOVA e o Strata gastam pelo menos 42% e 44,5% do tempo no VFS e na digestão.
- Escalabilidade de dados. Em oito nós NUMA com 224 threads, o ArckFS supera o OdinFS em até 1,3× e os demais sistemas em até 22× com I/O de 4KB. Nas cargas de dados do FxMark ele escala linearmente nas leituras e mantém o throughput máximo nas escritas, 3,2× sobre o OdinFS e até 850× sobre os demais. Com um nó, o ganho em 4KB é de 10% a 12%, e com 2MB todos os sistemas ficam parecidos.
- Escalabilidade de metadados. Com 224 threads o ArckFS lidera por 5,4× a 334× em open, 7,4× a 25× em enumerate, 2,3× a 21,2× em create, 8,9× a 32,7× em unlink e 16,2× a 36,4× em rename. Os autores dizem que gargalos do VFS (locks grossos nos caches de diretório e de inode, o lock global de rename) limitam os demais. O ArckFS não escala linearmente no MWCL e no MWUL, porque os acessos pequenos não são delegados, e cai no MWCM, no MWUM e no MWRM por contenção nas hash tables.
- Integridade. O verifier detecta a corrupção nos 134 cenários, e o controller restaura um arquivo consistente.
- Custo de compartilhamento. Para arquivos e diretórios pequenos ele é desprezível (abaixo de 5 µs) nas escritas e modesto nos creates, perto do NOVA. Com dois escritores em um arquivo de 1GB o ArckFS chega a 0,25 GiB/s contra 1,95 GiB/s com um trust group, o overhead de 7,8× dos autores, e 99% dele é mapear e desmapear, a 670 ms por iteração contra um lease de 100 ms. Criar em um diretório de 100 arquivos leva 32,7 µs contra 1,6 µs (20,4×), dominado pela verificação (300 µs, 81%) e pela reconstrução do estado auxiliar (12%).
- Filebench. Em oito nós NUMA o ArckFS lidera por 1,1× a 27,3× no Fileserver e 1,2× a 4,1× no Webserver, e com até 16 threads por 2,2× a 8,0× no Webproxy e 2,4× a 34,2× no Varmail.
- LevelDB. Na Tabela 5 (ops por ms), o ArckFS chega a 291 no Fill sync contra 211 do WineFS, o segundo melhor, e 17 do ext4, e a 144 no Read random contra 142 e 93. Os autores resumem como até 3,1× sobre o WineFS e 1,5× a 17× sobre o ext4. O ArckFS-no-dele é de 21% a 34% mais rápido que o ArckFS nas cargas de arquivos pequenos e 29% mais lento no Fill 100K.
- Customização. O KVFS supera o ArckFS em 1,3× e os demais em 2,9× no Webproxy. O FPFS supera o ArckFS em 1,2× e os demais em 21× no Varmail com diretórios profundos.
Análise crítica
O artigo é franco sobre o que custam o acesso direto e a verificação. Ele admite o seguinte.
- Não é totalmente POSIX. O Trio não permite escritas concorrentes em um arquivo por várias aplicações não confiáveis, a MMU não consegue impor a permissão de busca de um diretório, e alguns timestamps, como o horário de acesso de um arquivo somente leitura, não podem ser mantidos com exatidão.
- Custos e escopo. Compartilhar um arquivo entre escritores não confiáveis paga o mapeamento, a verificação e a reconstrução, que os trust groups evitam. A customização se limita ao estado auxiliar, o KVFS e o FPFS assumem cargas específicas (o FPFS não faz rename com eficiência), e a integridade dos dados fica a cargo das permissões de arquivo e dos desenhos construídos sobre o ArckFS.
- Lacunas na avaliação. A consistência em caso de falha foi testada com testes unitários, não com um framework como o Chipmunk. O Strata roda com uma thread, o ZoFS e o KucoFS não estavam disponíveis, o Aerie e o ctFS não rodaram, o Webproxy e o Varmail param em 16 threads por causa de um bug do Filebench, e o LevelDB só roda onde o mmap() funciona.
Os pontos a seguir são uma leitura das evidências, não afirmações do artigo.
- Os números do LevelDB não batem. O resumo diz de 3,1× a 17×, e o corpo diz até 3,1× sobre o WineFS e 1,5× a 17× sobre o ext4. A Tabela 5 dá de 1,01× (Read random) a cerca de 2,0× (Delete random, 494 contra 245) sobre o WineFS, enquanto 3,1× é a razão sobre o ext4 no Fill 100K e 17× é o Fill sync do ext4. O 1,3× do resumo para os dois sistemas customizados também difere dos 1,3× e 1,2× do corpo. Uso aqui os valores do corpo e da tabela.
- As maiores diferenças medem o VFS mais que o Trio. Os 334× e 850× são contra sistemas de arquivos de kernel que, segundo os autores, o VFS segura. O caminho de dados vem do OdinFS, um artigo anterior de dois dos mesmos autores, então a medida mais justa do acesso direto é o ganho sobre o OdinFS, de até 1,3× com 224 threads.
- A comparação com a intermediação é indireta. Nenhum experimento acrescenta intermediação ao próprio ArckFS. Os desenhos intermediados que rodaram são o SplitFS e o Strata (uma thread), e os overheads de 44% e 68% da intermediação vêm do artigo do ZoFS. A única decomposição é a parcela de VFS e digestão no create.
- O custo de compartilhamento se apoia em poucos casos. São dois tamanhos de arquivo e dois de diretório, e o teste de create força um unmap depois de cada operação. Um arquivo grande escrito por várias aplicações que desconfiam umas das outras é onde os números são piores e os trust groups não se aplicam, e nenhuma carga de aplicação exercita isso.
- O compartilhamento heterogêneo é argumentado, não medido. Não achei experimento em que o KVFS ou o FPFS compartilhe um arquivo com o ArckFS, e os sistemas customizados rodam sozinhos em cargas feitas sob medida, com 1,2× a 1,3× sobre o ArckFS.
- A evidência de segurança é desenhada pelos autores. Os 134 cenários seguem a lista de ameaças e as invariantes dos próprios autores, sem fuzzing independente nem argumento de que quatro invariantes bastam. O texto também não diz como as threads de delegação, que tocam a NVM em nome das aplicações, conferem que um pedido fica dentro das páginas mapeadas para aquela aplicação.
- Hardware e ruído. A delegação e seus limiares de 32KB e 256 bytes são ajustados para o Optane, e o próprio artigo cita uma notícia do fim dele pela Intel (referência 12). Os dispositivos CXL são motivação, não são medidos. Não achei contagens de repetição nem barras de erro, e a Tabela 5 traz valores únicos.
Pesquisas futuras
- Compartilhamento mais barato entre escritores não confiáveis, já que os números colocam o custo no mapeamento, no desmapeamento e na verificação, que crescem com o tamanho do arquivo. Verificar só as páginas de índice alteradas seria um caminho, uma lacuna que vejo, não um plano declarado.
- Testes de consistência em caso de falha com frameworks como o Chipmunk, incluindo programas de recuperação adversariais fornecidos por uma LibFS.
- Rodar em NVM baseada em CXL, que o artigo cita como alvo, e reajustar a delegação específica do Optane.
- Proteger os próprios dados dos arquivos, que os autores tratam como ortogonal, e um jeito seguro de mudar o core state sem privilégios.
Discussão · 0
Entre para participar da discussãoNenhum post ainda. Seja o primeiro a iniciar a discussão.