Do spisu treści tematu 6
 

    6.5.5 Pisanie do pliku - funkcja write()

Spis treści


 Algorytm - opis

Funkcja write składa się z dwóch części: niezależnej i zależnej od systemu plików.
Część niezależna sprawdza, czy proces ma prawo do pisania w pliku, czy nie ma założonej blokady do pisania, czy proces ma prawo czytania z obszaru pamięci, do którego adres przekazał jako parametr wywołania.
Następnie opuszczany jest semafor na i-węźle w celu wykluczenia jednoczesnych zapisów do pliku i wykonywana jest część zależna od systemu plików, po zakończeniu której semafor na i-węźle jest ponownie podnoszony. (Poniżej opisana zostanie tylko ta zależna od systemu plików część funkcji write, która jest stosowana do plików z systemu plików EXT2).
Jądro sprawdza, czy system plików nie jest systemem przeznaczonym tylko do odczytu; jeśli tak, to zwracany jest błąd.
Jeśli plik został otwarty do dopisywania, to znacznik bieżącej pozycji w pliku ustawiany jest na koniec pliku, w przeciwnym wypadku zapis będzie dokonany od pozycji określonej przez znacznik zapisany w tablicy plików.
Następnie obliczany jest numer bloku, który będzie zapisywany, a który odpowiada wcześniej ustawionemu znacznikowi bieżącej pozycji w pliku. Jednocześnie obliczane jest też miejsce w tymże bloku, od którego to rozpocznie się pisanie.
Teraz, aż do zapisania wszystkich przeznaczonych do tego danych (lub wystąpienia błędu) wykonywane są następujęce operacje: jądro sprawdza, czy bieżąca pozycja w pliku nie jest większa niż wielkość określona przez zmienną two_gb inicjowaną na wartość 2147483647, która odpowiada 2GB.
Potem pobierany jest bufor odpowiadający i-węzłowi pliku i obliczonemu numerowi bloku. Jeśli ilość bajtów pozostałych do zapisania jest mniejsza niż wielkość bufora, to należy go najpierw wczytać i modyfikować jego kawałek, bo zapisywać możemy tylko całe bloki, nie ich części. Jeśli mamy zapisać cały blok, to nie warto go wczytywać, bo i tak cały zostałby zamazany.
Kolejną operacją jest wczytanie, z adresu przekazanego jako argument funkcji, porcji danych do pobranego przed chwilą bufora, po czym uaktualniana jest znajdujaca się w pamięci podręcznej (cache) kopia strony, która odnosi się do właśnie zapisywanego bloku.
Potem wskaźniki bieżącej pozycji w pliku i bieżącego miejsca pobierania danych z miejsca wskazanego przy wywołaniu funkcji są przesuwane o tyle miejsc do przodu, ile bajtów zostało zapisanych, a bufor oznaczony zostaje jako aktualny i czysty, czyli, że to samo jest zapisane weń i w fizycznym pliku na dysku.
Jeśli plik został otwarty do operacji synchronicznych (vide: sposoby otwarcia pliku), wykorzystywany jest algorytm "pisania z opóźnieniem", który polega na tym, że plik nie jest zapisywany po jednym bloku lecz po wiele (standardowo stała NBUF, która określa tę ilość ma wartość 32). Działa to tak, że zapis prowadzony jest do specjalnej tablicy rozmiaru NBUF i dopiero, gdy tablica ta jest pełna wykonywany jest fizyczny zapis na urządzenie. Celem jest uniknięcie dodatkowych (czasochłonnych) operacji dyskowych, jeśliby miało się tak stać, że jakiś inny proces będzie czytał lub pisał do tego samego pliku (jak to ma miejsce np. w przypadku łączy, które przecież też są plikami).
Jeśli zaś plik nie był otwarty jako synchroniczny, to zajęty blok jest natychmiast zwalniany.
Gdy tablica z buforami zapełni się jej zawartość jest zapisywana w całości, a zajmowane bufory - zwalniane.
Jądro przechodzi do pracy nad następną porcją danych, wracając na początek pętli. Jeśli nie było już nic do zapisania, to pętla zostaje opuszczona, a pozostałe jeszcze w tablicy buforów dane - zapisane (wraz z następującym potem zwolnieniem buforów).
Na końcu wykonywania funkcji modyfikowany jest czas ostatniej modyfikacji pliku i czas ostaniej modyfikacji i-węzła (ustawiane są na czas bieżący). Modyfikowana jest także długość pliku zapisana w i-węźle. Jeśli bieżąca pozycja w pliku jest większa niż zapisana w i-węźle wartość, to zapis trzeba zaktualizować tzn. ustawić długość pliku na równą bieżącej pozycji w pliku. Po zaznaczeniu i-węzła jako "brudnego" i zwolnienia blokady nałożonej na i-węzeł funkcja kończy działanie.
 

 Źródła informacji

Maurice J. Bach "Budowa systemu operacyjnego UNIX"

Projekt Linux - opis funkcji write


Autor: Adam Kieżun