Как работи kmalloc
Разпределителят на паметта kmalloc е мощен и лесен за научаване поради сходството си с malloc. Функцията е бърза (освен ако не блокира) и не изчиства паметта, която получава; селекцията все още запазва предишното съдържание. (* Това означава, наред с други неща, че трябва изрично да изчистите всяка памет, която може да бъде прехвърлена в потребителско пространство или записана в устройството; в противен случай рискувате да разкриете информация, която трябва да се пази в тайна.) Разпределената област е непрекъсната във физическата памет . Ще говорим подробно за kmalloc в следващите няколко раздела, за да можете да го сравните с методите за разпределение на паметта, които ще обсъдим по-късно.
Аргумент на знамена
Не забравяйте, че прототипът за kmalloc е:
void * kmalloc (size_t size, int flags);
Първият аргумент на kmalloc е размерът на блока, който ще бъде разпределен. Вторият аргумент, знамена за разпределение, е много по-интересен, тъй като контролира поведението на kmalloc по редица начини.
Най-често използваният флаг, GFP_KERNEL, означава, че разпределението (което в крайна сметка се извършва вътрешно чрез извикване на __get_free_pages, което е източникът на префикса GFP_) се извършва от името на процес, изпълняван в пространството на ядрото. С други думи, това означава, че повикващият прави системно обаждане от името на процеса. Използването на GFP_KERNEL означава, че kmalloc може да постави текущия процес в режим на заспиване, за да изчака страница при извикване в ситуации с малко памет. Следователно, функция, която разпределя паметта с помощта на GFP_KERNEL, трябва да се върне обратно и не може да бъде изпълнена в атомен контекст. Докато текущият процес е заспал, ядрото предприема подходящи мерки за намиране на свободна памет, като изтрива буферите на диск или разтоварва потребителския процес от паметта.
GFP_KERNEL не винаги е правилният флаг за разпределение, който да се използва; понякога kmalloc се нарича извън контекста на даден процес. Този тип обаждане може да се случи, например, в манипулатори на прекъсвания, микрозадачи и таймери на ядрото. В този случай текущият процес не трябва да бъде приспан и вместо това драйверът трябва да използва флага GFP_ATOMIC. Ядрото обикновено се опитва да запази няколко свободни страници, за да извърши разпределение на атомна памет. Когато се използва GFP_ATOMIC, kmalloc може дори да използва последната безплатна страница. Ако обаче тази последна страница не съществува, изборът се проваля.
Други знамена могат да се използват вместо или в допълнение към GFP_KERNEL и GFP_ATOMIC, въпреки че тези две покриват повечето от нуждите на драйвера на устройството. Всички флагове са дефинирани в и някои флагове са с префикс с двойни долни черти, например __GFP_DMA. Освен това има символи за често използвани комбинации от знамена; те не са с префикс и понякога се наричат приоритети за разпределение. Последните включват:
Използва се за разпределяне на памет в манипулатори на прекъсвания и друг код извън контекста на процеса. Никога не заспива.
Нормално разпределение на паметта на ядрото. Може да заспи.
Използва се за разпределяне на памет за страници на потребителско пространство; може да заспи.
Подобно на GFP_USER, но разпределя от областта с голяма памет, ако има такава. Горната област на паметта е описана в следващия подраздел.
Тези флагове функционират като GFP_KERNEL, но те добавят ограничения върху това, което ядрото може да направи, за да задоволи тази заявка. Разпределението с GFP_NOFS не позволява да се извършват никакви повиквания към файловата система и GFP_NOIO предотвратява иницииране на вход/изход за всичко. Те се използват главно във файловата система и кода за виртуална памет, където операциите по разпределение могат да бъдат оставени да заспят, но рекурсивните извиквания към файловата система биха били лоша идея.