This shows you the differences between two versions of the page.
so2:laboratoare:lab07:exercitii [2017/04/05 13:27] razvan.deaconescu [4. [2p] Citirea datelor de pe disc] |
so2:laboratoare:lab07:exercitii [2018/04/12 11:40] (current) elena.sandulescu [6. [2p] Prelucrarea cererilor din coada la nivel de bio] |
||
---|---|---|---|
Line 1: | Line 1: | ||
====== Laborator 7: Exerciții ====== | ====== Laborator 7: Exerciții ====== | ||
- | Pentru desfășurarea laboratorului pornim de la [[http://elf.cs.pub.ro/so2/res/laboratoare/lab07-tasks.zip|arhiva de sarcini a laboratorului]]. Descărcăm și decomprimăm arhiva în directorul ''so2/'' din directorul home al utilizatorului ''student'' de pe sistemul de bază (stația ''eg106-pc''):<code bash> | + | ===== Pregătirea laboratorului ===== |
- | student@eg106-pc:~$ cd so2/ | + | |
- | student@eg106-pc:~/so2$ wget http://elf.cs.pub.ro/so2/res/laboratoare/lab07-tasks.zip | + | Pentru rezolvarea laboratorului, vom lucra în același director din care pornim mașina virtuală (''~/so2/linux/tools/labs''). |
- | student@eg106-pc:~/so2$ unzip lab07-tasks.zip | + | |
- | student@eg106-pc:~/so2$ tree lab07-tasks | + | Pașii de rezolvare sunt următorii: |
+ | * pregătirea scheletului de laborator | ||
+ | * compilarea modulelor de Kernel | ||
+ | * copierea modulelor pe mașina virtuală | ||
+ | * pornirea mașinii virtuale și testarea modulelor | ||
+ | |||
+ | ==== Pregătirea scheletului de laborator ==== | ||
+ | |||
+ | Scheletul de laborator este generat din sursele din directorul ''tools/labs/templates''. Putem genera scheletele pentru toate laboratoarele folosind următoarea comanda: | ||
+ | |||
+ | <code bash> | ||
+ | tools/labs $ make skels | ||
</code> | </code> | ||
- | În cadrul directorului ''lab07-tasks/'' se găsesc resursele necesare pentru dezvoltarea exercițiilor de mai jos: fișiere schelet de cod sursă, fișiere Makefile și Kbuild, scripturi și programe de test. | ||
- | Vom dezvolta exercițiile pe sistemul de bază (stația ''eg106-pc'') și apoi le vom testa pe [[:so2:resurse:masini-virtuale|mașina virtuală QEMU]]. După editarea și compilarea unui modul de kernel îl vom copia în directorul dedicat pentru mașina virtuală QEMU folosind o comandă de forma<code bash> | + | Pentru a genera scheletul pentru un singur laborator, vom folosi variabila de mediu ''LABS'': |
- | student@eg106-pc:~/so2$ cp /path/to/module.ko ~/so2/qemu-so2/fsimg/root/modules/ | + | |
- | </code> unde ''/path/to/module.ko'' este calea către fișierul obiect aferent modulului de kernel. Apoi vom porni, din directorul ''~/so2/qemu-so2/'', mașina virtuală QEMU folosind comanda<code bash> | + | <code bash> |
- | student@eg106-pc:~/so2/qemu-so2$ make | + | tools/labs $ make clean |
+ | tools/labs $ LABS=<lab name> make skels | ||
+ | </code> | ||
+ | |||
+ | <note important> | ||
+ | Numele laboratorului curent este ''block_device_drivers''. | ||
+ | </note> | ||
+ | |||
+ | Similar, putem genera și scheletul pentru un singur exercițiu, atribuind valoarea ''<lab_name>/<task_name>'' variabilei ''LABS''. | ||
+ | |||
+ | <note> | ||
+ | Scheletul este generat în directorul ''tools/labs/skels''. | ||
+ | </note> | ||
+ | |||
+ | ==== Compilarea modulelor ==== | ||
+ | |||
+ | Comanda ''make build'' compilează toate modulele din directorul ''skels''. | ||
+ | |||
+ | <code bash> | ||
+ | student@eg106:~/so2/linux/tools/labs$ make build | ||
+ | echo "# autogenerated, do not edit " > skels/Kbuild | ||
+ | echo "ccflags-y += -Wno-unused-function -Wno-unused-label -Wno-unused-variable " >> skels/Kbuild | ||
+ | for i in ./block_device_drivers/1-2-3-6-ram-disk/kernel ./block_device_drivers/4-5-relay-disk; do echo "obj-m += $i/" >> skels/Kbuild; done | ||
+ | </code> | ||
+ | |||
+ | ==== Copierea modulelor pe mașina virtuală ==== | ||
+ | |||
+ | Putem copia modulele generate pe mașina virtuală folosind target-ul ''copy'' al comenzii make, atunci când mașina virtuală este oprită. | ||
+ | |||
+ | <code bash> | ||
+ | student@eg106:~/so2/linux/tools/labs$ make copy | ||
+ | student@eg106:~/so2/linux/tools/labs$ make boot | ||
+ | </code> | ||
+ | |||
+ | Alternativ, putem copia fișierele prin ''scp'', pentru e evita repornirea mașinii virtuale. Pentru detalii despre folosirea interacțiunea prin rețea cu mașina virtuală citiți [[https://ocw.cs.pub.ro/courses/so2/resurse/masini-virtuale#interactiunea_cu_masina_virtuala|Interacțiunea cu mașina virtuală]]. | ||
+ | |||
+ | ==== Testarea modulelor ==== | ||
+ | |||
+ | Modulele generate sunt copiate pe mașina virtuală în directorul ''/home/root/skels/<lab_name>''. | ||
+ | |||
+ | <code bash> | ||
+ | root@qemux86:~/skels/block_device_drivers# ls | ||
+ | 1-2-3-6-ram-disk 4-5-relay-disk | ||
+ | root@qemux86:~/skels/block_device_drivers# ls 4-5-relay-disk/ | ||
+ | relay-disk.ko | ||
</code> | </code> | ||
- | După pornirea mașinii virtuale QEMU vom putea folosi comenzi în fereastra QEMU pentru a încărca și descărca modulul de kernel:<code> | + | După pornirea mașinii virtuale QEMU vom putea folosi comenzi în fereastra QEMU (sau în ''minicom'') pentru a încărca și descărca modulul de kernel:<code> |
- | # insmod modules/module-name.ko | + | root@qemux86:~# insmod skels/<lab_name>/<task_name>/<module_name>.ko |
- | # rmmod module/module-name | + | root@qemux86:~# rmmod skels/<lab_name>/<task_name>/<module_name>.ko |
- | </code> unde ''module-name'' este numele modulului de kernel. | + | </code> |
<note> | <note> | ||
Pentru dezvoltarea laboratorului, este recomandat să folosim trei terminale sau, mai bine, trei tab-uri de terminal. Pentru a deschide un nou tab de terminal folosim combinația de taste ''Ctrl+Shift+t''. Cele trei tab-uri de terminal îndeplinesc următoarele roluri: | Pentru dezvoltarea laboratorului, este recomandat să folosim trei terminale sau, mai bine, trei tab-uri de terminal. Pentru a deschide un nou tab de terminal folosim combinația de taste ''Ctrl+Shift+t''. Cele trei tab-uri de terminal îndeplinesc următoarele roluri: | ||
- În primul tab de terminal dezvoltăm modulul de kernel: editare, compilare, copiere în directorul dedicat pentru mașina virtuală QEMU. Lucrăm în directorul aferent rezultat în urma decomprimării arhivei de sarcini a laboratorului. | - În primul tab de terminal dezvoltăm modulul de kernel: editare, compilare, copiere în directorul dedicat pentru mașina virtuală QEMU. Lucrăm în directorul aferent rezultat în urma decomprimării arhivei de sarcini a laboratorului. | ||
- | - În al doilea tab de terminal pornim mașina virtuală QEMU și apoi testăm modulul de kernel: încărcare/descărcare modul, rulare teste. Lucrăm în directorul aferent mașinii virtuale: ''~/so2/qemu-so2/''. | + | - În al doilea tab de terminal pornim mașina virtuală QEMU și apoi testăm modulul de kernel: încărcare/descărcare modul, rulare teste. Lucrăm în directorul aferent mașinii virtuale: ''~/so2/linux/tools/labs''. |
- | - În al treilea tab de terminal accesăm directorul ''~/so2/linux-4.9.11/'' cu sursele nucleului unde putem folosi [[:so2:laboratoare:lab01#cscope|Vim și cscope]] pentru parcurgerea codului sursă. | + | - În al treilea tab de terminal accesăm directorul ''~/so2/linux/'' cu sursele nucleului unde putem folosi [[:so2:laboratoare:lab01#cscope|Vim și cscope]] pentru parcurgerea codului sursă. |
student@eg106-pc:~$ netcat -lup 6666 | student@eg106-pc:~$ netcat -lup 6666 | ||
</code> | </code> | ||
Line 31: | Line 85: | ||
- În primul tab să fie deschis [[:so2:laboratoare:lab07|breviarul laboratorului]]. | - În primul tab să fie deschis [[:so2:laboratoare:lab07|breviarul laboratorului]]. | ||
- În al doilea tab să fie deschisă [[:so2:laboratoare:lab07:exercitii|pagina curentă]]. | - În al doilea tab să fie deschisă [[:so2:laboratoare:lab07:exercitii|pagina curentă]]. | ||
- | - În al treilea tab să fie deschisă [[http://lxr.free-electrons.com/source/?v=4.9|pagina LXR]] pentru parcurgerea codului sursă din nucleu. | + | - În al treilea tab să fie deschisă [[https://elixir.bootlin.com/linux/v4.15/source|pagina LXR]] pentru parcurgerea codului sursă din nucleu. |
</note> | </note> | ||
Line 49: | 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/'' 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 64: | 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''. | ||
- | Decomentați apelurile de funcții ''create_block_device'' și ''delete_block_device''. | + | Urmăriți comentariile marcate cu ''TODO 2''. Folosiți funcțiile ''create_block_device'' și ''delete_block_device''. |
<note tip> | <note tip> | ||
Line 79: | Line 137: | ||
</note> | </note> | ||
- | Urmăriți secțiunile marcate cu ''TODO 2'' în scheletul de laborator. Completați funcția ''my_block_request'' pentru prelucrarea cozii de cereri fără a face o prelucrare efectivă a cererii: afișați mesajul ''%%"request received"%%'' și următoarele informații: sectorul de start, dimensiunea totală, dimensiunea datelor din bio-ul curent, direcția de tratare. | + | Completați funcția ''my_block_request'' pentru prelucrarea cozii de cereri fără a face o prelucrare efectivă a cererii: afișați mesajul ''%%"request received"%%'' și următoarele informații: sectorul de start, dimensiunea totală, dimensiunea datelor din bio-ul curent, direcția de tratare. Pentru a valida tipul unei cereri, folosiți funcția [[https://elixir.bootlin.com/linux/v4.15/source/include/linux/blkdev.h#L264|blk_rq_is_passthrough]] (funcția returnează ''0'' în cazul de care suntem interesați, atunci când cererea este generată de către sistemul de fișiere). |
<note tip> | <note tip> | ||
Line 85: | 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 100: | 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 109: | 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 124: | Line 182: | ||
</note> | </note> | ||
- | 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 ''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 136: | 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 159: | 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 189: | 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 204: | 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> |