Do spisu treści tematu 6
6.4.4 Specyficzne dla ext2 funkcje zarządzania i-ramkami
Spis treści
Skomentowany
plik fs/ext2/inode.c
Wprowadzenie
I-ramka ma za zadanie
przechowywać informacje o i-węźle niezależnie od systemu plików, z którego
korzystamy. Z tego wynika, że dla każdego systemu dostarczone muszą być
funkcje działające na tych obszarach i-ramki, gdzie znajdują się informacje
dla niego specyficzne.
I tak dla odczytania i-węzła z dysku do odpowiedniego
miejsca w pamięci - wyznaczonego przez i-ramkę - wykorzystujemy funkcję
read_inode, dla zapisu zmienionego i-węzła na dysk uruchamiamy
write_inode, żeby dowiedzieć się w którym miejscu na dysku
znajduje się n-ty blok pliku wywołujemy funkcję bmap.
Każda z tych funkcji jest specyficzna dla danego
systemu plików, ponieważ musi brać pod uwagę konkretne fizyczne położenie
danych na dysku. To położenie może być różne, a czasami nawet musi być
takim z powodu różnic koncepcyjnych: np. fat i ext2.
Te funkcje są oczywiście wysokopoziomowe - w zasadzie
ich nazwy są tylko ujednoliconym interfejsem, pod który podstawiane są
funkcje interesującego nas systemu. Dokładniej poprzez atrybuty i-ramki
można uzyskać dostęp do wskaźników na funkcje wykonujące odpowiednie działania
dla odpowiedniego systemu plików.
Przykład:
Chcąc obliczyć fizyczny
numer bloku na podstawie logicznego (algorytm bmap) - sprawdzamy, czy w
operacjach na i-węźle zdefiniowanych w i-ramce jest podstawiona specyficzna
dla danego systemu plików funkcja realizująca to działanie - bmap,
a następnie ją uruchamiamy i zapamiętujemy wynik. Ta specyficzna funkcja
dla systemu ext2 będzie miała nazwę ext2_bmap, a podstawienie
polega na przypisaniu polu bmap w odpowiedniej strukturze i-ramki,
operacji wskaźnika na naszą funkcję - ext2_bmap.
Tutaj zajmiemy się opisem funkcji realizujących przedstawione
powyżej operacje w systemie ext2, zamieszczonych w pliku fs/ext2/inode.c
(skomentowany kod) .
Zapis i-węzła na dysk
Operacja ta może zostać zrealizowana na dwa sposoby.
Jeden z nich wymusza natychmiastowy zapis na dysk (ext2_sync_inode
- skomentowany
kod), drugi natomiast dopuszcza możliwość opóźnienia fizycznej
zmiany na dysku (ext2_write_inode - skomentowany
kod). Sposób realizacji obu powyższych funkcji jest na tyle podobny,
że zdecydowano się zaimplementować funkcję ext2_update_inode
(skomentowany
kod), która wywoływana jest przez dwie wymienione wcześniej funkcje
- oczywiście zaznaczające jednym parametrem (do_sync), o którą z nich chodzi.
A oto jakie akcje są wykonywane przy żądaniu
zapisu i-węzła:
Najpierw sprawdzamy, czy i-węzeł do zapisu nie jest
przypadkiem i-węzłem korzenia systemu plików, oraz czy jego numer jest
poprawny; w przypadku wykrycia jednej z tych sytuacji - powracamy
nic nie robiąc.
Następnie znajdujemy fizyczną lokalizację i-węzła
na dysku, tzn. konkretny blok, w którym jest zapisany, wczytujemy ten blok,
aktualizujemy go oraz zapisujemy z powrotem na dysk, żądając natychmiastowego
zapisu, jeżeli synchronizacja jest wymuszona (do_sync=1).
W przypadku, gdy nie udaje nam się odczytać i-węzła
z dysku zwracamy błąd (EIO) oraz uznajemy obraz i-węzła w pamięci za zgodny
z wersją dyskową.
Odczyt i-węzła z dysku
Do odczytania i-węzła z dysku przeznaczona została
funkcja ext2_read_inode (skomentowany
kod), która dla fizycznego odczytu bloku i-węzła z dysku korzysta
z ext2_bread (skomentowany
kod).
Jako, że cały dostęp do dysku jest buforowany istnieje
konieczność skorzystania z bufora dla wyżej wspomnianego fizycznego odczytu
- może się przecież okazać, że wcale nie trzeba sięgać do dysku jeżeli
istnieje odpowiednio 'świeża' kopia tego bloku w pamięci - konkretnie istnieje
jakiś bufor zawierający ten blok. Za odnalezienie tego bufora odpowiada
funkcja ext2_getblk (skomentowany
kod).
Dla poprawy czytelności połączymy opis obu tych funkcji
w jednym kawałku, zaznaczając jednakże granice
na wstępie sprawdza się
czy zadany i-węzeł możemy dostać,
później oblicza się położenie
na dysku ( nr grupy, nr bloku, przesunięcie w bloku )
- ext2_bread (początek)
wywołuje getblk
z zadaniem znalezienia odpowiedniego bufora (dla grupy i bloku) ,
jeżeli bufor
zawiera aktualne dane to już OK
wpp inicjuje
czytanie danych z dysku do tego bufora
- ext2_bread (koniec)
a następnie ustawia sie pola w
i-węźle na podstawie otrzymanego bufora
Zamiana logicznego numeru bloku na adres fizyczny (ext2_bmap)
Jeżeli chcemy odczytać z pliku bajt o określonym
numerze - traktujemy plik jako nieprzerwany i ciągły strumień bajtów -
liczymy numer bloku (logiczny adres bloku), w którym ten
bajt się znajduje, żeby następnie wyznaczyć na podstawie tego numeru fizyczny
adres bloku na dysku (w którym naprawdę mieści się nasz bajt).
Algorytm bmap ma za zadanie przetworzyć logiczny
adres bloku na jego fizyczny odpowiednik.
Po sprawdzeniu poprawności parametrów - sprawdza
się na którym poziomie pośredniości jest dany blok.
Przy bloku bezpośrednim - adres zwracany jest od razu.
Przy pojedynczo pośrednim musimy najpierw odczytać z dysku blok zawierający
nasz adres.
Przy podwójnie pośrednim - najpierw czytamy z dysku blok pojedynczo
pośredni, zawierający adres do bloku bezpośredniego (którego też musimy
wczytać z dysku), w którym znajduje się adres do interesującego nas bloku.
Przy potrójnie pośrednim - analogicznie o jedno zagłębienie niżej.
Więcej informacji na temat algorytmu bmap znajdziesz w opracowaniu
na jego temat w projekcie Linux .
Funkcja ext2_bmap korzysta z:
- makra inode_bmap,
które na podstawie i-ramki oraz numeru bloku zwraca element
o numerze numer z tablicy bloków i-węzła zawartego w i-ramce
do skomentowanego kodu
inode_bmap
- funkcji block_bmap,
która na podstawie bufora zawierającego tablicę bloków i określonego
numeru, zwraca element z tej tablicy o numerze numer. Funkcja
po wykorzystaniu zwalnia ten bufor.
do skomentowanego
kodu block_bmap
Można się zastanawiać dlaczego zwalnianie i-ramki zostało
umieszczone wśród funkcji specyficznych dla systemu ext2. Związane jest
to między innymi z faktem, że w systemie tym istnieje możliwość wcześniejszego
zaalokowania bloków dyskowych dla danego pliku (i-węzła) i te bloki trzeba
przy końcu zwolnić, czym zajmuje się specyficzna dla omawianego systemu
funkcja ext2_discard_prealloc (skomentowany
kod).
Działanie funkcji polega więc na zwolnieniu wszystkich
bloków dyskowych zaalokowanych z wyprzedzeniem dla danego i-węzła, następnie
wszystkich bloków i-węzła, a na końcu zwolnieniu pamięci wykorzystywanej
przez i-ramkę.
Bibliografia
1. Pliki źródłowe:
- linux/fs/ext2/inode.c
- linux/fs/ext2/ialloc.c
2. Projekt
Linux
3. Linux
Kernel Hackers Guide
Grzegorz Gawron (reszta + korekta)