Kazde urzadzenie blokowe opisane jest przez strukture blk_dev_struct
zdefiniowana w pliku naglowkowym
blkdev.h
struct blk_dev_struct {
void (*request_fn)(void);
struct request *current_request;
struct request plug;
struct tq_struct plug_tq;
}
request_fn
current_request
plug
current_request
wskazuje na nie, kiedy kolejka jest
pusta i wlasnie dokladamy do niej nowe zadania,
plug_tq
plug
z kolejki zadan,
Struktury blk_dev_struct
sa elementami tablicy blk_dev
o rozmiarze MAX_BLKDEV, czyli 64 w wersji Linuxa 2.0.0.
Pozostale struktury danych (plik blkdev.h ) to:
int * blk_size[MAX_BLKDEV]
int * blksize_size[MAX_BLKDEV]
blk_size
struktura (tablica dwuwymiarowa),
zawierajaca wielkosc jednego bloku urzadzenia, jesli wartosc
blksize_size[nr_glowny]
nie jest zdefiniowana (NULL) to
przyjmuje sie wielkosc 1024 bajtow
int * hardsect_size[MAX_BLKDEV]
int read_ahead[MAX_BLKDEV]
int ro_bits[MAX_BLKDEV][8]
Programy obslugi urzadzen blokowych nie implementuja wlasnych funkcji
read
ani write
. Zamiast tego uzywaja wspolnych dla
wszystkich urzadzen blokowych funkcji block_read
i
block_write
. Funkcje te korzystaja z mechanizmu podrecznej
pamieci buforowej, wiec w ich lepszym zrozumieniu moze pomoc lektura poswieconego
buforom tematu 5 (szczegolnie opis funkcji
getblk, wait_on_buffer, brelse
).
DEFINICJA:
long block_read( struct inode *inode, /* i-wezel pliku specjalnego */
struct file *filp, /* opis pliku specjalnego
w tablicy plikow */
char *buf, /* bufor w przestreni uzytkownika
na odczytane dane */
unsigned long count ) /* liczba bajtow do przeczytania */
WYNIK: ilosc przeczytanych bajtow lub kod bledu EIO
{
bhreq - tablica wskaznikow na naglowki buforow;
zadeklaruj licznik przeczytanych bajtow;
pobierz z i-wezla numer urzadzenia;
ustal wielkosc bloku, pozycje w pliku i numer pierwszego bloku;
ustal liczbe blokow do odczytania;
do {
oproznij tablice bhreq;
aktualny = 1;
/*
zazadaj przydzielenia wolnych buforow, jesli
pierwszy z nich bedzie zawieral aktualne dane
to wyskocz z petli i przepisz je
*/
while (sa bloki do odczytania)
{
zmniejsz liczbe blokow do odczytania;
/* zazadaj przydzielenia buforow na blok :*/
getblk(numer urzadzenia, numer bloku, wielkosc bloku);
dodaj bufor do tablicy bhreq;
if (zadany bufor nia zawiera aktualnych danych)
aktualny = 0;
if (aktualny = 1)
break;
}
/* zazadaj wczytania danych do przydzielonych
buforow z tablicy bhreq:
*/
ll_rw_block(READ,liczba buforow do wczytania, bhreq);
do {
ustaw wskaznik bhe na poczatek tablicy bhreq;
/* czekaj na wczytanie bufora */
wait_on_buffer ( bhe );
/* sprawdz, czy nie ma bledu */
if ( bhe nie zawiera aktualnych danych )
{
zwolnij bufor bhe;
liczba bajtow do przeczytania = 0;
break;
}
przepisz dane z bufora do przestrzeni uzytkownika;
zwolnij bufor;
zwieksz licznik przeczytanych bajtow;
przesun wskaznik bhe;
} while (bhe nie wskazuje na NULL)
} while (liczba bajtow do przeczytania > 0)
zwolnij pozostale przydzielone bufory;
/* wywolujac dla kazdego brelse(bufor) */
if (liczba przeczytanych bajtow = 0)
return -EIO;
return ( liczba przeczytanych bajtow );
}
Komentarz:
hardsect_size
;
DEFINICJA:
long block_write( struct inode *inode, /* i-wezel czytanego pliku */
struct file *filp, /* struktura w tablicy plikow */
const char *buf, /* bufor z danymi do zapisania */
unsigned long count) /* ilosc bajtow do zapisania */
WYNIK: ilosc zapisanych bajtow lub kod bledu EIO;
{
bhlist - tablica przydzielonych buforow;
if( urzadzenie tylko do odczytu )
return -EPERM;
ustal wielkosc bloku, pozycje w pliku i ilosc blokow do zapisania;
while( bajtow do przeczytania > 0 )
{
if( numer zapisywanego bloku > wielkosc urzadzenia w blokach )
return( liczba bajtow zapisanych lub -ENOSPC jesli rowna 0);
/* zazadaj przydzialu wolnego bufora */
bufor = getblk( nr urzadzenia, nr bloku, wielkosc bloku );
if( aktualny blok jest ostatni do zapisania )
{
zazadaj przydzialu buforow na bloki
przeczytane z wyprzedzeniem (getblk) i
umiesc bufory w tablicy bhlist;
przeczytaj bloki z wyprzedzeniem ( ll_rw_block );
if( blad czytania )
return -EIO
zwolnij wszystkie oprocz pierwszego (brelse);
}
zmniejsz ilosc bajtow do czytania;
kopiuj dane do bufora;
zaznacz bufor jako aktualne (mark_buffer_uptodate);
if( uzylismy juz 64 buforow (wielkosc tablicy bhlist))
{
zazadaj zapisania buforow z bh_list (ll_rw_block);
czekaj na zapisanie buforow (wait_on_buffer);
}
}
zazadaj zapisania buforow z bh_list (ll_rw_block);
czekaj na zapisanie;
if( wystapil blad )
return -EIO;
return( ilosc przeczytanych bajtow );
}
Jak widac, ani block_read
ani block_write
nic
bezposrednio nie zapisuja ani nie czytaja, a tylko zlecaja odpowiednie
operacje funkcji ll_rw_block
, o ktorej w rozdziale o
szeregowaniu zadan.