Qual é a diferença entre vmalloc e kmalloc?

113

Pesquisei no Google e encontrei muitas pessoas defendendo o uso de kmalloc, já que é garantido que você obterá blocos físicos contíguos de memória. No entanto, também parece que kmallocpode falhar se um bloco físico contíguo que você deseja não puder ser encontrado.
Quais são as vantagens de ter um bloco contíguo de memória? Especificamente, por que eu precisaria ter um bloco físico contíguo de memória em uma chamada de sistema ? Existe alguma razão que eu não poderia simplesmente usar vmalloc?
Finalmente, se eu fosse alocar memória durante o tratamento de uma chamada de sistema, devo especificar GFP_ATOMIC? Uma chamada de sistema é executada em um contexto atômico?

GFP_ATOMIC
A alocação é de alta prioridade e não é suspensa. Este é o sinalizador a ser usado em manipuladores de interrupção, metades inferiores e outras situações onde você não consegue dormir.

GFP_KERNEL Esta é uma alocação normal e pode bloquear. Este é o sinalizador a ser usado no código de contexto do processo quando é seguro dormir.

Memoria livre
fonte
4
Esse artigo afirma coisas sem sentido como: "Geralmente uma arquitetura de 32 bits tem tamanho de página de 4 KB e uma arquitetura de 64 bits tem tamanho de página de 8 KB". Eu não li completamente, mas eu não diria que é "bom", nem mesmo confiaria em uma palavra dele.
Alexandro Sánchez
1
Nota (semi-relacionado): vmallocé mais rápido com Kernel 5.2 (Q2 2019)
VonC de

Respostas:

96

Você só precisa se preocupar em usar memória fisicamente contígua se o buffer for acessado por um dispositivo DMA em um barramento endereçado fisicamente (como PCI). O problema é que muitas chamadas de sistema não têm como saber se seu buffer será passado para um dispositivo DMA: uma vez que você passa o buffer para outro subsistema do kernel, você realmente não pode saber para onde ele está indo. Mesmo que o kernel não use o buffer para DMA hoje, um desenvolvimento futuro pode fazer isso.

vmalloc geralmente é mais lento que kmalloc, porque pode ter que remapear o espaço do buffer em um intervalo virtualmente contíguo. kmalloc nunca remapeia, embora se não for chamado com GFP_ATOMIC kmalloc pode bloquear.

kmalloc é limitado no tamanho do buffer que pode fornecer: 128 KBytes *) . Se você precisa de um buffer muito grande, deve usar o vmalloc ou algum outro mecanismo, como reservar muita memória na inicialização.

*) Isso era verdade para os kernels anteriores. Em kernels recentes (testei isso no 2.6.33.2), o tamanho máximo de um único kmalloc é de até 4 MB! (Eu escrevi um post bastante detalhado sobre isso .) - kaiwan

Para uma chamada de sistema, você não precisa passar GFP_ATOMIC para kmalloc (), você pode usar GFP_KERNEL. Você não é um manipulador de interrupções: o código do aplicativo entra no contexto do kernel por meio de uma armadilha, não é uma interrupção.

DGentry
fonte
1
Pensei que as chamadas do sistema fossem inseridas acionando int $ 0x80? (ou seja, uma interrupção)?
FreeMemory
2
int $ 0x80 é uma interrupção de software, também chamada de trap. O que significa manipuladores de interrupção é uma interrupção de hardware, como quando o usuário pressiona uma tecla ou move os movimentos.
Branan,
As chamadas de sistema são para transições do espaço do usuário para o espaço do kernel ... kmalloc é usado apenas no contexto do kernel ??
AIB
3
@FreeMemory: int $ 0x80 é específico para x86 e, portanto, também é um método antigo substituído por sysenter / syscall (em x86).
jørgensen
18

Resposta curta: baixe os drivers de dispositivos Linux e leia o capítulo sobre gerenciamento de memória.

Sério, existem muitos problemas sutis relacionados ao gerenciamento de memória do kernel que você precisa entender - eu gasto muito do meu tempo depurando problemas com ele.

vmalloc () é muito raramente usado, porque o kernel raramente usa memória virtual. kmalloc () é o que normalmente é usado, mas você precisa saber quais são as consequências dos diferentes sinalizadores e precisa de uma estratégia para lidar com o que acontece quando ele falha - particularmente se você estiver em um manipulador de interrupções, como sugeriu.

Mike Heinz
fonte
1
"porque o kernel raramente usa memória virtual", por que isso?
Trey
Porque você geralmente não quer o bloco do kernel enquanto ele espera o kernel trocar a memória dentro ou fora do armazenamento em disco ...
Mike Heinz
Não, a memória do kernel alocada com vmalloc nunca é trocada. Apenas a memória do espaço do usuário pode ser trocada. O espaço de endereço do kernel não pode ser trocado e o vmalloc é alocado no espaço de endereço do kernel.
user2679859
13

O Linux Kernel Development por Robert Love (Capítulo 12, página 244 na 3ª edição) responde a isso de forma muito clara.

Sim, a memória fisicamente contígua não é necessária em muitos dos casos. O principal motivo para kmalloc ser usado mais do que vmalloc no kernel é o desempenho. O livro explica, quando grandes blocos de memória são alocados usando vmalloc, o kernel precisa mapear os blocos fisicamente não contíguos (páginas) em uma única região de memória virtual contígua. Como a memória é virtualmente contígua e fisicamente não contígua, vários mapeamentos de endereço virtual para físico terão que ser adicionados à tabela de páginas. E no pior caso, haverá (tamanho do buffer / tamanho da página) número de mapeamentos adicionados à tabela de páginas.

Isso também aumenta a pressão sobre o TLB (as entradas de cache que armazenam mapeamentos de endereço virtual para físico recentes) ao acessar esse buffer. Isso pode levar a uma surra .

codetwiddler
fonte
11

As funções kmalloc()& vmalloc()são uma interface simples para obter memória do kernel em blocos do tamanho de bytes.

  1. A kmalloc()função garante que as páginas sejam fisicamente contíguas (e virtualmente contíguas).

  2. A vmalloc()função funciona de maneira semelhante kmalloc(), exceto que aloca memória que é apenas virtualmente contígua e não necessariamente fisicamente contígua.

Yogeesh HT
fonte
4

Quais são as vantagens de ter um bloco contíguo de memória? Especificamente, por que eu precisaria ter um bloco físico contíguo de memória em uma chamada de sistema? Existe alguma razão para eu não poder simplesmente usar o vmalloc?

Do Google's "I'm Feeling Lucky" em vmalloc:

kmalloc é a forma preferida, desde que você não precise de áreas muito grandes. O problema é que, se você quiser fazer DMA de / para algum dispositivo de hardware, precisará usar kmalloc e provavelmente precisará de um pedaço maior. A solução é alocar memória o mais rápido possível, antes que a memória seja fragmentada.

Shikari escuro
fonte
Veja, eu li isso e não faz sentido para mim. Eu entendo o uso de kmalloc para grandes áreas; mas para pequenas alocações, por que não usar o vmalloc para evitar a fragmentação da memória física?
FreeMemory de
Porque você deve confiar no kernel para fazer o que é melhor; se achar que é melhor alocar um único pedaço, ele o fará. vmalloc é apenas para quando você absolutamente deve ter um pedaço contíguo.
Dark Shikari
Acho que faz sentido, mas parece contra-intuitivo. kmalloc parece que deve ser usado quando o desempenho é de extrema preocupação (ou seja, não posso ser atormentado por E / S de disco). Além disso, o que acontece com GFP_ATOMIC?
FreeMemory de
2

Em um sistema de 32 bits, kmalloc () retorna o endereço lógico do kernel (embora seja um endereço virtual) que possui o mapeamento direto (na verdade, com deslocamento constante) para o endereço físico. Esse mapeamento direto garante que obtenhamos um pedaço físico contíguo de RAM. Adequado para DMA, onde fornecemos apenas o ponteiro inicial e esperamos um mapeamento físico contíguo depois disso para nossa operação.

vmalloc () retorna o endereço virtual do kernel que, por sua vez, pode não ter um mapeamento contíguo na RAM física. Útil para grande alocação de memória e nos casos em que não nos importamos que a memória alocada para nosso processo seja contínua também na RAM física.

a.saurabh
fonte
1

Uma das outras diferenças é que kmalloc retornará um endereço lógico (caso contrário, você especificará GPF_HIGHMEM). Os endereços lógicos são colocados em "memória baixa" (no primeiro gigabyte de memória física) e são mapeados diretamente para endereços físicos (use a macro __pa para convertê-los). Essa propriedade implica que a memória kmalloced é memória contínua.

Por outro lado, o Vmalloc é capaz de retornar endereços virtuais de "memória alta". Esses endereços não podem ser convertidos em endereços físicos de forma direta (você deve usar a função virt_to_page).

Jérôme Pouiller
fonte