Выбрать главу

Таблица 11.3. Модификаторы операций

Флаг Описание
__GFP_WAIT Операция выделения памяти может переводить текущий процесс в состояние ожидания
__GFP_HIGH Операция выделения памяти может обращаться к аварийным запасам
__GFP_IO Операция выделения памяти может использовать дисковые операции ввода-вывода
__GFP_FS Операция выделения памяти может использовать операции ввода- вывода файловой системы
__GFP_COLD Операция выделения памяти должна использовать страницы памяти, содержимое которых не находится в кэше процессора (cache cold)
__GFP_NOWARN Операция выделения памяти не будет печатать сообщения об ошибках
__GFP_REPEAT Операция выделения памяти повторит попытку выделения в случае ошибки
__GFP_NOFAIL Операция выделения памяти будет повторять попытки выделения неопределенное количество раз
__GFP_NORETRY Операция выделения памяти никогда не будет повторять попытку выделения памяти
__GFP_NO_GROW Используется внутри слябового распределителя памяти (slab layer)
__GFP_COMP Добавить метаданные составной (compound) страницы памяти. Используется кодом поддержки больших страниц памяти (hugetlb)

Описанные модификаторы можно указывать вместе, как показано в следующем примере.

ptr = kmalloc(size, __GFP_WAIT | __GFP_IO | __GFP_FS);

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

Большинство запросов на выделение памяти указывают эти модификаторы, но это делается косвенным образом с помощью флагов типа, которые скоро будут рассмотрены. Не нужно волноваться, у вас не будет необходимости каждый раз разбираться, какие из этих ужасных флагов использовать при выделении памяти!

Модификаторы зоны

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

Существует всего два модификатора зоны, поскольку, кроме зоны ZONE_NORMAL (из которой по умолчанию идет выделение памяти), существует всего две зоны. В табл. 11.4 приведен список модификаторов зоны.

Таблица 11.4. Модификаторы зоны

Флаг Описание
__GFP_DMA Выделять память только из зоны ZONE_DMA
__GFP_HIGHMEM Выделять память только из зон ZONE_HIGHMEM и ZONE_NORMAL

Указание одного из этих флагов изменяет зону, из которой ядро пытается выделить память. Флаг __GFP_DMA требует, чтобы ядро выделило память только из зоны ZONE_DMA Этот флаг эквивалентен следующему высказыванию в форме жесткого требования: "Мне абсолютно необходима память, в которой можно выполнять операции прямого доступа к памяти". Флаг __GFP_HIGHMEM, наоборот, требует, чтобы выделение памяти было из зон ZONE_NORMAL и ZONE_HIGHMEM (вторая более предпочтительна). Этот флаг эквивалентен запросу: "Я могу использовать верхнюю память, но мне на самом деле, все равно, и делайте, что хотите, обычная память тоже подойдет".

Если не указан ни один из флагов, то ядро пытается выделять память из зон ZONE_NORMAL и ZONE_DMA, отдавая значительное предпочтение зоне ZONE_NORMAL.

Флаг __GFP_HIGHMEM нельзя укалывать при вызове функций __get_free_pages() или kmalloc(). Это связано с тем, что они возвращают логический адрес, а не структуру page, и появляется возможность, что эти функции выделят память, которая в данный момент не отображается в виртуальное адресное пространство ядра и поэтому не имеет логического адреса. Только функция alloc_pages() может выделять страницы в верхней памяти. Однако в большинстве случаев в запросах на выделение памяти не нужно указывать модификаторы зоны, так как достаточно того, что используется зона ZONE_NORMAL.

Флаги типов

Флаги типов указывают модификаторы операций и зон, которые необходимы для выполнения запросов определенных типов. В связи с этим, в коде ядра стараются использовать правильный флаг типа и не использовать больших наборов модификаторов. Это одновременно и проще и при этом меньше шансов ошибиться. В табл. 11.5 приведен список возможных флагов типов, а в табл. 11.6 показано, какие модификаторы соответствуют какому флагу.

Таблица 11.5. Флаги типов

Флаг Описание
GFP_ATOMIC Запрос на выделение памяти высокоприоритетный и в состояние ожидания переходить нельзя. Этот флаг предназначен для использования в обработчика: прерываний, нижних половин и в других ситуациях, когда нельзя переходить в состояние ожидания
GFP_NOIO Запрос на выделение памяти может блокироваться, но при его выполнении нельзя выполнять операции дискового ввода-вывода. Этот флаг предназначен для использования в коде блочного ввода-вывода, когда нельзя инициировать новые операции ввода-вывода
GFP_NOFS Запрос на выделение памяти может блокироваться и выполнять дисковые операции ввода-вывода, но запрещено выполнять операции, связанные с файловыми системами. Этот флаг предназначен для использования в коде файловых систем, когда нельзя начинать выполнение новых файловых операций
GFP_KERNEL Обычный запрос на выделение памяти, который может блокироваться. Этот флаг предназначен для использования в коде, который выполняется в контексте процесса, когда безопасно переходить в состояние ожидания
GFP_USER Обычный запрос на выделение памяти, который может блокироваться. Этот флаг используется для выделения памяти процессам пространства пользователя
GFP_HIGHUSER Запрос на выделение памяти из зоны ZONE_HIGHMEM, который может блокироваться. Этот флаг используется для выделения памяти процессам пространства пользователя
GFP_DMA Запрос на выделение памяти из зоны ZONE_DMA. Драйверам устройств, которым нужна память для выполнения операций по ПДП, необходимо использовать этот флаг обычно в комбинации с одним из описанных выше флагов