Do spisu tresci tematu 6

Czytanie-funkcja read()



Spis tresci


Wprowadzenie

Funkcje systemowe ogolnie mozna podzielic na funkcje obslugujace istniejace pliki, sluzaca do tworzenia nowych plikow,obslugujace i-wezel, pozwalaace przemieszczac sie w systemie plikow, rozszerzajace drzewo systemu plikow i zmieniaja struktore hierarchii systemu plikow.
Funkcja systemowa read sluzy do obslugi istniejacego pliku, stanowi ona przeciwienstwo funkcji write. Powoduje ona wczytanie odpowiedniej ilosci bajtow danych z otwartego pliku do odpowiedniej struktory danych uzytkownika. Czytanie rozpoczyna sie od biezacej pozycji wskaznika w pliku; po zakonczeniu czytania wskaznik do pliku bedzie zwiekszony o liczbe przeczytanych bajtow. W odroznieniu od funkcji write, funkcja systemowa read nie moze oszukiwac, opozniajac wczytywanie danych. Jesli dane nie znajduja sie juz w wewnetrznym buforze jadra, to proces musi zaczekac na pobranie ich z dysku. Zazwyczaj jadro systemu probuje przyspieszyc dzialanie, zwracajac uwage na sposob dostepu do pliku, sugerujac sekwencyjne wczytywanie kolejnych blokow dyskowych i w konsekwencji wczytujac dane z wyprzedzeniem. Jesli system nie jest zbyt przeciazony i dane moga przez pewien czas pozostawac w buforze a operacje czytania przebiegaja sekwencyjnie, to wczytywanie z wyprzedzeniem jest calkiem skuteczne.

Opis funkcji read dla wszystkich systemow plikow

Funkcja read:


DEFINICJA:
int read(unsigned int fd, char *buf, unsigned int count );

WYNIK: liczba wczytanych bajtow, 
                 0 w przypadku napotkania na koniec pliku,
                 -1 w przypadku bledu; 
	errno =EDEADLOCK(jezeli na plik lub rekordy jest zalozona blokada)
	       EFAULT(w przestrzeni wirtualnej nie ma zaalokowanego
		      bufora uzytkownika )
	       EINVAL(jezeli nie mozemy wywolac funkcji read dla konkreatnego systemu plikow)

fd jest deskryptorem czytanego pliku
buf jest adresem struktory danych uzytkownika do ktorego wczytujemy dane
count jest to liczba bajtow, ktore chce wczytac uzytkownik

Dla wszystkich systemu plikow dana jest ta sama funkcja read:

{
   pobieramy i-wezel korzystajac z deskryptora pliku uzytkownika
   
   sprawdzamy w tablicy plikow prawo do czytania dla pliku
   
   sprawdzamy czy mozemy wywolac read dla konkretnego systemu plikow
   
   upewniamy sie czy nie ma blokady na rekord do czytania(wywolujemy funkcje locks_verivy_area)
   
   upewniamy sie czy struktura danych uzytkownika jest zaalokowana w jego przestrzeni(funkcja verify_area)
   
   dla systemu plikow EXT2 wywolujemy funkcje generic_file_read
}     
  

Opis wazniejszych struktur danych

struct file {

struct file_operations /* operacje na pliku w konkretnym file-systemie */


Opis funkcji generic_file_read

Funkcja generic_file_read:


DEFINICJA:
int generic_file _read(struct inode *inode,struct file *filp, char *buf,int count)

WYNIK:
	liczba wczytanych bajtow
	0 w przypadku napotkania na koniec pliku
	-1 w przypadku bledu
        errno=ENOMEM(blad przy tworzeniu ramki pamieci)
              EIO(blad wejscia-wyjscia)
Parametry buf i count takie same jak w wywolaniu read.
inode jest i-wezlem czytanego pliku
filp pozycja w tablicy plikow odpowiadajaca danemu plikowi
buf jest adresem struktory danych uzytkownika do ktorego wczytujemy dane
count jest to liczba bajtow, ktore chce wczytac uzytkownik
Funkcja generic_file_read wykorzystuje czytanie z wyprzedzeniem, gdy stwierdzi ze odczyt jest sekwencyjny. W strukturze struct_file czytanego pliku znajduja sie pola f_ramax i f_rawin. Oczywiscie wartosc pola f_ramax zmienia sie dynamicznie w trakcie wykonywania sie funkcji read i dodatkowo nie moze byc wieksza niz zdefiniowana stala MAX_READAHEAD=PAGE_SIZE*18 i mniejsza niz MIN_READAHEAD=PAGE_SIZE*3, gdzie PAGE_SIZE jest rozmiarem ramki w pamieci operacyjnej.
Z tych pol korzysta funkcja generic_file _readahead, ktora zwraca nam ramke pamieci czytajac z wyprzedzeniem lub 0 gdy nie udalo sie jej znalezc lub stworzyc nowej ramki.

Algorytm funkcji generic_file_read:

{
 Jesli aktualna pozycja w pliku znajduje sie poza obszarem 
 poprzednio wczytanym z wyprzedzeniem, to ustawiamy pola 
 f_rawin, f_ramax na 0
 W przeciwnym przypadku stierdzamy, ze dostep do pliku jest sekwencyjny
 i kontynuujemy czytanie z wyprzedzeniem ustawiajac zmienna reada_ok na 1   
 
 Jesli ilosc danych do przeczytania z pliku jest mniejsza niz polowa rozmiaru 
 ramki pamieci(PAGE_SIZE=4kb) to f_ramax=0
 W przeciwnym przypadku  jesli ilosc bajtow do przeczytania jest wieksza niz f_ramax
 to f_ramax=(ilosc danych do przeczytania)

 for(;;)
 {
    Probujemy znalezc ramke pamieci zawierajaca dane z pliku na aktualnej
    pozycji
    Jesli udalo sie nam to idziemy do etykiety znaleziono_ramke   
    Jesli nie to do etykiety nie_znaleziono_ramki

znaleziono_ramke:
    Jesli ramka jest aktualna lub zablokowana(np. z powodu zapelniania jej danymi) to
    probujemy dostac nastepna ramke wywolujac funkcje generic_file_read
    W przeciwnym przypadku pole f_ramax ustawiamy na MIN_READAHEAD  
    
    Czekamy na ramke(nie na ta dodatkowa byc moze zwrocona przez generic_file_readahead)

    Jesli ramka jest nieaktualna to idziemy do etykiety ramka_blad
    Jesli jest aktualna to do etykiety sukces  

sukces:
    Obliczamy ilosc bajtow, ktore mamy wczytac z ramki
    
    Kopjujemy dane z ramki do bufora uzytkownika
    
    Nie zwalniamy ramki ale zmniejszamy licznik odwolan do niej
    
    Zwiekszamy pozycje w pliku, pozycje w buforze, ilosc przeczytanych bajtow i ilosc bajtow, ktore mamy
    do  przeczytania o ilosc bajtow przeczytanych z ramki

    Jesli nie mamy nic do czytania to wyskocz z petli for 
    W przeciwnym przypadku idz na poczatek petli for(continue)

nie_znaleziono_ramki:
    Jesli nie mamy dodatkowej ramki przeczytanej z wyprzedzeniem to tworzymy nowa ramke (_get_free_page)
    i jesli funkcja nie zwrocila bledu to idziemy na poczatek petli for(continue)
    
     W przeciwnym przypadku jesli mamy dodatkowa ramke pamieci to dodajemy ja do kolejki haszujacej 
     ramek (wywolujemy funkcje add_to_page_cache) a nastepnie wywolujemy funkcje readpage zglaszajac
     zadanie zapisania ramki danymi z dysku
     Jesli operacja zakonczy sie pomyslnie to idziemy do etykiety znaleziono_ramke 
     Jesli blad to wyskakujemy z petli for

ramka_blad::
     /*znalezlismy ramke ale nie jest aktualna*/
     Zglaszamy zadanie zapisu ramki (funkcja readpage)
     
     Jesli wszystko poszlo dobrze to czekamy na ramke (byc moze jest w trakcie zapelniania)
     i idziemy do etykiety sukces

      W przeciwnym przypadku wyskakujemy z petli for
 }/*koniec petli for*/
 
 Jesli mamy dodatkowa ramke to ja zwalniamy
 
 Jesli i-wezel nie jest tylko do odczytu to aktualizujemy czas ostatniego dostepu do i-wezla na aktualny
 
 Zaznaczamy ze i-wezel jest brudny
 
  Zwracamy ilosc przeczytanych bajtow
}/*koniec algorytmu funkcji generic_file_read  	  

Zrodla informacji:

Przy opracowywaniu tego tematu korzystalem z nastepujacych zrodel:
  1. Pliki zrodlowe linuxa:

Autor: Andrzej Silaczuk