Do spisu tresci tematu 6

6.13.1 Funkcja mount()




Spis tresci


Wprowadzenie

Funkcja mount() dolacza podany system plikow (ang. filesystem) do istniejacej hierarchii systemu plikow. Zadaniem tej funkcji jest umozliwienie uzytkownikowi korzystania z danych na danym urzadzeniu, nie kazac mu wnikac w strukture tego urzadzenia.

Rysunek 1

Rys. 1 Drzewo systemu plikow po zamontowaniu nowego systemu plikow. Zrodlo: [1]

Po zamontowaniu przedstawionym na rysunku, system plikow /dev/hdd3 jest dostepny pod nazwa /mnt. Kazdy uzytkownik moze do niego siegac (jesli ma do tego uprawnienia).


Struktury danych

Struktura vfsmount

Jadro w Linuxie przechowuje liste (ang. mount table) zamontowanych systemow plikow (czyli liczba mozliwych do zamontowania systemow plikow jest limitowana tylko przez pamiec) o nazwie vfsmntlist. W trybie uzytkownika mozna obejrzec ta liste w pliku /etc/mtab.
Trzymane sa rowniez dwa wskazniki do elementow tej listy: Struktura vfsmount przechowywana w tej liscie przedstawia sie nastepujaco (opis jest zawarty w pliku naglowkowym include/linux/mount.h):
struct vfsmount {
    kdev_t              mnt_dev;    /* glowny i drugorzedny numer urzadzenia */
    char               *mnt_devname;/* nazwa urzadzenia (/dev/hdd3 na rysunku) */
    char               *mnt_dirname;/* punkt zamontowania (/mnt na rysunku) */
    unsigned int        mnt_flags;  /* flagi z jakimi zamontowany jest system plikow */
    struct super_block *mnt_sb;     /* wskaznik do superbloku zaalokowanego przez system plikow */
    struct vfsmount    *mnt_next;   /* nastepny system plikow w liscie */
    /*...*/
};

Struktura file_system_type

Dodatkowo jadro przechowuje liste typow systemow plikow, ktore mozna w danym momencie zamontowac. Lista ta jest do wgladu w pliku /proc/filesystems. Moze ona sie dynamicznie zmieniac jesli mamy skompilowane moduly do obslugi odpowiednich typow systemow plikow (zazwyczaj w katalogu /usr/src/linux/modules) oraz dzialajacy demon kerneld (jak dziala jest opisane w tresci algorytmu mount()) lub wykonamy polecenie /sbin/insmod /sciezka/nazwa_modulu (nazwa modulu to najczesciej typ_systemu_plikow.o, np.: nfs.o lub vfat.o dla systemu plikow Windows 95). Struktura file_system_type z pliku naglowkowego include/linux/fs.h wyglada nastepujaco:
struct file_system_type {
    const char *name;           /* nazwa typu systemu plikow */
    int         requires_dev;
    /* ... */
};
Dodatkowe wyjasnienia:
requires_dev
Okresla czy dany system plikow wymaga rzeczywistego fizycznego urzadzenia na danej maszynie. Wartosc 1 oznacza, ze wymaga, wartosc 0 - nie. Systemy plikow, dla ktorych flaga przyjmuje wartosc 0 to ncp, nfs, proc i smb. Proc to system plikow okreslajacy parametry systemu, a pozostale trzy to sieciowe systemy plikow.

Tablica unnamed_dev_in_use

Systemy plikow, ktore nie wymagaja fizycznego urzadzenia (ang. virtual filesystems) nie sa przechowywane na liscie vfsmntlist lecz w tablicy liczb calkowitych unnamed_dev_in_use o rozmiarze 256/(8*sizeof(unsigned int)). Tablica ta jest zdefiniowana w pliku fs/super.c.

Struktura super_block

Struktura super_block z pliku naglowkowego include/linux/fs.h> ma miedzy innymi takie pola:
struct super_block {
    kdev_t          s_dev;      /* tak jak w strukturze vfsmount */
    unsigned long   s_flags;    /* tak jak w strukturze vfsmount */
    struct inode   *s_covered;  /* i-wezel korzenia systemu plikow - rozny od i-wezla
                                   urzadzenia */
    struct inode   *s_mounted;  /* i-wezel punktu zamontowania */
    /* ... */
};

Rysunek 2

Rys. 2 Struktury danych po wykonaniu funkcji mount(). Zrodlo: [1]


Algorytm mount

DEFINICJA: int mount(char *dev_name, char *dir_name, char *type, unsigned long new_flags,
                     void *data)
    WYNIK: 0 w przypadku sukcesu
           gdy blad: errno = EPERM (uzytkownik nie ma praw superuzytkownika)
                             ENODEV (zla nazwa urzadzenia lu nie skompilowana obsluga systemu plikow)
                             ENOTBLK (urzadzenie wirtualne, a powinno byc fizyczne)
                             EBUSY (i-wezel jest zajety)
                             EINVAL (zly parametr)
                             EFAULT (parametry poza przestrzenia adresowa uzytkownika)
                             ENOMEM (brak pamieci)
                             ENAMETOOLONG (zbyt dluga nazwa)
                             ENOENT (zla sciezka)
                             ENOTDIR (punkt zamontowania nie jest katalogiem)
                             EACCES (brak uprawnien do odczytu i-wezla)
                             ENXIO (glowny numer urzadzenia poza zakresem)
                             EMFILE (pelna tablica unnamed_dev_in_use)
Pierwszym argumentem funkcji jest nazwa urzadzenia, drugim - punkt zamontowania (ang. mounting point), trzecim - nazwa systemu plikow. Znaczenie tych argumentow zostalo omowione powyzej.
Flagi, z jakimi mozna zamontowac system plikow sa nastepujace:

Nazwa Wartosc Opis
MS_RDONLY 1 tylko do odczytu
MS_NOSUID 2 ignorowane sa bity suid i sgid
MS_NODEV 4 zabiera dostep do plikow specjalnych urzadzenia
MS_NOEXEC 8 zabrania wykonywania programow
MS_SYNCHRONOUS 16 kazdy zapis jest natychmiast synchronizowany
MS_REMOUNT 32 zmienia flagi zamontowanego systemu plikow
S_WRITE 128 zapis na pliku/katalogu/symbolicznym linku
S_APPEND 256 plik, do ktorego mozna tylko dopisywac
S_IMMUTABLE 512 plik staly, niezmienny
MS_MGC_VAL 0xC0ED0000 liczba magiczna

Flagi MS_REMOUNT i MS_MGC_VAL sa tylko atrybutami funkcji mount(), a nie sa flagami systemu plikow.
Przy przemontowywaniu mozna jedynie zmienic ustawienie flagi MS_RDONLY.
Na jednym systemie plikow moze byc zalozonych do 16 flag wlacznie.
Liczba magiczna oznacza, ze mamy do czynienia z wersja jadra Linuxa 2.0.0 i nowymi mozliwosciami. Tymi mozliwosciami jest piaty argument wywolania funkcji. Zawiera on jakies dodatkowe informacje o systemie plikow.

Implementacja funkcji:

{
    if (uzytkownik nie ma uprawnien superuzytkownika)
        return -EPERM;
    if (ustawione flagi MS_REMOUNT i MS_MGC_VAL) {
        kopiuj data do przestrzeni adresowej jadra;
        pobierz i-wezel punktu zamontowania;
        if (pod i-wezlem nie zamontowany system plikow)
            return -EINVAL;
        if (urzadzenie tylko do odczytu i nie ustawiona flaga MS_RDONLY)
            return -EACCES;
        if (ustawiona flaga MS_RDONLY i sa otwarte pliki do odczytu/zapisu)
            return -EBUSY;
        zmien flagi superbloku danego systemu plikow; /* pole w strukturze superblock */
        zmien flagi superbloku; /* mozna jedynie zdjac lub zalozyc flage MS_RDONLY */
        znajdz odpowiednia pozycje w tablicy montowania;
        zmien flagi w strukturze vfsmount;
        return 0;
    }
    pobierz strukture file_system_type dla zadanego systemu plikow i przypisz na zmienna fstype;
    if (pobrano strukture pusta - nie ma danego systemu plikow na liscie file_systems) {
        #ifdef CONFIG_KERNELD /* dziala demon kerneld */
        if (dany system plikow nie skompilowany w postaci modulu)
            return -ENODEV;
        dolacz system plikow do listy file_systems i przypisz na zmienna fstype;
    }
    if (fstype->requires_dev) {
        pobierz i-wezel urzadzenia;
        if (nie jest to i-wezel urzadzenia blokowego)
            return -ENOTBLK;
        if (nie ma dostepu do pliku specjalnego)
            return -EACCES;
        pobierz glowny i drugorzedny numer urzadzenia;
        if (glowny numer urzadzenia >= MAX_BLKDEV)
            return -ENXIO;
        pobierz operacje dla urzadzenia;
        if (zdefiniowana specjalna operacja open)
            wykonaj specjalna operacje open;
    } else
    {
        if (nie ma miejsca w tablicy unnamed_dev_in_use)
            return -EMFILE;
        zaznacz kolejna pozycje w tablicy unnamed_dev_in_use;
        pobierz glowny i drugorzedny numer urzadzenia;
    }
    if (nie ustawiona flaga MS_RDONLY i urzadzenie tylko do odczytu)
        return -EACCESS;
    pobierz i-wezel punktu zamontowania;
    if (licznik punktu zamontowania != 1 lub cos jest juz tam zamontowane)
        return -EBUSY;
    if (punkt zamontowania nie jest katalogiem)
        return -ENOTDIR;
    if (wszystkie superbloki zajete)
        return -EINVAL;
    zainicjalizuj superblok danego systemu plikow; /* inicjalizacja to przypisanie */
    zainicjalizuj superblok;                       /* na pola w strukturze odpowiednich wartosci */
						   /* oraz wykonanie takich czynnosci */
						   /* jak wlaczenie quoty */
    dodaj pozycje do listy zamontowania i zainicjalizuj strukture;
    return 0;
}
W opisie funkcji pominiete zostaly operacje zwalniania i-wezla i strony w przestrzeni adresowej jadra.

Bibliografia

  1. Maurice J. Bach: Budowa systemu operacyjnego UNIX
  2. Pliki zrodlowe Linuxa:
  3. Manual do funkcji systemowej mount() (man 2 mount)

Pytania i odpowiedzi

Jesli chcesz zadac mi jakies pytanie musisz wyslac do mnie e-mail.

1. Jakie struktury danych znalezione w plikach zrodlowych sa najwazniejsze?

Patrz opis struktur danych powyzej.

2. Jakie sa (w tej konkretnej wersji Linuxa) ograniczenia na rozne zasoby systemowe?

Znalazlem dwa istotne ograniczenia:

3. Jakie pliki zrodlowe byly wykorzystane przy opracowaniu tematu?

Patrz bibliografia powyzej.

4. Jakie rozwiazania programistyczne znalezione w plikach zrodlowych sa najciekawsze?

Po pierwsze ciekawym pomyslem jest uzycie zmiennej mru_vfsmnt, ktora przechowuje ostatni system plikow, na ktorym byla wykonywana jakas operacja. Przy przegladaniu listy zamontowanych systemow plikow, przed korzystaniem z listy vfsmntlist najpierw sprawdzana jest ta zmienna.
Po drugie interesujace wydaje mi sie korzystanie ze specjalnego demona kerneld w celu automatycznego dodawania modulu obslugi systemu plikow do jadra.
Trzecia koncepcja nie jest widoczna w opisie algorytmu. Funkcja read_super pobierajaca nowy superblok dla systemu plikow przed sprawdzeniem czy temu systemowi plikow byl juz uprzednio przydzielony superblok wywoluje funkcje check_disk_change() sprawdzajaca czy wymienialne urzadzenie (np. dyskietka lub cd-rom) zostalo zmienione.


Autor: Pawel Kot