This shows you the differences between two versions of the page.
so2:laboratoare:lab08:exercitii [2017/04/10 16:48] octavian.purdila |
so2:laboratoare:lab08:exercitii [2018/04/18 09:36] (current) ionel.ghita [5. [0.5p] Înregistrare și deînregistrare sistem de fișiere minfs] |
||
---|---|---|---|
Line 1: | Line 1: | ||
====== Laborator 8: Exerciții ====== | ====== Laborator 8: Exerciții ====== | ||
- | Pentru desfășurarea laboratorului pornim de la [[http://elf.cs.pub.ro/so2/res/laboratoare/lab08-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 ''mjolnir''):<code bash> | + | ===== Pregătirea laboratorului ===== |
- | student@mjolnir:~$ cd so2/ | + | |
- | student@mjolnir:~/so2$ wget http://elf.cs.pub.ro/so2/res/laboratoare/lab08-tasks.zip | + | Pentru rezolvarea laboratorului, vom lucra în același director din care pornim mașina virtuală (''~/so2/linux/tools/labs''). |
- | student@mjolnir:~/so2$ unzip lab08-tasks.zip | + | |
- | student@mjolnir:~/so2$ tree lab08-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 ''lab08-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 ''mjolnir'') ș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@mjolnir:~/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@mjolnir:~/so2/qemu-so2$ make | + | tools/labs $ make clean |
+ | tools/labs $ LABS=<lab name> make skels | ||
</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> | + | <note important> |
- | # insmod modules/module-name.ko | + | Numele laboratorului curent este ''filesystems''. |
- | # rmmod module/module-name | + | </note> |
- | </code> unde ''module-name'' este numele modulului de kernel. | + | |
+ | Similar, putem genera și scheletul pentru un singur exercițiu, atribuind valoarea ''<lab_name>/<task_name>'' variabilei ''LABS''. | ||
<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+Alt+t''. Cele trei tab-uri de terminal îndeplinesc următoarele roluri: | + | Scheletul este generat în directorul ''tools/labs/skels''. |
- | - În primul tab de terminal dezvoltăm modulul de kernel: editare, compilare, copiere în directorul dedicat pentru mașina virtaulă QEMU. Lucrăm în directorul aferent rezultat în urma decomprimării arhivei de sarcini a laboratorului. | + | </note> |
- | - Î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 treilea tab de terminal pornim [[:so2:laboratoare:lab02#minicom|minicom]] sau un server UDP care să primească [[:so2:laboratoare:lab02#netconsole|mesajele de netconsole]]. Nu contează în ce director ne aflăm. Folosim comanda<code bash> | + | ==== Compilarea modulelor ==== |
- | student@mjolnir:~$ netcat -lup 6666 | + | |
+ | 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 ./filesystems/minfs/kernel ./filesystems/myfs; do echo "obj-m += $i/" >> skels/Kbuild; done | ||
</code> | </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/filesystems# ls | ||
+ | minfs myfs | ||
+ | root@qemux86:~/skels/filesystems# ls myfs/ | ||
+ | myfs.ko test-myfs.sh | ||
+ | </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> | ||
+ | root@qemux86:~# insmod skels/<lab_name>/<task_name>/<module_name>.ko | ||
+ | root@qemux86:~# rmmod skels/<lab_name>/<task_name>/<module_name>.ko | ||
+ | </code> | ||
+ | |||
+ | <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: | ||
+ | - Î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/linux/tools/labs''. | ||
+ | - Î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 | ||
+ | </code> | ||
+ | |||
+ | Pentru buna desfășurare a laboratorului recomandăm să aveți deschise trei tab-uri de browser: | ||
+ | - În primul tab să fie deschis [[:so2:laboratoare:lab08|breviarul laboratorului]]. | ||
+ | - În al doilea tab să fie deschisă [[:so2:laboratoare:lab08:exercitii|pagina curentă]]. | ||
+ | - Î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 warning> | ||
+ | Citiți cu atenție toate precizările unui exercițiu înainte de a începe rezolvarea acestuia. | ||
+ | </note> | ||
+ | |||
+ | <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> | </note> | ||
Line 33: | Line 101: | ||
Pentru început ne propunem să ne acomodăm cu interfața expusă de nucleul Linux și de componenta VFS (//Virtual File System//). De aceea, pentru început vom lucra cu un sistem de fișiere simplu, virtual (adică fără suport fizic pe disc). Sistemul de fișiere poartă denumirea ''myfs''. | Pentru început ne propunem să ne acomodăm cu interfața expusă de nucleul Linux și de componenta VFS (//Virtual File System//). De aceea, pentru început vom lucra cu un sistem de fișiere simplu, virtual (adică fără suport fizic pe disc). Sistemul de fișiere poartă denumirea ''myfs''. | ||
- | Pentru aceasta vom accesa subdirectorul ''myfs/'' din [[http://elf.cs.pub.ro/so2/res/laboratoare/lab08-tasks.zip|arhiva de sarcini a laboratorului]]. Vom implementa în cadrul acestui laborator operațiile pe superbloc, iar [[:so2:laboratoare:lab09|laboratorul viitor]] vom continua cu operațiile pe inode. | + | Pentru aceasta vom accesa subdirectorul ''myfs/'' din scheletul de laborator. Vom implementa în cadrul acestui laborator operațiile pe superbloc, iar [[:so2:laboratoare:lab09|laboratorul viitor]] vom continua cu operațiile pe inode. |
==== 1. [1.5p] Înregistrare și deînregistrare sistem de fișiere myfs ==== | ==== 1. [1.5p] Înregistrare și deînregistrare sistem de fișiere myfs ==== | ||
Line 42: | Line 110: | ||
<note tip> | <note tip> | ||
- | În cadrul structurii de sistem de fișiere, pentru completarea superbloculului (efectuată la montare) folosiți funcția ''myfs_mount'', prezentă în scheletul de cod. În cadrul funcției ''myfs_mount'' apelați funcția specifică unui sistem de fișiere fără suport pe disc (vedeți secțiunea [[:so2:laboratoare:lab08#functiile_mount_kill_sb|Funcțiile mount, kill_sb]]; este vorba de funcția [[http://lxr.free-electrons.com/source/fs/super.c?v=4.9#L1110|mount_nodev]]). Ca argument pentru funcția de mount specifică folosiți funcția de tipul [[:so2:laboratoare:lab08#functia_fill_super|funcția fill_super]] definită în scheletul de cod. | + | În cadrul structurii de sistem de fișiere, pentru completarea superbloculului (efectuată la montare) folosiți funcția ''myfs_mount'', prezentă în scheletul de cod. În cadrul funcției ''myfs_mount'' apelați funcția specifică unui sistem de fișiere fără suport pe disc (vedeți secțiunea [[:so2:laboratoare:lab08#functiile_mount_kill_sb|Funcțiile mount, kill_sb]]; este vorba de funcția [[https://elixir.bootlin.com/linux/v4.15/source/fs/super.c#L1155|mount_nodev]]). Ca argument pentru funcția de mount specifică folosiți funcția de tipul [[:so2:laboratoare:lab08#functia_fill_super|funcția fill_super]] definită în scheletul de cod. |
- | Pentru distrugerea superblocului (efectuată la demontare) folosiți funcția [[http://lxr.free-electrons.com/source/fs/super.c?v=4.9#L948|kill_litter_super]], funcție specifică, de asemenea, unui sistem de fișiere fără suport pe disc. | + | Pentru distrugerea superblocului (efectuată la demontare) folosiți funcția [[https://elixir.bootlin.com/linux/v4.15/source/fs/super.c#L997|kill_litter_super]], funcție specifică, de asemenea, unui sistem de fișiere fără suport pe disc. |
</note> | </note> | ||
- | După completarea secțiunilor marcate cu ''TODO 1'', compilați modulul, copiați-l în directorul dedicat pentru mașina virtuală QEMU și porniți mașina virtuală. Încărcați modulul în kernel și apoi verificați prezența sistemului de fișiere ''myfs'' în cadrul fișierului ''/proc/filesystems''. | + | După completarea secțiunilor marcate cu ''TODO 1'', compilați modulul, copiați-l pe mașina virtuală QEMU și porniți mașina virtuală. Încărcați modulul în kernel și apoi verificați prezența sistemului de fișiere ''myfs'' în cadrul fișierului ''/proc/filesystems''. |
Pe moment sistemul de fișiere este doar înregistrat, nu expune operații de utilizare a acestuia. Dacă încercăm să-l montăm, operația va eșua. Pentru a încerca montarea, creăm punctul de montare ''/mnt/myfs/''<code> | Pe moment sistemul de fișiere este doar înregistrat, nu expune operații de utilizare a acestuia. Dacă încercăm să-l montăm, operația va eșua. Pentru a încerca montarea, creăm punctul de montare ''/mnt/myfs/''<code> | ||
Line 85: | Line 153: | ||
Inode-ul rădăcină este inode-ul aferent directorului rădăcină al sistemului de fișiere (adică ''/''). Inițializarea sa se face la montare. Funcția ''myfs_fill_super'', apelată la montare, este cea care apelează funcția ''myfs_get_inode'' care creează și inițializează un inode. În mod obișnuit, funcția este folosită pentru crearea și inițializarea tuturor inode-urilor; în acest exercițiu, însă, vom crea doar inode-ul rădăcină. | Inode-ul rădăcină este inode-ul aferent directorului rădăcină al sistemului de fișiere (adică ''/''). Inițializarea sa se face la montare. Funcția ''myfs_fill_super'', apelată la montare, este cea care apelează funcția ''myfs_get_inode'' care creează și inițializează un inode. În mod obișnuit, funcția este folosită pentru crearea și inițializarea tuturor inode-urilor; în acest exercițiu, însă, vom crea doar inode-ul rădăcină. | ||
- | [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=4.9#L604 | Inode-ul]] este alocat în cadrul funcției ''myfs_get_inode''. Este vorba de variabila locală ''inode'', alocată cu ajutorul apelului [[http://lxr.free-electrons.com/source/fs/inode.c?v=4.9#L900|new_inode]]. | + | [[https://elixir.bootlin.com/linux/v4.15/source/include/linux/fs.h#L570 | Inode-ul]] este alocat în cadrul funcției ''myfs_get_inode''. Este vorba de variabila locală ''inode'', alocată cu ajutorul apelului [[https://elixir.bootlin.com/linux/v4.15/source/fs/inode.c#L901|new_inode]]. |
- | Pentru a definitiva cu succes montarea sistemului de fișiere, va trebui să completați funcția ''myfs_get_inode''. Urmăriți indicațiile marcate cu ''TODO 3''. Un punct de plecare este funcția [[http://lxr.free-electrons.com/source/fs/ramfs/inode.c?v=4.9#L53|ramfs_get_inode]]. | + | Pentru a definitiva cu succes montarea sistemului de fișiere, va trebui să completați funcția ''myfs_get_inode''. Urmăriți indicațiile marcate cu ''TODO 3''. Un punct de plecare este funcția [[https://elixir.bootlin.com/linux/v4.15/source/fs/ramfs/inode.c#L61|ramfs_get_inode]]. |
<note tip> | <note tip> | ||
- | Pentru inițializarea ''uid'', ''gid'', ''mode'', puteți folosi funcția [[http://lxr.free-electrons.com/source/fs/inode.c?v=4.9#L1993|inode_init_owner]] așa cum este folosită și în funcția [[http://lxr.free-electrons.com/source/fs/ramfs/inode.c?v=4.9#L53|ramfs_get_inode]]. Când apelați funcția [[http://lxr.free-electrons.com/source/fs/inode.c?v=4.9#L1999|inode_init_owner]] folosiți ''NULL'' ca al doilea parametru, întrucât nu există director părinte pentru inode-ul creat. | + | Pentru inițializarea ''uid'', ''gid'', ''mode'', puteți folosi funcția [[https://elixir.bootlin.com/linux/v4.15/source/fs/inode.c#L1997|inode_init_owner]] așa cum este folosită și în funcția [[https://elixir.bootlin.com/linux/v4.15/source/fs/ramfs/inode.c#L61|ramfs_get_inode]]. Când apelați funcția [[https://elixir.bootlin.com/linux/v4.15/source/fs/inode.c#L1997|inode_init_owner]] folosiți ''NULL'' ca al doilea parametru, întrucât nu există director părinte pentru inode-ul creat. |
- | Inițializați câmpurile ''i_atime'', ''i_ctime'' și ''i_mtime'' ale inode-ului VFS la valoarea [[http://lxr.free-electrons.com/source/include/linux/time.h?v=4.9#L154|CURRENT_TIME]]. | + | Inițializați câmpurile ''i_atime'', ''i_ctime'' și ''i_mtime'' ale inode-ului VFS la valoarea întoarsă de funcția [[https://elixir.bootlin.com/linux/v4.9/source/fs/inode.c#L2104|current_time]]. |
Va trebui să inițializați operațiile pentru inode-ul de tip director. Pentru aceasta urmați pașii: | Va trebui să inițializați operațiile pentru inode-ul de tip director. Pentru aceasta urmați pașii: | ||
- | - Verificați dacă este vorba de inode de tip director folosind macro-ul [[http://lxr.free-electrons.com/source/include/uapi/linux/stat.h?v=4.9#L21|S_ISDIR]]. | + | - Verificați dacă este vorba de inode de tip director folosind macro-ul [[https://elixir.bootlin.com/linux/v4.15/source/include/uapi/linux/stat.h#L23|S_ISDIR]]. |
- Pentru câmpurile, ''i_op'' și ''i_fop'', folosiți funcţii din kernel deja implementate: | - Pentru câmpurile, ''i_op'' și ''i_fop'', folosiți funcţii din kernel deja implementate: | ||
- | * pentru ''i_op'': [[http://lxr.free-electrons.com/source/fs/libfs.c?v=4.9#L226| simple_dir_inode_operations]]. | + | * pentru ''i_op'': [[https://elixir.bootlin.com/linux/v4.15/source/fs/libfs.c#L227| simple_dir_inode_operations]]. |
- | * pentru ''i_fop'': [[http://lxr.free-electrons.com/source/fs/libfs.c?v=4.9#L216|simple_dir_operations]] | + | * pentru ''i_fop'': [[https://elixir.bootlin.com/linux/v4.15/source/fs/libfs.c#L217|simple_dir_operations]] |
- | - Incrementați numărul de link-uri pentru director folosind funcția [[http://lxr.free-electrons.com/source/fs/inode.c?v=4.9#L336|inc_nlink]]. | + | - Incrementați numărul de link-uri pentru director folosind funcția [[https://elixir.bootlin.com/linux/v4.15/source/fs/inode.c#L330|inc_nlink]]. |
</note> | </note> | ||
Line 134: | Line 202: | ||
./test-myfs.sh | ./test-myfs.sh | ||
</code> | </code> | ||
- | Statisticile afişate pentru sistemul de fişiere sunt minimale, întrucât informaţiile sunt furnizate de către funcţia [[http://lxr.free-electrons.com/source/fs/libfs.c?v=4.9#L33 | simple_statfs]]. | + | Scriptul este copiat pe mașina virtuală folosind comanda ''make copy'' doar dacă este executabil: |
+ | <code bash> | ||
+ | student@workstation:~/so2/linux/tools/labs$ chmod +x skels/filesystems/myfs/test-myfs.sh | ||
+ | </code> | ||
+ | Statisticile afișate pentru sistemul de fișiere sunt minimale, întrucât informațiile sunt furnizate de către funcția [[https://elixir.bootlin.com/linux/v4.15/source/fs/libfs.c#L34 | simple_statfs]]. | ||
</note> | </note> | ||
Line 141: | Line 213: | ||
În continuare vom implementa bazele unui sistem de fișiere foarte simplu, denumit ''minfs'', cu suport pe disc. Vom folosi un disc din cadrul mașinii virtuale pe care îl vom formata și monta cu sistemul de fișiere ''minfs''. | În continuare vom implementa bazele unui sistem de fișiere foarte simplu, denumit ''minfs'', cu suport pe disc. Vom folosi un disc din cadrul mașinii virtuale pe care îl vom formata și monta cu sistemul de fișiere ''minfs''. | ||
- | Pentru aceasta vom accesa directorul ''minfs/'' din archiva de sarcini a laboratorului și vom folosi scheletul de cod ''minfs.c''. La fel ca la ''myfs'' nu vom implementa operații de lucru cu inode-urile, limitându-ne doar la operațiile de lucru cu superblocul și, așadar, la montare. Restul operațiilor le vom implementa în [[:so2:laboratoare:lab09|laboratorul următor]]. | + | Pentru aceasta vom accesa directorul ''minfs/kernel'' din scheletul laboratorului și vom folosi scheletul de cod ''minfs.c''. La fel ca la ''myfs'' nu vom implementa operații de lucru cu inode-urile, limitându-ne doar la operațiile de lucru cu superblocul și, așadar, la montare. Restul operațiilor le vom implementa în [[:so2:laboratoare:lab09|laboratorul următor]]. |
Urmăriți diagrama de mai jos pentru a clarifica rolul structurilor din cadrul sistemului de fișiere ''minfs''. | Urmăriți diagrama de mai jos pentru a clarifica rolul structurilor din cadrul sistemului de fișiere ''minfs''. | ||
Line 147: | Line 219: | ||
==== 5. [0.5p] Înregistrare și deînregistrare sistem de fișiere minfs ==== | ==== 5. [0.5p] Înregistrare și deînregistrare sistem de fișiere minfs ==== | ||
+ | |||
+ | <note important> | ||
+ | Înainte de rezolvarea exercițiului, este necesar să adaugăm un disc 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=1M count=100</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''). Noul argument pentru comanda ''qemu'' trebuie sa fie adăugat după cel corespunzător discului existent (''YOCTO_IMAGE''). | ||
+ | </note> | ||
Pentru înregistrarea și deînregistrarea sistemului de fișiere va trebui să completați, în fișierul ''minfs.c'', structura ''minfs_fs_type'' și funcția ''minfs_mount''. Urmăriți indicațiile marcate cu ''TODO 1''. | Pentru înregistrarea și deînregistrarea sistemului de fișiere va trebui să completați, în fișierul ''minfs.c'', structura ''minfs_fs_type'' și funcția ''minfs_mount''. Urmăriți indicațiile marcate cu ''TODO 1''. | ||
<note tip> | <note tip> | ||
- | În cadrul structurii de sistem de fișiere, pentru montare folosiți funcția ''minfs_mount'' prezentă în scheletul de cod. În cadrul acestei funcții apelați funcția aferentă pentru montarea unui sistem de fișiere cu suport de disc (vedeți secțiunea [[:so2:laboratoare:lab08#functiile_mount_kill_sb|Funcțiile mount, kill_sb]]; este vorba de funcția [[http://lxr.free-electrons.com/source/fs/super.c?v=4.9#L1020|mount_bdev]]). | + | În cadrul structurii de sistem de fișiere, pentru montare folosiți funcția ''minfs_mount'' prezentă în scheletul de cod. În cadrul acestei funcții apelați funcția aferentă pentru montarea unui sistem de fișiere cu suport de disc (vedeți secțiunea [[:so2:laboratoare:lab08#functiile_mount_kill_sb|Funcțiile mount, kill_sb]]; este vorba de funcția [[https://elixir.bootlin.com/linux/v4.15/source/fs/super.c#L1065|mount_bdev]]). |
- | Alegeți funcția cea mai potrivită pentru distrugerea superblocului (efectuată la demontare); țineți cont de faptul că este un sistem de fișiere cu suport pe disc. Este vorba de funcția [[http://lxr.free-electrons.com/source/fs/super.c?v=4.9#L1095|kill_block_super]]. | + | Alegeți funcția cea mai potrivită pentru distrugerea superblocului (efectuată la demontare); țineți cont de faptul că este un sistem de fișiere cu suport pe disc. Este vorba de funcția [[https://elixir.bootlin.com/linux/v4.15/source/fs/super.c#L1140|kill_block_super]]. |
Inițializați câmpul ''fs_flags'' al structurii ''minfs_fs_type'' cu valoarea corespunzătoare pentru un sistem de fișiere cu suport pe disc. Vedeți secțiunea [[:so2:laboratoare:lab08#inregistrarea_si_deinregistrarea_sistemelor_de_fisiere|Înregistrarea și deînregistrarea sistemelor de fișiere]]. | Inițializați câmpul ''fs_flags'' al structurii ''minfs_fs_type'' cu valoarea corespunzătoare pentru un sistem de fișiere cu suport pe disc. Vedeți secțiunea [[:so2:laboratoare:lab08#inregistrarea_si_deinregistrarea_sistemelor_de_fisiere|Înregistrarea și deînregistrarea sistemelor de fișiere]]. | ||
Line 160: | Line 236: | ||
</note> | </note> | ||
- | După completarea secțiunilor marcate cu ''TODO 1'', compilați modulul, copiați-l în directorul dedicat pentru mașina virtuală QEMU și porniți mașina virtuală. Încărcați modulul în kernel și apoi verificați prezența sistemului de fișiere ''minfs'' în cadrul fișierului ''/proc/filesystems''. | + | După completarea secțiunilor marcate cu ''TODO 1'', compilați modulul, copiați-l în mașina virtuală QEMU și porniți mașina virtuală. Încărcați modulul în kernel și apoi verificați prezența sistemului de fișiere ''minfs'' în cadrul fișierului ''/proc/filesystems''. |
- | Pentru a putea testa montarea sistemului de fișiere va trebui să formatăm discul cu structura acestuia. Formatarea necesită utilitarul de formatare ''mkfs.minfs'' compilabil din fișierul ''mk_minfs.c'' folosind comanda<code bash> | + | Pentru a putea testa montarea sistemului de fișiere va trebui să formatăm discul cu structura acestuia. Formatarea necesită utilitarul de formatare ''mkfs.minfs'', din directorul ''minfs/user''. Utilitarul se compilează automat la comanda <code bash>make build</code> și se copiază pe mașina virtuală la <code bash>make copy</code>. |
- | student@mjolnir:~so2/lab08-tasks/minfs$ make -f Makefile.format | + | |
- | </code> | + | |
- | În urma compilării rezultă executabilul ''mkfs.minfs'' care trebuie copiat, împreună cu modulul de kernel, în mașina virtuală. | + | |
- | După compilare, copiere și pornirea mașinii virtuale, formatăm discul ''/dev/sdb'' folosind utilitarul de formatare:<code> | + | După compilare, copiere și pornirea mașinii virtuale, formatăm discul ''/dev/vdb'' folosind utilitarul de formatare:<code> |
- | # ./mkfs.minfs /dev/sdb | + | # ./mkfs.minfs /dev/vdb |
</code> | </code> | ||
Line 176: | Line 249: | ||
# mkdir -p /mnt/minfs/ | # mkdir -p /mnt/minfs/ | ||
</code> și montăm sistemul de fișiere<code> | </code> și montăm sistemul de fișiere<code> | ||
- | # mount -t minfs /dev/sdb /mnt/minfs/ | + | # mount -t minfs /dev/vdb /mnt/minfs/ |
</code> | </code> | ||
Operaţia eşuează din cauză că inode-ul rădăcină nu este iniţializat. | Operaţia eşuează din cauză că inode-ul rădăcină nu este iniţializat. | ||
+ | |||
==== 6. [2.5] Completare superbloc minfs ==== | ==== 6. [2.5] Completare superbloc minfs ==== | ||
- | Pentru a putea monta sistemul de fișiere va trebui să completați superblocul (adică o structură de tip ''struct super_block'') în cadrul funcției ''minfs_fill_super''; este vorba de argumentul ''s'' al funcției. Structura de operații pe superbloc este definită: ''minfs_ops''. Urmăriți indicațiile marcate cu ''TODO 2''. Puteți urmări implementarea funcției [[http://lxr.free-electrons.com/source/fs/minix/inode.c?v=4.9#L158|minix_fill_super]]. | + | Pentru a putea monta sistemul de fișiere va trebui să completați superblocul (adică o structură de tip ''struct super_block'') în cadrul funcției ''minfs_fill_super''; este vorba de argumentul ''s'' al funcției. Structura de operații pe superbloc este definită: ''minfs_ops''. Urmăriți indicațiile marcate cu ''TODO 2''. Puteți urmări implementarea funcției [[https://elixir.bootlin.com/linux/v4.15/source/fs/minix/inode.c#L158|minix_fill_super]]. |
<note tip> | <note tip> | ||
Line 188: | Line 262: | ||
Pentu informații legate de lucrul cu buffere, parcurgeți secțiunea [[:so2:laboratoare:lab08#buffer_cache-ul|Buffer cache-ul]]. | Pentu informații legate de lucrul cu buffere, parcurgeți secțiunea [[:so2:laboratoare:lab08#buffer_cache-ul|Buffer cache-ul]]. | ||
- | Citiți primul bloc de pe disc (**blocul cu indexul 0**). Pentru a citi blocul, folosiți funcția [[http://lxr.free-electrons.com/source/include/linux/buffer_head.h?v=4.9#L298|sb_bread]]. Convertiți datele citite (câmpul ''b_data'' din ''struct buffer_head'') la structura de tip informație de superbloc de pe disc: ''struct minfs_super_block'', definită în fișierul cod sursă. | + | Citiți primul bloc de pe disc (**blocul cu indexul 0**). Pentru a citi blocul, folosiți funcția [[https://elixir.bootlin.com/linux/v4.15/source/include/linux/buffer_head.h#L304|sb_bread]]. Convertiți datele citite (câmpul ''b_data'' din ''struct buffer_head'') la structura de tip informație de superbloc de pe disc: ''struct minfs_super_block'', definită în fișierul cod sursă. |
Structura ''struct minfs_super_block'' deține informații specifice sistemului de fișiere, care nu se regăsesc în structura generică ''struct super_block'' (în cazul de față doar versiunea). Acele informații suplimentare (care se găsesc în ''struct minfs_super_block'' (disc) dar nu în ''struct super_block'' (VFS)) vor fi stocate în structura ''struct minfs_sb_info''. | Structura ''struct minfs_super_block'' deține informații specifice sistemului de fișiere, care nu se regăsesc în structura generică ''struct super_block'' (în cazul de față doar versiunea). Acele informații suplimentare (care se găsesc în ''struct minfs_super_block'' (disc) dar nu în ''struct super_block'' (VFS)) vor fi stocate în structura ''struct minfs_sb_info''. | ||
Line 198: | Line 272: | ||
==== 7. [1.5p] Creare și distrugere inode-uri minfs ==== | ==== 7. [1.5p] Creare și distrugere inode-uri minfs ==== | ||
- | Pentru montare avem nevoie de inițializarea inode-ului rădăcină, iar pentru inițializarea inode-ului rădăcină avem nevoie de implementarea funcțiilor de lucru cu inode-uri. Adică trebuie să implementați funcțiile ''minfs_alloc_inode'' și ''minfs_destroy_inode''. Urmăriții indicațiile marcate cu ''TODO 3''. Puteți folosi ca model funcțiile [[http://lxr.free-electrons.com/source/fs/minix/inode.c?v=4.9#L62|minix_alloc_inode]] și [[http://lxr.free-electrons.com/source/fs/minix/inode.c?v=4.9#L77|minix_destroy_inode]]. | + | Pentru montare avem nevoie de inițializarea inode-ului rădăcină, iar pentru inițializarea inode-ului rădăcină avem nevoie de implementarea funcțiilor de lucru cu inode-uri. Adică trebuie să implementați funcțiile ''minfs_alloc_inode'' și ''minfs_destroy_inode''. Urmăriții indicațiile marcate cu ''TODO 3''. Puteți folosi ca model funcțiile [[https://elixir.bootlin.com/linux/v4.15/source/fs/minix/inode.c#L62|minix_alloc_inode]] și [[https://elixir.bootlin.com/linux/v4.15/source/fs/minix/inode.c#L77|minix_destroy_inode]]. |
În implementare urmăriți macro-urile și structurile din fișierul ''minfs.h''. | În implementare urmăriți macro-urile și structurile din fișierul ''minfs.h''. | ||
<note tip> | <note tip> | ||
- | Pentru alocarea/dezalocarea de memorie în cadrul funcțiilor ''minfs_alloc_inode'' și ''minfs_destroy_inode'' recomandăm folosirea [[http://lxr.free-electrons.com/source/include/linux/slab.h?v=4.9#L629|kzalloc]] și [[http://lxr.free-electrons.com/source/mm/slab.c?v=4.9#L3804|kfree]]. | + | Pentru alocarea/dezalocarea de memorie în cadrul funcțiilor ''minfs_alloc_inode'' și ''minfs_destroy_inode'' recomandăm folosirea [[https://elixir.bootlin.com/linux/v4.15/source/include/linux/slab.h#L682|kzalloc]] și [[https://elixir.bootlin.com/linux/v4.15/source/mm/slab.c#L3780|kfree]]. |
În funcția ''minfs_alloc_inode'' alocați inode-uri de tip ''minfs_inode_info'', dar returnați doar structuri de tip ''struct inode'', adică cele date de câmpul ''vfs_inode''. | În funcția ''minfs_alloc_inode'' alocați inode-uri de tip ''minfs_inode_info'', dar returnați doar structuri de tip ''struct inode'', adică cele date de câmpul ''vfs_inode''. | ||
- | În funcția de ''minfs_alloc_inode'' apelați funcția [[http://lxr.free-electrons.com/source/fs/inode.c?v=4.9#L359|inode_init_once]] pentru inițializarea inode-ului. | + | În funcția de ''minfs_alloc_inode'' apelați funcția [[https://elixir.bootlin.com/linux/v4.15/source/fs/inode.c#L365|inode_init_once]] pentru inițializarea inode-ului. |
- | În funcția ''destroy_inode''. să puteți accesa structura de tip ''struct minfs_inode_info'' folosiți macro-ul [[http://lxr.free-electrons.com/source/include/linux/kernel.h?v=4.9#L828|container_of]]. | + | În funcția ''destroy_inode''. să puteți accesa structura de tip ''struct minfs_inode_info'' folosiți macro-ul [[https://elixir.bootlin.com/linux/v4.15/source/include/linux/kernel.h#L922|container_of]]. |
</note> | </note> | ||
Line 218: | Line 292: | ||
Inițializarea inode-ului rădăcină este necesară pentru montarea sistemului de fișiere. Pentru aceasta va trebui să completați structura ''minfs_ops'' cu funcțiile ''minfs_alloc_inode'' și ''minfs_destroy_inode'' și să completați funcția ''minfs_iget''. Funcția ''minfs_iget'' este funcția apelată pentru alocarea unui inode de tip VFS (adică ''struct inode'') și completarea acestuia cu informații specifice inode-ului ''minfs'' de pe disc (adică ''struct minfs_inode''). Urmăriții indicațiile marcate cu ''TODO 4''. | Inițializarea inode-ului rădăcină este necesară pentru montarea sistemului de fișiere. Pentru aceasta va trebui să completați structura ''minfs_ops'' cu funcțiile ''minfs_alloc_inode'' și ''minfs_destroy_inode'' și să completați funcția ''minfs_iget''. Funcția ''minfs_iget'' este funcția apelată pentru alocarea unui inode de tip VFS (adică ''struct inode'') și completarea acestuia cu informații specifice inode-ului ''minfs'' de pe disc (adică ''struct minfs_inode''). Urmăriții indicațiile marcate cu ''TODO 4''. | ||
- | Completați câmpurile ''alloc_inode'' și ''destroy_inode'' ale structurii [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=4.9#L1786 | struct super_operations]] cu funcțiile implementate la pasul anterior. | + | Completați câmpurile ''alloc_inode'' și ''destroy_inode'' ale structurii [[https://elixir.bootlin.com/linux/v4.15/source/include/linux/fs.h#L1803 | struct super_operations]] cu funcțiile implementate la pasul anterior. |
Informațiile despre inode-ul rădăcină se găsesc în al doilea bloc de pe disc (**inode-ul cu indexul 1**). Realizați, în cadrul funcției ''minfs_iget'' citirea inode-ului rădăcină de tip ''minfs'' de pe disc (''struct minfs_inode'') și completarea inode-ului VFS (''struct inode''). | Informațiile despre inode-ul rădăcină se găsesc în al doilea bloc de pe disc (**inode-ul cu indexul 1**). Realizați, în cadrul funcției ''minfs_iget'' citirea inode-ului rădăcină de tip ''minfs'' de pe disc (''struct minfs_inode'') și completarea inode-ului VFS (''struct inode''). | ||
Line 225: | Line 299: | ||
<note tip> | <note tip> | ||
- | Pentru a citi un bloc folosiți funcția [[http://lxr.free-electrons.com/source/include/linux/buffer_head.h?v=4.9#L298|sb_bread]]. Convertiți datele citite (câmpul ''b_data'' al structurii ''struct buffer_head'') la inode-ul de tip ''minfs'' de pe disc (''struct minfs_inode''). | + | Pentru implementarea funcției ''minfs_iget'' urmăriți implementarea funcției [[https://elixir.bootlin.com/linux/v4.15/source/fs/minix/inode.c#L460|V1_minix_iget]]. |
- | Câmpurile ''i_uid'', ''i_gid'', ''i_mode'', ''i_size'' le completați în cadrul inode-ului VFS cu valorile din inode-ul de pe disc. Pentru initializarea câmpurilor ''i_uid'' și ''i_gid'', folosiți funcțiile ''i_uid_write'', și, respectiv, ''i_gid_write''. | + | Pentru a citi un bloc folosiți funcția [[https://elixir.bootlin.com/linux/v4.15/source/include/linux/buffer_head.h#L304|sb_bread]]. Convertiți datele citite (câmpul ''b_data'' al structurii ''struct buffer_head'') la inode-ul de tip ''minfs'' de pe disc (''struct minfs_inode''). |
- | Inițializați câmpurile ''atime'', ''ctime'' și ''mtime'' ale inode-ului VFS la valoarea [[http://lxr.free-electrons.com/source/include/linux/time.h?v=4.9#L154|CURRENT_TIME]]. | + | Câmpurile ''i_uid'', ''i_gid'', ''i_mode'', ''i_size'' le completați în cadrul inode-ului VFS cu valorile din inode-ul de pe disc. Pentru initializarea câmpurilor ''i_uid'' și ''i_gid'', folosiți funcțiile [[https://elixir.bootlin.com/linux/v4.15/source/include/linux/fs.h#L1461|i_uid_write]], și, respectiv, [[https://elixir.bootlin.com/linux/v4.15/source/include/linux/fs.h#L1466|i_gid_write]]. |
+ | |||
+ | Inițializați câmpurile ''i_atime'', ''i_ctime'' și ''i_mtime'' ale inode-ului VFS la valoarea întoarsă de funcția [[https://elixir.bootlin.com/linux/v4.15/source/fs/inode.c#L2107|current_time]]. | ||
Va trebui să inițializați operațiile pentru inode-ul de tip director. Pentru aceasta urmați pașii: | Va trebui să inițializați operațiile pentru inode-ul de tip director. Pentru aceasta urmați pașii: | ||
- | - Verificați dacă este vorba de inode de tip director folosind macro-ul [[http://lxr.free-electrons.com/source/include/uapi/linux/stat.h?v=4.9#L21|S_ISDIR]]. | + | - Verificați dacă este vorba de inode de tip director folosind macro-ul [[https://elixir.bootlin.com/linux/v4.15/source/include/uapi/linux/stat.h#L23|S_ISDIR]]. |
- Pentru câmpurile, ''i_op'' și ''i_fop'', folosiți funcții din kernel deja implementate: | - Pentru câmpurile, ''i_op'' și ''i_fop'', folosiți funcții din kernel deja implementate: | ||
- | * pentru ''i_op'': [[http://lxr.free-electrons.com/source/fs/libfs.c?v=4.9#L226| simple_dir_inode_operations]]. | + | * pentru ''i_op'': [[https://elixir.bootlin.com/linux/v4.15/source/fs/libfs.c#L227| simple_dir_inode_operations]]. |
- | * pentru ''i_fop'': [[http://lxr.free-electrons.com/source/fs/libfs.c?v=4.9#L216|simple_dir_operations]] | + | * pentru ''i_fop'': [[https://elixir.bootlin.com/linux/v4.15/source/fs/libfs.c#L217|simple_dir_operations]] |
- | - Incrementați numărul de link-uri pentru director folosind funcția [[http://lxr.free-electrons.com/source/fs/inode.c?v=4.9#L336|inc_nlink]]. | + | - Incrementați numărul de link-uri pentru director folosind funcția [[https://elixir.bootlin.com/linux/v4.15/source/fs/inode.c#L330|inc_nlink]]. |
</note> | </note> | ||
Line 253: | Line 329: | ||
Alternativ, pentru testarea întregii funcționalității puteți folosi scriptul ''test-minfs.sh'':<code> | Alternativ, pentru testarea întregii funcționalității puteți folosi scriptul ''test-minfs.sh'':<code> | ||
# ./test-minfs.sh | # ./test-minfs.sh | ||
+ | </code> | ||
+ | Scriptul este copiat pe mașina virtuală la rularea comenzii ''make copy'' doar dacă este executabil. | ||
+ | <code bash> | ||
+ | student@workstation:~/so2/linux/tools/labs$ chmod +x skels/filesystems/minfs/user/test-minfs.sh | ||
</code> | </code> | ||
</note> | </note> |