Уровень слябового распределения памяти делит объекты на группы, которые называются struct task_struct
), а другой — для индексов файловых систем (struct inode
). Интересно, что интерфейс kmalloc()
построен на базе уровня слябового распределения памяти и использует семейство кэшей общего назначения.
Далее кэши делятся на
Каждый сляб содержит некоторое количество
В качестве примера рассмотрим структуры inode
, которые являются представлением в оперативной памяти индексов дисковых файлов (см. главу 12). Эти структуры часто создаются и удаляются, поэтому есть смысл управлять ими с помощью слябового распределителя памяти. Структуры struct inode
выделяются из кэша inode_cachep
(такое соглашение по присваиванию названий является стандартом). Этот кэш состоит из одного или более слябов, скорее всего слябов много, поскольку много объектов. Каждый сляб содержит максимально возможное количество объектов типа struct inode
. Когда ядро выделяет новую структуру типа struct inode
, возвращается указатель на уже выделенную, но не используемую структуру из частично заполненного сляба или, если такого нет, из пустого сляба. Когда ядру больше не нужен объект типа inode
, то слябовый распределитель памяти помечает этот объект как свободный. На рис. 11.1 показана диаграмма взаимоотношений между кэшами, слябами и объектами.
Рис. 11.1. Взаимоотношения между кэшами, слябами и объектами
Каждый кэш представляется структурой kmem_cache_s
. Эта структура содержит три списка slab_full
, slab_partial
и slab_empty
, которые хранятся в структуре kmem_list3
. Эти списки содержат все слябы, связанные с данным кэшем. Каждый сляб представлен следующей структурой struct slab
, которая является дескриптором сляба.
struct slab {
struct list head list; /* список полных, частично заполненных
или пустых слябов */
unsigned long colouroff; /* смещение для окрашивания слябов */
void *s_mem; /* первый объект сляба */
unsigned int inuse; /* количество выделенных объектов */
kmem_bufctl_tfree; /* первый свободный объект, если есть */
};
Дескриптор сляба выделяется или за пределами сляба, в кэше общего назначения, или в начале самого сляба. Дескриптор хранится внутри сляба, либо если общий размер сляба достаточно мал, либо если внутри самого сляба остается достаточно места, чтобы разместить дескриптор.
Слябовый распределитель создает новые слябы, вызывая интерфейс ядра нижнего уровня для выделения памяти __get_free_pages()
следующим образом.
static void *kmem_getpages(kmem_cache_t *cachep,
int flags, int nodeid) {
struct page *page;
void *addr;
int i;
flags |= cachep->gfpflags;
if (likely(nodeid == -1)) {
addr = (void*)__get_free_pages(flags, cachep->gfporder);
if (!addr)
return NULL;
page = virt_to_page(addr);
} else {
page = alloc_pages_node(nodeid, flags, cachep->gfporder);
if (!page)
return NULL;
addr = page_address(page);
}
i = (1 << cachep->gfporder);