• SLAB_MUST_HWCACHE_ALIGN
. Если включен режим отладки, то может оказаться невозможным одновременная отладка и выравнивание положения объектов по строкам системного кэша. Этот флаг указывает уровню слябового распределения памяти, что необходимо форсировать выравнивание положения объектов по строкам системного кэша. В обычной ситуации этот флаг указывать необязательно, и достаточно использовать предыдущий. Установка этого флага в режиме отладки слябового распределителя памяти (по умолчанию отладка запрещена) может привести к значительному увеличению затрат памяти. Только для объектов, которые критичны к выравниванию по строкам системного кэша, таких как дескрипторы процессов, необходимо указывать данный флаг.
• SLAB_POISON
— этот флаг указывает на необходимость заполнения слябов известным числовым значением (a5a5a5a5). Эта операция называется "отравлением" ( poisoning ) и служит для отслеживания доступа к неинициализированной памяти.
• SLAB_RED_ZONE
— этот флаг указывает на необходимость выделения так называемых "красных зон" ( red zone ) для облегчения детектирования переполнений буфера.
• SLAB_PANIC
— этот флаг указывает на необходимость перевода ядра в состояние паники, если выделение памяти было неудачным. Данный флаг полезен, если выделение памяти всегда должно завершаться успешно, как, например, в случае создания кэша структур VMA (областей виртуальной памяти, см. главу 14, "Адресное пространство процесса") при загрузке системы.
• SLAB_CACHE_DMA
— этот флаг указывает уровню слябового распределения, что все слябы должны выделяться в памяти, с которой возможны операции прямого доступа к памяти. Это необходимо, когда объекты используются в операциях ПДП и должны находиться в зоне ZONE_DMA
. В противном случае эта возможность не нужна и этот флаг не нужно устанавливать.
Два последних параметра ctor
и dtor
— это конструктор и деструктор кэша соответственно. Конструктор вызывается, когда в кэш добавляются новые страницы памяти. Деструктор вызывается, когда из кэша удаляются страницы памяти. Если указан деструктор, то должен быть указан и конструктор. На практике кэши ядра ОС Linux обычно не используют функции конструктора и деструктора. В качестве этих параметров можно указывать значение NULL
.
В случае успешного выполнения функция kmem_cache_create()
возвращает указатель на созданный кэш. В противном случае возвращается NULL
. Данная функция не может вызываться в контексте прерывания, так как она может переводить процесс в состояние ожидания. Для ликвидации кэша необходимо вызвать следующую функцию.
int kmem_cache_destroy(kmem_cache_t *cachep);
Эта функция ликвидирует указанный кэш. Она обычно вызывается при выгрузке модуля, который создает свой кэш. Из контекста прерывания эту функцию вызывать нельзя, так как она может переводить вызывающий процесс в состояние ожидания. Перед вызовом этой функции необходимо, чтобы были выполнены следующие два условия.
• Все слябы кэша являются пустыми. Действительно, если в каком-либо слябе существует объект, который все еще используется, то как можно ликвидировать кэш?
• Никто не будет обращаться к кэшу во время и особенно после вызова функции kmem_cache_destroy()
. Эту синхронизацию должен обеспечить вызывающий код.
В случае успешного выполнения функция возвращает нуль, в других случаях возвращается ненулевое значение.
После того как кэш создан, из него можно получить объект путем вызова следующей функции.
void* kmem_cache_alloc(kmem_cache_t *cachep, int flags);
Эта функция возвращает указатель на объект из кэша, на который указывает параметр cachep
. Если ни в одном из слябов нет свободных объектов, то уровень слябового распределения должен получить новые страницы памяти с помощью функции kmem_getpages()
, значение параметра flags
передается в функцию __get_free_pages()
. Это те самые флаги, которые были рассмотрены ранее. Скорее всего, необходимо указывать GFP_KERNEL
или GFP_ATOMIC
.
Далее для удаления объекта и возвращения его в сляб, из которого он был выделен, необходимо использовать следующую функцию.
void kmem_cache_free(kmem_cache_t *cachep, void *objp);
Данная функция помечает объект, на который указывает параметр objp
, как свободный.
Пример использования слябового распределителя памяти
Давайте рассмотрим пример из реальной жизни, связанный с работой со структурами task_struct
(дескрипторы процессов). Показанный ниже код в несколько более сложной форме приведен в файле kernel/fork.c.
Читать дальше