Linux Kernel (Ядро линукса) (часть 1)


Интерфейс между slab-аллокатором и зонным аллокатором страничных кадров

Когда slab-аллокатор создает новый участок памяти, при получении группы свободных смежных страничных кадров он пользуется услугами зонного аллокатора страничных кадров. С этой целью он вызывает функцию kmem getpages , которая в UMA-системе эквивалентна следующему коду:
void kmem_getpages(kmem_cache_t cachep, int flags)
{struct page page; int i;
flags |= cachep->gfpflags;
page = alloc_pages(flags, cachep->gfporder); if (!page)
return NULL; i = (1 « cache->gfporder); if (cachep->flags & SLAB_RECLAIM_ACCOUNT) atomic_add(i, &slab_reclaim_pages); while (i—)
SetPageSlab(page++); return page_address(page);}

Два параметра этой функции имеют следующий смысл:

- cachep — указывает на дескриптор кэша, нуждающегося в дополнительных страничных кадрах (их количество определяется значением порядка в ПОЛе cachep->gfporder);
- flags — задает способ запрашивания страничного кадра. Этот набор флагов комбинируется с флагами выделения специального кэша, хранящимися в поле gfpf lags дескриптора кэша.

Размер запрашиваемой памяти задается в поле gfporder дескриптора кэша, которое кодирует размер участка в кэше. Если кэш участков памяти был создан при установленном флаге slab reclaim account, страничные кадры, присваиваемые участкам памяти, считаются утилизируемыми страницами, когда ядро проверяет, достаточно ли памяти для удовлетворения некоторых запросов в пользовательском режиме. Кроме того, функция устанавливает флаг PG siab в дескрипторах выделенных страничных кадрах.

В ходе обратной операции страничные кадры, присвоенные участку памяти, могут быть освобождены С ПОМОЩЬЮ функции kmem freepages :
void kmem_freepages(kmem_cache_t cachep, void addr)
{unsigned long i = (l«cachep->gfporder) ; struct page page = virt_to_page (addr) ;if (current->reclaim_state)
current->reclaim_state->reclaimed_slab += i; while (i—)
ClearPageSlab(page++); free_pages((unsigned long) addr, cachep->gfporder); if (cachep->flags & SLAB_RECLAIM_ACCOUNT)
atomic_sub (l«cachep->gfporder, &slab_reclaim_pages) ;}
Эта функция освобождает страничные кадры, начиная с кадра, имеющего линейный адрес addr и выделенного участку в кэше, идентифицируемом параметром cachep. Если текущий процесс выполняет утилизацию памяти (поле
current->reclaim_state не содержит NULL), ТО ПОЛе reclaimed_slab структуры reciaim state увеличивается должным образом, чтобы только что освобожденные страницы были учтены алгоритмом утилизации страничных кадров. Кроме того, если флаг slab_reclaim_account установлен, переменная siab_reciaim_pages должным образом уменьшается.

Выделение участка памяти кэшу

Только что созданный кэш не содержит участков памяти и, следовательно, не содержит свободных объектов. Новые участки присваиваются кэшу, только когда удовлетворены оба следующих условия:
- выдан запрос на выделение нового объекта;
- кэш не содержит ни одного свободного объекта.
В этой ситуации slab-аллокатор присваивает новый участок памяти кэшу, вызывая функцию cache_grow. Она, в свою очередь, вызывает функцию kmem getpages , чтобы получить от зонного аллокатора страничных кадров группу кадров, необходимых для хранения одного участка, а затем — функцию aiioc siabmgmt о, чтобы получить новый дескриптор участка. Если флаг cflgs off slab дескриптора кэша установлен, дескриптор участка памяти выделяется из общего кэша, на который указывает поле siabp cache дескриптора кэша. В противном случае дескриптор участка выделяется в первом страничном кадре участка памяти.

Ядро должно уметь определять по данному кадру, используется ли он slab- аллокатором, и, если используется, быстро вычислять адреса соответствующих дескрипторов кэша и участка памяти. Поэтому функция cache_grow перебирает дескрипторы всех страничных кадров, присвоенных новому участку памяти, и записывает в подполя next и prev полей iru этих дескрипторов адреса дескриптора кэша и дескриптора участка памяти соответственно. Здесь все корректно, потому что поле iru используется функциями buddy- системы, только когда страничный кадр свободен, в то время как кадры, с которыми работают функции slab-аллокатора, имеют установленный флаг PG siab и не являются свободными с точки зрения buddy-системы8. Ответ на противоположный вопрос, какие страничные кадры реализуют данный участок в кэше, может быть получен с помощью поля s mem дескриптора участка памяти и поля gfporder (размер участка) дескриптора кэша.

Затем функция cache_grow вызывает функцию cache init objs о, которая применяет метод-конструктор (если он определен) ко всем объектам, содержащимся в новом участке памяти.

ПОД конец работы функция cache_grow вызывает функцию list_add_tail , чтобы добавить только что полученный дескриптор участка siabp в конец списка полностью свободных участков, содержащегося в дескрипторе кэша cachep, и обновляет счетчик свободных объектов в кэше:
list_add_tail(&slabp->list, &cachep->lists->slabs_free); cachep->lists->free_objects += cachep->num;
Освобождение участка памяти из кэша
Участки памяти могут быть уничтожены в двух случаях:
-в кэше участков находится слишком много свободных объектов;
- некоторая периодическая вызываемая функция определяет наличие совершенно неиспользуемых участков, которые могут быть освобождены
В обоих случаях вызывается функция siab destroyо, которая уничтожает участок и освобождает соответствующие страничные кадры для зонного аллокатора страничных кадров:
void slab_destroy(kmem_cache_t cachep, slab_t slabp)
{if (cachep->dtor) { int i ;
for (i = 0; i num; i++) {
void objp = slabp->s_mem+cachep->objsizei;
(cachep->dtor)(objp, cachep, 0);}}
kmem_freepages(cachep, slabp->s_mem — slabp->colouroff); if (cachep->flags & CFLGS_OFF_SLAB)
kmem_cache_free(cachep->slabp_cache, slabp);}
Функция проверяет, имеется ли у кэша метод-деструктор его объектов (поле dtor должно быть отлично от null), и, если это так, применяет деструктор ко всем объектам в участке, причем локальная переменная objp отслеживает текущий объект. Затем функция вызывает функцию kmem_f reepages , которая возвращает buddy-системе все смежные страничные кадры, использованные участком. Наконец, если дескриптор участка памяти хранится вне участка, функция освобождает его из кэша дескрипторов участков.

На самом деле, функция устроена немного сложнее. Например, кэш участков памяти может быть создан при установленном флаге slab destroy by rcu, означающем, что участки должны уничтожаться с отсрочкой, путем регистрации обратного вызова, с помощью функции caii rcuo Функция обратного вызова, в свою очередь, вызывает функцию kmem_ f reepages И, ВОЗМОЖНО, функцию kmem cache f гее , как В ОСНОВНОМ случае, описанном ранее.

Предыдущая страница | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | Следующая страница




Возможно, Вас также заинтересует:

ОС Knoppix - это Linux без про...

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

Linux Kernel (Ядро линукса) (ч...

Спин-блокировкаСпин-блокировка необходима в многопроцессорной системе, потому что могут возникнуть...

Linux Kernel (Ядро линукса) (ч...

Копирование при записи В системах Unix первых поколений создание процесса было реализовано довольно...

Linux Kernel (Ядро линукса) (ч...

Буферы блоков и головы буферовУ каждого буфера есть дескриптор голова буфера, имеющий тип buffer...