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