Differences

This shows you the differences between two versions of the page.

Link to this comparison view

so2:laboratoare:lab07:exercitii [2018/04/09 17:29]
ionel.ghita
so2:laboratoare:lab07:exercitii [2018/04/12 11:40] (current)
elena.sandulescu [6. [2p] Prelucrarea cererilor din coada la nivel de bio]
Line 103: Line 103:
  
 ===== [10.5p] Exerciții ===== ===== [10.5p] Exerciții =====
 +
 +<note important>​
 +Înainte de începerea rezolvării laboratorului,​ rulați comanda ''​%%git pull --rebase%%''​ in directorul ''​~/​so2/​linux'',​ pentru a obține ultima versiune a scheletului de laborator.
 +</​note>​
  
 ==== 1. [1p] Dispozitiv de tip bloc ==== ==== 1. [1p] Dispozitiv de tip bloc ====
  
-Creați un modul de kernel care să permită înregistrarea,​ respectiv deînregistrarea unui dispozitiv de tip bloc. Porniți de la fișierele din directorul ''​1-2-3-6-ram-disk/​kernel''​ din arhiva de sarcini a laboratorului.+Creați un modul de kernel care să permită înregistrarea,​ respectiv deînregistrarea unui dispozitiv de tip bloc. Porniți de la fișierele din directorul ''​1-2-3-6-ram-disk/​kernel''​ din scheletul ​laboratorului.
  
 Urmăriți secțiunile marcate cu ''​TODO 1''​ în scheletul de laborator. Folosiți macrodefinițiile existente (''​MY_BLOCK_MAJOR'',​ ''​MY_BLKDEV_NAME''​). Verificați valoarea întoarsă de funcția de înregistrare și, în caz de eroare, întoarceți cod de eroare. Urmăriți secțiunile marcate cu ''​TODO 1''​ în scheletul de laborator. Folosiți macrodefinițiile existente (''​MY_BLOCK_MAJOR'',​ ''​MY_BLKDEV_NAME''​). Verificați valoarea întoarsă de funcția de înregistrare și, în caz de eroare, întoarceți cod de eroare.
Line 118: Line 122:
 </​note>​ </​note>​
  
-Schimbați valoarea macroului ''​MY_BLOCK_MAJOR''​ la valoarea ''​7''​. Compilați modulul, copiați-l pe mașina virtuală și încărcați-l în nucleu. Observați că încărcarea eșuează întrucât există deja un alt driver/​dispozitiv care are majorul ''​7''​ înregistrat în nucleu.+Schimbați valoarea macroului ''​MY_BLOCK_MAJOR''​ la valoarea ''​254''​. Compilați modulul, copiați-l pe mașina virtuală și încărcați-l în nucleu. Observați că încărcarea eșuează întrucât există deja un alt driver/​dispozitiv care are majorul ''​254''​ înregistrat în nucleu.
  
 Restaurați valoarea ''​240''​ pentru macroul ''​MY_BLOCK_MAJOR''​. Restaurați valoarea ''​240''​ pentru macroul ''​MY_BLOCK_MAJOR''​.
  
-==== 2. [1.5p] Înregistrare disc ====+==== 2. [2p] Înregistrare disc ====
  
 Modificați modulul anterior pentru a adăuga un disc asociat driverului. Analizați macrodefinițiile,​ structura ''​struct my_block_dev''​ și funcțiile existente din fișierul ''​ram-disk.c''​. Modificați modulul anterior pentru a adăuga un disc asociat driverului. Analizați macrodefinițiile,​ structura ''​struct my_block_dev''​ și funcțiile existente din fișierul ''​ram-disk.c''​.
Line 139: Line 143:
 </​note>​ </​note>​
  
-Folosiți [[http://lxr.free-electrons.com/​source/​block/​blk-core.c?v=4.9#L2879|__blk_end_request_all]] pentru încheierea prelucrării cererii.+Folosiți [[https://elixir.bootlin.com/​linux/​v4.15/​source/​block/​blk-core.c#​L3206|__blk_end_request_all]] pentru încheierea prelucrării cererii.
  
 Inserați modulul în kernel. Folosiți ''​dmesg''​ pentru a observa un mesaj transmis de modul. În momentul adăugării dispozitivului se transmite o cerere către acesta. Verificați prezența ''/​dev/​myblock''​ și dacă nu există creați dispozitivul folosind comanda<​code>​ Inserați modulul în kernel. Folosiți ''​dmesg''​ pentru a observa un mesaj transmis de modul. În momentul adăugării dispozitivului se transmite o cerere către acesta. Verificați prezența ''/​dev/​myblock''​ și dacă nu există creați dispozitivul folosind comanda<​code>​
Line 154: Line 158:
 Modificați modulul anterior pentru a crea un RAM disc: cererile către dispozitiv vor rezulta în citiri/​scrieri într-o zonă de memorie. ​ Modificați modulul anterior pentru a crea un RAM disc: cererile către dispozitiv vor rezulta în citiri/​scrieri într-o zonă de memorie. ​
  
-Zona de memorie aferentă ''​%%dev->​data%%''​ este deja alocată în codul sursă din modul folosind [[http://lxr.free-electrons.com/​source/​mm/​vmalloc.c?v=4.9#L1752 | vmalloc]]((Pentru simplitate, se folosește funcția vmalloc pentru alocarea vectorului în memorie; funcția vmalloc alocă o zonă de memorie contiguă în spațiul de adrese virtuale, iar funcția vfree o dealocă. Mai multe despre alocarea memoriei în kernel găsiți în [[http://​lwn.net/​images/​pdf/​LDD3/​ch08.pdf | Linux Device Drivers 3rd Edition, Chapter 8. Allocating memory]])). Pentru dezalocare în modul se folosește [[http://lxr.free-electrons.com/​source/​mm/​vmalloc.c?v=4.9#L1514 | vfree]].+Zona de memorie aferentă ''​%%dev->​data%%''​ este deja alocată în codul sursă din modul folosind [[https://elixir.bootlin.com/​linux/​v4.15/​source/​mm/​vmalloc.c#​L1829 | vmalloc]]((Pentru simplitate, se folosește funcția vmalloc pentru alocarea vectorului în memorie; funcția vmalloc alocă o zonă de memorie contiguă în spațiul de adrese virtuale, iar funcția vfree o dealocă. Mai multe despre alocarea memoriei în kernel găsiți în [[http://​lwn.net/​images/​pdf/​LDD3/​ch08.pdf | Linux Device Drivers 3rd Edition, Chapter 8. Allocating memory]])). Pentru dezalocare în modul se folosește [[https://elixir.bootlin.com/​linux/​v4.15/​source/​mm/​vmalloc.c#​L1581 | vfree]].
  
 <​note>​ <​note>​
Line 163: Line 167:
  
 <note tip> <note tip>
-Pentru a afla dimensiunea datelor din request folosiți macro-ul [[http://lxr.free-electrons.com/​source/​include/​linux/​blkdev.h?v=4.9#L865|blk_rq_cur_bytes]]. **Nu** folosiți macro-ul [[http://lxr.free-electrons.com/​source/​include/​linux/​blkdev.h?v=4.9#L860|blk_rq_bytes]].+Pentru a afla dimensiunea datelor din request folosiți macro-ul [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​blkdev.h#​L1032|blk_rq_cur_bytes]]. **Nu** folosiți macro-ul [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​blkdev.h#​L1027|blk_rq_bytes]].
 </​note>​ </​note>​
  
Line 178: Line 182:
 </​note>​ </​note>​
  
-Pentru testare folosiți fișierul de test ''​ram-disk-test.c''​. Îl compilați folosindpe sistemul fiziccomanda<​code>​ +Pentru testare folosiți fișierul de test ''​user/ram-disk-test.c'', ​care se compilează automat la ''​make build''​se copiază pe mașina virtuală la ''​make copy'' ​și se rulează ​folosind, pe mașina virtuală QEMU, comanda<​code>​
-make -f Makefile.test +
-</​code>​ +
-și apoi îl rulați ​folosind, pe mașina virtuală QEMU, comanda<​code>​+
 ./​ram-disk-test ./​ram-disk-test
 </​code>​ </​code>​
Line 190: Line 191:
 ==== 4. [2p] Citirea datelor de pe disc ==== ==== 4. [2p] Citirea datelor de pe disc ====
  
-Scopul acestui exercițiu este să citiți datele de pe discul ''​PHYSICAL_DISK_NAME''​ direct din kernel.+Scopul acestui exercițiu este să citiți datele de pe discul ''​PHYSICAL_DISK_NAME'' ​(''/​dev/​vdb''​) ​direct din kernel. 
 + 
 +<note important>​ 
 +Înainte de rezolvarea exercițiului,​ este necesar să adaugăm discul la mașina virtuală. Pentru aceasta, generați un fișier pe care îl vom folosi ca imaginea discului folosind comanda <​code>​dd if=/​dev/​zero of=qemu/​mydisk.img bs=1024 count=1</​code>​ și adăugați argumentul ''​-drive file=qemu/​mydisk.img,​if=virtio,​format=raw''​ comenzii ''​qemu'',​ în fișierul ''​qemu/​Makefile''​ (în variabila ''​QEMU_OPTS''​) 
 +</​note>​
  
-Urmăriți comentariile marcate cu ''​TODO 4''​ în directorul ''​4-5-relay-disk/''​ și completați funcțiile ''​open_disk''​ și ''​close_disk''​. Folosiți funcțiile [[http://lxr.free-electrons.com/​source/​fs/​block_dev.c?v=4.9#L1467 | blkdev_get_by_path]] și [[http://lxr.free-electrons.com/​source/​fs/​block_dev.c?v=4.9#L1619 | blkdev_put]]. Dispozitivul trebuie deschis în mod read-write exclusiv (''​FMODE_READ | FMODE_WRITE | FMODE_EXCL''​),​ iar ca holder trebuie să folosiți modulul curent (''​THIS_MODULE''​).+Urmăriți comentariile marcate cu ''​TODO 4''​ în directorul ''​4-5-relay-disk/''​ și completați funcțiile ''​open_disk''​ și ''​close_disk''​. Folosiți funcțiile [[https://elixir.bootlin.com/​linux/​v4.15/​source/​fs/​block_dev.c#​L1642 | blkdev_get_by_path]] și [[https://elixir.bootlin.com/​linux/​v4.15/​source/​fs/​block_dev.c#​L1752 | blkdev_put]]. Dispozitivul trebuie deschis în mod read-write exclusiv (''​FMODE_READ | FMODE_WRITE | FMODE_EXCL''​),​ iar ca holder trebuie să folosiți modulul curent (''​THIS_MODULE''​).
  
-Completați funcția ''​send_test_bio''​. Va trebui să creați un nou bio pe care să-l completați,​ să-l submiteți și să-l așteptați. Citiți primul sector al discului. Pentru așteptare folosiți [[http://lxr.free-electrons.com/​source/​block/​bio.c?v=4.9#L863|submit_bio_wait]].+Completați funcția ''​send_test_bio''​. Va trebui să creați un nou bio pe care să-l completați,​ să-l submiteți și să-l așteptați. Citiți primul sector al discului. Pentru așteptare folosiți [[https://elixir.bootlin.com/​linux/​v4.15/​source/​block/​bio.c#​L928|submit_bio_wait]].
  
 <note tip> <note tip>
-Primul sector al discului este sectorul cu indexul ''​0''​. La această valoare trebuie inițializat câmpul ''​bi_iter.bi_sector''​ al structurii [[http://lxr.free-electrons.com/​source/​include/​linux/​blk_types.h?v=4.9#L25|bio]].+Primul sector al discului este sectorul cu indexul ''​0''​. La această valoare trebuie inițializat câmpul ''​bi_iter.bi_sector''​ al structurii [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​blk_types.h#​L50|bio]].
  
-Pentru operația de citire folosiți macro-urile ''​REQ_OP_READ''​ și [[http://lxr.free-electrons.com/​source/​include/​linux/​blk_types.h?v=4.9#L95|bio_set_op_attrs]].+Pentru operația de citire folosiți macro-urile ''​REQ_OP_READ''​ și [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​blk_types.h#​L271|bio_set_op_attrs]].
  
 </​note>​ </​note>​
  
-După terminarea operației afișați primii 3 octeți din datele citite de bio. Folosiți formatul ''​%%"​%02x"​%%''​ la ''​printk''​ pentru afișarea datelor și macrourile [[http://lxr.free-electrons.com/​source/​arch/​x86/​mm/​highmem_32.c?v=4.9#L55 | kmap_atomic]],​ respectiv [[http://lxr.free-electrons.com/​source/​include/​linux/​highmem.h?v=4.9#L124 | kunmap_atomic]].+După terminarea operației afișați primii 3 octeți din datele citite de bio. Folosiți formatul ''​%%"​%02x"​%%''​ la ''​printk''​ pentru afișarea datelor și macrourile [[https://elixir.bootlin.com/​linux/​v4.15/​source/​arch/​x86/​mm/​highmem_32.c#​L55 | kmap_atomic]],​ respectiv [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​highmem.h#​L125 | kunmap_atomic]].
  
 <note tip> <note tip>
-Ca argument pentru [[http://lxr.free-electrons.com/​source/​arch/​x86/​mm/​highmem_32.c?v=4.9#L55 | kmap_atomic]] folosiți chiar pagina alocată mai sus în cod în cadrul variabilei ''​page''​.+Ca argument pentru [[https://elixir.bootlin.com/​linux/​v4.15/​source/​arch/​x86/​mm/​highmem_32.c#​L55 | kmap_atomic]] folosiți chiar pagina alocată mai sus în cod în cadrul variabilei ''​page''​.
 </​note>​ </​note>​
  
Line 213: Line 218:
 </​note>​ </​note>​
  
-Pentru testare folosiți scriptul ''​test-relay-disk''​. Nu este nevoie să încărcați modulul în nucleu, va fi încărcat de test. Pentru a rula scriptul folosiți comanda<​code>​+Pentru testare folosiți scriptul ''​test-relay-disk'',​ care este copiat pe mașina virtuală la ''​make copy''​. Dacă nu este copiat, asigurați-vă că este executabil (''​chmod +x test-relay-disk''​). Nu este nevoie să încărcați modulul în nucleu, va fi încărcat de test. Pentru a rula scriptul folosiți comanda<​code>​
 ./​test-relay-disk ./​test-relay-disk
 </​code>​ </​code>​
 Scriptul scrie ''​%%"​abc"​%%''​ la începutul discului indicat de ''​PHYSICAL_DISK_NAME''​. În urma rulării, modulul va afișa ''​61 62 63''​ (valorile hexazecimale corespunzătoare). Scriptul scrie ''​%%"​abc"​%%''​ la începutul discului indicat de ''​PHYSICAL_DISK_NAME''​. În urma rulării, modulul va afișa ''​61 62 63''​ (valorile hexazecimale corespunzătoare).
  
-==== 5. [2p] Scrierea unui mesaj pe disc ====+==== 5. [1.5p] Scrierea unui mesaj pe disc ====
  
 Urmăriți comentariile marcate cu ''​TODO 5''​ pentru scrierea unui mesaj (''​BIO_WRITE_MESSAGE''​) pe disc.  Urmăriți comentariile marcate cu ''​TODO 5''​ pentru scrierea unui mesaj (''​BIO_WRITE_MESSAGE''​) pe disc. 
  
-Trebuie să actualizați funcția ''​send_test_bio'' ​pentru a primi ca argument tipul operației (citire sau scriere). Apelați în ''​relay_init''​ funcția pentru citire iar în ''​relay_exit''​ funcția pentru scriere. Recomandăm folosirea macro-urilor ​ ''​REQ_OP_READ''​ și ''​REQ_OP_WRITE''​.+Funcția ''​send_test_bio'' ​primește ​ca argument tipul operației (citire sau scriere). Apelați în ''​relay_init''​ funcția pentru citire iar în ''​relay_exit''​ funcția pentru scriere. Recomandăm folosirea macro-urilor ​ ''​REQ_OP_READ''​ și ''​REQ_OP_WRITE''​.
  
-În cadrul funcției ''​send_test_bio'',​ dacă operația este de scriere, completați buffer-ul aferent bio-ului cu mesajul ''​BIO_WRITE_MESSAGE''​. Folosiți macrourile [[http://lxr.free-electrons.com/​source/​arch/​x86/​mm/​highmem_32.c?v=4.9#L55 | kmap_atomic]],​ respectiv [[http://lxr.free-electrons.com/​source/​include/​linux/​highmem.h?v=4.9#L124 | kunmap_atomic]] pentru lucrul cu buffer-ul aferent bio-ului.+În cadrul funcției ''​send_test_bio'',​ dacă operația este de scriere, completați buffer-ul aferent bio-ului cu mesajul ''​BIO_WRITE_MESSAGE''​. Folosiți macrourile [[https://elixir.bootlin.com/​linux/​v4.15/​source/​arch/​x86/​mm/​highmem_32.c#​L55 | kmap_atomic]],​ respectiv [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​highmem.h#​L125 | kunmap_atomic]] pentru lucrul cu buffer-ul aferent bio-ului.
  
 <note tip> <note tip>
-Trebuie să actualizați tipul operației [[http://lxr.free-electrons.com/​source/​include/​linux/​blk_types.h#​L46|structurii bio]] folosind macrodefiniția ''​bio_set_op_attrs''​+Trebuie să actualizați tipul operației [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​blk_types.h#​L50|structurii bio]] folosind macrodefiniția ''​bio_set_op_attrs''​
 </​note>​ </​note>​
  
Line 243: Line 248:
 Configurați macro-ul ''​USE_BIO_TRANSFER''​ la valoarea 1. Configurați macro-ul ''​USE_BIO_TRANSFER''​ la valoarea 1.
  
-Implementați funcția ''​my_xfer_request''​. Folosiți [[http://lxr.free-electrons.com/​source/​include/​linux/​blkdev.h?v=4.9#L754|rq_for_each_segment]] pentru a parcurge structurile [[http://lxr.free-electrons.com/​source/​include/​linux/​bvec.h?v=4.9#L29 | bio_vec]] ale fiecărui [[http://lxr.free-electrons.com/​source/​include/​linux/​blk_types.h?v=4.9#L25 | bio]] din [[http://lxr.free-electrons.com/​source/​include/​linux/​blkdev.h?v=4.9#L88|request]].+Implementați funcția ''​my_xfer_request''​. Folosiți [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​blkdev.h#​L927|rq_for_each_segment]] pentru a parcurge structurile [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​bvec.h#​L30 | bio_vec]] ale fiecărui [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​blk_types.h#​L50 | bio]] din [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​blkdev.h#​L135|request]].
  
 <note tip> <note tip>
Line 258: Line 263:
  
 <note tip> <note tip>
-Folosiți macro-ul [[http://lxr.free-electrons.com/​source/​include/​linux/​fs.h?v=4.9#L2510|bio_data_dir]] pentru a afla direcția de citire sau scriere pentru un bio.+Folosiți macro-ul [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​bio.h#L76|bio_data_dir]] pentru a afla direcția de citire sau scriere pentru un bio.
 </​note>​ </​note>​
  
-Folosiți macrourile [[http://lxr.free-electrons.com/​source/​arch/​x86/​mm/​highmem_32.c?v=4.9#​L55|kmap_atomic]],​ respectiv [[http://lxr.free-electrons.com/​source/​include/​linux/​highmem.h?v=4.9#L120|kunmap_atomic]] pentru maparea paginilor fiecărui bio și accesarea bufferelor acestuia. Pentru transferul efectiv, apelați funcția ''​my_block_transfer''​ implementată la exercițiul anterior.+Folosiți macrourile [[https://elixir.bootlin.com/​linux/​v4.15/​source/​arch/​x86/​mm/​highmem_32.c#​L55|kmap_atomic]],​ respectiv [[https://elixir.bootlin.com/​linux/​v4.15/​source/​include/​linux/​highmem.h#​L125|kunmap_atomic]] pentru maparea paginilor fiecărui bio și accesarea bufferelor acestuia. Pentru transferul efectiv, apelați funcția ''​my_block_transfer''​ implementată la exercițiul anterior.
  
-Pentru testare folosiți fișierul de test ''​ram-disk-test.c''​. ​Îl compilați folosind, pe sistemul fizic, comanda<​code>​ +Pentru testare folosiți fișierul de test ''​ram-disk-test.c''​.
-make -f Makefile.test+
 </​code>​ </​code>​
-și apoi îl rulați folosind, pe mașina virtuală QEMU, comanda<​code>​+îl rulați folosind, pe mașina virtuală QEMU, comanda<​code>​
 ./​ram-disk-test ./​ram-disk-test
 </​code>​ </​code>​
so2/laboratoare/lab07/exercitii.1523284150.txt.gz · Last modified: 2018/04/09 17:29 by ionel.ghita
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0