Opis funkcji inicjalizującej system podręcznej pamięci buforowej stron

Do inicjalizacji buforów stron służy funkcja page_cache_init. Oto ona wraz z moimi komentarzami:

void __init page_cache_init(unsigned long mempages)
/**
 * Bufor stron jest inicjalizowany przy starcie systemu.
 * Tak więc ta funkcja jest wołana tylko raz w funkcji:
 * start_kernel() z parametrem num_physpages, przy czym 
 * num_physpages = ilość pamięci w systemie wyrażona w ramkach.
 */
{
  unsigned long htable_size, order;

  htable_size = mempages;
  htable_size *= sizeof(struct page *); 
  /* na i386 jest to równoważne: htable_size *= 16; */

  for(order = 0; (PAGE_SIZE << order) < htable_size; order++)
    ;
  /**
   * pętla ustawia order tak żeby htable_size mieścił się w 2^order
   * stron. Order przyjmie następujące wartości w zależności od
   * rozmiaru pamięci:
   *       pamięć      | order | rozmiar tablicy page_hash_table
   *   4MB --   8MB-1B |  3    |       2048    kubełków
   *   8MB --  16MB-1B |  4    |       4096    -- // --
   *  16MB --  32MB-1B |  5    |       8192
   *  32MB --  64MB-1B |  6    |      16384
   *  64MB -- 128MB-1B |  7    |      32768
   * 128MB -- 256MB-1B |  8    |      65536
   * 256MB -- 512MB-1B |  9    |     131072
   * 512MB --   4GB    |  9 bo order jest poźniej (przy przydzie-
   *                   | laniu pamięci) przycinany tak, żeby nie
   *                   | przekraczał stałej MAX_ORDER równej 10
   *
   *    Uzależnienie wielkości tablicy page_hash_table od pamięci
   * ma na celu, z jednej strony oszczędność pamięci, a z drugiej
   * poprawienie właściwości funkcji mieszającej.
   */
  do {
    unsigned long tmp =(PAGE_SIZE << order) / sizeof(struct page *);
    /**
     * tmp jest liczbą wskaźników jakie się pomieszczą
     * w (PAGE_SIZE << order) bajtach pamięci.
     *
     * Poniższe operacje wyznaczają logarytm dwójkowy z tmp. 
     * Jak się potem okaże, tak uzyskana wartość page_hash_bits
     * będzie podstawą do wyznaczenia liczby pozycji przechowy-
     * wanych w tablicy page_hash_table. Patrz do punktu o 
     * strukturach danych.
     */
    page_hash_bits = 0;
    while((tmp >>= 1UL) != 0UL)
      page_hash_bits++;

    page_hash_table = (struct page **)
                      __get_free_pages(GFP_ATOMIC, order); 
    /**
     * __get_free_pages zwraca NULL jeśli order >= MAX_ORDER,
     * lub gdy nie udało się przydzielić pamięci, wpp. zwraca
     * wskaźnik do pierwszej z 2^order ramek pamięci 
     * przydzielonych na tablicę page_hash_table. 
     * Przydzielone ramki są powiązane w listę dwukierunkową.
     */

  } while(page_hash_table == NULL && --order > 0);

  /**
   * w printk jest mały BŁĄD, bo przez wzgląd na warunek 
   * ostatniej pętli powinno być (order + 1)
   */
  printk(
    "Page-cache hash table entries: %d (order: %ld, %ld bytes)\n"
    ,(1 << page_hash_bits), order, (PAGE_SIZE << order));
  /**
   * Tak więc w tablicy page_hash_table będziemy mieć:
   * (1 << page_hash_bits) pozycji!
   */

  if (!page_hash_table)
    panic("Failed to allocate page hash table\n");
  memset((void *)page_hash_table, 0, 
          PAGE_HASH_SIZE * sizeof(struct page *));
}


Tomasz Szymko 25 listopada 2001