Готовый перевод Linux Device Drivers 3 / Драйверы устройств Линукс (третье издание): 8.1. The Real Story of kmalloc

8.1 Вся правда о kmalloc.

Механизм выделения памяти kmalloc это мощный инструмент, простой и понятный из за сходства с malloc. Выполняется быстро (если не блокируется) и не очищает выделенную память, содержимое остается на месте.[1] Выделенный фрагмент не фрагментирован в физической памяти. В следующих нескольких секциях, мы в деталях опишем работу функции kmalloc, чтобы Вы могли сравнить способы выделения памяти, которые мы обсудим позже.

[1] Среди прочего, это подразумевает, что Вы должны явным образом очистить память, которая может быть использована в юзерспейсе или для записи в устройство; в противном случае, Вы рискуете раскрыть информацию, которая должна оставаться приватной.

8.1.1. Аргумент флаги
Запомните как выглядит прототип:
#include
void *kmalloc(size_t size, int flags);

Первый аргумент kmalloc это размер выделяемого блока. Второй аргумент, флаги выделения, значительно интереснее, так как контролирует различные стороны поведения kmalloc.

Наиболее часто используемый флаг, GFP_KERNEL, означает, что выделение памяти (внутренне выполняемое через вызов __get_free_pages, являющейся исходником GFP_prefix ) выполняется от имени процесса выполняющегося с приоритетом уровня ядра. Другими словами, это значит что запуск функции приводит к системному вызову от имени процесса. Используя GFP_KERNEL означает, что kmalloc может заставить процесс уснуть в ожидании свободной страницы памяти если вызов произошел в момент ее недостатка. Функция, выделяющая память, используя GFP_KERNEL, должна, тем не менее, быть повторно входимой и не может быть запущена во время атомарной операции. Пока текущий процесс спит, ядро выполняет необходимые операции для выделения свободной памяти, сбрасывая буферы на диск или свопируя память самого процесса.

Не всегда полезно использовать флаг GFP_KERNEL; иногда kmalloc вызывается за пределами контекста процесса. Такой тип вызова может случиться, например, в обработчиках прерываний, тасклетах и таймерах ядра. В этом случае, текущий процесс не уснет, и драйвер должен использовать флаг GFP_ATOMIC вместо этого. На самом деле, ядро старается иметь в запасе несколько страниц памяти чтобы поддерживать атомарные операции выделения памяти. Когда Вы используете GFP_ATOMIC, kmalloc может использовать даже самые последние странички. Однако, если этих последних страниц нет, то выделение закончится неудачей.

Другие флаги можно использовать вместе с GFP_KERNEL и GFP_ATOMIC, или вместо них, хотя эти два удовлетворяют большую часть потребностей драйверов устройств. Все флаги определены в , индивидуальные флаги имеют префикс с двойным подчеркиванием, вроде __GFP_DMA. В добавок, наиболее употребимые комбинации флагов не имеют префикса и их иногда называют"предпочтения выделения". Вот они:

GFP_ATOMIC
Используется для выделения памяти за пределами контекста процесса. Процесс не засыпает.

GFP_KERNEL
Нормальное выделение памяти ядра. Процесс может уснуть.

GFP_USER
Используется для выделения памяти для страниц в юзерспейсе. Процесс может уснуть.

GFP_HIGHUSER
Работает так же как и GFP_USER, но выделение происходит в верхней памяти, если она есть. Верхняя память описана в следующем подразделе.

GFP_NOIO
GFP_NOFS
Эти флаги работают как GFP_KERNEL, но для них есть ограничения в действиях ядра направленных на обработку данного запроса. GFP_NOFS запрещает использовать какие-либо вызовы файловой системы, а GFP_NOIO запрещает любой ввод/вывод вообще. Они используются главным образом в коде файловой системы и виртуальной памяти где процесс выделения может быть прерван, тогда как рекурсивные вызовы файловой системы являются очень плохой идеей.

Флаги, описанные выше, могут дополняться с помощью побитового ИЛИ следующими флагами, которые изменяют алгоритм выделения:

__GFP_DMA
Этот флаг запрашивает память из зоны, котоая может быть использована для DMA. Конкретное значение зависит от платформы и обсуждается в следующем разделе.

__GFP_HIGHMEM
Этот флаг говорит, что выделяемая память может размещаться в верхней памяти.

__GFP_COLD
Обычно, аллокатор памяти пытается вернуть "кэш-теплые" страницы, т.е. страницы, которые недавно оказывались в кэше процессора. Этот флаг напротив, запрашивает холодные страницы, т.е. те которые не использовались уже некоторое время. Это полезно для выделения страниц для чтения через DMA, где бесполезна связь страницы памяти с кэшем. Полное описание выделения буферов для DMA находится в Главе 15 .

__GFP_NOWARN
Этот флаг используется редко, он заставляет ядро не выводить предупреждения (с помощью printk) когда выделение памяти невозможно.

__GFP_HIGH
Этот флаг определяет запрос высокого приоритета, который позволяет употребить даже последние страницы памяти, отложенные ядром для экстренных случаев.

__GFP_REPEAT
__GFP_NOFAIL
__GFP_NORETRY
Эти флаги определяют поведение аллокатора когда есть трудности с выделением. __GFP_REPEAT подразумевает "постарайся немного лучше" повторив попытку, но выделение все еще может закончиться неудачей. __GFP_NOFAIL говорит аллокатору, что нужно выполнить запрос во что бы то ни стало; и он пашет как проклятый, пытаясь выполнить задание. Использование __GFP_NOFAIL очень и очень нежелательно; по правде сказать, вряд ли найдутся убедительные причины использовать это флаг в драйвере устройства. И наконец, __GFP_NORETRY говорит аллокатору оставить попытки немедленно если запрашиваемая память недоступна.

Переведено на Нотабеноиде
http://notabenoid.org/book/11832/38312

Переводчики: VectorVT44Mil

Настройки

Готово:

60.60% КП = 1.0

Непереведённые фрагменты будут пропущены.