Do spisu treści tematu 6

6.4.1 Opis ogólny modułu

 

Spis treści

          Po pierwsze nazewnictwo...


Wprowadzenie

    Plik jest pojęciem w pewnym sensie abstrakcyjnym. Dla użytkownika powinien być widoczny jedynie interfejs, dostarczony przez system plików, który zgodnie z ideą pliku - zbioru informacji, nie zmusza biednego użytkownika do szukania wiadomości gdzie na dysku leży, powiedzmy piętnasty rekord jego danych.
System, dla zaimplementowania takiej idei pliku, wykorzystuje i-węzły - są one zbiorem informacji o cechach pliku: prawach dostępu, rozmiarze, jego położeniem na dysku itd.
    System przechowuje i-węzły, a także informacje o nich w  odpowiednich strukturach  pamięci. Te, związane z konkretnym i-węzłem dane (m.in. dowiązania do list i-węzłów; gdzie, na którym urządzeniu się znajduje; itd) zapisane są w odpowiedniej strukturze, nazwanej przeze mnie i-ramką (patrz:  uwaga na temat nazewnictwa ).
    Moduł, którym się zajmuję odpowiada za obsługę wprowadzonych do obsługi i-węzłów struktur danych oraz za dostarczenie procedurom wyższego poziomu (jak open, close) możliwości korzystania z nich.
 

Po co ten cały ambaras

    I-węzły trzymane są na dysku, więc po co wprowadzać cały moduł zajmujący się ich wczytywaniem do pamięci i póżniejszą obsługą ? Powodów jest kilka,  spróbuję je omówić poczynając od tych najbardziej ogólnych.
 

powód pierwszy: VFS - Virtual File System

    Po pierwsze muszę zadać fałsz tezie wypowiedzianej w pytaniu na początku poprzedniego akapitu - nieprawdą jest jakoby każdy system plików miał dokładnie odpowiadające sobie struktury będące i-węzłami. Prawda - każdy musi utrzymywać jakieś informacje o plikach i to w z grubsza podobnej formie, ale oczywiście zapis tych informacji na urządzeniu fizycznym jest zdecydowanie różny.
    I tutaj dochodzimy od strony i-węzłów do modelu zwanego wirtualnym systemem plików (VFS - Virtual File System).  Model ten można  traktować jako logiczny system zarządzania danymi na dysku, całkowicie niezależny od używanego systemu plików.
    Tak jak VFS chce zapewnić nam interfejs obsługi dowolnego systemu plików, tak  i-ramka , która zresztą jest jego częścią ma umożliwić uniwersalne gromadzenie informacji o pliku, niezależnie od tego czy korzystamy z partycji DOS, czy też EXT2.
    Oprócz informacji, wspólnych dla wszystkich systemów istnieją także takie, które zależą ściśle od konkretnej platformy - co więcej - nie możemy mówić tylko o przechowywaniu informacji dla jakiegoś systemu, albowiem w jakiś sposób trzeba je także odczytać z dysku, czy też - po zmodyfikowaniu - zapisać na niego od nowa. Jasne jest jednak, że nie może istnieć wspólna funkcja do odczytu np. rozmiaru pliku dla systemów, które zapisują tę właśnie wielkość w całkowicie różnych miejscach na fizycznym urządzeniu!
    I tutaj przychodzi nam na pomoc i-ramka: w niej to przechowywane są wskaźniki do tych, interesujących nas w tym momencie funkcji, oczywiście zależne od systemu, na którym znajduje się nasz plik.

    Podsumowując - i-ramka ma umożliwić nam uniwersalny, niezależny od systemu plików dostęp do danych zgromadzonych na dyskach, czy też innych nośnikach.
 

powód drugi: wykluczanie

    Każdy z omawianych powodów, aż prosi się o podanie odniesienia do coraz to innej dziedziny wiedzy. Tym razem trzeba wspomnieć o współbieżnym wykonywaniu operacji. Załóżmy, że mamy dwa procesy: A i B, które chcą jednocześnie (z dokładnością do przydziału czasu procesora) coś na naszym pliku zapisać, co wiąże się jednocześnie między innymi ze zmianą czasu ostatniej modyfikacji pliku, trzymanej oczywiście w i-węźle - pojawia się dobrze znany problem wprowadzenia sekcji krytycznej. Otóż mając i-ramkę mamy równocześnie semafor, który opuszczamy sobie w odpowiednim momencie i .... już po sprawie.
    Oczywiście wszystkie struktury danych pozwalają na występowanie tylko jednej kopii i-węzła w pamięci. Dlatego, chociaż mamy kilka struktur przechowujących i-węzły, wszystkie one operują jedynie na wskaźnikach.

powód trzeci: efektywność

    Spójrzmy na numer omawianej wersji Linuxa - 2.0.32 - czyż nie budzi respektu? Ale spróbujmy wgłębić się w istotę tej liczby  -  przypuszczalnie była wersja 31 (beta), jakaś dwudziestka, kilka nastek... to o czymś świadczy - o tym mianowicie, że każdy kawałek został poddany wnikliwej analizie, między innymi pod względem efektywności. Tak zapewne stało się i w tej sytuacji. Kiedy szanowny czytelnik przejdzie do opisu np funkcji  iget , dowie się, że kiedy załadujemy już jakiś i-węzeł do  i-ramki w pamięci - nie usuniemy go prędko - dopiero, kiedy nie będzie już żadnych innych wolnych i-ramek do wykorzystania.  Ta swego rodzaju inercja pozwala w większości sytuacji na zaoszczędzenie czasu ładowania i-węzła z dysku do i-ramki w pamięci.


Główna idea i założenia

struktury danych:

    Istnieją dwie podstawowe struktury danych, przeznaczone do wspomagania operowania na i-ramkach w pamięci operacyjnej:
  1. dwukierunkowa Lista (będę ją tak od tej pory nazywał) przechowująca wszystkie i-ramki,
  2. tablica haszująca list dwukierunkowych zawierających i-ramki.
    Ad. 1.
Na Liście umiejscowione są wszystkie dostępne, czyli utworzone wcześniej i-ramki.
 
    Ad. 2.
Każdy i-węzeł identyfikowany jest poprzez swój numer oraz numer urządzenia na którym się znajduje. Tablica haszująca umożliwia szybki dostęp do i-ramki zawierającej i-węzeł poprzez obliczenie funkcji haszującej dla i-węzła i wyszukanie odpowiadającej mu i-ramki na liście w tablicy. Jest więc ona jedynie nakładką na Listę, przyspieszającą dostęp do i-ramek.
W oryginalnym komentarzu na początku pliku fs/inode.c zamieszczono ostrzeżenie, żeby uważać przy wykorzystywaniu tablicy haszującej  w związku z równoczesnym jej używaniem przez różne procesy.

    Jak wynika z wcześniejszego opisu, i-ramka dla danego i-węzła występuje w pamięci operacyjnej dokładnie raz. Dlatego zarówno tablica haszująca, jak i Lista przechowują jedynie wskaźniki na rozpatrywane obiekty.

    Wszystkie dołączenia do list (tych w tablicy haszującej, a także tej, zawierającej wszsystkie i-ramki) przechowywane są w i-ramkach.

    Dla ściślejszego zorientowania się jak powyższe struktury są wykorzystywane polecam zapoznanie się z opisami dotyczącymi algorytmów obsługi pobierania i-ramki (iget ) oraz jej zwalniania (iput ).
 

stałe:

NR_INODE : maksymalna ilość i-ramek możliwa do utworzenia w systemie; ustawiona w include/linux/fs.h na 3072
NR_IHASH : rozmiar tablicy haszującej; ustawiona w fs/inode.c na 512
 


Uwagi

Istnieje pewien problem dotyczący nazewnictwa. Mianowicie używane jest jedno słowo na określenie dwóch różnych rzeczy: i-węzeł(i-node) może być zarówno na dysku, jak i w pamięci. Ta rzecz określana jest w kodzie systemowym Linuxa poprzez: inode (dla i-węzła pamięciowego) oraz ext2_inode (dla i-węzła na dysku) - gdzie ext2 jest tylko przykladem systemu.
Dlatego wzorem ramki dla strony w stronicowaniu pamięci chciałbym wprowadzić i-ramkę dla i-węzła. Dlaczego tak ?   Tak jak ramka zawiera stronę, tak i-ramka zawiera i-węzeł, oczywiście i-ramka zawiera jeszcze więcej informacji oprócz samego i-węzła, ale to nie przeszkadza w intuicyjnym rozumieniu tego słowa.

Bibliografia

        1.    Pliki źródłowe:
            -    linux/include/fs.h
            -    linux/fs/inode.c
            -    linux/fs/ext2/inode.c
        2.    Projekt Linux
        3.    Linux Kernel Hackers Guide
Autor: Grzegorz Gawron