Następna Poprzednia Spis Linux, jądro 2.4.7

4. Obsługa plików i urządzeń wymiany

Omówię tu sposób, w jaki Linux wykorzystuje pliki i urządzenia wymiany w celu wirtualnego rozszerzenia dostępnej w systemie pamięci RAM.

4.1 Kilka definicji

Urządzenie wymiany
urządzenie, najczęściej dyskowe, umożliwiające zachowywanie na nim stron pamięci. Może być zaimplementowane jako:
  • plik stałej wielkości - jego części mogą być zapisane w różnych miejscach dysku, co spowalnia czas dostępu
  • urządzenie blokowe - oddzielna partycja dysku twardego
  • Obszar wymiany
    miejsce udostępniane przez urządzenie/plik wymiany do zapisywania stron pamięci.

    Slot strony
    blok obszaru wymiany zawierający dokładnie jedną stronę (Linux: 4096 B). Każdy obszar wymiany dzielimy na szereg kolejnych slotów.

    4.2 Struktury danych

    Linux umożliwia zdefiniowanie MAX_SWAPFILES (obecnie 8) obszarów wymiany. Posiadanie kilku obszarów wymiany umożliwia:

  • dynamiczne zwiększanie przestrzeni wymiany (bez restartu systemu)
  • umieszczenie obszarów wymiany na różnych dyskach - można z nich korzystać jednocześnie
  • Pierwszy slot obszaru wymiany zawiera informacje o obszarze wymiany - jego format opisuje unia swap_header.
    Na globalnej zmiennej nr_swap_pages przechowywana jest ilość wolnych slotów we wszystkich obszarach wymiany.
    W tablicy swap_info przechowywane są deskryptory obszarów wymiany, zdefiniowane następująco:

    struct swap_info_struct {
    	unsigned int flags;		// SWP_USED - czy obszar wymiany jest aktywny
    					   SWP_WRITEOK -czy do obszaru można zapisywać
    	kdev_t swap_device;		// numer urządzenia
    	spinlock_t sdev_lock;		
    	struct dentry * swap_file;	// pozycja katalogu pliku/pliku urządzenia
    	struct vfsmount *swap_vfsmnt;
    	unsigned short * swap_map;	// tablica liczników użycia slotów
    	unsigned int lowest_bit;	// pierwszy wolny slot
    	unsigned int highest_bit;	// ostatni wolny slot
    	int prio;			// priorytet urządzenia
    	int pages;			// liczba użytecznych slotów
    	unsigned long max;		// rozmiar w stronach
    	unsigned int cluster_next;	//
    	unsigned int cluster_nr;	// wykorzystywane przy wyborze wolnego slotu
    	int next;			//
    };
    




    Aby stwierdzić, gdzie dana strona została wymieniona, należy zidentyfikować obszar wymiany i numer slotu, w którym się znajduje. Informacje te tworzą identyfikator wymienionej strony, zapisywany w momencie wymiany w odpowiedniej pozycji Tablicy Stron.
    Najmłodszy bit identyfikatora - flaga Present - jest wyzerowany, co oznacza, że strona opisywana przez daną pozycję Tablicy Stron nie znajduje się w pamięci RAM.
    W manipulowaniu identyfikatorem wymienionej strony pomagają następujące makra:
    SWP_TYPE(id_strony) - pobierz numer obszaru
    SWP_OFFSET(id_strony) - pobierz indeks slotu strony
    SWP_ENTRY(type, offset) - stwórz identyfikator wymienionej strony

    4.3 Dołączanie nowego urządzenia wymiany

    Aby móc z urządzenia wymiany korzystać, superużytkownik musi je uaktywnić.
    Służy do tego funkcja:
    long sys_swapon(const char * specialfile, /* ścieżka dostępu do pliku urządzenia/zwykłego
    					   pliku, który chcemy aktywować */
    		int swap_flags)		/* priorytet urządzenia (domyślnie -1) */
    
    Funkcja ta:
  • sprawdza poprawność danych o urządzeniu zawartych w 1-szym slocie, wpisanych tam w momencie tworzenia partycji wymiany
  • znajduje wolne miejsce w tablicy swap_info i umieszcza tam nowy deskryptor obszaru wymiany
  • inicjuje pola deskryptora (ustawia liczbę uszkodzonych stron, alokuje pamięć na tablice, itp)
  • 4.4 Odłączanie urządzenia wymiany

    Proces odłączania urządzenia jest o wiele bardziej skomplikowany. Wykonuje go funkcja:
    long sys_swapoff(const char * specialfile) /* ścieżka dostępu do pliku urządzenia lub
    					     zwykłego pliku, który chcemy aktywować */
    
    Problemem jest wczytanie wszystkich stron z odłączanego urządzenia do pamięci RAM oraz uaktualnienie we wszystkich tablicach stron wszystkich procesów identyfikatora wymienionej strony na adres fizyczny wczytanego bloku stronicowego.
    Jeśli w pewnym momencie zabraknie pamięci na wczytanie kolejnej strony z odłączanego urządzenia, operacja kończy się niepowodzeniem i urządzenie wymiany pozostaje aktywne.

    4.5 Znajdowanie wolnego slotu

    Główny priorytet: zajęte sloty muszą tworzyć jak najbardziej spójny obszar

    Powód: zminimalizowanie czasu przeszukiwania dysku przy korzystaniu z obszaru wymianu

    Przyjęte rozwiązanie:
    Staramy się, by wymieniane strony tworzyły w obszarze wymiany jak najbardziej spójne bloki. W tym celu dla stron wchodzących w skład jednej grupy alokuje się kolejne wolne sloty. Grupę taką nazywamy klastrem - jego rozmiar wynosi SWAPFILE_CLUSTER (tu: 256). Gdy zaalokujemy SWAPFILE_CLUSTER stron, zaczynamy nowy klaster. Będzie to pierwszy poczynając od początku obszaru wymiany spójny blok SWAPFILE_CLUSTER slotów. Może się jednak zdażyć, iż takiego bloku nie ma - wtedy zaczynamy 'wypełniać dziury' - alokujemy wolne sloty poczynając od pierwszego wolnego, dopóki nie wypełnimy SWAPFILE_CLUSTER slotów.
    Zadanie to wypełnia funkcja scan_swap_map(), która znajduje wolny slot w danym obszarze wymiany.

    int scan_swap_map
    	(struct swap_info_struct *si, /* wsk. na deskr. obszaru wymiany */
    	 unsigned short count)		/* liczba użytkowników slotu      */
    	/* i-ty slot jest wolny <=> si->swap_map[i] == 0 
    	cluster_next - indeks slotu strony, od którego zaczynamy szukać wolnego slotu
    	cluster_nr - liczba dotychczas zaalokowanych slotów w klastrze
    	*/
    	
    	jeśli  w obszarze wymiany nie ma już wolnych slotów rób
    		return 0
    
    	jeśli  si->cluster_nr > 0 rób
    		offset = min{ nr wolnego slotu o numerze >=  si->cluster_next }
    		si->cluster_nr --
    	wpp { /* rozpocznij nowy klaster */
    		si->cluster_nr = SWAPFILE_CLUSTER;
    
    		jeśli istnieje spójny ciągu SWAPFILE_CLUSTER wolnych slotów rób
    			offset = min { numer pierwszego slotu takiego obszaru }
    		wpp
    			offset = pierwszy wolny slot
    	}
    
    	Uaktualnij pola si->lowest_bit i si->highest_bit
    	si->swap_map[offset] = count;
    	nr_swap_pages--;/* liczba wolnych slotów zmniejsza się */
    	si->cluster_next = offset+1;/* w tym miejscu zaczniemy szukać następnym razem */
    	return offset; /* zwróć indeks zaalokowanej strony */
    

    4.6 Alokowanie slotu strony

    Za wybór slotu, w którym zostanie zapisana wymieniana na dysk strona odpowiada funkcja
    swp_entry_t __get_swap_page(unsigned short count)
    Na początku ustala ona, z którego obszaru wymiany skorzystać. Kładzie się nacisk na wykorzystanie obszarów położonych na najszybszych dyskach. Każdy deskryptor obszaru wymiany w polu prio przechowuje informację o priorytecie obszaru - im szybszy dysk tym wyższy priorytet. Deskryptory aktywnych obszarów wymiany tworzą posortowaną malejąco względem pola prio listę, na której początek wskazuje zmienna swap_list. Gdy slot danego obszaru wymiany o priorytecie równym X zostanie zajęty, to następnym razem wolnego slotu będziemy poszukiwać poczynając od:
    - następnego obszaru wymiany na liście swap_list, jeśli jego priorytet jest równy X
    - pierwszego obszaru wymiany na liście swap_list w przeciwnym przypadku.
    Podejście to zapewnia równomierne obciążenie obszarów wymiany o tym samym priorytecie.

    Gdy wiadomo już, z którego obszaru wymiany skorzystać, wywoływana jest funkcja scan_swap_map(), która zwraca numer znajdującego sie w tym obszarze slotu do zaalokowania. Na podstawie numeru obszaru wymiany i numeru slotu strony tworzony jest identyfikator wymienianej strony, który jest zwracany.

    4.7 Zwalnianie slotu strony

    Za zwolnienie danego slotu odpowiada funkcja

    __swap_free(swp_entry_t entry, unsigned short count)
    która wykonuje następujące operacje:
  • uaktualnia pola lowest_bit i highest_bit deskryptora obszaru wymiany
  • zmniejsza licznik swap_map[nr_zwalnianego_slotu]
  • jeśli swap_map[nr_zwalnianego_slotu] == 0 oznacza to, że nikt nie korzysta z zawartości slotu, a więc liczba wolnych slotów zwiększa się (nr_swap_pages--)
  • 4.8 Źródła

    Źródła omawianych tutaj struktur i funkcji można znaleźć w plikach:

    mm/swapfile.c
    mm/swap.c
    


    Następna Poprzednia Spis Autor: Tomasz Pylak, 2001