This shows you the differences between two versions of the page.
so2:laboratoare:lab07 [2017/04/02 19:29] octavian.purdila [Terminarea unei cereri] update lxr links for 4.9 |
so2:laboratoare:lab07 [2018/05/02 12:31] (current) theodor.stoican [Structura block_device_operations] |
||
---|---|---|---|
Line 3: | Line 3: | ||
===== Obiectivele laboratorului ===== | ===== Obiectivele laboratorului ===== | ||
- | *dobândirea de cunoștințe legate de funcționarea subsistemului de I/O pe Linux | + | * dobândirea de cunoștințe legate de funcționarea subsistemului de I/O pe Linux |
- | *acomodarea cu structurile și funcțiile de lucru cu dispozitive de tip bloc | + | * acomodarea cu structurile și funcțiile de lucru cu dispozitive de tip bloc |
- | *obținerea unor deprinderi de bază de utilizare a API-ului pentru dispozitive de tip bloc prin rezolvarea exercițiilor | + | * obținerea unor deprinderi de bază de utilizare a API-ului pentru dispozitive de tip bloc prin rezolvarea exercițiilor |
===== Cuvinte cheie ===== | ===== Cuvinte cheie ===== | ||
- | *dispozitive de tip block | + | * dispozitive de tip block |
- | *subsistemul de I/O | + | * subsistemul de I/O |
- | *înregistrare/deînregistrare | + | * înregistrare/deînregistrare |
- | *''struct gendisk'' | + | * ''struct gendisk'' |
- | *sector | + | * sector |
- | *''struct block_device_operations'' | + | * ''struct block_device_operations'' |
- | *cereri -- ''struct request'' | + | * cereri -- ''struct request'' |
- | *cozi de cereri -- ''struct request_queue'' | + | * cozi de cereri -- ''struct request_queue'' |
- | *prelucrarea unei cereri | + | * prelucrarea unei cereri |
- | *''struct bio'', ''submit_bio'' | + | * ''struct bio'', ''submit_bio'' |
===== Materiale ajutătoare ===== | ===== Materiale ajutătoare ===== | ||
- | *[[http://elf.cs.pub.ro/so2/res/laboratoare/lab07-slides.pdf | Slide-uri de suport pentru laborator]] | + | * [[http://elf.cs.pub.ro/so2/res/laboratoare/lab07-slides.pdf | Slide-uri de suport pentru laborator]] |
- | *[[http://elf.cs.pub.ro/so2/res/extra/so2_reference.pdf | SO2 Reference Card]] | + | * [[http://elf.cs.pub.ro/so2/res/extra/so2_reference.pdf | SO2 Reference Card]] |
===== Noțiuni generale ===== | ===== Noțiuni generale ===== | ||
Line 35: | Line 35: | ||
===== Device drivere de tip bloc în Linux ===== | ===== Device drivere de tip bloc în Linux ===== | ||
+ | |||
==== Înregistrarea unui dispozitiv de tip bloc ==== | ==== Înregistrarea unui dispozitiv de tip bloc ==== | ||
Line 69: | Line 70: | ||
} | } | ||
</code> | </code> | ||
+ | |||
==== Înregistrarea unui disc ==== | ==== Înregistrarea unui disc ==== | ||
Line 130: | Line 132: | ||
Structura [[http://lxr.free-electrons.com/source/include/linux/genhd.h?v=4.9#L180 | struct gendisk]] are următoarele câmpuri importante: | Structura [[http://lxr.free-electrons.com/source/include/linux/genhd.h?v=4.9#L180 | struct gendisk]] are următoarele câmpuri importante: | ||
- | *''major'', ''first_minor'', ''minors'', care descriu identificatorii folosiți de disc; un disc trebuie să aibă cel puțin un minor; dacă discul permite operația de partiționare, trebuie alocat un minor pentru fiecare partiție posibilă | + | * ''major'', ''first_minor'', ''minors'', care descriu identificatorii folosiți de disc; un disc trebuie să aibă cel puțin un minor; dacă discul permite operația de partiționare, trebuie alocat un minor pentru fiecare partiție posibilă |
- | *''disk_name'', care reprezintă numele discului, așa cum apare în ''/proc/partitions'' și în ''sysfs'' (''/sys/block'') | + | * ''disk_name'', care reprezintă numele discului, așa cum apare în ''/proc/partitions'' și în ''sysfs'' (''/sys/block'') |
- | *''fops'', care reprezintă operațiile asociate discului | + | * ''fops'', care reprezintă operațiile asociate discului |
- | *''queue'', care reprezintă coada de cereri ((Despre structura struct request_queue și operațiile pentru prelucrarea cozilor de cereri se va discuta în secțiunea [[#cozi_de_cereri | Cozi de cereri]])) | + | * ''queue'', care reprezintă coada de cereri ((Despre structura struct request_queue și operațiile pentru prelucrarea cozilor de cereri se va discuta în secțiunea [[#cozi_de_cereri | Cozi de cereri]])) |
- | *''capacity'', care reprezintă capacitatea discului în sectoare de 512 octeți; se inițializează folosind funcția [[http://lxr.free-electrons.com/source/include/linux/genhd.h?v=4.9#L451 | set_capacity]] | + | * ''capacity'', care reprezintă capacitatea discului în sectoare de 512 octeți; se inițializează folosind funcția [[http://lxr.free-electrons.com/source/include/linux/genhd.h?v=4.9#L451 | set_capacity]] |
- | *''private_data'', care reprezintă un pointer către datele private | + | * ''private_data'', care reprezintă un pointer către datele private |
Un exemplu de completare a unei structuri [[http://lxr.free-electrons.com/source/include/linux/genhd.h?v=4.9#L180 | struct gendisk]] este prezentat în continuare: | Un exemplu de completare a unei structuri [[http://lxr.free-electrons.com/source/include/linux/genhd.h?v=4.9#L180 | struct gendisk]] este prezentat în continuare: | ||
Line 251: | Line 253: | ||
} | } | ||
- | static int my_block_release(struct gendisk *gd, fmode_t mode) | + | static void my_block_release(struct gendisk *gd, fmode_t mode) |
{ | { | ||
//... | //... | ||
- | |||
- | return 0; | ||
} | } | ||
Line 349: | Line 349: | ||
Funcțiile utilizate pentru prelucrarea cererilor din coadă, descrise mai jos, sunt: | Funcțiile utilizate pentru prelucrarea cererilor din coadă, descrise mai jos, sunt: | ||
- | *[[http://lxr.free-electrons.com/source/block/blk-core.c?v=4.9#L2333| blk_peek_request]] - obține o referință la prima cerere din coadă; cererea trebuie pornită folosind [[http://lxr.free-electrons.com/source/block/blk-core.c?v=4.9#L2460 | blk_start_request]]; | + | * [[http://lxr.free-electrons.com/source/block/blk-core.c?v=4.9#L2333| blk_peek_request]] - obține o referință la prima cerere din coadă; cererea trebuie pornită folosind [[http://lxr.free-electrons.com/source/block/blk-core.c?v=4.9#L2460 | blk_start_request]]; |
- | *[[http://lxr.free-electrons.com/source/block/blk-core.c?v=4.9#L2460 | blk_start_request]] - extrage cererea din coadă și o pornește pentru procesare; în general funcția primește ca referință un pointer la o cerere întors de [[http://lxr.free-electrons.com/source/block/blk-core.c?v=4.9#L2333|blk_peek_request]]; | + | * [[http://lxr.free-electrons.com/source/block/blk-core.c?v=4.9#L2460 | blk_start_request]] - extrage cererea din coadă și o pornește pentru procesare; în general funcția primește ca referință un pointer la o cerere întors de [[http://lxr.free-electrons.com/source/block/blk-core.c?v=4.9#L2333|blk_peek_request]]; |
- | *[[http://lxr.free-electrons.com/source/block/blk-core.c?v=4.9#L2491 | blk_fetch_request]] - obține prima cerere din coadă (folosind [[http://lxr.free-electrons.com/source/block/blk-core.c?v=4.9#L2333 | blk_peek_request]]) și o pornește (folosind [[http://lxr.free-electrons.com/source/block/blk-core.c?v=4.9#L2460|blk_start_request]]); | + | * [[http://lxr.free-electrons.com/source/block/blk-core.c?v=4.9#L2491 | blk_fetch_request]] - obține prima cerere din coadă (folosind [[http://lxr.free-electrons.com/source/block/blk-core.c?v=4.9#L2333 | blk_peek_request]]) și o pornește (folosind [[http://lxr.free-electrons.com/source/block/blk-core.c?v=4.9#L2460|blk_start_request]]); |
- | *[[http://lxr.free-electrons.com/source/block/blk-core.c?v=4.9#L1334 | blk_requeue_request]] - pentru reinserarea cererii în coadă. | + | * [[http://lxr.free-electrons.com/source/block/blk-core.c?v=4.9#L1334 | blk_requeue_request]] - pentru reinserarea cererii în coadă. |
Înainte de a apela aceste funcții, trebuie obținut spinlock-ul asociat cozii. Dacă aceste funcții sunt apelate în funcția de tip [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=4.9#L224|request_fn_proc]], spinlock-ul este deja deținut. | Înainte de a apela aceste funcții, trebuie obținut spinlock-ul asociat cozii. Dacă aceste funcții sunt apelate în funcția de tip [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=4.9#L224|request_fn_proc]], spinlock-ul este deja deținut. | ||
+ | |||
==== Cereri pentru dispozitive de tip bloc ==== | ==== Cereri pentru dispozitive de tip bloc ==== | ||
Line 360: | Line 361: | ||
Câmpurile structurii [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=4.9#L88 | struct request]] includ: | Câmpurile structurii [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=4.9#L88 | struct request]] includ: | ||
- | *''cmd_flags'', o serie de flag-uri printre care și direcția (citire sau scriere); pentru a afla direcția se folosește macrodefiniția [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=4.9#L614 | rq_data_dir]], care returnează 0 pentru o cerere de citire și 1 pentru o cerere de scriere pe dispozitiv; | + | * ''cmd_flags'', o serie de flag-uri printre care și direcția (citire sau scriere); pentru a afla direcția se folosește macrodefiniția [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=4.9#L614 | rq_data_dir]], care returnează 0 pentru o cerere de citire și 1 pentru o cerere de scriere pe dispozitiv; |
- | *''%%__sector%%'', primul sector al cererii de transfer; dacă sectorul dispozitivului are altă dimensiune, trebuie facută conversia corespunzătoare; pentru accesarea acestui câmp se folosește macro-ul [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=4.9#L855 | blk_rq_pos]]; | + | * ''%%__sector%%'', primul sector al cererii de transfer; dacă sectorul dispozitivului are altă dimensiune, trebuie facută conversia corespunzătoare; pentru accesarea acestui câmp se folosește macro-ul [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=4.9#L855 | blk_rq_pos]]; |
- | *''%%__data_len%%'', numărul total de octeți de transferat; pentru accesarea acestui câmp se folosește macro-ul [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=4.9#L860 | blk_rq_bytes]]; | + | * ''%%__data_len%%'', numărul total de octeți de transferat; pentru accesarea acestui câmp se folosește macro-ul [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=4.9#L860 | blk_rq_bytes]]; |
- | *în general, se vor transfera date din [[#Structura bio | bio-ul curent]]; dimensiunea datelor se obține cu ajutorul macro-ului [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=4.9#L865 | blk_rq_cur_bytes ]]; | + | * în general, se vor transfera date din [[#Structura bio | bio-ul curent]]; dimensiunea datelor se obține cu ajutorul macro-ului [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=4.9#L865 | blk_rq_cur_bytes ]]; |
- | *''bio'', o listă dinamică de structuri [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=4.9#L25 | bio]] care reprezintă un set de bufere asociate cu cererea; acest câmp se accesează cu ajutorul macrodefiniției [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=4.9#L754 | rq_for_each_segment]] pentru cazul în care există mai multe buffere sau cu macrodefiniția [[http://lxr.free-electrons.com/source/include/linux/bio.h?v=4.9#L113|bio_data]] pentru cazul în care există un singur bufer asociat; ''bio_data'' intoarce adresa buferului asociat cererii | + | * ''bio'', o listă dinamică de structuri [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=4.9#L25 | bio]] care reprezintă un set de bufere asociate cu cererea; acest câmp se accesează cu ajutorul macrodefiniției [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=4.9#L754 | rq_for_each_segment]] pentru cazul în care există mai multe buffere sau cu macrodefiniția [[http://lxr.free-electrons.com/source/include/linux/bio.h?v=4.9#L113|bio_data]] pentru cazul în care există un singur bufer asociat; ''bio_data'' intoarce adresa buferului asociat cererii |
* despre structura bio și operațiile asociate se va discuta în secțiunea [[#structura_bio | Structura bio]] | * despre structura bio și operațiile asociate se va discuta în secțiunea [[#structura_bio | Structura bio]] | ||
Line 379: | Line 380: | ||
==== Prelucrarea cererilor ==== | ==== Prelucrarea cererilor ==== | ||
- | Partea centrală a unui driver de tip bloc este metoda de tip [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=3.13#L226 | request_fn_proc]]. În exemplele anterioare, funcția care satisfăcea acest rol era ''my_block_request''. După cum s-a precizat și în secțiunea [[#Crearea și ștergerea cozii de cereri | Crearea și ștergerea cozii de cereri]], această funcție este atașată driverului prin apelarea [[http://lxr.free-electrons.com/source/block/blk-core.c?v=3.13#L666 | blk_init_queue]]. | + | Partea centrală a unui driver de tip bloc este metoda de tip [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=4.9#L224 | request_fn_proc]]. În exemplele anterioare, funcția care satisfăcea acest rol era ''my_block_request''. După cum s-a precizat și în secțiunea [[#Crearea și ștergerea cozii de cereri | Crearea și ștergerea cozii de cereri]], această funcție este atașată driverului prin apelarea [[http://lxr.free-electrons.com/source/block/blk-core.c?v=4.9#L781 | blk_init_queue]]. |
- | Această metodă este apelată atunci când kernel-ul consideră că driverul trebuie să proceseze cereri de I/O. Metoda trebuie să pornească procesarea cererilor din coada, dar nu este obligată să le și termine, cererile putând fi terminate din alte părți ale driverului. | + | Această metodă este apelată atunci când kernel-ul consideră că driverul trebuie să proceseze cereri de I/O. Metoda trebuie să pornească procesarea cererilor din coadă, dar nu este obligată să le și termine, cererile putând fi terminate din alte părți ale driverului. |
Parametrul ''lock'', transmis la crearea unei cozi de cereri, reprezintă un spinlock pe care kernel-ul îl deține atunci când execută metoda ''request''. Din acest motiv, metoda ''request'' rulează în context atomic și trebuie să respecte regulile pentru cod atomic (nu trebuie să apeleze funcții care pot duce la sleep etc.). Acest lock asigură și faptul că nu vor fi adăugate în coada alte cereri pentru device în timp ce se execută metoda request. | Parametrul ''lock'', transmis la crearea unei cozi de cereri, reprezintă un spinlock pe care kernel-ul îl deține atunci când execută metoda ''request''. Din acest motiv, metoda ''request'' rulează în context atomic și trebuie să respecte regulile pentru cod atomic (nu trebuie să apeleze funcții care pot duce la sleep etc.). Acest lock asigură și faptul că nu vor fi adăugate în coada alte cereri pentru device în timp ce se execută metoda request. | ||
Line 387: | Line 388: | ||
Apelarea funcției de prelucrare a cozii de cereri este asincronă relativ la acțiunile oricărui proces din userspace și nu trebuie făcute presupuneri privind procesul în contextul căruia rulează. De asemenea nu trebuie presupus că buffer-ul oferit de o cerere este din kernelspace sau userspace, orice operație care accesează userspace-ul fiind eronata. | Apelarea funcției de prelucrare a cozii de cereri este asincronă relativ la acțiunile oricărui proces din userspace și nu trebuie făcute presupuneri privind procesul în contextul căruia rulează. De asemenea nu trebuie presupus că buffer-ul oferit de o cerere este din kernelspace sau userspace, orice operație care accesează userspace-ul fiind eronata. | ||
- | În continuare este prezentată una dintre cele mai simple metode de tip [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=3.13#L226 | request_fn_proc]]: | + | În continuare este prezentată una dintre cele mai simple metode de tip [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=4.9#L224 | request_fn_proc]]: |
<code c> | <code c> | ||
Line 400: | Line 401: | ||
break; | break; | ||
- | if (rq->cmd_type != REQ_TYPE_FS) { | + | if (blk_rq_is_passthrough(rq)) { |
printk (KERN_NOTICE "Skip non-fs request\n"); | printk (KERN_NOTICE "Skip non-fs request\n"); | ||
__blk_end_request_all(rq, -EIO); | __blk_end_request_all(rq, -EIO); | ||
Line 416: | Line 417: | ||
Funcția ''my_block_request'' conține un ciclu while de parcurgere a cererilor din coada de cereri transmisă ca argument. Operațiile realizate în cadrul acestui ciclu sunt: | Funcția ''my_block_request'' conține un ciclu while de parcurgere a cererilor din coada de cereri transmisă ca argument. Operațiile realizate în cadrul acestui ciclu sunt: | ||
- | * Se citește prima cerere din coadă folosind [[http://lxr.free-electrons.com/source/block/blk-core.c?v=3.13#L2288 | blk_fetch_request]]. Așa cum a fost descrisă [[#Funcții utile pentru prelucrarea cozilor de cereri|aici]], funcția ''blk_fetch_request'' obține primul element din coada de cereri și pornește cererea. | + | * Se citește prima cerere din coadă folosind [[http://lxr.free-electrons.com/source/block/blk-core.c?v=4.9#L2491 | blk_fetch_request]]. Așa cum a fost descrisă [[#Funcții utile pentru prelucrarea cozilor de cereri|aici]], funcția ''blk_fetch_request'' obține primul element din coada de cereri și pornește cererea. |
* Dacă funcția întoarce ''NULL'', s-a ajuns la sfârșitul cozii de cereri (nu mai este nici o cerere de prelucrat) și se iese din funcție. | * Dacă funcția întoarce ''NULL'', s-a ajuns la sfârșitul cozii de cereri (nu mai este nici o cerere de prelucrat) și se iese din funcție. | ||
* Un dispozitiv de tip bloc poate primi cereri care nu transferă blocuri de date (operații low-level asupra discului, instrucțiuni referitoare la moduri speciale de accesare a dispozitivului). Majoritatea driverelor nu știu cum să trateze aceste cereri și întorc eroare. | * Un dispozitiv de tip bloc poate primi cereri care nu transferă blocuri de date (operații low-level asupra discului, instrucțiuni referitoare la moduri speciale de accesare a dispozitivului). Majoritatea driverelor nu știu cum să trateze aceste cereri și întorc eroare. | ||
- | * Terminarea cu eroare se realizează prin apelul funcției [[http://lxr.free-electrons.com/source/block/blk-core.c?v=3.13#L2669 | __blk_end_request_all]] cu al doilea argument ''-EIO''. | + | * Terminarea cu eroare se realizează prin apelul funcției [[http://lxr.free-electrons.com/source/block/blk-core.c?v=4.9#L2879 | __blk_end_request_all]] cu al doilea argument ''-EIO''. |
* Se prelucrează cererea conform nevoilor dispozitivului aferent. | * Se prelucrează cererea conform nevoilor dispozitivului aferent. | ||
- | * Se încheie cererea. În cazul de față, se apelează funcția [[http://lxr.free-electrons.com/source/block/blk-core.c?v=3.13#L2669 | __blk_end_request_all]] pentru a încheiea complet cererea. Dacă toate sectoarele cererii au fost prelucrate, se folosește funcția [[http://lxr.free-electrons.com/source/block/blk-core.c?v=3.13#L2655 | __blk_end_request]]. | + | * Se încheie cererea. În cazul de față, se apelează funcția [[http://lxr.free-electrons.com/source/block/blk-core.c?v=4.9#L2879 | __blk_end_request_all]] pentru a încheiea complet cererea. Dacă toate sectoarele cererii au fost prelucrate, se folosește funcția [[http://lxr.free-electrons.com/source/block/blk-core.c?v=4.9#L2860 | __blk_end_request]]. |
==== Structura bio ==== | ==== Structura bio ==== | ||
- | Fiecare structură [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=3.13#L97 | struct request]] reprezintă o cerere block I/O, dar poate proveni din combinarea mai multor cereri independente de la un nivel mai înalt. Sectoarele ce trebuie transferate pentru o cerere pot fi dispersate în memoria principală, dar întotdeauna corespund unui set de sectoare consecutive de pe dispozitiv. Cererea este reprezentată ca o mulțime de segmente, fiecare corespunzând unui buffer din memorie. Kernel-ul poate combina cereri care se referă la sectoare adiacente, dar nu va combina cereri de scriere cu cereri de citire într-o singură structură [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=3.13#L97 | struct request]]. | + | Fiecare structură [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=4.9#L88 | struct request]] reprezintă o cerere block I/O, dar poate proveni din combinarea mai multor cereri independente de la un nivel mai înalt. Sectoarele ce trebuie transferate pentru o cerere pot fi dispersate în memoria principală, dar întotdeauna corespund unui set de sectoare consecutive de pe dispozitiv. Cererea este reprezentată ca o mulțime de segmente, fiecare corespunzând unui buffer din memorie. Kernel-ul poate combina cereri care se referă la sectoare adiacente, dar nu va combina cereri de scriere cu cereri de citire într-o singură structură [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=4.9#L88 | struct request]]. |
- | O structură [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=3.13#L97 | struct request]] este implementată ca o listă înlănțuită de structuri [[http://lxr.free-electrons.com/source/include/linux/blk_types.h#L46 | bio]] împreună cu informații care permit driver-ului să-și rețină poziția curentă în timp ce procesează cererea. | + | O structură [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=4.9#L88 | struct request]] este implementată ca o listă înlănțuită de structuri [[http://lxr.free-electrons.com/source/include/linux/blk_types.h#L46 | bio]] împreună cu informații care permit driver-ului să-și rețină poziția curentă în timp ce procesează cererea. |
- | Structura [[http://lxr.free-electrons.com/source/include/linux/blk_types.h#L46 | bio]] este o descriere low-level a unei porțiuni dintr-o cerere block I/O. | + | Structura [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=4.9#L25 | bio]] este o descriere low-level a unei porțiuni dintr-o cerere block I/O. |
<code c> | <code c> | ||
struct bio { | struct bio { | ||
- | sector_t bi_sector; /* device address in 512 byte | + | //... |
- | sectors */ | + | struct gendisk *bi_disk; |
- | struct block_device *bi_bdev; | + | unsigned int bi_opf; /* bottom bits req flags, top bits REQ_OP. Use accessors. */ |
- | unsigned long bi_rw; /* bottom bits READ/WRITE, | + | |
- | * top bits priority | + | |
- | */ | + | |
//... | //... | ||
- | unsigned int bi_size; /* residual I/O count */ | ||
- | |||
- | //... | ||
struct bio_vec *bi_io_vec; /* the actual vec list */ | struct bio_vec *bi_io_vec; /* the actual vec list */ | ||
- | bio_end_io_t *bi_end_io; | + | //... |
- | atomic_t bi_cnt; /* pin count */ | + | struct bvec_iter bi_iter; |
+ | /... | ||
void *bi_private; | void *bi_private; | ||
//... | //... | ||
}; | }; | ||
</code> | </code> | ||
- | La rândul ei, structura [[http://lxr.free-electrons.com/source/include/linux/blk_types.h#L46 | bio]] conține un vector ''bi_io_vec'' de tipul [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=3.13#L25 | struct bio_vec]]. Acesta este format din paginile individuale din memoria fizică ce trebuie transferate. Pentru a parcurge o structura ''bio'', trebuie parcurs acest vector de structuri [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=3.13#L25 | struct bio_vec]] și transferate datele din fiecare pagină fizică. | + | |
+ | La rândul ei, structura [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=4.9#L25 | bio]] conține un vector ''bi_io_vec'' de tipul [[http://lxr.free-electrons.com/source/include/linux/bvec.h?v=4.9#L29 | struct bio_vec]]. Acesta este format din paginile individuale din memoria fizică ce trebuie transferate, offsetul în cadrul paginii și dimensiunea buferului. Pentru a parcurge o structura ''bio'', trebuie parcurs acest vector de structuri [[http://lxr.free-electrons.com/source/include/linux/bvec.h?v=4.9#L29 | struct bio_vec]] și transferate datele din fiecare pagină fizică. Pentru a simplifica parcurgerea vectorului se folosește [[http://lxr.free-electrons.com/source/include/linux/bvec.h?v=4.9#L35|struct bvec_iter]]. Această structură menține informații despre câte bufere și sectoare au fost consumate în timpul parcurgerii. Tipul cererii este encodat în câmpul ''bi_opf'', pentru determinarea acestuia folosiți funcția [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=4.9#L2507|bio_data_dir]]. | ||
==== Crearea unei structuri bio ==== | ==== Crearea unei structuri bio ==== | ||
- | Pentru crearea unei structuri [[http://lxr.free-electrons.com/source/include/linux/blk_types.h#L46 | bio]] se pot folosi două funcții: | + | Pentru crearea unei structuri [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=4.9#L25 | bio]] se pot folosi două funcții: |
- | *[[http://lxr.free-electrons.com/source/include/linux/bio.h?v=3.13#L235 | bio_alloc]] - alocă spațiu pentru o nouă structură; structura trebuie inițializată; | + | * [[http://lxr.free-electrons.com/source/include/linux/bio.h?v=4.9#L391 | bio_alloc]] - alocă spațiu pentru o nouă structură; structura trebuie inițializată; |
- | *[[http://lxr.free-electrons.com/source/include/linux/bio.h?v=3.13#L240 | bio_clone]] - realizează o copie a unei structuri bio existente; structura nou obținută este inițializată cu valorile câmpurilor structurii clonate. | + | * [[http://lxr.free-electrons.com/source/include/linux/bio.h?v=4.9#L396 | bio_clone]] - realizează o copie a unei structuri bio existente; structura nou obținută este inițializată cu valorile câmpurilor structurii clonate; buferele sunt partajate cu structura bio care a fost clonată astfel încât accesul la bufere trebuie făcut cu atenție pentru a evita accesul la aceași zonă de memorie din cele două clone |
- | Ambele funcții întorc o nouă structură [[http://lxr.free-electrons.com/source/include/linux/blk_types.h#L46 | bio]]. | + | Ambele funcții întorc o nouă structură [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=4.9#L25 | bio]]. |
==== Transmiterea unei structuri bio ==== | ==== Transmiterea unei structuri bio ==== | ||
- | De obicei o structură [[http://lxr.free-electrons.com/source/include/linux/blk_types.h#L46 | bio]] este creată de nivelurile superioare ale kernel-ului (de obicei sistemul de fișiere). O structură astfel creată este apoi transmisă subsistemului de I/O care adună mai multe structuri [[http://lxr.free-electrons.com/source/include/linux/blk_types.h#L46 | bio]] într-o cerere. | + | De obicei o structură [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=4.9#L25 | bio]] este creată de nivelurile superioare ale kernel-ului (de obicei sistemul de fișiere). O structură astfel creată este apoi transmisă subsistemului de I/O care adună mai multe structuri [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=4.9#L25 | bio]] într-o cerere. |
- | Pentru transmiterea unei structuri [[http://lxr.free-electrons.com/source/include/linux/blk_types.h#L46 | bio]] către driverul dispozitivului I/O asociat se folosește funcția [[http://lxr.free-electrons.com/source/block/blk-core.c?v=3.13#L1849 | submit_bio]]. Funcția primește ca argument o structură [[http://lxr.free-electrons.com/source/include/linux/blk_types.h#L46 | bio]] inițializată care va fi adăugată unei cereri din coada de cereri a unui dispozitiv I/O. Din acea coadă de cereri va putea fi prelucrată de driverul dispozitivului I/O cu o funcție specializată. Primul argument al funcției ''submit_bio'' este un flag ce specifică dacă este vorba de o operație de scriere (''1'') sau de citire (''0'') (acest flag se va combina cu valoarea curentă a ''bio->bi_rw''). | + | Pentru transmiterea unei structuri [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=4.9#L25 | bio]] către driverul dispozitivului I/O asociat se folosește funcția [[http://lxr.free-electrons.com/source/block/blk-core.c?v=4.9#L2058 | submit_bio]]. Funcția primește ca argument o structură [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=4.9#L25 | bio]] inițializată care va fi adăugată unei cereri din coada de cereri a unui dispozitiv I/O. Din acea coadă de cereri va putea fi prelucrată de driverul dispozitivului I/O cu o funcție specializată. |
==== Așteptarea încheierii unei structuri bio ==== | ==== Așteptarea încheierii unei structuri bio ==== | ||
- | Transmiterea unei structuri [[http://lxr.free-electrons.com/source/include/linux/blk_types.h#L46 | bio]] unui driver are ca efect adăugarea acesteia într-o cerere din coada de cereri de unde va fi ulterior prelucrată. Astfel, în momentul în care funcția [[http://lxr.free-electrons.com/source/block/blk-core.c?v=3.13#L1849 | submit_bio]] se întoarce, nu se garantează încheierea prelucrării structurii. | + | Transmiterea unei structuri [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=4.9#L25 | bio]] unui driver are ca efect adăugarea acesteia într-o cerere din coada de cereri de unde va fi ulterior prelucrată. Astfel, în momentul în care funcția [[http://lxr.free-electrons.com/source/block/blk-core.c?v=4.9#L2058 | submit_bio]] se întoarce, nu se garantează încheierea prelucrării structurii. Dacă se dorește așteptarea prelucrării cererii se va folosi funcția [[http://lxr.free-electrons.com/source/block/bio.c?v=4.9#L863|submit_bio_wait]]. |
- | Dacă se dorește să se aștepte încheierea prelucrării unei structuri [[http://lxr.free-electrons.com/source/include/linux/blk_types.h#L46 | bio]], va trebui folosit câmpul [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=3.13#L62 | bi_end_io]] al structurii. În acest câmp se precizează funcția care va fi apelată la încheierea prelucrării structurii bio. De obicei, funcția se folosește împreună cu o structură [[http://lxr.free-electrons.com/source/include/linux/completion.h?v=3.13#L25 | completion]]. Structura [[http://lxr.free-electrons.com/source/include/linux/completion.h?v=3.13#L25 | completion]] încapsulează o [[http://lxr.free-electrons.com/source/include/linux/wait.h#L39 | coadă de așteptare]] și o condiție de așteptare. | + | Pentru a fi notificați atunci când se încheie prelucrarea unei structuri [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=4.9#L25 | bio]] (atunci când nu folosim ''submit_bio_wait''), va trebui folosit câmpul [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=4.9#L52 | bi_end_io]] al structurii. În acest câmp se precizează funcția care va fi apelată la încheierea prelucrării structurii bio. Pentru a pasa informații către funcție se poate folosi câmpul [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=3.13#L64 | bi_private]] al structurii. |
- | Un exemplu uzual este prezent în [[http://lxr.free-electrons.com/source/drivers/md/md.c?v=3.13 | drivers/md/md.c]]. Partea relevantă este prezentată în extrasul de cod de mai jos: | ||
- | |||
- | <code c> | ||
- | static void bi_complete(struct bio *bio, int error) | ||
- | { | ||
- | complete((struct completion*)bio->bi_private); | ||
- | } | ||
- | |||
- | /* functie de prelucrare a bio */ | ||
- | int sync_page_io(struct block_device *bdev, sector_t sector, int size, | ||
- | struct page *page, int rw) | ||
- | { | ||
- | struct bio *bio = bio_alloc(GFP_NOIO, 1); | ||
- | struct completion event; | ||
- | //... | ||
- | init_completion(&event); | ||
- | bio->bi_private = &event; | ||
- | bio->bi_end_io = bi_complete; | ||
- | submit_bio(rw, bio); | ||
- | wait_for_completion(&event); | ||
- | //... | ||
- | } | ||
- | </code> | ||
- | |||
- | După cum se poate observa, câmpul [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=3.13#L64 | bi_private]] al structurii este folosit pentru a reține pointer-ul la structura [[http://lxr.free-electrons.com/source/include/linux/completion.h?v=3.13#L25 | completion]]. Acest pointer va putea fi folosit în funcția apelată la încheierea bio-ului la apelul [[http://lxr.free-electrons.com/source/kernel/sched/completion.c?v=3.13#L29 | complete]]. | ||
==== Inițializarea unei structuri bio ==== | ==== Inițializarea unei structuri bio ==== | ||
- | După ce o structură [[http://lxr.free-electrons.com/source/include/linux/blk_types.h#L46 | bio]] a fost alocată și înainte de a fi transmisă, trebuie inițializată. | + | După ce o structură [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=4.9#L25 | bio]] a fost alocată și înainte de a fi transmisă, trebuie inițializată. |
- | + | ||
- | Inițializarea structurii presupune completarea câmpurilor importante. După cum s-a precizat anterior, câmpul [[http://lxr.free-electrons.com/source/include/linux/blk_types.h#L71 | bi_end_io]] este folosit pentru a preciza funcția apelată la încheierea prelucrării structurii. Câmpul [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=3.13#L64 | bi_private]] este folosit pentru a stoca date utile ce pot fi accesate în funcția [[http://lxr.free-electrons.com/source/include/linux/blk_types.h#L71 | bi_end_io]]. | + | |
- | Câmpul [[http://lxr.free-electrons.com/source/include/linux/blk_types.h#L51 | bi_rw]] specifică dacă este vorba de o operație de scriere (''1'') sau de citire (''0''). | + | Inițializarea structurii presupune completarea câmpurilor importante. După cum s-a precizat anterior, câmpul [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=4.9#L52 | bi_end_io]] este folosit pentru a preciza funcția apelată la încheierea prelucrării structurii. Câmpul [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=4.9#L54 | bi_private]] este folosit pentru a stoca date utile ce pot fi accesate în funcția [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=4.9#L52 | bi_end_io]]. |
- | Tot din exemplul din [[http://lxr.free-electrons.com/source/drivers/md/md.c?v=3.13#L779 | drivers/md/md.c]] se poate observa inițializarea a celorlalte câmpuri utile: | + | Câmpul [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=4.9#L29 | bi_opf]] specifică tipul operației. Folosiți [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=4.9#L95|bio_set_op_attrs]] pentru a inițializa tipul operației. |
<code c> | <code c> | ||
- | int sync_page_io(struct block_device *bdev, sector_t sector, int size, | ||
- | struct page *page, int rw) | ||
- | { | ||
struct bio *bio = bio_alloc(GFP_NOIO, 1); | struct bio *bio = bio_alloc(GFP_NOIO, 1); | ||
//... | //... | ||
- | bio->bi_bdev = bdev; | + | bio->bi_disk = bdev->bd_disk; |
- | bio->bi_sector = sector; | + | bio->bi_iter.bi_sector = sector; |
- | bio_add_page(bio, page, size, 0); | + | bio_set_op_attrs(bio, REQ_OP_READ, 0); |
+ | bio_add_page(bio, page, size, offset); | ||
//... | //... | ||
</code> | </code> | ||
- | În extrasul de mai sus se specifică dispozitivul de tip bloc către care va fi trimis bio-ul, sectorul de început și conținutul. Conținutul unui bio este dat de o [[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=3.13#L44 | pagină]]. | + | În extrasul de mai sus se specifică dispozitivul de tip bloc către care va fi trimis bio-ul, sectorul de început, operația (''REQ_OP_READ'' or ''REQ_OP_WRITE'') și conținutul. Conținutul unui bio este un bufer descris prin: o [[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=4.9#L32 | pagină fizică]], offset-ul în pagină și dimensiunea buferului. O pagină poate fi alocată folosind apelul [[http://lxr.free-electrons.com/source/include/linux/gfp.h?v=4.9#L484 | alloc_page]]. |
- | **Atenție** : Câmpul ''size'' al apelului [[http://lxr.free-electrons.com/source/fs/bio.c?v=3.13#L750 | bio_add_page]] trebuie să fie multiplu de dimensiunea sectorului dispozitivului. | + | <note important> |
- | + | Câmpul ''size'' al apelului [[http://lxr.free-electrons.com/source/block/bio.c?v=4.9#L799 | bio_add_page]] trebuie să fie multiplu de dimensiunea sectorului dispozitivului. | |
- | O pagină poate fi alocată folosind apelul [[http://lxr.free-electrons.com/source/include/linux/gfp.h?v=3.13#L345 | alloc_page]]. | + | </note> |
==== Folosirea conținutului unei structuri bio ==== | ==== Folosirea conținutului unei structuri bio ==== | ||
- | Pentru folosirea conținutului unei structuri [[http://lxr.free-electrons.com/source/include/linux/blk_types.h#L46 | bio]], paginile de suport ale structurii trebuie mapate în spațiul de adresă nucleu de unde vor putea fi accesate. Pentru mapare/demapare se folosesc macrourile [[http://lxr.free-electrons.com/source/include/linux/bio.h?v=3.13#L100 | __bio_kmap_atomic]] și [[http://lxr.free-electrons.com/source/include/linux/bio.h?v=3.13#L104 | __bio_kunmap_atomic]] ((Mai multe informații despre maparea atomică a memoriei găsiți în [[http://lwn.net/images/pdf/LDD3/ch15.pdf | Linux Device Drivers 3rd Edition, Chapter 15. Memory Mapping and DMA - The Memory Map and Struct Page]])). | + | Pentru folosirea conținutului unei structuri [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=4.9#L25 | bio]], paginile de suport ale structurii trebuie mapate în spațiul de adresă nucleu de unde vor putea fi accesate. Pentru mapare/demapare se folosesc macrourile [[http://lxr.free-electrons.com/source/arch/x86/mm/highmem_32.c?v=4.9#L55 | kmap_atomic]] și [[http://lxr.free-electrons.com/source/include/linux/highmem.h?v=4.9#L124 | kunmap_atomic]] ((Mai multe informații despre maparea atomică a memoriei găsiți în [[http://lwn.net/images/pdf/LDD3/ch15.pdf | Linux Device Drivers 3rd Edition, Chapter 15. Memory Mapping and DMA - The Memory Map and Struct Page]])). |
Un exemplu tipic de folosire este: | Un exemplu tipic de folosire este: | ||
Line 537: | Line 504: | ||
static int my_xfer_bio(struct my_block_dev *dev, struct bio *bio) | static int my_xfer_bio(struct my_block_dev *dev, struct bio *bio) | ||
{ | { | ||
- | int i; | + | struct bio_vec bvec; |
- | struct bio_vec *bvec; | + | struct bvec_iter i; |
- | size_t start = bio->bi_sector * KERNEL_SECTOR_SIZE; | + | int dir = bio_data_dir(bio); |
- | /* Do each segment independently. */ | + | /* Do each segment independently. */ |
- | bio_for_each_segment(bvec, bio, i) { | + | bio_for_each_segment(bvec, bio, i) { |
- | char *buffer = __bio_kmap_atomic(bio, i); | + | sector_t sector = i.bi_sector; |
+ | char *buffer = kmap_atomic(bvec.bv_page); | ||
+ | unsigned long offset = bvec.bv_offset; | ||
+ | size_t len = bvec.bv_len; | ||
+ | |||
+ | /* process mapped buffer */ | ||
+ | my_block_transfer(dev, sector, len, buffer + offset, dir); | ||
- | /* process mapped buffer */ | + | kunmap_atomic(buffer); |
- | my_block_transfer(dev, start, bio_cur_bytes(bio), buffer, bio_data_dir(bio) == WRITE); | + | } |
- | + | ||
- | start += bio_cur_bytes(bio); | + | |
- | __bio_kunmap_atomic(buffer); | + | |
- | } | + | |
return 0; | return 0; | ||
} | } | ||
</code> | </code> | ||
+ | |||
+ | După cum se observă din exemplul de mai sus, parcurgerea unui ''bio'' presupune iterarea prin toate segmentele acestuia. Un segment ([[http://lxr.free-electrons.com/source/include/linux/bvec.h?v=4.9#L29|bio_vec]]) este definit de pagina adresei fizice, offset-ul în pagină și dimensiunea acestuia. | ||
+ | |||
+ | Pentru a simplifica procesarea unui bio se folosește macrodefiniția [[http://lxr.free-electrons.com/source/include/linux/bio.h?v=4.9#L184|bio_for_each_segment]]. Aceasta va itera prin toate segmentele și de asemenea va actualiza informații globale, stocate într-un iterator ([[http://lxr.free-electrons.com/source/include/linux/bvec.h?v=4.9#L35|bvec_iter]]), cum ar fi sectorul curent precum și alte informații interne (indexul în vectorul de segmente, numărul de octeți rămași de procesat, etc.). | ||
Se pot stoca informații în buffer-ul mapat sau se pot extrage informații. | Se pot stoca informații în buffer-ul mapat sau se pot extrage informații. | ||
- | Următoarele câmpuri ale structurii ''bio'' sunt accesate fie direct, fie cu ajutorul unor macrodefiniții: | + | În cazul în care se folosesc cozile de cereri și se dorește prelucrarea cererilor la nivel de structură ''bio'', se va folosi macrodefiniția [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=4.9#L754 | rq_for_each_segment]] în locul [[http://lxr.free-electrons.com/source/include/linux/bio.h?v=4.9#L184 | bio_for_each_segment]]. Această macrodefiniție parcurge fiecare segment din fiecare structură ''bio'' a unei cereri ''struct request'' și actualizează o structură [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=4.9#L742 | struct req_iterator]]. Structura [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=4.9#L742 | struct req_iterator]] conține structura curentă ''bio'' și iteratorul ce parcurge segmentele acestuia. Un exemplu tipic de folosire este: |
- | *''bi_sector'', primul sector de transferat, exprimat în sectoare de 512 octeți | + | |
- | *[[http://lxr.free-electrons.com/source/include/linux/bio.h?v=3.13#L69 | bio_sectors]], pentru obținerea numărului total de sectoare de transferat din cererea ''bio'' curentă | + | |
- | *[[http://lxr.free-electrons.com/source/include/linux/bio.h?v=3.13#L72 | bio_cur_bytes]], pentru obținerea numărului de octeți de transferat din pagina curentă | + | |
- | *[[http://lxr.free-electrons.com/source/include/linux/fs.h?v=3.13#L2237 | bio_data_dir]], pentru a determina dacă este o cerere de citire (''0'') sau de scriere (''1'') | + | |
- | *[[http://lxr.free-electrons.com/source/include/linux/bio.h?v=3.13#L138 | bio_for_each_segment]], pentru a parcurge vectorul de structuri [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=3.13#L25 | struct bio_vec]] ce conține paginile de memorie fizică dintr-o structură ''bio''. | + | |
- | În cazul în care se folosesc cozile de cereri și se dorește prelucrarea cererilor la nivel de structură ''bio'', se va folosi macrodefiniția [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=3.13#L749 | rq_for_each_segment]] în locul [[http://lxr.free-electrons.com/source/include/linux/bio.h?v=3.13#L138 | bio_for_each_segment]]. Această macrodefiniție parcurge fiecare segment din fiecare structură ''bio'' a unei cereri ''struct request'' și actualizează o structură [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=3.13#L737 | struct req_iterator]]. Structura [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=3.13#L737 | struct req_iterator]] conține structura curentă ''bio'' și indicele segmentului curent. | + | <code c> |
- | ==== Eliberarea unei structuri bio ==== | + | struct bio_vec bvec; |
+ | struct req_iterator iter; | ||
+ | |||
+ | rq_for_each_segment(bvec, req, iter) { | ||
+ | sector_t sector = iter.iter.bi_sector; | ||
+ | char *buffer = kmap_atomic(bvec.bv_page); | ||
+ | unsigned long offset = bvec.bv_offset; | ||
+ | size_t len = bvec.bv_len; | ||
+ | int dir = bio_data_dir(iter.bio); | ||
+ | |||
+ | my_block_transfer(dev, sector, len, buffer + offset, dir); | ||
+ | |||
+ | kunmap_atomic(buffer); | ||
+ | } | ||
+ | </code> | ||
- | După ce un subsistem al nucleului folosește o structură [[http://lxr.free-electrons.com/source/include/linux/blk_types.h#L46 | bio]] va trebui să elibereze referința către aceasta. Acest lucru se realizează cu ajutorul funcției [[http://lxr.free-electrons.com/source/fs/bio.c?v=3.13#L496 | bio_put]]. Funcția [[http://lxr.free-electrons.com/source/fs/bio.c?v=3.13#L496 | bio_put]] este apelată și în exemplul anterior din [[http://lxr.free-electrons.com/source/drivers/md/md.c?v=3.13#L779 | drivers/md/md.c]]. | ||
+ | ==== Eliberarea unei structuri bio ==== | ||
+ | |||
+ | După ce un subsistem al nucleului folosește o structură [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=4.9#L26 | bio]] va trebui să elibereze referința către aceasta. Acest lucru se realizează cu ajutorul funcției [[http://lxr.free-electrons.com/source/block/bio.c?v=4.9#L529 | bio_put]]. | ||
==== Configurarea unei cozi de cerere la nivel de bio ==== | ==== Configurarea unei cozi de cerere la nivel de bio ==== | ||
- | Cu ajutorul funcției [[http://lxr.free-electrons.com/source/block/blk-core.c?v=3.13#L666 | blk_init_queue]] se putea specifica o funcție care să fie folosită pentru prelucrarea cererilor transmise driverului. Funcția primea ca argument coada de cereri și realiza prelucrări la nivel de structuri [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=3.13#L97|request]]. | + | Cu ajutorul funcției [[http://lxr.free-electrons.com/source/block/blk-core.c?v=4.9#L781 | blk_init_queue]] se putea specifica o funcție care să fie folosită pentru prelucrarea cererilor transmise driverului. Funcția primea ca argument coada de cereri și realiza prelucrări la nivel de structuri [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=4.9#L88|request]]. |
- | Dacă, din motive de flexibilitate, se dorește specificarea unei funcții care să realizeze prelucrări la nivel de [[http://lxr.free-electrons.com/source/include/linux/blk_types.h#L46 | bio]], trebuie folosită funcția [[http://lxr.free-electrons.com/source/block/blk-settings.c?v=3.13#L175 | blk_queue_make_request]] în conjuncție cu funcția [[http://lxr.free-electrons.com/source/block/blk-core.c?v=3.13#L546|blk_alloc_queue]]. Mai jos este prezentat un exemplu tipic de inițializare a unei funcții de prelucrare la nivel de [[http://lxr.free-electrons.com/source/include/linux/blk_types.h#L46 | bio]]: | + | Dacă, din motive de flexibilitate, se dorește specificarea unei funcții care să realizeze prelucrări la nivel de [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=4.9#L25 | bio]], trebuie folosită funcția [[http://lxr.free-electrons.com/source/block/blk-settings.c?v=4.9#L136 | blk_queue_make_request]] în conjuncție cu funcția [[http://lxr.free-electrons.com/source/block/blk-core.c?v=4.9#L645| blk_alloc_queue]]. Mai jos este prezentat un exemplu tipic de inițializare a unei funcții de prelucrare la nivel de [[http://lxr.free-electrons.com/source/include/linux/blk_types.h?v=4.9#L25 | bio]]: |
<code c> | <code c> | ||
Line 592: | Line 577: | ||
</code> | </code> | ||
- | Funcția ''my_make_request'' este de tipul [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=3.13#L227 | make_request_fn]]. Un exemplu de folosire a unei astfel de funcții se găsește în [[http://lxr.free-electrons.com/source/drivers/md/raid1.c#L1047 | drivers/md/raid1.c]]. | + | Funcția ''my_make_request'' este de tipul [[http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=4.9#L225 | make_request_fn]]. Un exemplu de folosire a unei astfel de funcții se găsește în [[http://lxr.free-electrons.com/source/drivers/md/md.c?v=4.9#L4987 | drivers/md/md.c]]. |
- | În cazul în care se folosește această metodă, nu se mai folosesc cozile de cereri, fiecare cerere fiind reprezentă de o structură ''bio''. Astfel, transferul de date se reduce la parcurgerea fiecărei structuri ''bio'' după cum a fost prezentat [[#Folosirea_con.C8.9Binutului_unei_structurii_bio|mai sus]] și semnalarea terminării prelucrării acesteia cu ajutorul funcției [[http://lxr.free-electrons.com/source/include/linux/blk_types.h#L71 | bio_endio]]. | + | În cazul în care se folosește această metodă, nu se mai folosesc cozile de cereri, fiecare cerere fiind reprezentă de o structură ''bio''. Astfel, transferul de date se reduce la parcurgerea fiecărei structuri ''bio'' după cum a fost prezentat [[#Folosirea_con.C8.9Binutului_unei_structurii_bio|mai sus]] și semnalarea terminării prelucrării acesteia cu ajutorul funcției [[http://lxr.free-electrons.com/source/block/bio.c?v=4.9#L1734 | bio_endio]]. |
===== Resurse utile ===== | ===== Resurse utile ===== |