powrót do spisu treści tematu

                                Funkcja breada()

Spis treści:


Opis działania funkcji systemowej breada:

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.



Algorytm działania:

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.



Bibliografia:

- projekt Linux
- tekst źródłowy breada umieszczony poniżej



Skomentowany tekst zródłowy funkcji breada():

/* 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
    niepoprawne bądź getblk daje NULL to wychodzimy zwracając NULL*/

             index = BUFSIZE_INDEX(bh-&gtb_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&ltblocks; 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&gt1) ll_rw_block(READA, (j-1), bhlist+1);
             for(i=1; i&ltj; 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;
}



autor: Grzegorz Chojnacki