next up previous contents
Next: Zwolnienie pamięci Up: Realizacja Previous: Realizacja   Spis rzeczy

Przydział pamięci

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



Adam Koprowski 2001-12-18