Systemy Operacyjne – semestr drugi
Wyk a
ł d jedenasty
Wirtualny system plików
Oprócz alokatora plastrowego twórcy jądra Linuksa zapo y
ż czyli z systemu Solaris wirtualny system plików (ang. Virtulal File System – VFS). Jest to warstwa po r ś ednicząca
mi d
ę zy rzeczywistym systemem plików, a resztą jądra. Dzi k
ę i niej Linux mo e
ż obs u
ł giwać ró n
ż e, czasami diametralnie ró n
ż iące się systemy plików. To rozwiązanie jest
również ciekawe pod innym wzgl d
ę em – kod wirtualnego systemu plików ma większość cech charakterystycznych dla techniki programowania obiektowego, mimo e ż nie
został napisany w j z
ę yku obiektowym. Wirtualny system plików pozwala na unifikację rzeczywistych systemów plików. Oznacza to, e ż procesy u y
ż tkownika, jak również
inne elementy systemu operacyjnego obsługują pliki, niezale n
ż ie od tego, w jakim systemie plików są one zapisane, zawsze za pomocą takich wywołań systemowych jak open (), read(), write(), close() itd. Warstwa VFS „przekłada” te wywołania, na operacje charakterystyczne dla danego systemu plików. Powy s ż zy opis mo n
ż a podsumować
stwierdzeniem, e
ż wirtualny system plików tworzy wspólny model (abstrakcj )
ę systemu plików, pozwalający na reprezentację cech i operacji jakie są mo l ż iwe
w rzeczywistych systemach plików.
Konstrukcja owego wspólnego modelu plików jest c
ś i l
ś e związana z macierzystym systemem plików oryginalnego systemu Unix. Podstawowymi elementami w takim systemie były: pliki, katalogi, i-w z
ę ły (ang. i-node = index node) oraz punkty montowania. System plików jest strukturą przechowującą dane, w której obowi z ą uje pewna
hierarchia. W systemach uniksowych systemy plików montowane są w okre l
ś onym punkcie wspólnego drzewa katalogowego1 - tworzą przestrzeń nazw wspólną dla całego systemu, choć w Linuksie, od wersji 2.4 ka d
ż y z procesów mo e
ż mieć swoją własną, okre l
ś oną przestrzeń nazw. Pliki są uporz d
ą kowanymi ciągami bajtów2. Z ka d
ż ym
z plików jest związana identyfikująca go nazwa. Na plikach mo n
ż a wykonywać takie operacje jak: otwarcie, zamknięcie, zapis, odczyt. Katalogi są plikami, które przechowują informacje o innych plikach. Mogą one posiadać inne, zagnie d
ż
on
ż
e katalogi nazywane podkatalogami. Kolejne nazwy zagnie d
ż
on
ż
ych katalogów tworzą c
ś ie k
ż i
dostępu. Ka d
ż y z elementów takiej c
ś ie k
ż i tworzy wpis katalogowy (ang. dentry = directory entry). Linux traktuje katalogi jak zwykłe pliki, w związku z tym mo n ż a na nich
przeprowadzić część tych samych operacji, co na plikach. Informacje o pliku (np.: data utworzenia, rozmiar, czyli metadane pliku) w systemach uniksowych gromadzone są tak e
ż w osobnych blokach na dysku, zwanych i-węzłami. Informacje steruj c
ą e i kontrolne związane z całym systemem plików (metadane systemu plików) przechowywane są w bloku głównym, który jest nazywany superblokiem. Niektóre systemy plików nie są zgodne z przedstawionym wy ej ż modelem, mimo to mo l
ż iwe jest ich u y
ż cie w systemie
Linux. Jest to „zasługą” VFS, który przedstawia wszystkie niezbędne elementy tych systemów, tak aby pasowały one do ogólnego modelu.
Wirtualny system plików jest oparty o model obiektowy, mimo e
ż jest zrealizowany od pocz t
ą ku do końca w języku C, który takiego modelu bezpo r
ś ednio nie wspiera.
Obiekty VFS są po prostu zmiennymi, których typ okre l
ś ają struktury, które są z kolei odpowiednikami klas3. Ka d
ż a z takich struktur zawiera wskaźnik do struktury
wska n
ź ików na funkcje realizujące okre l
ś one operacje na elementach u y
ż tkowanego systemu plików (odpowiedniki metod). W VFS istnieją cztery typy tych obiektów: obiekty bloku g ów
ł
nego reprezentuj c
ą e zamontowane systemy plików, obiekty i-węzła reprezentujące pojedynczy plik, obiekty wpisu katalogowego reprezentujące pojedynczy wpis katalogowy oraz obiekty pliku skojarzone z otwartymi przez proces plikami. Ka d ż y z obiektów tych typów zawiera charakterystyczne dla jego typu obiekty operacji: super_operations zawiera metody wła c
ś iwe dla danego systemu plików, inode_operations – metody dotyczące konkretnego pliku, dentry_operations – metody w a ł
c
ś iwe dla
wpisu katalogowego i w końcu obiekty plikowe grupują metody do obsługi otwartych plików. Część tych metod mo e ż być „dziedziczona” z grupy funkcji rodzajowych, które
implementują wersje tych metod wspólne dla wszystkich systemów plików.
Ka d
ż y system plików posiada swój własny obiekt bloku głównego (superbloku), który przechowuje wszystkie niezbędne informacje dotyczące tego systemu plików. Zazwyczaj jego zawartość ca k
ł owicie lub w dużej mierze pokrywa si
ę z zawarto c
ś ią odpowiedniego bloku na dysku twardym lub innym no n
ś iku danych. Istnieją jednak pewne systemy
plików, które nie mają swojej fizycznej implementacji np.: sysfs lub procfs. Te systemy plików istnieją wyłącznie jako dane w pamięci operacyjnej. Typ obiektów superbloku okre l
ś ony jest przez strukturę struct super_block. Zawiera ona mi d
ę zy innymi takie pola jak identyfikator urządzenia na którym znajduje się opisywany przez obiekt system plików, maksymalny rozmiar plików, typ systemu plików, liczba aktywnych odwoła ,
ń itd. Obiekt bloku g ów
ł
nego jest równocześnie tworzony i inicjalizowany przez funkcję
alloc_super(). Najwa n
ż iejszym polem tego obiektu jest pole s_op zawierające tablicę operacji na bloku g ów ł
nym, która jest reprezentowana przez typ struct super_operations.
Ka d
ż y element tej tablicy jest wska n
ź ikiem na funkcję wywoływaną wtedy, gdy jądro chce wykonać jakieś operacje na systemie plików, np. zapis bloku głównego odbywa się za pomocą instrukcji sb->s_op->write_super(sb). Przekazanie wska n
ź ika na strukturę superbloku do funkcji write_super() jest konieczne, gdyż w j z
ę yku C nie ma wska n
ź ika
this. Do metod obiektu operacji superbloku należą alloc_inode(), która tworzy i inicjalizuje obiekt i-węzła, destroy_inode() - zwalnia obiekt i-w z ę a
ł , read_inode() - s u
ł
y
ż do
odczytania z dysku bloku zawieraj c
ą ego i-w z
ę eł, dirty_inode() - funkcja wywoływana przez VFS po modyfikacji obiektu i-węz a
ł , write_inode() - s u
ł
y
ż do zapisu i-w z
ę ła na
dysk, put_inode() - zwalnia wskazany i-w z
ę e ,
ł drop_inode() - funkcja wywo y
ł wana przez VFS w momencie zwolnienia ostatniego odwołania do i-w z
ę ła, delete_inode() -
funkcja usuwa i-w z
ę eł z dysku, put_super() - funkcja wywoływana przy odmontowywaniu systemu plików w celu zwolnienia obiektu superbloku, write_super() - funkcja służąca do zapisania danych superbloku na dysk, sync_fs() - funkcja służąca do uaktualnienia metadanych systemu plików, write_super_lockfs() - funkcja blokuje zmiany w systemie plików i aktualizuje blok no n
ś ika zawieraj c
ą ych dane o systemie plików, unlockfs() - jest komplementarna do poprzedniej, statfs() - funkcja pozwala uzyskać informacje na temat systemu plików, remount_fs() - służy do ponownego montowania systemu plików, clear_inode() - zwalnia i-węz y ł i czy c
ś i strony pami c
ę i z nimi związane,
umont_begin() – funkcja słu y
ż do przerwania operacji odmontowywania, jest wykorzystywana przez sieciowe systemy plików, takie jak np. NFS. Nie wszystkie te operacje muszą by
ć zaimplementowane w poszczególnych systemach plików. Je l
ś i nie są, to wska n
ź iki na odpowiadające im funkcje mają wartoś
ć NULL.
Obiekty i-w z
ę ła przechowują wszystkie informacje niezb d
ę ne do przeprowadzenia operacji na plikach i katalogach, z którymi są zwi z ą ane. W przypadku niektórych
nieuniksowych systemów plików te informacje są pobierane wprost z pliku lub z innego miejsca na dysku, gdzie są przechowywane i umieszczane w obiekcie. Część z tych informacji nie jest obecna w niektórych systemach plików. W takich wypadkach pola im odpowiadające wype n ł iane są dowolnymi wartościami. Obiekty i-w z
ę łów mogą być
związane nie tylko z fizycznymi plikami, ale również z plikami specjalnymi, np. plikami urządzeń lub kolejek FIFO. Pojedynczy obiekt i-w z ę ła zawiera między innymi takie
pola, jak np.: identyfikator wła c
ś iciela pliku, prawdziwy numer urządzenia na którym plik jest zapisany, tryb dostępu, numer i-w z ę ła, rozmiar pliku. Zawiera on również
pole i_fop wskazujące na obiekt operacji, które mogą zostać przeprowadzone na plikach. Oprócz tego pola istnieje inne pole wska n ź ikowe o nazwie i_op wskazujące na
strukturę zawierającą wska n
ź iki na funkcje realizujące operacje na obiekcie i-węzła. Do tych operacji należą: create() - stworzenie nowego i-węz a ł związanego z zadanym
obiektem wpisu katalogowego, lookup() - przeszukuje katalog w celu znalezienia i-węzła z okre l ś onym wpisem katalogowym, sym_link() - tworzy dowiązanie symboliczne,
mkdir() - tworzy plik będący katalogiem, rmdir() - usuwa katalog, mknod() - funkcja tworzy plik specjalny (reprezentujący urz d ą zenie), rename() - zmienia nazwę pliku,
read_link() - odczytuje okre l
ś oną część pełnej c
ś ie k
ż i zwi z
ą anej z dowiązaniem symbolicznym, follow_link() - konwertuje dowiązanie do i-w z ę ła docelowego, truncate() -
modyfikuje rozmiar pliku, permission() - obsługuje prawa dostępu w niektórych systemach plików, setattr() - inicjuje powiadomienie o zmianie zawarto c ś i i-węzła, getattr() -
powiadamia, że i-w z
ę eł powinien zostać ponownie odczytany z dysku, setxattr() - ustawia atrybuty rozszerzone, getxattr() - odczytuje wartość atrybutu rozszerzonego, listxattr() - kopiuje list
ę wszystkich rozszerzonych atrybutów do bufora, removexattr() - funkcja usuwa wskazany atrybut rozszerzony z listy.
Obiekty wpisu katalogowego związane są z ka d
ż ą nazwą katalogu pojawiaj c
ą ą się w c
ś ie c
ż e dostępu. Tak więc np. dla c
ś ie k
ż i /usr/java stworzone zostaną trzy takie obiekty:
dla katalogu głównego „/”, dla katalogu „usr” i dla katalogu „java”. S u
ł żą one do realizowania operacji, które są charakterystyczne dla katalogów, a nie dla plików, jak, np.
przeszukiwanie katalogów. Je l
ś i c
ś ie k
ż ę ko c
ń zy zwykły plik, to jest on również reprezentowany przez obiekt wpisu katalogowego. Do c ś ie k
ż i dost p
ę u mogą również nale e
ż ć
punkty montowania. Obiekty wpisu katalogowego są tworzone na bież c
ą o, w trakcie analizowania c
ś ie k
ż i dostępu. Typ takich obiektów jest okre l
ś ony strukturą struct
dentry. Te obiekty nie są związane z a
ż dnymi danymi na dysku, więc struktura je opisująca nie zawiera a
ż dnego znacznika informującego o zmianie ich zawarto c
ś i. Obiekt
wpisu katalogowego mo e
ż znajdować się w jednym z trzech stanów: używanym, nieu y
ż wanym lub ujemnym. Obiekt w stanie „używany” odpowiada poprawnemu i-w z
ę łowi
i jest wykorzystywany w obecnym przedziale czasowym przez u y
ż tkowników systemu. Obiekt w stanie „nieu y
ż wany” również odpowiada poprawnemu i-w z
ę łowi, ale obecnie
1
Jest to bardzo jednolity opis. Sięgając do określonego pliku nie musimy wiedzieć na jakim fizyczne urządzeniu się znajduje. Systemy plików na wszystkich takich urządzeniach współtworzą wspólne drzewo katalogów. Przykładem innego podej c
ś ia są systemy MS Windows.
2
Nale y
ż zaznaczy ,
ć że pojęcie pliku jest podstawowym, obok procesu, pojęciem w systemie Unix. Nie wszystkie pliki są „pojemnikami” na dane, niektóre z nich reprezentują np.: urządzenia.
3
W języku C++ mo n
ż a tworzy
ć klasy przy u y
ż ciu słowa kluczowego struct zamiast class. Osobom zainteresowanym bardziej szczegó ow ł
ymi informacjami polecam ksią k
ż ę
Bruce'a Eckela „Thinking in C++”.
1
Systemy Operacyjne – semestr drugi
nie jest u y
ż wany. Ten obiekt nie jest niszczony, na wypadek, gdyby trzeba go by o
ł u y
ż ć w niedalekiej przyszło c
ś i, chyba e
ż zaczyna brakować wolnej pami c
ę i operacyjnej.
Obiekt w stanie „ujemny” związany jest z i-w z
ę łem, który został usuni t
ę y, lub nie ma do niego poprawnej c
ś ie k
ż i. Ten obiekt również nie jest usuwany, je l
ś i nie istnieje taka
potrzeba, gdyż jego obecność mo e
ż zapobiec niepotrzebnym operacjom przeszukiwania, które nie zako c
ń zą się sukcesem. Zwolnione obiekty wpisów trafiają do dedykowanej
pami c
ę i podr c
ę znej obsługiwanej przez alokator plastrowy. Jądro utrzymuje również bufor wpisów katalogowych , przechowujący dotychczas utworzone wpisy katalogowe.
Składa się on z trzech cz
c
ęś i: listy u y
ż wanych wpisów katalogowych, listy ostatnio wykorzystywanych obiektów wpisów, która zawiera głównie obiekty wpisów nieu y
ż wanych i ujemnych, oraz tablicy skrótów (ang. hash table). Ta ostatnia wykorzystuje technikę haszowania, celem przyspieszenia odnajdywania obiektów wpisów katalogowych w buforze. Nale y
ż zaznaczy ,
ć e
ż jako pierwszy wyszukiwany jest obiekt związany z plikiem docelowym. Oprócz bufora obiektów wpisów katalogowych istnieje również bufor i-w z
ę ów
ł
związanych ze zbuforowanymi wpisami katalogowymi. Operacje na wpisach katalogowych zgromadzone są w strukturze struct dentry_operations.
Należą do nich: d_revalidate() - okre l
ś a poprawność wskazywanego obiektu wpisu katalogowego, d_hash() - funkcja haszująca, d_compare() - porównuje dwie nazwy plików, d_delete() - wywo y
ł wana gdy licznik odwołań do obiektu osiągnie wartoś
ć zerową, d_release() - zwalnia obiekt wpisu katalogowego, d_iput() - wywoływana, gdy obiekt wpisu katalogowego traci związany z nim i-w z
ę eł.
Z punktu widzenia procesów przestrzeni użytkownika obiekty plików są najwa n
ż iejsze ze wszystkich obiektów VFS. Tworzone są one przez wywołanie systemowe open(), a niszczone przez close(). Obiekty takie wskazują na obiekty wpisu katalogowego, a te z kolei wskazują na obiekty i-węzłów związane z plikami otwartymi przez proces.
Z ka d
ż ym z plików mo e
ż być zwi z
ą anych kilka obiektów plików, w zale n
ż o c
ś i od tego ile procesów go otworzyło. Typ takiego obiektu jest opisany strukturą struct file. Ta struktura zawiera oczywi c
ś ie pole wskazujące na obiekt operacji, które mo n
ż a zrealizować na pliku. Ten obiekt jest okre l
ś ony strukturą struct file_operations i mo e
ż
zawierać wska n
ź iki na funkcje realizujące nast p
ę ujące operacje: llseek() - aktualizuje wska n
ź ik pozycji pliku, read() - odczytuje plik, aio_read() - realizuje asynchroniczny odczyt z pliku, write() - zapis do pliku, aio_write() - realizuje asynchroniczny zapis do pliku, readdir() - odczytuje następny katalog na li c ś ie katalogów, poll() - zawiesza
proces w oczekiwaniu na sygnał aktywno c
ś i pliku, ioctl() - słu y
ż do realizacji operacji charakterystycznych dla urządzenia reprezentowanego przez plik, mmap()
- odwzorowuje plik w pami c
ę i, open() - otwiera plik, flush() - jej działanie jest zale n
ż e od systemu plików, ale zawsze jest wywoływana przy zmniejszeniu liczby odwołań do pliku, release() - wywoływana przy wyzerowaniu licznika odwo a
ł ń do pliku, fsync() - zapisuje wszystkie buforowane zmiany na dysk, aio_fsync() - jak poprzedniczka, ale zapisuje w sposób nieblokujący, fasync() - funkcja uaktywnia lub dezaktywuje sygna y ł powiadamiające o zakończeniu asynchronicznych operacji wejścia – wyj c
ś ia, readv()
- funkcja odczytuje dane z pliku i umieszcza je we wskazanych buforach, writev() - funkcja zapisuje dane do pliku ze wskazanych buforów, sendfile() - kopiuje dane z jednego do drugiego pliku, sendpage() - realizuje przekaz danych mi d
ę zy plikami, get_unmapped_area() - funkcja odwzorowująca wskazany plik na niewykorzystaną pami
.
ęć
Poza opisanymi wy ej
ż obiektami VFS wykorzystuje jeszcze kilka innych struktur. Struktura file_system_type zawiera informacje dotyczące poszczególnych systemów plików, w szczególno c
ś i wska n
ź ik na funkcję get_sb(), s u
ł ż c
ą ą do odczytu zawarto c
ś i bloku głównego okre l
ś onego systemu plików. Z ka d
ż ym typem systemu plików obsługiwanego
przez Linuksa powi z
ą ana jest jedna taka struktura. Po zamontowaniu systemu plików w systemie tworzona jest zmienna, której typ jest okre l ś ony strukturą
struct vfsmount. Zmienna ta zawiera informacje na temat punktu montownia do których należą między innymi znaczniki montowania okre l ś ające jakie operacje mo n
ż a
w tym systemie przeprowadzić. Z ka d
ż ym procesem związane są trzy struktury danych: struct files_struct – zawierająca wszystkie informacje zwi z ą ane z otwartymi przez
proces plikami i deskryptorami plików, struct fs_struct – zawierająca informacje o związanym z procesem systemie plików i struct namespace – okre l ś a dla procesu unikalną
perspektywę systemu plików. Dwie pierwsze struktury mogą być współu y
ż tkowane przez procesy spokrewnione, ostatnia jest domyślnie współdzielona przez wszystkie procesy, ale istnieje mo l
ż iwoś
ć okre l
ś enia dla procesu odrębnej takiej struktury podczas jego tworzenia.
2