Wykorzystywane są pola pages_min, pages_low i pages_high ze struktury opis strefy - zone_t. Są one inicjowane następująco (jest to uproszczony kod!):
static char *zone_names[MAX_NR_ZONES] = { "DMA", "Normal", "HighMem" }; static int zone_balance_ratio[MAX_NR_ZONES] = { 32, 128, 128, }; static int zone_balance_min[MAX_NR_ZONES] = { 10 , 10, 10, }; static int zone_balance_max[MAX_NR_ZONES] = { 255 , 255, 255, }; for (j = 0; j < MAX_NR_ZONES; j++) { unsigned long mask = zones_size[j] / zone_balance_ratio[j]; if (mask < zone_balance_min[j]) mask = zone_balance_min[j]; else if (mask > zone_balance_max[j]) mask = zone_balance_max[j]; zone->pages_min = mask; zone->pages_low = mask*2; zone->pages_high = mask*3; }Główna praca wykonywana przy przydziale pamięci odbywa się w funkcji __alloc_pages, która korzysta z funkcji:
static struct page * __alloc_pages_limit(zonelist_t *zonelist, unsigned int order, int limit, int direct_reclaim);Powyższa funkcja przegląda strefy w kolejności występowania na liście zonelist (odpowiada to preferencjom co do wyboru strefy) i jeśli w którejś z nich ilość stron całkowicie wolnych + ilość stron na liście inactive_clean (ramki algorytmu wymiany, które są `czyste' i mogą w razie potrzeby zostać zwolnione) przekroczy jedną z wartości pages_min, pages_low, pages_high (parametr limit określa którą) to funkcja ta uaktualnia struktury (opisane wcześniej) i przydziela pamięć. W przeciwnym wypadku zwraca NULL. Parametr direct_reclaim określa czy funkcja może bezpośrednio odsyskać strony z listy inactive_clean_list (wołając funkcję reclaim_page).
struct page * __alloc_pages(unsigned int gfp_mask, unsigned long order, zonelist_t *zonelist); { int direct_reclaim = 0; if (order == 0 && (gfp_mask & __GFP_WAIT)) // dla żądań jednej direct_reclaim = 1; // strony z możliwością przeszeregowania try_again: -- Próba przydzielenia pamięci ze strefy gdzie ilość wolnych stron -- (free) większa od pages_low. Gdy się powiedzie wyjście z sukcesem! // Jeśli tu jesteśmy to brak strefy z dużą ilością całkowicie nieużywanej // pamięci. Jednak przy dużej aktywności wymiany stron na dysk poniższe // żądanie powinno się powieść page = __alloc_pages_limit(zonelist, order, PAGES_HIGH, direct_reclaim); if (page) return page; // Hmmm... Spróbujmy obniżyć wymagania page = __alloc_pages_limit(zonelist, order, PAGES_LOW, direct_reclaim); if (page) return page; // No więc naprawdę brakuje pamięci. Trzeba coś z tym zrobić. wakeup_kswapd(); // Budzimy kswapd if (gfp_mask & __GFP_WAIT) schedule(); // Jeśli możemy oddać procesor robimy to // kswapd powinien dostarczyć nam trochę pamięci page = __alloc_pages_limit(zonelist, order, PAGES_MIN, direct_reclaim); // PF_MEMALLOC to flaga procesu ustawiana przy wołaniu try_to_free_pages. if (!(current->flags & PF_MEMALLOC)) { // dla uniknięcia pętli nieskończonej if (order > 0 && (gfp_mask & __GFP_WAIT)) { -- Wołamy page_launder. Funkcja ta czyści brudne strony i przenosi -- je do listy inactive_clean_list. -- Następnie próbujemy odzyskać strony z listy inactive_clean_list -- (reclaim_page) i dokonać alokacji. } // jeśli dotarliśmy tutaj to naprawdę brakuje pamięci. // Staramy się sprostać żądaniom o 1 ramkę. if (gfp_mask & __GFP_WAIT) { if (!order || free_shortage()) { // wołamy try_to_free_pages - opisane w części referatu // dotyczącej wymiany int progress = try_to_free_pages(gfp_mask); if (progress || (gfp_mask & __GFP_FS)) goto try_again; return NULL; } } -- Próba przydzielenia czegokolwiek co zostało - tylko najbardziej -- krytyczne żądania pamięci mogą tu dotrzeć i skorzystać z rezerw. printk(KERN_ERR "__alloc_pages: %lu-order allocation failed.\n", order); return NULL; }