Можно сказать, что свойства флага GFP_ATOMIC лежат на противоположном конце спектра. Так как этот флаг указывает, что операция выделения памяти не может переходить в состояние ожидания, то такая операция очень ограничена в том, какую память можно использовать для выделения. Если нет доступного участка памяти заданного размера, то ядро, скорее всего, не будет пытаться освободить память, поскольку вызывающий код не может переходить в состояние ожидания. При использовании флага GFP_KERNEL, наоборот, ядро может перевести вызывающий код в состояние ожидания, чтобы во время ожидания вытеснить страницы на диск (swap out), очистить измененные страницы памяти путем записи их в дисковый файл (flush dirty pages) и т.д. Поскольку при использовании флага GFP_ATOMIC нет возможности выполнить ни одну из этих операций, то и шансов успешно выполнить выделение памяти тоже меньше (по крайней мере, когда в системе недостаточно памяти). Тем не менее использование флага GFP_ATOMIC — это единственная возможность, когда вызывающий код не может переходить в состояние ожидания, как в случае обработчиков прерываний и нижних половин.
По своим свойствам между рассмотренными флагами находятся флаги GFP_NOIC и GFP_NOFS. Операции выделения памяти, которые запущены с этими флагами, могут блокироваться, но они воздерживаются от выполнения некоторых действий. Выделение памяти с флагом GFP_NOIO не будет запускать никаких операций дискового ввода-вывода. С другой стороны, при использовании флага GFP_NOFS могут запускаться операции дискового ввода-вывода, но не могут запускаться операции файловых систем. Когда эти флаги могут быть полезны? Они соответственно необходимы для определенного низкоуровневого кода блочного ввода-вывода или кода файловых систем. Представьте себе, что в некотором часто используемом участке кода файловых систем используется выделение памяти GFP_NOFS. Если выделение памяти требует выполнения операций файловой системы, то выделение памяти приведет к еще
Флаг GFP_DMA применяется для указания, что система выделения памяти должна при выполнении запроса предоставить память из зоны ZONE_DMA. Этот флаг используется драйверами устройств, для которых необходимо выполнение операций прямого доступа к памяти. Обычно этот флаг должен комбинироваться с флагами GFP_ATOMIC или GFP_KERNEL.
В подавляющем большинстве случаев при разработке кода вам будет необходимо использовать флаги GFP_ATOMIC или GFP_KERNEL. В табл. 11.7 показано какие флаги и в каких ситуациях необходимо использовать. Независимо от типа операции выделения памяти, необходимо проверять результат и обрабатывать ошибки.
Таблица 11.7. Какой флаг и когда необходимо использовать
| Ситуация | Решение |
|---|---|
| Контекст процесса, можно переходить в состояние ожидания | Используется флаг GFP_KERNEL |
| Контекст процесса, нельзя переходить в состояние ожидания | Используется флаг GFP_ATOMIC или память выделяется с использованием флага GFP_KERNEL но в более ранний или поздний момент, когда можно переходить в состояние ожидания |
| Обработчик прерывания | Используется флаг GFP_ATOMIC |
| Обработка нижней половины | Используется флаг GFP_ATOMIC |
| Необходима память для выполнения операций ПДП, можно переходить в состояние ожидания | Используются флаги (GFP_DMA | GFP_KERNEL) |
| Необходима память для выполнения операций ПДП, нельзя переходить в состояние ожидания | Используются флаги (GFP_DMA | GFP_ATOMIC) или выделение выполняется в более поздний или более ранний момент времени |
Функция kfree()
Обратной к функции kmalloc() является функция kfree(), которая определена в файле следующим образом.
void kfree(const void *ptr);