¿Cuál es la diferencia entre vmalloc y kmalloc?

113

Busqué en Google y encontré a la mayoría de las personas que abogan por el uso de kmalloc, ya que está garantizado que obtendrá bloques de memoria físicos contiguos. Sin embargo, también parece que kmallocpuede fallar si no se puede encontrar un bloque físico contiguo que desea.
¿Cuáles son las ventajas de tener un bloque de memoria contiguo? Específicamente, ¿por qué necesitaría tener un bloque físico de memoria contiguo en una llamada al sistema ? ¿Hay alguna razón por la que no pueda usar vmalloc?
Finalmente, si tuviera que asignar memoria durante el manejo de una llamada al sistema, ¿debería especificar GFP_ATOMIC? ¿Se ejecuta una llamada al sistema en un contexto atómico?

GFP_ATOMIC
La asignación es de alta prioridad y no duerme. Esta es la bandera para usar en los manejadores de interrupciones, mitades inferiores y otras situaciones en las que no puede dormir.

GFP_KERNEL Esta es una asignación normal y podría bloquearse. Esta es la bandera que se debe usar en el código de contexto del proceso cuando es seguro dormir.

Memoria libre
fuente
Un buen artículo sobre vmalloc y kmalloc http://learnlinuxconcepts.blogspot.in/2014/02/linux-memory-management.html
JIN007
4
Ese artículo afirma tonterías como: "Generalmente, una arquitectura de 32 bits tiene un tamaño de página de 4 KB y una arquitectura de 64 bits tiene un tamaño de página de 8 KB". No lo he leído completamente, pero no lo llamaría "bueno", ni siquiera confiaría en una palabra de él.
Alexandro Sánchez
1
Nota (semi-relacionado): vmalloces más rápido con Kernel 5.2 (Q2 2019)
VonC

Respuestas:

96

Solo debe preocuparse por usar memoria físicamente contigua si un dispositivo DMA accederá al búfer en un bus con dirección física (como PCI). El problema es que muchas llamadas al sistema no tienen forma de saber si su búfer eventualmente se pasará a un dispositivo DMA: una vez que pasa el búfer a otro subsistema del kernel, realmente no puede saber a dónde irá. Incluso si el kernel no usa el búfer para DMA hoy, un desarrollo futuro podría hacerlo.

vmalloc es a menudo más lento que kmalloc, porque puede tener que reasignar el espacio de búfer en un rango virtualmente contiguo. kmalloc nunca reasigna, aunque si no se llama con GFP_ATOMIC, kmalloc puede bloquear.

kmalloc tiene un tamaño limitado de búfer que puede proporcionar: 128 KBytes *) . Si necesita un búfer realmente grande, debe usar vmalloc o algún otro mecanismo como reservar mucha memoria en el arranque.

*) Esto era cierto para los núcleos anteriores. En kernels recientes (probé esto en 2.6.33.2), ¡el tamaño máximo de un solo kmalloc es de hasta 4 MB! (Escribí una publicación bastante detallada sobre esto ) - kaiwan

Para una llamada al sistema, no necesita pasar GFP_ATOMIC a kmalloc (), puede usar GFP_KERNEL. No eres un manejador de interrupciones: el código de la aplicación ingresa al contexto del kernel por medio de una trampa, no es una interrupción.

DGentrada
fuente
1
Pensé que las llamadas al sistema se ingresaron activando int $ 0x80? (es decir, una interrupción)?
FreeMemory
2
int $ 0x80 es una interrupción de software, también llamada trampa. Lo que se entiende por manejadores de interrupciones es una interrupción de hardware, como cuando el usuario presiona una tecla o mueve los movimientos.
Branan
Las llamadas al sistema son para transiciones de espacio de usuario a espacio de kernel ... ¿kmalloc se usa solo en el contexto del kernel?
AIB
3
@FreeMemory: int $ 0x80 es específico de x86, y luego, también es un método antiguo reemplazado por sysenter / syscall (en x86).
jørgensen
18

Respuesta corta: descargue los controladores de dispositivo Linux y lea el capítulo sobre administración de memoria.

En serio, hay muchos problemas sutiles relacionados con la administración de la memoria del kernel que debe comprender; paso mucho tiempo depurando problemas con él.

vmalloc () se usa muy raramente, porque el kernel rara vez usa memoria virtual. kmalloc () es lo que se usa normalmente, pero debe saber cuáles son las consecuencias de los diferentes indicadores y necesita una estrategia para lidiar con lo que sucede cuando falla, particularmente si está en un controlador de interrupciones, como sugirió.

Mike Heinz
fuente
1
"Debido a que el kernel rara vez usa memoria virtual", ¿por qué?
Trey
Porque generalmente no desea que el kernel bloquee mientras espera que el kernel intercambie memoria dentro o fuera del almacenamiento en disco ...
Mike Heinz
No, la memoria del kernel asignada con vmalloc nunca se intercambia. Solo se puede intercambiar la memoria del espacio de usuario. El espacio de direcciones del kernel no es intercambiable y vmalloc asigna en el espacio de direcciones del kernel.
user2679859
13

El desarrollo del kernel de Linux por Robert Love (Capítulo 12, página 244 en la 3ª edición) responde a esto muy claramente.

Sí, en muchos casos no se requiere memoria físicamente contigua. La razón principal por la que kmalloc se usa más que vmalloc en el kernel es el rendimiento. El libro explica, cuando se asignan grandes trozos de memoria usando vmalloc, el kernel tiene que mapear los trozos (páginas) físicamente no contiguos en una única región de memoria virtual contigua. Dado que la memoria es virtualmente contigua y físicamente no contigua, se deberán agregar varias asignaciones de direcciones virtuales a físicas a la tabla de páginas. Y en el peor de los casos, habrá (tamaño de búfer / tamaño de página) número de asignaciones agregadas a la tabla de páginas.

Esto también agrega presión sobre TLB (las entradas de caché que almacenan asignaciones de direcciones virtuales a físicas recientes) al acceder a este búfer. Esto puede provocar una paliza .

codetwiddler
fuente
11

Las funciones kmalloc()& vmalloc()son una interfaz simple para obtener la memoria del kernel en fragmentos del tamaño de un byte.

  1. La kmalloc()función garantiza que las páginas sean físicamente contiguas (y virtualmente contiguas).

  2. La vmalloc()función funciona de manera similar a kmalloc(), excepto que asigna memoria que es solo virtualmente contigua y no necesariamente contigua físicamente.

Yogeesh HT
fuente
4

¿Cuáles son las ventajas de tener un bloque de memoria contiguo? Específicamente, ¿por qué necesitaría tener un bloque físico de memoria contiguo en una llamada al sistema? ¿Hay alguna razón por la que no pueda usar vmalloc?

De "I'm Feeling Lucky" de Google en vmalloc:

kmalloc es la forma preferida, siempre que no necesite áreas muy grandes. El problema es que si desea hacer DMA desde / hacia algún dispositivo de hardware, necesitará usar kmalloc, y probablemente necesitará una porción más grande. La solución es asignar memoria lo antes posible, antes de que se fragmente.

Shikari oscuro
fuente
Mira, leí eso y no tiene sentido para mí. Entiendo el uso de kmalloc para áreas grandes ; pero para asignaciones pequeñas, ¿por qué no usar vmalloc para evitar fragmentar la memoria física?
FreeMemory
Porque debe confiar en que el kernel hará lo mejor; si cree que es mejor asignar un solo fragmento, lo hará. vmalloc es solo para cuando es absolutamente necesario tener un fragmento contiguo.
Dark Shikari
Supongo que tiene sentido, pero parece contradictorio. kmalloc parece que debería usarse cuando el rendimiento es de suma importancia (es decir, no puedo estar plagado de E / S de disco). Además, ¿qué pasa con GFP_ATOMIC?
FreeMemory
2

En un sistema de 32 bits, kmalloc () devuelve la dirección lógica del kernel (aunque es una dirección virtual) que tiene la asignación directa (en realidad con desplazamiento constante) a la dirección física. Este mapeo directo asegura que obtenemos una porción física contigua de RAM. Adecuado para DMA donde damos solo el puntero inicial y esperamos un mapeo físico contiguo a partir de entonces para nuestra operación.

vmalloc () devuelve la dirección virtual del kernel que, a su vez, podría no tener un mapeo contiguo en la RAM física. Útil para una gran asignación de memoria y en los casos en los que no nos importa que la memoria asignada a nuestro proceso sea continua también en la RAM física.

a.saurabh
fuente
1

Una de las otras diferencias es que kmalloc devolverá la dirección lógica (de lo contrario, especifique GPF_HIGHMEM). Las direcciones lógicas se colocan en "memoria baja" (en el primer gigabyte de memoria física) y se asignan directamente a direcciones físicas (utilice la macro __pa para convertirla). Esta propiedad implica que la memoria kmalloced es una memoria continua.

Por otro lado, Vmalloc puede devolver direcciones virtuales desde "memoria alta". Estas direcciones no se pueden convertir en direcciones físicas de forma directa (debe utilizar la función virt_to_page).

Jérôme Pouiller
fuente