¿Cuál es la diferencia entre vmalloc y kmalloc?
linux-kernel (7)
Busqué en Google y descubrí que la mayoría de las personas abogaban por el uso de kmalloc
, ya que se garantiza que obtendrás bloques físicos contiguos de memoria. Sin embargo, también parece que kmalloc
puede fallar si no se puede encontrar un bloque físico contiguo que desee.
¿Cuáles son las ventajas de tener un bloque de memoria contiguo? Específicamente, ¿por qué necesitaría tener un bloque físico contiguo de memoria 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 manejadores de interrupciones, mitades inferiores y otras situaciones donde no puede dormir.
GFP_KERNEL
Esta es una asignación normal y puede bloquear. Esta es la bandera para usar en el código de contexto del proceso cuando es seguro dormir.
El desarrollo del kernel de Linux por Robert Love (Capítulo 12, página 244 en 3ra edición) responde esto muy claramente.
Sí, la memoria contigua físicamente no es necesaria en muchos de los casos. La razón principal para usar kmalloc más que vmalloc en kernel es el rendimiento. El libro explica, cuando los trozos de memoria grandes se asignan usando vmalloc, kernel tiene que mapear los fragmentos (páginas) físicamente no contiguos en una sola región de memoria virtual contigua. Como la memoria es virtualmente contigua y físicamente no contigua, varias asignaciones de direcciones virtuales a físicas deberán agregarse a la tabla de páginas. Y en el peor de los casos, habrá (tamaño del búfer / tamaño de página) el 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 llevar a una thrashing .
En un sistema de 32 bits, kmalloc () devuelve la dirección lógica del núcleo (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 garantiza que obtengamos un fragmento físico contiguo de RAM. Adecuado para DMA donde damos solo el puntero inicial y esperamos un mapeo físico contiguo para nuestra operación.
vmalloc () devuelve la dirección virtual del kernel, que a su vez puede no estar teniendo una asignación contigua en la RAM física. Útil para grandes asignaciones de memoria y en los casos en que no nos preocupa que la memoria asignada a nuestro proceso sea continua también en la RAM física.
Las kmalloc()
y vmalloc()
son una interfaz simple para obtener memoria kernel en fragmentos de tamaño byte.
La función
kmalloc()
garantiza que las páginas sean físicamente contiguas (y virtualmente contiguas).La función
vmalloc()
funciona de manera similar akmalloc()
, excepto que asigna memoria que es solo virtualmente contigua y no necesariamente contigua físicamente.
Respuesta corta: descargue 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 kernel que necesita comprender: paso mucho tiempo depurándolo de problemas.
vmalloc () se usa muy raramente, porque el kernel raramente usa memoria virtual. kmalloc () es lo que normalmente se usa, pero debes saber cuáles son las consecuencias de las diferentes banderas y necesitas una estrategia para lidiar con lo que sucede cuando falla, especialmente si estás en un manejador de interrupciones, como sugeriste.
Solo debe preocuparse por utilizar una memoria físicamente contigua si se accede al almacenamiento intermedio mediante un dispositivo DMA en un bus físicamente direccionado (como PCI). El problema es que muchas llamadas al sistema no tienen forma de saber si su búfer finalmente 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 utiliza 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 del búfer en un rango virtualmente contiguo. kmalloc nunca reasigna, aunque si no se llama con GFP_ATOMIC puede bloquear kmalloc.
kmalloc está limitado en el tamaño del búfer que puede proporcionar: 128 KBytes *) . Si necesita un búfer realmente grande, debe usar vmalloc u otro mecanismo como reservar memoria alta en el arranque.
*) Esto fue cierto para kernels anteriores. En núcleos recientes (¡lo probé 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 es un controlador de interrupciones: el código de la aplicación ingresa al contexto del kernel por medio de una trampa, no es una interrupción.
Una de las otras diferencias es que kmalloc devolverá la dirección lógica (si no especifica 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 (use __pa macro para convertirlo). Esta propiedad implica que la memoria kmalloced es 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 usar la función virt_to_page).
¿Cuáles son las ventajas de tener un bloque de memoria contiguo? Específicamente, ¿por qué necesitaría tener un bloque físico contiguo de memoria en una llamada al sistema? ¿Hay alguna razón por la que no pueda usar vmalloc?
De Google "I''m Feeling Lucky" en vmalloc
:
kmalloc es la forma preferida, siempre que no necesite áreas muy grandes. El problema es que si quieres hacer DMA desde / hacia algún dispositivo de hardware, necesitarás usar kmalloc, y probablemente necesites un pedazo más grande. La solución es asignar memoria tan pronto como sea posible, antes de que la memoria se fragmente.