linux721 MFZCQ272JLICHM6QT4KARHMXN3PL574OYYZK7UY




urzadzenia blokowe



do spisu tresci tematu 7

7.2.1 Urzadzenia blokowe - wprowadzenie


Spis tresci

Struktury danych
Operacje wejscia-wyjscia
Zrodla informacji



Struktury danych

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
wskaznik na procedure strategii (strategy routine) czyli najwazniejsza
czesc programu obslugi urzadzenia blokowego, zajmujaca sie szeregowaniem zadan
current_request
kolejka struktur opisujacych zadania wejscia-wyjscia skierowane do urzadzenia
plug
specjalne, nieaktywne zadanie sluzace tylko do "zatkania" kolejki,
wskaznik current_request wskazuje na nie, kiedy kolejka jest
pusta i wlasnie dokladamy do niej nowe zadania,
plug_tq
struktura typu task queue,
(patrz kolejki zadan), zawiera funkcje
usuwajaca strukture 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]
indeksowana numerami glownymi urzadzen tablica, ktorej elementami sa
indeksowane numerami drugorzednymi tablice zawierajace ilosc blokow, ktore
zawiera urzadzenie,
int * blksize_size[MAX_BLKDEV]
Podobna do 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]
dwuwymiarowa tablica zawierajaca wielkosci sektorow, zalezne od fizycznej
budowy urzadzenia; domyslna wielkoscia sektora jest 512 bajtow
int read_ahead[MAX_BLKDEV]
ilosc sektorow, ktore maja zostac przeczytane przy operacji czytania
z wyprzedzeniem,
int ro_bits[MAX_BLKDEV][8]
flagi, ktorych ustawienie oznacza, ze urzadzenie jest tylko do odczytu;



Operacje wejscia-wyjscia na urzadzeniach blokowych

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 ).


Algorytm block_read (z pliku
fs/block_dev.c)



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:

ilosc blokow do odczytania = max( ilosc bajtow do odczytania /
rozmiar bloku, najwieksza wielokrotnosc (rozmiar strony / rozmiar bloku)
mniejsza od (ilosc bajtow do odczytania / rozmiar bloku + wielkosc
read_ahead / ilosc sektorow w bloku) (hmm...)
Co ciekawe, obliczajac ilosc sektorow w bloku dzieli sie wielkosc bloku
przez 512, zamiast odczytac wielkosc sektora z tablicy hardsect_size;
zwolnienie pozostalych przydzielonych buforow dotyczy buforow
zawierajacych dane odczytane z wyprzedzeniem oraz buforow z ktorych dane
nie zostaly odczytane, bo wczesniej wystapil blad odczytu.



Algorytm block_write
(z pliku fs/block_dev.c)


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.


Zrodla informacji

Pliki z kodem zrodlowym Linuxa 2.0.0:
include/linux/blk.h

include/linux/blkdev.h
fs/block_dev.c.html


Michael K. johnson: Kernel Hackers' Guide - artykul o urzadzeniach
blokowych

Michael K. Johnson: Writing Linux Device Drivers



Artur Zawlocki




Wyszukiwarka

Podobne podstrony:
Linux714 (3)
Linux714
Linux735
Linux712 (4)
Linux736 (4)
Linux736 (3)
Linux722 (4)
Linux713 (2)

więcej podobnych podstron