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;
}