Algorytm iget jest częścią wirtualnego systemu plików VFS.

Przypomnę podstawowe pojęcia związane z VFS:

Opis algorytmu iget:

W jądrze 2.4.7 funkcją pobierającą i-węzeł z pamięci jest iget4().
struct inode *iget4(struct super_block *sb, unsigned long ino, find_inode_t find_actor, void *opaque)

Przyjmowane parametry to kolejno: adres struktury superbloku, numer i-węzła, dwa opcjonalne parametry przekazywane dalej - do funkcji find_inode. Zwraca ona wskaźnik do struktury i-węzła w pamięci albo - w przypadku niepowodzenia - NULL.

Funkcja iget4() najpierw sprawdza, czy szukany i-węzeł jest już w pamięci. W tym celu oblicza funkcją hash(sb,ino) indeks w tablicy haszującej, spod którego odczytuje do zmiennej head głowę listy, na której może znajdować się szukany i-węzeł. Teraz zakładany jest spin-lock (funkcja spin_lock()), który gwarantuje, że następujący po nim fragment kodu będzie wykonywany jednocześnie najwyżej przez jeden procesor. Wywoływana jest funkcja find_inode, która ma za zadanie znaleźć i-węzeł na liście head. Jeśli zwróci ona NULL, po zwolnieniu spin-locka (funkcja spin_unlock()) wywoływana jest funkcja get_new_inode(), mająca za zadanie wczytanie i-węzła z dysku. Natomiast jeśli funkcja find_inode zwróci i-węzeł, wywoływana jest funkcja __iget(), uaktualniająca pola struktury inode, następnie zwalniany jest spin-lock i proces zawiesza się w kolejce funkcją wait_on_inode(). Po wyjściu z tej funkcji iget4 zwraca znaleziony i-węzeł.


Funkcja find_inode() szuka i-węzła na liście cyklicznej.

static struct inode *find_inode(struct super_block *sb, unsigned long ino, struct list_head *head, find_inode_t find_actor, void *opaque)

Aby ustalić, czy kolejny element na liście to szukany i-węzeł, sprawdza po kolei: czy zgadzają się numery, czy zgadzają się superbloki oraz ewentualnie wywołujemy funkcję find_actor (z parametrem opaque) charakterystyczną dla danego systemu plików (zaimplementowana jedynie w systemach plików nfs i coda).


Funkcja get_new_inode() wczytuje i-węzeł z dysku (używając funkcji specyficznych dla danego systemu plików).

static struct inode *get_new_inode(struct super_block *sb, unsigned long ino, struct list_head *head, find_inode_t find_actor, void *opaque)

Najpierw funkcja alokuje pamięć dla struktury inode (i-węzła) funkcją alloc_inode(). Jeśli alokacja nie powiodła się, funkcja zwraca NULL. Zakładany jest spin-lock. Ponieważ spin-lock był przez jakiś czas zwolniony, ponawiana jest próba znalezienia węzła w pamięci funkcją find_inode. Jeśli się udała, to zwalniany jest spin-lock, zwalniany jest inode, do zmiennej inode przypisywany jest znaleziony i-węzeł, proces zawiesza się w funkcji wait_on_inode; po wyjściu z niej funkcja zwraca inode. Jeśli w pamięci nie ma węzła, trzeba wczytać go z dysku. Wykonywane są kolejno: zwiększenie licznika i-węzłów (inodes_stat.nr_inodes), dodanie węzła do listy i-węzłów (inodes_in_use), dodanie go do odpowiedniej listy w tablicy haszowanej, inicjalizacja pól struktury - i_sb, i_dev, i_ino, i_flags, i_count, i_state. Następnie zwalniany jest spin-lock, wywoływane clean_inode(inode). Z superbloku wołana jest funkcja wczytująca i-węzeł z dysku - read_inode (dla reiserfs - read_inode2). Czyszczony jest bit I_LOCK we fladze i_state oraz budzone są procesy czekające na dany węzeł (kolejka inode->i_wait).


Funkcja __iget() uaktualnia pola struktury i-węzła, która jest pobierana z pamięci.

static inline void __iget(struct inode *inode)

Funkcja atomowo (tzn. z gwarancją, że tylko jeden procesor wykonuje jednocześnie daną operację) odczytuje licznik odwołań do struktury i-węzła (pole i_count). Jeśli jest ono większe od zera, zwiększa je (atomowo) i wychodzi z funkcji. W przeciwnym wypadku atomowo zwiększa i_count, a następnie, jeśli i-węzeł nie jest brudny ani zablokowany, zostaje usunięty ze swojej listy i dodany do listy i-węzłów używanych. Na końcu zmniejszany jest licznik węzłów nieużywanych (inode_stat.nr_unused).