Problem z odczytywaniem danych z urządzeń blokowych (dyski, cd-rom, pamieć flash) polega na tym, że dane nie są odczytywane sekwensyjnie tak jak z urządzeń znakowych. Możliwe jest odczytywanie i zapisywanie w dowolne miejsce urządzenia.
Buffer_head bezpośrednio mapuje blok na dysku z buforem w pamięci. Jest w jądrach wcześniejszych niż 2.6 podstawową jednostką przechowującą dane potrzebne do manipulowania operacjami I/O.
Wadą tego rozwiązania jest fakt, że duże operacje I/O muszą być rozbijane przez jądro i część informacji jest powtarzana w każdym buforze co jest nieefektywne i uciążliwe. Dlatego powstała struktura bio dużo elastyczniejsza niż buffer_head.
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 */ };
Struktura bio nie jest skomplikowana. Główne jej elementy to:
Struktura bio_vect ma bardzo prostą definicję:
struct bio_vec { struct page *bv_page; unsigned int bv_len; unsigned int bv_offset; };
Struktura bio śledzi bufor z danymi za pomocą wskaźnika struct page co pociąga za sobą:
Na pierwszy rzut oka struktura bio wydaje się trudniejsza do obsługi niż stary buffer_head, który od razu zapewniał adres do pojedyńczego kawałka danych. Praca z bio nie jest jednak skomplikowana.
Początkowy sektor dla całego bio znajduje się w polu bi_sector. Całkowity rozmiar operacji w polu bi_size (w bajtach). Można zdobyć rozmiar operacji w sektorach za pomocą:
bio_sectors(struct bio *bio);
Makro:
int bio_data_dir(struct bio *bio);zwraca READ lub WRITE w zależności od typu operacji.
Jeśli chcemy coś zrobić z całą tablicą bio_vec przyda mam się makro:
bio_for_each_segment(bvec, bio, segno) { /* Do something with this segment */ }W pętli segno przechowuje aktualną pozycję w tablicy a bvec jest wskażnikim na aktualną strukturę bio_vec.
Przy kończeniu operacji I/O wykorzystuje się funkcję:
void bio_endio(struct bio *bio, unsigned int nbytes, int error);