Spis treści:
specyfikacja: struct buffer_head * breada(kdev_t dev, int block, int
bufsize,
unsigned int pos,
unsigned int filesize)
parametry:
dev - numer urządzenia(systemu plików)
block - numer bloku, który chcemy dostać z urządzenia
dev
bufsize - rozmiar bufora pos - pozycja bufora w pliku
filesize - długość pliku
Funkcja wczytuje dane do bufora wyznaczonego przez (dev,block) i zwraca jego wskaźnik bądź null jeśli dane są niepoprawne bądź wystąpił jakiś błąd. Poza tym wczytuje do pamięci kolejne bufory z pliku. Przyśpiesza w ten sposób odwołania do dysku, gdy bedziemy chcieli odwołać się do kolejnego bloku z pliku będzie on już w pamięci buforowej.
1. Sprawdzamy poprawność danych, gdy zachodzi jeden z następujących
warunków zwracamy null: pos>size, block<0, bh=getblk(dev,block,bufsize)==null.
2. Jeżeli bufor znaleziony przez getblk ma ustawiony na true bit bh_uptodate,
to zwracamy wskaźnik niego kończąc działanie.
3. Wczytujemy do bh aktualne dane za pomocą procedury systemowej ll_rw_block.
4. Teraz ustalamy ile bloków będziemy czytać z wyprzedzeniem. Blocks=ile
bloków od pos do końca pliku. Potem sprawdzamy, czy tyle bloków znajduje
się na dev, jeżeli jest mniej to zmniejszamy blocks, a na końcu blocks=min(blocks,NBUF),
gdzie NBUF jest stałą zadeklarowaną na 16.
5. Na zerowej pozycji w bhlist umieszczamy wskaźnik do bh. Teraz w
pętli wykonywanej blocks razy wykonujemy kolejno: - za pomocą getblk odczytujemy
wskaźnik do kolejnego bufora, jeżeli otrzymany bufor zawiera aktualne dane
(bh_uptodate) to go zwalniamy i wychodzimy z petli, w przeciwnym razie
zapamiętujemy wskaźnik do bufora na kolejnym miejscu tablicy bhlist.
6. Teraz odczytujemy bufory z bhlist (te, które nie miały aktualnych
danych) po czym kolejno je zwalniamy.
7. Wykonujemy operację wait_on_buffer(bhlist[0]), czyli na pierwszym
wczytanym buforze, jeżeli po tej operacji zawiera on aktualne dane to zwracamy
wskaźnik do niego, wpp zwalniamy go (brelse) i zwracamy null.
- projekt Linux
- tekst źródłowy breada umieszczony poniżej
/* NBUF to maksymalna ilość bloków jaką można czytać z wyprzedzeniem */
define NBUF 16
struct buffer_head * breada(kdev_t dev, int block, int bufsize,
unsigned int pos, unsigned int filesize)
{
struct buffer_head * bhlist[NBUF];
unsigned int blocks;
struct buffer_head * bh;
int index;
int i, j;
if (pos >= filesize) return NULL;
if (block < 0 || !(bh = getblk(dev,block,bufsize))) return NULL;
/* sprawdzamy poprawność danych wejściowych, wywołujemy getblk
która
zwraca wzkaźnik do bufora zawierającego szukany
blok. Gdy dane są
niepoprawne bądź getblk daje NULL to wychodzimy
zwracając NULL*/
index = BUFSIZE_INDEX(bh->b_size);
if (buffer_uptodate(bh)) return(bh);
else ll_rw_block(READ, 1, &bh);
/* jeśli bufor zawiera aktualne dane to zwracamy wskaźnik do niego
w
przeciwnym razie uaktualniamy dane w buforze, odczytujemy
je z dysku */
/* teraz najważniejsza część funkcji określamy ile buforów
ma być czytanych z
wyprzedzeniem */
/* najpierw określamy ile bloków do końca pliku */
blocks = (filesize - pos) >> (9+index);
/* sprawdzamy czy na urządzeniu dev znajduje sie blocks bloków
jeśli jest
mniej to odpowiednio uaktualniamy blocks */
if (blocks < (read_ahead[MAJOR(dev)] >> index))
blocks = read_ahead[MAJOR(dev)] >> index;
/* teraz jeszcze blocks=min(NBUF,blocks) */
if (blocks > NBUF) blocks = NBUF;
/* if (blocks)
printk("breada (new) %d blocks\n",blocks); */
/* wywołujemy getblk blocks razy, chyba że w trakcie okaże się
że bufor który
chcemy uzyskać zawiera aktualne dane, wtedy
przerywamy tę operacje */
bhlist[0] = bh;
j = 1;
for(i=1; i<blocks; i++) {
bh = getblk(dev,block+i,bufsize);
if (buffer_uptodate(bh)) {
brelse(bh);
break;
}
else bhlist[j++] = bh; }
/* Request the read for these buffers, and then release them */
/* wczytujemy dane do buforów uzyskanych w poprzednim kroku i
kolejno
je zwalniamy */
if (j>1) ll_rw_block(READA, (j-1), bhlist+1);
for(i=1; i<j; i++) brelse(bhlist[i]);
/* Wait for this buffer, and then continue on */
/* czekamy na bufor bhlist[0] czyli na pierwszy wczytany, jak
zawiera aktualne
dane to kończymy działanie zwracając do niego
wskaźnik w przeciwnym
przypadku zwalniamy go i kończymy działanie
zwracając NULL */
bh = bhlist[0];
wait_on_buffer(bh);
if (buffer_uptodate(bh)) return bh;
brelse(bh);
return NULL;
}