Dowolny plik w systemie plikow jest opisywany przez nazwe sciezkowa zbudowana za pomoca nazw katalogow oddzielonych "/" i jego nazwy . Poniewaz jadro wewnetrznie posluguje sie iwezlami , konieczne jest przeksztalcanie nazwy sciezkowej w i-wezel . Poczatek przeszukiwania jest latwy do ustalenia , poniewaz rozpoczyna sie ono zawsze od korzenia systemu plikow (gdy sciezka zaczyna sie od znaku "/" )badz od biezacego katalogu procesu (dane na temat korzenia systemu plikowi biezacego katalogu procesu mozna znalezc w u-obszarze procesu .Nie mozna uzywac zmiennej globalnej zawierajacej korzen systemu plikow , gdyz proces funkcja systemowa chroot moze zmienic swoje pojecie korzenia systemu plikow ).
Przy kazdym dostepie do pliku nastepuje przeksztalcanie nazwy sciezkowej w i-wezel . Generalnie odpowiedzialny za to jest algorytm namei , z ktorego korzysta wiekszosc funkcji operujacych na plikach . Jednak niektore funkcje systemowe np. open i write maja wlasne algorytmy przeksztalcajace sciezke w i-wezel . Ja zajme sie ogolnym algorytmem .
Generalnie algorytm namei dziala poslugujac sie roboczymi i-wezlami (pierwszym jest korzen lub aktualny katalog ) wg nastepujacego schematu :
Szczegolnego traktowania wymagaja dowiazania symboliczne (pliki zawierajace nazwy sciezkowe innych plikow). Obsluga ich zajmuje sie funkcja followlink
Funkcja follow_link
DEFINCJA: int follow_link(struct inode * dir, struct inode * inode, int flag, int mode ,struct inode ** result) /* dir - i-wezel katalogu /* inode,mode - i-wezel i typ pliku WYNIK:0 i wskaznik do iwezla na result w przypadku sukcesu kod bledu w przypadku porazki ELOOP ( mozliwosc petli) ENOENT ( nie istnieje taka pozycja katalogowa ) EIO ( nie mozna wczytac bloku do bufora ) { if( i-wezel pliku lub katklogu jest rowny null) { zwolnij i-wezly pliku i katalogu (iput); na resinode przypisz null; return(-ENOENT); } if(w iwezlie pliku w strukturze i_op nie jest zdefiniowana funkcja followlink) /* plik nie jest dowiazaniem symbolicznym */ { zwolnij i-wezel katalogu ; na resinode przypisz i-wezel pliku; return( 0); } /* Tu wywolywana jest funkcja ext2_followlink wpisana wpisana w stukturze i_op w iwezlie pliku , ktorej kod zrodlowy mozna znalezc w pliku linux/fs/ext2/symlink.c. Dla czytelnosci opis jej umieszczam w opisie glownej funkcji followlink */ if(plik nie jest dowiazaniem symbolicznym ) { zwolnij i-wezel katalogu ; na resinode przpisz i-wezel pliku; return(0); } if( licznik dowiazan symbolicznych (przechowywany w u-obszarze procesu - current->link_count) jest wiekszy od 5) /* Liczenie ilosci dowiazan symbolicznych zapobiega powstawaniu petli*/ { zwolnij i-wezel y katalogu i pliku (iput); return(-ELOOP); } if(z plikiem zwiazany jest blok danych) { if( nie udalo sie wczytac bloku do bufora) { zwolnij i-wezly katalogu i pliku; return( -EIO); } else na zmienna pomocnicza link przypisz sciezke wczytana z pliku; } else na zmienna link przypisz sciezke wpisana do bloku identyfikacyjnego; zwieksz licznik dowiazan symbolicznych w u-obszarze; znajdz i-wezel opisywany przez nazwe sciezkowa wpisana pod zmienna link wywolujac funkcje open_namei( jedna z wersji funkcji namei); zmniejsz licznik dowiazan symbolicznych w u_obszarze procesu; zwolnij i-wezel pliku; if( z iwezlem zwiazany blok danych ) zwolnij bufor do ktorego wczytano sciezke }
Tak wiec obsluga dowiazan symbolicznych sprowadza sie do zapoczatkowania przeszukiwania nazwy sciezkowej utworzonej z zawartosci dowiazania symbolicznego. Aby zopobiec zapetleniu sie funkcji , liczy sie dowiazania symboliczne podczas przeszukiwania nazw sciezek i sygnalizuje blad wowczas ' gdy zostanie przekroczona ich gorna granica (5). Jezeli plik nie jest dowiazaniem symbolicznym to followlink zwraca ten plik.
Przed przystapieniem do szczegolowego pisu algorytmu namei zapoznajmy sie wczesniej z pomocnicza funkcja lookup , ktora majac i-wezel katalogu i nazwe pozycji katalogowej znajduje i-wezel tej pozycji.
Funkcja lookup
DEFINICJA: int lookup( struct inode * dir ,const char * name, int len , struct inode **resinode) /* dir - i-wezel katalogu /* name,len - nazwa i dlugosc nazwy pozycji katalogowej WYNIK:0 i szukany i-wezel na *resinode w przypadku sukcesu kod bledu w przypadku porazki ENOENT ( nie istnieje taka pozycja katalogowa ) EACCES ( brak koniecznych praw )
{ if(katalog roboczy jest rowny null) return( -ENOENT); sprawdz czy proces ma prawo wykonywac katalog; if(skladowa jest "..") { if(katalog roboczy jest korzeniem systemu plikow - jest rowny current->fs->root) { na result wpisz katalog wejsciowy; return( 0); } if (katalog roboczy jest korzeniem podmontowanego systemu plikow -jest rowny sb->s_mounted) { zwolnij i-wezel katalogu roboczego; jako nowy katalog roboczy wez i-wezel katalogu , do ktorego podmontowano systm plikow (sb->s_coverd); if(katalog roboczy jest nullem) return( -ENOENT); zwieksz licznik odwolan do katalogu roboczego (i_count w i-wezlie); } } if(w i-wezlie katalogu roboczego w strukturze i_op nie jest zdefiniowana funkcja lookup) { zwolnij i-wezel katalogu roboczego; return(- ENOENT); } if(sprawdzanie praw wykonywania katalogu nie przebieglo pomyslnie) { zwolnij i-wezel katalogu roboczego; return( -EACCES); } if(dlugosc nazwy jest rowna 0) /*pozwala to na wystepowanie sciezek typu /pr1//pr2 i traktowanie ich jak /pr1/./pr2 */ { na result przypisz katalog roboczy; return(0); } /* W tym miejscu wywolywana jest funkcja ext2_lookup wpisana do iwezla w strukturze i_op ,ktorej kod zrodlowy mozna znalezc w pliku linux/fs/ext2/namei. Dla czytelnosci opis jej umieszczam w opisie glownej funkcji lookup.*/ if(i-wezel katalogu roboczego nie jest iwezlem katalogu ) return( - ENOENT); if(pozycja znajduje sie w tablicy haszujacej -funkcja dcache_lookup nie zwrocila nulla) { if( numer i-wezla znaleziony przez dcache_lookup jest rowny 0) /* Pozycja nie istnieje w katalogu */ { zwolnij i-wezel katalogu(iput); return( -ENOENT); } if(nie udalo sie przydzielic iwezla o numerze zwroconym przez dcache_lookup - iget zwrocila blad) { zwolnij i-wezel katalogu (iput); return( -EACCES); } zwlonij i-wezel katalogu (iput); return( 0); } if(nie udalo sie znalezc pozycji katalogowej na dysku - ext2_find_entry zwrocila null) { if(w miedzyczasie inny proces nie zmienil katalogu) dodaj do tablicy haszujacej pozycje katalogowa z numerem i-wezla rownym 0 (dcache_add); zwolnij i-wezel katalogu(iput); return( -ENOENT); } na ino przypisz znaleziony numer iwezla; dodaj nowa pozycje do tablicy haszujacej (dcache_add) z ino jako numer i-wezla; zwolnij bufor do ktorego byla wczytana pozycja; if(nie udalo sie przydzielic iwezla o numerze ino - iget zwrocila blad) { zwolnij i-wezel katalogu roboczego (iput); return(-EACCES); } zwolnij i-wezel katalogu roboczego(iput); return(0); }
Funkcje dcashe_add i dcashe_lookup szczegolowo zostaly opisane w rozdziale poswieconym katalogom . Ext2_find _entry dziala analogicznie do funkcji czytajacej plik - uzywajac uzywajac funkcij ext2_bread i brelse czyta po kolei bloki danych zwiazane z katalogiem wejsciowym szukajac danej pozycji.
Podsumowujac lookup zwraca i-wezel szukanj pozycji katalogowej. Jezeli znajdowala sie ona juz w pamieci to ustawia ja na koniec kolejki level2_cache (w razie potrzeby przenoszac ja z level1_cache i usuwajac pierwszy element z level2_cache) Jezeli nie bylo jej w pamieci to wstawia ja na koniec kolejki level1_cache usuwajac jej pierwszy element (Jesli nie bylo jej i na dysku to numer i-wezla jest 0 ).
Teraz mozemy przejsc do funkcji namei ,ktorej kod mozemy znalezc w
Funkcja namei
DEFINICJA: int namei(const char *pathname, struct inode ** resinode) WYNIK: 0 i szukany i-wezel na * resinode w przypadku sukcesu kod bledu w przypadku porazki - bledy takie jak w funkcjach followlink i lookup plus ENAMETOOLONG ( sciezka nie miesci sie na jednej stronie ) ENOMEM ( brakuje pamieci , aby wczytac sciezke ) { wczytaj nazwe sciezkowa do przestrzeni adresowj jadra ; /* wielkosc nazwy nie moze przekraczac wielkosci strony */ /* W tym momencie wywolywana jest fukcja dir_namei zwracajaca i-wezel katalogu maciezystego szukanego pliku .Kod jej znajduje sie w pliku linux/fs/namei.c . Dla czytelnosci opis jej umieszcze w opisie namei */ if(sciezka zaczyna sie od "/") jako katalog roboczu wez korzen systemu plikow (current->fs->root) else jako katalog roboczy wez bierzacy katalog procesu(current->fs->pwd); zwieksz licznik odwolan do katalogu roboczego (i_count); while(1) { wczytaj kolejne skladowe nazwy sciezkowej; if(skladowa pusta) /*koniec sciezki*/ break; zwieksz licznik odwolan do katalogu roboczego(i_count); znajdz pozycje katalogowa wywolujac lookup; if(lookup zwrocila blad) { zwolnij i-wezel katalogu roboczego(iput); wyjdz z bledem zwroconym przez lookup; } wywolaj followlink w celu obslugi ewentualnego dowiazania symbolicznego; /* Jako wskaznik na ktory followlink wpisze wynik wez wskaznik do katalogu roboczego , dzieki temu po followlink katalog roboczy bedzie zmieniony na nastepny w nazwie sciezkowej */ if(followlink zwrocila blad ) wyjdz z bledem zwroconym przez followlink; } /* tu jest koniec funkcji dir_namei */ wywolaj lookup , aby znalezc koncowy plik; if(lookup zwrocila blad ) wyjdz z bledem zwroconym przez lookup; wywolaj followlink do obslugi ewentualnego dowiazania symbolicznego; zwolnij strone w pamieci jadra ,gdzie wpisana jest sciezka; zwroc 0; }
Autor: Malgorzata Guziak