Wydajniejsza obsługa blokowych operacji I/O

Spis treści


Wstęp

Urządzenia blokowe to np. dyski, cd-rom, pamieć flash. Obsługa urządzeń blokowych jest trudniejsza niż znakowych – dane nie muszą być czytane sekwencyjnie.


Struktura buffer_head

Sektor jest to jednostka fizyczna na dysku. Blok – jednostka abstrakcyjna, reprezentująca sektor

Kiedy blok jest w pamięci jest przechowywany w buforze. Każdy bufor jest powiązany z dokładnie jednym blokiem i z deskryptorem – buffer head, typu struct buffer_head. Buffer_head przechowuje informacje, które jądro potrzebuje do manipulowania buforami i jest zdefiniowany w <linux/buffer_head.h>.

Buffer_head istnieje po to by opisać mapowanie pomiędzy blokami na dysku a buforami w pamięci. W jądrach wcześniejszych niż 2.6 buffer head był dużo ważniejszą strukturą. Służył nie tylko do mappowania, ale także jako kontener dla wszystkich blokowych operacji I/O. Powodowało to dwa problemy:


Struktura bio

Zdefiniowana w <linux/bio.h>.


 struct bio {
         sector_t                bi_sector;
         struct bio              *bi_next;       /* request queue link */
         struct block_device     *bi_bdev;
         unsigned long           bi_flags;       /* status, command, etc */
         unsigned long           bi_rw;          /* bottom bits READ/WRITE,
                                                  * top bits priority
                                                  */
 
         unsigned short          bi_vcnt;        /* how many bio_vec's */
         unsigned short          bi_idx;         /* current index into bvl_vec */
 
         /* Number of segments in this BIO after
          * physical address coalescing is performed.
          */
         unsigned short          bi_phys_segments;
 
         /* Number of segments after physical and DMA remapping
          * hardware coalescing is performed.
          */
         unsigned short          bi_hw_segments;
 
         unsigned int            bi_size;        /* residual I/O count */
         unsigned int            bi_max_vecs;    /* max bvl_vecs we can hold */

         struct bio_vec          *bi_io_vec;     /* the actual vec list */
 
         bio_end_io_t            *bi_end_io;
         atomic_t                bi_cnt;         /* pin count */
 
         void                    *bi_private;
 
         bio_destructor_t        *bi_destructor; /* destructor */
 };

Ta struktura przedstawia aktywne blokowe operacje I/O jako listę segmentów. Segment jest to kawałek bufora spójny w pamięci. Dzięki temu bufor nie musi być spójny w pamięci.

Struktura bio reprezentuje przede wszystkim aktywne operacje blokowe.

Najważniejszymi polami w strukturze są:


Bio_vec

Bi_io_vec wskazuje na tablicę struktur bio_vec. Każdy bio_vec jest traktowany jako wektor <page, offset, len>, który opisuje konkretny segment: fizyczna strona, na której on leży, położenie bloku względem początku strony, długość bloku. Cała tablica tych wektorów opisuje bufor.

Strukturę bio można łatwo rozdzielać na dyski (raid) (bi_idx ustawiany odpowiednio na każdym dysku)


kernel 2.4 vs kernel 2.6

bio – jedna lub więcej stron w pamięci

buffer_head – pojedynczy bufor, który opisuje pojedynczy blok na dysku.

Zalety zmiany buffer_head na bio:

Buffor head jest ciągle obecna, ale pełni jedynie funkcję mappowania bloków z dysku na strony. Przechowuje informacje o buforach. Struktury bio i buffor_head są trzymane oddzielnie co pozwala zachować każdą z nich tak małą jak to tylko możliwe.

Źródła

Źródła:


powrót do strony głównej