ALGORYTMY:
open, creat, close, read, write, mknod

Dotyczy wersji jądra: 2.4.7

Autor: Jan Domański
nr. indeksu: 171767




Wstęp.


Każdy z omawianych dalej algorytmów jest używany przy wywołaniu odpowiedniej funkcji systemowej. Funkcje takie są oczywiście wywołane przez dany proces. Dalej zostaną opisane struktury danych, używane przy obsłudze plików przez procesy.
Wszystkie dane dotyczące procesu znajdują się w strukturze task_struct:

  struct task_struct {
    ...
    struct fs_struct *fs;
    struct files_struct *files;
    ...
  };
 
Jeśli chodzi o obsługe plików to ważne są dwa (wymienione) pola tej struktury.
Pole fs zawiera wskaźnik do struktury fs_struct zawierającej informację o katalogu głównym i roboczym procesu.
Struktura fs_struct zawiera między innymi pola:
  • struct dentry * root; - wskaźnik do obiektu pozycji katalogu powiązanego z korzeniem systemu plików dostępnego dla danego procesu.
  • struct dentry * pwd; - wskaźnik do obiektu pozycji katalogu powiązanego z aktualnym/roboczym katalogiem dla danego procesu.
  • int umask; - maska początkowych uprawnień dla plików tworzonych przez proces.
Pole files zawiera wskaźnik do struktury files_struct zawierającej informację o plikach aktualnie otwartych przez proces.
Struktura files_struct wraz z opisem pól:
  struct files_struct {
    /* Liczba procesów współdzielących daną strukturę */
    atomic_t count;
    rwlock_t file_lock;
    /* Maksymalna liczba obiektów plików używanych przez proces */
    int max_fds;
    /* Maksymalna liczba deskryptorów plików */
    int max_fdset;
    /* Pierwszy wolny deskryptor */
    int next_fd;
    /* Wskaźnik do tablicy wskaźników obiektów plików.
          Tablica ta jest indeksowana deskryptorami plików.
          Pole max_fds zawiera jej rozmiar.
          Pole to jest używane jedynie jeśli proces otworzy
          więcej niż NR_OPEN_DEFAULT plików. W przeciwnym
          przypadku używana jest tablica fd_array.
          Dwa elty tablicy mogą wskazywać na ten sam
          obiekt pliku (dwa deskryptory odnoszą się do
          tego samego pliku - patrz np. f. systemowa dup()).
    */
    struct file ** fd;
    /* Wskaźnik do zbioru deskryptorów, które będa zamknięte
          przy exec.
       */
    fd_set *close_on_exec;
    /* Wskaźnik do zbioru deskryptorów otwartych plików.
          Zbiór jest realizowany jako mapa bitowa identyfikująca
          deskryptory plików aktualnie otwartych.
          Rozmiar mapy: 1024 bity (w miarę potrzeby może
                        zostać dynamicznie zwiększony)
        */
    fd_set *open_fds;
    /* Początkowy zbiór deskryptorów zamykanych przy exec. */
    fd_set close_on_exec_init;
    /* Początkowy zbiór deskryptorów otwartych plików. */
    fd_set open_fds_init;
    /* Początkowa tablica wskaźników otwartych plików */
    struct file * fd_array[NR_OPEN_DEFAULT];
  };
 

Uwaga! Każdy proces może odwołać się do swojego deskryptora przy pomocy wskaźnika current (w rzeczywistości jest to makrodefinicja assemblerowa). Gdy proces chce znaleźć wskaźnik do obiektu pliku o deskryptorze d moze wywołać plik=current->files->fd[d].

Z punktu widzenia obsługi obiektów plików przez procesy ważne są dwie funkcje dostępne w jądrze (definicja ich znajduje się w pliku fs/file_table.c):
  • struct file * fget(unsigned int fd)
    Parametrem funkcji jest deskryptor pliku. Jest ona wywoływana gdy jądro zaczyna używać obiektu pliku (określonego przez deskryptor).
    Jeśli istnieje obiekt pliku odpowiadający deskryptorowi to zwracany jest adres current->files->fd[fd] czyli adres odpowiedniego obiektu pliku dla danego procesu. Zwiększany jest również o 1 licznik użycia obiektu pliku f_count (zwiększenie to odbywa się "atomowo", za pomocą specjalnej funkcji asemblerowej: atomic_inc(unsigned int). Jeśli nie istnieje obiekt odpowiadający deskryptorowi to zwracana jest wartość NULL.
  • void fput(struct file * file) Funkcja ta jest używana gdy ścieżka wykonania jądra skończy używać obiekt pliku. Parametrem jej jest obiekt pliku.
    Na początku funkcja zmniejsza licznik użycia obiektu pliku f_count (zmniejszenie jest wykonywane atomowo - funkcja atomic_dec_and_test(unsigned int)). Jeśli nowa wartość licznika użycia jest równa 0 to funkcja:
    1. Jeśli jest zdefiniowana funkcja release(...) dla danego obiektu pliku (pole f_op obiektu nie jest NULL oraz f_op->release nie jest NULL) to wywołuje f_op->release.
    2. Ustawia pola f_dentry i f_vfsmnt danego obiektu pliku na NULL.
    3. Jeśli plik był otwarty do zapisu to zmniejsza pole i_writecount odpowiedniego obiektu i-węzła ("atomowo" przy użyciu: atomic_dec(unsigned int)).
    4. Uruchamia odpowiednie funkcje uwalniające dla obiektów pozycji katalogu i obiektu typu struct vfsmount powiązanych z danym obiektem pliku (wskaźniki do tych obiektów są trzymane w zmiennych lokalnych, wcześniej odpowiednie pola obiektu pliku zostały ustawione na NULL).
    5. Usuwa obiekt pliku z "listy używanych obiektów pliku" i wstawia do "listy nie używanych obiektów pliku": (free_list).


Opisane powyżej struktury danych i mechanizmy jak i opisy struktur danych, dotyczących VFS (zawarte w osobnym dokumencie: vfs.html), znacznie ułatwią przedstawienie algorytmów zadanych w temacie.



Algorytm open.


Open(...) jest wywołaniem systemowym (następuje przejście z Trybu Użytkownika do Trybu Jądra). Funkcja ta musi być wywołana przez proces zawsze gdy chce on uzyskać dostęp do pliku. Jest ona odpowiedzialna za przygotowanie odpowiednich struktur związanych z plikiem w jądrze, tak aby proces mógł traktować plik jako ciąg bajtów mający nazwę.
Jeśli wywołanie zakończy się sukcesem to zwracany jest deskryptor pliku czyli indeks do tablicy wskaźników do obiektów pliku dla procesu (current->files->fd). W przeciwnym przypadku zostanie zwrócona wartość -1.

Za realizację wywołania Open(...) odpowiada funkcja:
long sys_open(const char * filename, int flags, int mode)

Opis parametrów funkcji:

  • filename - scieżka dostępu do pliku, który ma być otworzony.
  • flags - flagi określające tryb otworzenia pliku:
    • O_RDONLY - Otwarcie pliku tylko do czytania.
    • O_WRONLY - Otwarcie pliku tylko do pisania.
    • O_RDWR - Otwarcie pliku do czytania i pisania.
    • O_CREAT - Jeśli plik nie istnieje to zostanie utworzony.
    • O_EXCL - Jeśli plik istnieje i flaga O_CREAT jest ustawiona to funkcja się nie powiedzie.
    • O_NOCTTY - Jeśli pathname odnosi się do urządzenia terminalowego to terminal nie stanie się kontrolującym proces nawet gdy proces takiego nie ma.
    • O_TRUNC - Jeśli plik istnieje to zostanie obcięty.
    • O_APPEND - Tryb dopisywania do pliku. Początkowo i przed każdym wywołaniem write wskaźnik pliku jest ustawiay na jego koniec.
    • O_NONBLOCK lub O_NDELAY - Otwieranie pliku w trybie nieblokującym
    • O_SYNC - Otwieranie pliku dla synchronicznego I/O. Wszelkie wywołania write na deskryptorze pliku będą blokować proces wołający aż do fizycznego zapisania danych do podlegającego sprzętu.
    • Dodatkowe flagi nieobecne we wcześniejszych wersjach jądra: O_ACCMODE, FASYNC, O_DIRECT, O_LARGEFILE, O_DIRECTORY, O_NOFOLLOW, O_INVISIBLE.
  • mode - w przypadku tworzenia nowego pliku jest to maska bitowa uprawnień (szczegóły: man 2 open)

Algorytm
Na rysunku jest przedstawiony ogólny schemat działania algorytmu Open (bez podziału na wywoływane funkcje, opisu zmiennych, struktur danych).



Przedstawiony teraz zostanie bardziej szczegółowy opis algorytmu(w punktach):
  1. Wywołana zostaje funkcja getname(filename). Funkcja ta odczytuje scieżkę dostępu do pliku z przestrzeni adresowej procesu. Od tej pory w zmiennej lokalnej (tmp) w obszarze pamięci jądra znajduje się właściwa ścieżka dostępu do pliku. Jeśli wszystkow w porządku to:


  2. Wywołana zostaje funkcja get_unused_fd() w celu znalezienia pierwszego wolnego deskryptora pliku (indeksu w tablicy obiektów plikowych) dla procesu wywołującego. Szukane jest wolne miejsce w tablicy current->files->fs. Funkcja get_unused_fd() dodatkowo sprawdza czy nie trzeba zwiększyć rozmiaru mapy bitowej current->files->open_fds (opisującej zestaw otwartych deskryptorów) lub tablicy current->files->fs. Jeśli trzeba to próbuje powiększyć te obiekty. Znaleziony deskryptor jest zachowywany w zmiennej lokalnej fd. Jeśli wszystkow w porządku to:


  3. Wywołana zostaje funkcja filp_open(tmp, flags, mode). Odpowiednie parametry to: tmp - ścieżka dostępu do pliku, flags,mode - tak jak przy wywołaniu sys_open. Funkcja filp_open działa następująco:

    1. Na podstawie przekazanych do funkcji flag ustalane są nowe flagi (namei_flags) potrzebne przy późniejszym wywołaniu funkcji open_namei(...).


    2. Wywoływana jest funkcja open_namei(filename, namei_flags, mode, nd); gdzie filename to ścieżka dostępu do pliku (przekazana wcześniej zmienna tmp), a nd to wskaźnik do specjalnej struktury struct nameidata (namei_flags już zostało opisane, mode się nie zmienia). Funkcja open_namei(...) jest najdłuższą funkcją używaną w całym algorytmie. W skrócie działa ona tak:

      1. Jeśli plik nie ma zostać stworzony (nie jest ustawiona flaga O_CREAT) to:
        Interpretuje ścieżkę dostępu do pliku i pobiera obiekt pozycji katalogu związany z tym plikiem. Używa do tego funkcji pary funkcji:
        • path_init(pathname, lookup_flags(flag), nd) - funkcja inicjalizująca, pobiera obiekt pozycji katalogu do pola nd->dentry. Na początku jest on związany z początkowym miejscem przeszukiwań zależnym od przekazanej ścieżki pathname (czy na początku był znak '/') oraz od roboczego katalogu dla danego procesu (current->fs->pwd).

        • path_walk(pathname, nd) - właściwa funkcja zamieniająca pathname na obiekt typu dentry. Będzie on dostępny przez pole nd->dentry. Od tej pory w zmiennej dentry trzymany jest właściwy obiekt pozycji katalogu.


      2. Jeśli plik ma zostać stworzony to:
        1. Używana jest para funkcji: path_init(pathname, PARENT_LOOKUP, nd) oraz path_walk(pathname, nd) w celu pobierania obiektu pozycji katalogu związanego z ojcem podanego pliku. Obiekt katalogu związany z katalogiem, w którym ma być stworzony plik będzie dostępny przez pole dir Jeśli wszystko w porządku to:
        2. Uruchamiana jest funkcja lookup_hash(...), która w rezultacie zwraca obiekt katalogu związany z plikiem, który ma zostać stworzony. Jeśli wszystko w porządku to:
        3. Wywoływana jest funkcja vfs_create(dir->d_inode, dentry, mode), która jest odpowiedzialna za wywołanie (jeśli jest zdefinowana) odpowiedniej funkcji tworzącej plik (będącej operacją i-węzła) dla danego systemu plików (patrz.Opis mknod()

      3. Wykonuje serię testów w celu sprawdzenia czy proces ma uprawnienia umożliwiające otwarcie pliku zgodnie z przekazanymi flagami. Jeśli nie napotkano żadnego błędu to zwracana jest wartość 0, a pole nd->dentry zawiera obiekt pozycji katalogu odpowiadający otwieranemu plikowi.

    3. Jeśli funkcja open_namei(...) zwróciła wartość 0 to wywoływana jest funkcja dentry_open(...), do której są przekazywane min. orginalne flagi: flags, oraz obiekt pozycji katalogu, odpowiadający otwieranemu plikowi: dentry. Funkcja dentry_open(...) działa tak:

      1. Wywoływana jest funkcja get_empty_filp(), która pobiera nowy obiekt pliku, zostaje on przypisany na zmienną f.


      2. Ustawiane są odpowiednio pola f->f_flags i f->f_mode.


      3. Jeśli proces chce zapisywać do pliku to sprawdzana jest wartość pola i_writecount obiektu i-węzła powiązanego z dentry. W tym celu jest uruchamiana funkcja get_write_access(inode), która zwiększa liczbę i_writecount jeśli była ona większa lub równa zero, a zwraca błąd jeśli była mniejsza od zera (plik został odwzorowany w pamięci i nie można zezwolic na zapis).


      4. Inicjowane są pola obiektu pliku f. Np. f->f_op jest inicjowane na inode->i_fop.


      5. Obiekt pliku jest przesuwany do kolejki obiektów "w użyciu" (kolejki, do której wskaźniki znajdują się w polu s_files odpowiedniego superbloku).


      6. Jeśli zdefiniowany jest wskaźnik do funkcji open dla pliku (f->f_op->open) to wykonywana jest ta funkcja dla tego pliku f.


      7. Pole f->f_flags jest czyszczone z flag: O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC.


      8. Funkcja dentry_open(...) zwraca obiekt pliku f.

    4. Funkcja filp_open(...) zwraca zwrócony przez dentry_open(...) obiekt pliku.


    Jeśli wszystkow w porządku to:

  4. Wywołana zostaje funkcja fd_install(fd, f), która ustawia pole current->files->fd[fd] na adres obiektu pliku f zwróconego przez funkcję filp_open(...).


  5. Zwalniana jest zmienna tmp przy pomocy putname(tmp). Zwracana jest wartość fd.




Algorytm creat.


Creat(...) jest wywołaniem systemowym. Funkcja ta odpowiedzialna jest za utworzenie nowego pliku. Jest ona równoważna z wywołaniu open z argumentem flags ustawionym na O_CREAT|O_WRONLY|O_TRUNC.

Za realizację wywołania odpowiada funkcja:
long sys_creat(const char * pathname, int mode)
Funkcja sys_creat wywołuje po prostu:
sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode)



Algorytm close.


Close(...) jest wywołaniem systemowym. Funkcja ta jest odpowiedzialna za zamykanie otwartego deskryptora pliku (deskryptor jest podany jako parametr). Po jej wywołaniu deskryptor taki nie dotyczy już żadnego pliku i może być użyty ponownie. Jeśli wywołanie się powiedzie to jest zwracana wartość 0, jeśli nie -1.

Za realizację wywołania odpowiada funkcja:
long sys_close(unsigned int fd)

Opis parametrów funkcji:
Jedynym parametrem funkcji jest deskryptor pliku, który ma być zamknięty przez dany proces.

Algorytm
Na rysunku jest przedstawiony ogólny schemat działania algorytmu Close.



Dalej zostanie przedstawiony bardziej szczegółowy opis algorytmu (w punktach):

  1. Zmienna lokalna files jest ustawiana na current->files czyli jest wskaźnikiem do struktury typu files_struct dla wywołującego procesu. Na początku jest uruchamiana funkcja write_lock(&files->file_lock), która blokuje dostęp do zapisywania do pliku.


  2. Na zmienną filp zostaje pobrany adres obiektu pliku znajdujący się w polu fd tablicy deskryptorów związanej z wywołującym procesem (filp=files->fd[fd]). Jeśli adres ten jest równy NULL to zwracany jest błąd.


  3. Zmienna files->fd[fd] jest ustawiana na NULL.


  4. Uwolniony zostaje deskryptor pliku fd poprzez wyczyszczenie odpowiednich bitów w mapach bitowych wskazywanych przez:

    • files->close_on_exec - funkcja: FD_CLR(fd, files->close_on_exec).
    • files->open_fds - funkcja: __put_unused_fd(files, fd);

  5. Zdejmuje blokadę zapisu i uruchamia funkcję filp_close(filp, files) która:

    1. Jeśli dla danego obiektu pliku była zdefiniowana metoda flush (filp->f_op->flush) to ją wykonuje dla danego obiektu pliku (przed wykonaniem wywołuje lock_kernel() - blokowanie dostępu do sekcji krytycznej jądra, a po unlock_kernel())
    2. Zwalnia wszystkie blokady dotyczące pliku.
    3. Zwalnia obiekt pliku przy pomocy metody fput(filp).
      Zwraca kod błędu metody flush().

  6. Funkcja sys_close(...) zwraca kod zwrócony przez filp_close(...).



Algorytm read.


Read(...) jest wywołaniem systemowym. Parametry jakie przyjmuje to: int fd, void *buf, size_t count. Wywołanie to jest odpowiedzialne za pobranie maksymalnie count bajtów z pliku, któremu odpowiada deskryptor fd, do bufora buf. Jeśli wywołanie się powiedzie zwracana jest liczba odczytanych bajtów (zero oznacza koniec pliku) i przesuwana jest pozycja w pliku o tą wartość. W przypadku błędu zwracane jest -1.

Za realizację wywołania odpowiada funkcja:
ssize_t sys_read(unsigned int fd, char * buf, size_t count)

Opis parametrów funkcji:

  • fd - deskryptor pliku, z którego proces chce czytać.
  • buf - wskaźnik bufora w pamięci, do którego mają zostać przeczytane dane.
  • count - liczba bajtów, które należy przeczytać
Algorytm
Na rysunku przedstawiony został schemat działania algorytmu Read.



Bardziej szczegółowy opis algorytmu(w punktach):
  1. Wywoływana jest funkcja fget(fd) w celu pobrania wskaźnika do obiektu pliku określonego przez deskryptor (zwiększany jest również licznik użycia obiektu pliku). Wskaźnik ten będzie znajdował się w zmiennej file.


  2. Następuje sprawdzenie czy flaga file->f_mode pozwala na odczyt z pliku.


  3. Wywoływana jest funkcja locks_verify_area w celu sprawdzenia czy nie ma blokad dostępu do pliku.


  4. Jeśli dla danego obiektu pliku jest zdefiniowana metoda read ((file->f_op->read) != NULL) to wywoływana jest funkcja read(...) z danego obiektu pliku w celu przeniesienia danych do buf (wywoływane jest file->f_op->read(...)) z pliku.


  5. Zwalniany jest obiekt pliku: fput(file).
    Funkcja zwraca liczbę naprawdę przeczytanych bajtów.




Algorytm write.


Write(...) jest wywołaniem systemowym. Parametry jakie przyjmuje to: int fd, const void *buf, size_t count. Wywołanie to jest odpowiedzialne za zapisanie maksymalnie count bajtów do pliku, któremu odpowiada deskryptor fd. Dane do zapisania znajdują się w buforze buf. Jeśli wywołanie się powiedzie zwracana jest liczba zapisanych bajtów (zero oznacza, że nic nie zostało zapisane). W przypadku błędu zwracane jest -1.

Za realizację wywołania odpowiada funkcja:
ssize_t sys_write(unsigned int fd, const char * buf, size_t count)

Opis parametrów funkcji:

  • fd - deskryptor pliku, do którego proces chce pisać.
  • buf - wskaźnik bufora w pamięci, z którego dane mają zostać przeniesione do pliku.
  • count - liczba bajtów, które należy przenieść.
Algorytm
Poniżej zostanie przedstawiony opis działania algorytmu write():
  1. Wywoływana jest funkcja fget(fd) w celu pobrania wskaźnika do obiektu pliku określonego przez deskryptor (zwiększany jest również licznik użycia obiektu pliku). Wskaźnik ten będzie znajdował się w zmiennej file.


  2. Następuje sprawdzenie czy flaga file->f_mode pozwala na zapis do pliku.


  3. Wywoływana jest funkcja locks_verify_area w celu sprawdzenia czy nie ma blokad dostępu do pliku.


  4. Jeśli dla danego obiektu pliku jest zdefiniowana metoda write ((file->f_op->write) != NULL) to wywoływana jest funkcja write(...) z danego obiektu pliku w celu przeniesienia danych z buf do pliku (wywoływane jest file->f_op->write(...))


  5. Zwalniany jest obiekt pliku: fput(file).
    Funkcja zwraca liczbę naprawdę przeniesionych bajtów.



Algorytm mknod.


Mknod(...) jest wywołaniem systemowym. Wywołanie to umożliwia tworzenie plików specjalnych urządzeń (blokowych lub znakowych), kolejek FIFO, gniazd (ang. socket) oraz zwykłych plików. Przy jego pomocy nie można tworzyć katalogów (słuzy do tego mkdir). Parametrami jakie przyjmuje wywołanie są: const char *pathname, mode_t mode, dev_t dev. Gdzie:

  • pathname - nazwa tworzonego pliku.
  • mode - maska praw dostępu wraz z typem tworzonego pliku.
  • dev - główny i drugorzędny numer urządzenia (dla plików specjalnych urządzeń).
Za realizację wywołania odpowiada funkcja:
long sys_mknod(const char * filename, int mode, dev_t dev), która przyjmuje takie same parametry jak wywołanie systemowe.

Algorytm
Zasada działania algorytmu jest podobna do działania algorytmu open gdy ustawiona jest flaga tworzenia nowego pliku.
Dalej zostanie przedstawiony opis algorytmu mknod (w punktach):
  1. Na początku, na podstawie maski mode, następuje sprawdzenie czy tworzony plik ma być katalogiem. Jeśli tak to zostaje zwrócony błąd, a wpp:


  2. Wywołana zostaje funkcja getname(filename), która odczytuje scieżkę dostępu do pliku z przestrzeni adresowej procesu. Od tej pory w zmiennej lokalnej (tmp) w obszarze pamięci jądra znajduje się właściwa ścieżka dostępu do pliku. Jeśli wszystko w porządku to:


  3. Używana jest para funkcji: path_init(pathname, PARENT_LOOKUP, nd) oraz path_walk(pathname, nd) w celu pobierania obiektu pozycji katalogu związanego z ojcem podanego pliku.(porównaj Algorytm open) Obiekt katalogu związany z katalogiem, w którym ma być stworzony plik będzie dostępny przez pole nd->dentry gdzie nd jest strukturą typu struct nameidata. Jeśli wszystko w porządku to:


  4. Uruchamiana jest funkcja lookup_create(&nd, 0), która zwraca obiekt katalogu związany z plikiem, który ma zostać stworzony. Zmieniana jest zmienna mode zgodnie z polem umask struktury typu fs_struct przyporządkowanej danemu procesowi (current->fs->umask). Jeśli wszystko w porządku to:


  5. Zależnie od flag zawartych w mode uruchamiane są funkcje:

    • vfs_create(nd.dentry->d_inode,dentry,mode) - jeśli stworzony ma być zwykły plik. Funkcja ta:

      1. Blokuje katalog macierzysty przekazany jako pierwszy parametr.
      2. Sprawdza czy można utworzyć plik w tym katalogu (wystarczające uprawnienia, nie istnieje już taki plik) may_create(dir, dentry)
      3. Jeśli w obiekcie i-węzła tego katalogu jest zdefiniowana operacja create (i_op->create!=NULL) to: blokowana jest sekcja krytyczna jądra;
        wykonywana jest ta operacja create dla obiektu pozycji katalogu tworzonego pliku dir->i_op->create(dir, dentry, mode);
        odblokowywana jest sekcja krytyczna jądra;
        Nowy plik jest uwzględniany w limitach dyskowych (jeśli potrzeba).
      4. Odblokowany zostaje katalog macierzysty.


    • vfs_mknod(nd.dentry->d_inode,dentry,mode,dev) - jeśli stworzony ma być plik urządzenia blokowego, kolejka FIFO lub gniazdo. Funkcja ta:

      1. Blokuje katalog macierzysty przekazany jako pierwszy parametr.
      2. Sprawdza czy można utworzyć plik w tym katalogu (wystarczające uprawnienia, nie istnieje już taki plik) may_create(dir, dentry)
      3. Jeśli w obiekcie i-węzła tego katalogu jest zdefiniowana operacja mknod (i_op->mknod!=NULL) to: blokowana jest sekcja krytyczna jądra;
        wykonywana jest ta operacja mknod dla obiektu pozycji katalogu tworzonego pliku dir->i_op->mknod(dir, dentry, mode, dev);
        odblokowywana jest sekcja krytyczna jądra;
        Nowy plik jest uwzględniany w limitach dyskowych (jeśli potrzeba).
      4. Odblokowany zostaje katalog macierzysty.


  6. Zwalniany jest obiekt katalogu dentry oraz zmienna nd. Zwalniana jest zmienna tmp przy pomocy putname(tmp).