This shows you the differences between two versions of the page.
so2:laboratoare:lab09:exercitii [2016/04/20 13:55] razvan.deaconescu [4. [1.5p] Operația lookup (minfs)] |
so2:laboratoare:lab09:exercitii [2019/04/16 23:19] (current) ionel.ghita [1. [2p] Operații pentru lucrul cu directoare (myfs)] |
||
---|---|---|---|
Line 1: | Line 1: | ||
====== Laborator 9: Exerciții ====== | ====== Laborator 9: Exerciții ====== | ||
- | Pentru desfășurarea laboratorului pornim de la [[http://elf.cs.pub.ro/so2/res/laboratoare/lab09-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/lab09-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 lab09-tasks.zip | + | |
- | student@mjolnir:~/so2$ tree lab09-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 ''lab09-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 fizic ș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-vm/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-vm/'' mașina virtuală QEMU folosind comanda<code bash> | + | <code bash> |
- | student@mjolnir:~/so2/qemu-vm$ 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-vm/''. | + | |
- | - În al treilea tab de terminal pornim 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> | ||
+ | |||
</note> | </note> | ||
+ | |||
+ | ===== Exerciții ===== | ||
<note important> | <note important> | ||
- | Să parcurgeți întreg enunțul unui exercițiu înainte de a vă apuca de rezolvarea sa. | + | Î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. |
- | Atunci când primiți un val de erori și warning-uri, urmăriți **prima** eroare/warning și rezolvați-o pe aceea înainte de a vă apuca de celelalte erori. | + | În acest laborator, vom continua implementarea sistemelor de fișiere începută în laboratorul trecut. |
+ | Pentru aceasta, vom genera scheletul de laborator folosind comanda <code bash>TODO=5 LABS=filesystems make skels</code> și vom porni implementarea începând de la ''TODO 5''. | ||
</note> | </note> | ||
Line 39: | Line 97: | ||
Pentru exercițiile din continuare vom folosi sistemul de fișiere ''myfs'' a cărui dezvoltare am început-o [[:so2:laboratoare:lab09|laboratorul trecut]]. Ne-am oprit la montarea sistemului de fișiere iar acum vom continua cu operațiile pe directoare și fișiere obișnuite. La finalul acestor exerciții vom putea crea, modifica și șterge directoare și fișiere obișnuite. | Pentru exercițiile din continuare vom folosi sistemul de fișiere ''myfs'' a cărui dezvoltare am început-o [[:so2:laboratoare:lab09|laboratorul trecut]]. Ne-am oprit la montarea sistemului de fișiere iar acum vom continua cu operațiile pe directoare și fișiere obișnuite. La finalul acestor exerciții vom putea crea, modifica și șterge directoare și fișiere obișnuite. | ||
- | Vom folosi preponderent structurile VFS [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=3.13#L519|inode]] și [[http://lxr.free-electrons.com/source/include/linux/dcache.h?v=3.13#L108|dentry]]. Structura [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=3.13#L519|inode]] definește un fișier (de orice tip: obișnuit, director, link), în vreme ce structura [[http://lxr.free-electrons.com/source/include/linux/dcache.h?v=3.13#L108|dentry]] definește un nume, adică o intrare într-un director (//directory entry//). | + | Vom folosi preponderent structurile VFS [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=4.9#L604|inode]] și [[http://lxr.free-electrons.com/source/include/linux/dcache.h?v=4.9#L83|dentry]]. Structura [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=4.9#L604|inode]] definește un fișier (de orice tip: obișnuit, director, link), în vreme ce structura [[http://lxr.free-electrons.com/source/include/linux/dcache.h?v=4.9#L83|dentry]] definește un nume, adică o intrare într-un director (//directory entry//). |
- | Pentru aceasta vom accesa subdirectorul ''myfs/'' din [[http://elf.cs.pub.ro/so2/res/laboratoare/lab09-tasks.zip|arhiva de sarcini a laboratorului]]. Scheletul de cod conține rezolvarea laboratorului trecut; vom porni de la aceasta. Ca și în laboratorul trecut, vom folosi ca punct de plecare [[http://lxr.free-electrons.com/source/fs/ramfs?v=3.13|implementarea sistemului de fișiere ramfs]]. | + | Pentru aceasta vom accesa subdirectorul ''myfs/'' din scheletul laboratorului. Scheletul de cod generat anterior conține rezolvarea laboratorului trecut; vom porni de la aceasta. Ca și în laboratorul trecut, vom folosi ca punct de plecare [[http://lxr.free-electrons.com/source/fs/ramfs?v=4.9|implementarea sistemului de fișiere ramfs]]. |
==== 1. [2p] Operații pentru lucrul cu directoare (myfs) ==== | ==== 1. [2p] Operații pentru lucrul cu directoare (myfs) ==== | ||
Line 49: | Line 107: | ||
La finalul acestui exercițiu vom putea crea și șterge intrări în sistemul de fișiere. Nu vom putea citi și scrie în fișiere obișnuite; vom face acest lucru la exercițiul următor. | La finalul acestui exercițiu vom putea crea și șterge intrări în sistemul de fișiere. Nu vom putea citi și scrie în fișiere obișnuite; vom face acest lucru la exercițiul următor. | ||
- | Urmăriți indicațiile marcate cu ''TODO 1'' care vă vor ghida pașii pe care trebuie să îi faceți. | + | Urmăriți indicațiile marcate cu ''TODO 5'' care vă vor ghida pașii pe care trebuie să îi faceți. |
Va trebui să precizați următoarele operații pentru directoare: | Va trebui să precizați următoarele operații pentru directoare: | ||
Line 60: | Line 118: | ||
* redenumire (''rename'') | * redenumire (''rename'') | ||
- | Pentru aceasta, definiți structura ''myfs_dir_inode_operations'' în cod, unde este marcat ''TODO 1&2: Fill operations structures.'' Pentru început definiți **doar** structura ''myfs_dir_inode_operations''; structurile ''myfs_file_inode_operations'', ''myfs_file_operations'' și ''myfs_aops'' le veți defini la [[#p_operatii_pentru_lucrul_cu_fisiere_myfs|exercițiul următor]]. | + | Pentru aceasta, definiți structura ''myfs_dir_inode_operations'' în cod, unde este marcat cu ''TODO 5''. Pentru început definiți **doar** structura ''myfs_dir_inode_operations''; structurile ''myfs_file_inode_operations'', ''myfs_file_operations'' și ''myfs_aops'' le veți defini la [[#p_operatii_pentru_lucrul_cu_fisiere_myfs|exercițiul următor]]. |
<note tip> | <note tip> | ||
Parcurgeți secțiunea [[:so2:laboratoare:lab09#operatii_asupra_inode-urilor_de_tip_director|Operații asupra inode-urilor de tip director]]. | Parcurgeți secțiunea [[:so2:laboratoare:lab09#operatii_asupra_inode-urilor_de_tip_director|Operații asupra inode-urilor de tip director]]. | ||
- | Ca model urmăriți structura [[http://lxr.free-electrons.com/source/fs/ramfs/inode.c?v=3.13#L141|ramfs_dir_inode_operations]]. | + | Ca model urmăriți structura [[http://lxr.free-electrons.com/source/fs/ramfs/inode.c?v=4.9#L140|ramfs_dir_inode_operations]]. |
</note> | </note> | ||
- | Implementați operațiile ''mkdir'' și ''create'' pe inode-urile director în cadrul funcțiilor ''myfs_mkdir()'' și ''myfs_create''. Aceste operații vă vor permite, respectiv, crearea de directoare și de fișiere în sistemul de fișiere. | + | Implementați operațiile ''mkdir'', ''mknod'' și ''create'' pe inode-urile director în cadrul funcțiilor ''myfs_mkdir'', ''myfs_mknod'' și ''myfs_create''. Aceste operații vă vor permite, respectiv, crearea de directoare și de fișiere în sistemul de fișiere. |
<note tip> | <note tip> | ||
Line 75: | Line 133: | ||
Pentru citire și alocare de inode folosiți funcția ''myfs_get_inode'', deja implementată. | Pentru citire și alocare de inode folosiți funcția ''myfs_get_inode'', deja implementată. | ||
- | Ca model urmăriți implementările din [[http://lxr.free-electrons.com/source/fs/ramfs/?v=3.7|sistemul de fișiere ramfs]]: | + | Ca model urmăriți implementările din [[http://lxr.free-electrons.com/source/fs/ramfs/?v=4.9|sistemul de fișiere ramfs]]: |
- | * [[http://lxr.free-electrons.com/source/fs/ramfs/inode.c?v=3.13#L90|ramfs_mknod]] | + | * [[http://lxr.free-electrons.com/source/fs/ramfs/inode.c?v=4.9#L94|ramfs_mknod]] |
- | * [[http://lxr.free-electrons.com/source/fs/ramfs/inode.c?v=3.13#L109|ramfs_mkdir]] | + | * [[http://lxr.free-electrons.com/source/fs/ramfs/inode.c?v=4.9#L108|ramfs_mkdir]] |
- | * [[http://lxr.free-electrons.com/source/fs/ramfs/inode.c?v=3.13#L117|ramfs_create]] | + | * [[http://lxr.free-electrons.com/source/fs/ramfs/inode.c?v=4.9#L116|ramfs_create]] |
</note> | </note> | ||
Line 85: | Line 143: | ||
În cadrul funcției ''myfs_get_inode'' inițializați câmpurile de operații ale inode-urilor de tip director: | În cadrul funcției ''myfs_get_inode'' inițializați câmpurile de operații ale inode-urilor de tip director: | ||
* ''i_op'' inițializat la adresa structurii ''myfs_dir_inode_operations''; | * ''i_op'' inițializat la adresa structurii ''myfs_dir_inode_operations''; | ||
- | * ''i_fop'' inițializat la adresa structurii [[http://lxr.free-electrons.com/source/fs/libfs.c?v=3.13#L192|simple_dir_operations]], predefinită în VFS. | + | * ''i_fop'' inițializat la adresa structurii [[http://lxr.free-electrons.com/source/fs/libfs.c?v=4.9#L216|simple_dir_operations]], predefinită în VFS. |
<note tip> | <note tip> | ||
- | ''i_op'' este un pointer către o structură de tipul [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=3.13#L1552|struct inode_operations]] cu operații care au de-a face cu inode-ul, adică, pentru un director, crearea unei noi intrări, listarea intrărilor, ștergerea de intrări. | + | ''i_op'' este un pointer către o structură de tipul [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=4.9#L1736|struct inode_operations]] cu operații care au de-a face cu inode-ul, adică, pentru un director, crearea unei noi intrări, listarea intrărilor, ștergerea de intrări. |
- | ''i_fop'' este un pointer către o structură de tipul [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=3.13#L1521|struct file_operations]] cu operații care au de-a face cu structura file aferentă inode-lui, adică operații de tipul read, write și lseek. | + | ''i_fop'' este un pointer către o structură de tipul [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=4.9#L1696|struct file_operations]] cu operații care au de-a face cu structura file aferentă inode-lui, adică operații de tipul read, write și lseek. |
</note> | </note> | ||
Line 125: | Line 183: | ||
</code> | </code> | ||
+ | Scriptul este copiat pe mașina virtuală folosind comanda ''make copy'' doar dacă este executabil. | ||
Dacă implementarea este validă, nu vor fi afișate mesaje de eroare în urma rulării scriptului de mai sus. | Dacă implementarea este validă, nu vor fi afișate mesaje de eroare în urma rulării scriptului de mai sus. | ||
Line 130: | Line 189: | ||
Dorim să implementăm operațiile pentru lucrul cu fișiere, adică modificarea conținutului unui fișier: scrierea într-un fișier, modificarea conținutului, trunchierea unui fișier. | Dorim să implementăm operațiile pentru lucrul cu fișiere, adică modificarea conținutului unui fișier: scrierea într-un fișier, modificarea conținutului, trunchierea unui fișier. | ||
- | Pentru aceasta veți preciza operațiile descrise în cadrul structurilor [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=3.13#L1552|struct inode_operations]], [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=3.13#L1521|struct file_operations]] și [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=3.13#L347|struct address_space_operations]] pentru fișier. | + | Pentru aceasta veți preciza operațiile descrise în cadrul structurilor [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=4.9#L1736|struct inode_operations]], [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=4.9#L1696|struct file_operations]] și [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=4.9#L371|struct address_space_operations]] pentru fișier. |
- | Urmăriți indicațiile marcate cu ''TODO 2'' care vă vor ghida pașii pe care trebuie să îi faceți. | + | Urmăriți indicațiile marcate cu ''TODO 6'' care vă vor ghida pașii pe care trebuie să îi faceți. |
- | Începeți cu definirea structurilor ''myfs_file_inode_operations'' și ''myfs_file_operations''. Definirea structurilor o faceți mai jos în cod, unde este marcat ''TODO 1 & 2: Fill operations structures.'' | + | Începeți cu definirea structurilor ''myfs_file_inode_operations'' și ''myfs_file_operations''. |
<note tip> | <note tip> | ||
Line 141: | Line 200: | ||
Folosiți funcțiile generice oferite de VFS. | Folosiți funcțiile generice oferite de VFS. | ||
- | Exemplu de implementare este [[http://lxr.free-electrons.com/source/fs/ramfs/?v=3.13|sistemul de fișiere ramfs]]. Urmăriți implementarea structurilor [[http://lxr.free-electrons.com/source/fs/ramfs/file-mmu.c?v=3.13#L52|ramfs_file_inode_operations]] și [[http://lxr.free-electrons.com/source/fs/ramfs/file-mmu.c?v=3.13#L40|ramfs_file_operations]]. | + | Exemplu de implementare este [[http://lxr.free-electrons.com/source/fs/ramfs/?v=4.9|sistemul de fișiere ramfs]]. Urmăriți implementarea structurilor [[http://lxr.free-electrons.com/source/fs/ramfs/file-mmu.c?v=4.9#L52|ramfs_file_inode_operations]] și [[http://lxr.free-electrons.com/source/fs/ramfs/file-mmu.c?v=4.9#L41|ramfs_file_operations]]. |
</note> | </note> | ||
Line 155: | Line 214: | ||
Folosiți funcțiile generice oferite de VFS. | Folosiți funcțiile generice oferite de VFS. | ||
- | Exemplu de implementare este [[http://lxr.free-electrons.com/source/fs/ramfs/?v=3.13|sistemul de fișiere ramfs]]: structura [[http://lxr.free-electrons.com/source/fs/ramfs/file-mmu.c?v=3.13#L33|ramfs_aops]]. | + | Exemplu de implementare este [[http://lxr.free-electrons.com/source/fs/ramfs/?v=4.9|sistemul de fișiere ramfs]]: structura [[http://lxr.free-electrons.com/source/fs/ramfs/inode.c?v=4.9#L46|ramfs_aops]]. |
Nu este nevoie să definiți funcție de tipul ''set_page_dirty''. | Nu este nevoie să definiți funcție de tipul ''set_page_dirty''. | ||
</note> | </note> | ||
- | Inițializați câmpul ''%%i_mapping->a_ops%%'' al structurii [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=3.13#L519|inode]] la ''myfs_aops''. | + | Inițializați câmpul ''%%i_mapping->a_ops%%'' al structurii [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=4.9#L604|inode]] la ''myfs_aops''. |
=== Testare === | === Testare === | ||
Line 179: | Line 238: | ||
Pentru exercițiile din continuare vom folosi sistemul de fișiere ''minfs'' a cărui dezvoltare am început-o [[:so2:laboratoare:lab09|laboratorul trecut]]. Este vorba de un sistem de fișiere cu suport pe disc. Ne-am oprit la montarea sistemului de fișiere iar acum vom continua cu operațiile pe directoare și fișiere obișnuite. La finalul acestor exerciții vom putea crea, și șterge intrări în sistemul de fișiere. | Pentru exercițiile din continuare vom folosi sistemul de fișiere ''minfs'' a cărui dezvoltare am început-o [[:so2:laboratoare:lab09|laboratorul trecut]]. Este vorba de un sistem de fișiere cu suport pe disc. Ne-am oprit la montarea sistemului de fișiere iar acum vom continua cu operațiile pe directoare și fișiere obișnuite. La finalul acestor exerciții vom putea crea, și șterge intrări în sistemul de fișiere. | ||
- | Vom folosi preponderent structurile VFS [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=3.13#L519|inode]] și [[http://lxr.free-electrons.com/source/include/linux/dcache.h?v=3.13#L108|dentry]]. Structura [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=3.13#L519|inode]] definește un fișier (de orice tip: obișnuit, director, link), în vreme ce structura [[http://lxr.free-electrons.com/source/include/linux/dcache.h?v=3.13#L108|dentry]] definește un nume, adică o intrare într-un director (//directory entry//). | + | Vom folosi preponderent structurile VFS [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=4.9#L604|inode]] și [[http://lxr.free-electrons.com/source/include/linux/dcache.h?v=4.9#L83|dentry]]. Structura [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=4.9#L604|inode]] definește un fișier (de orice tip: obișnuit, director, link), în vreme ce structura [[http://lxr.free-electrons.com/source/include/linux/dcache.h?v=4.9#L83|dentry]] definește un nume, adică o intrare într-un director (//directory entry//). |
- | Pentru aceasta vom accesa subdirectorul ''minfs/'' din [[http://elf.cs.pub.ro/so2/res/laboratoare/lab09-tasks.zip|arhiva de sarcini a laboratorului]]. Scheletul de cod conține rezolvarea laboratorului trecut; vom porni de la aceasta. Ca și în laboratorul trecut, vom folosi ca punct de plecare [[http://lxr.free-electrons.com/source/fs/minix?v=3.13|implementarea sistemului de fișiere minix]]. | + | Pentru aceasta vom accesa subdirectorul ''minfs/kernel'' din scheletul laboratorului. Scheletul de cod generat conține rezolvarea laboratorului trecut; vom porni de la aceasta. Ca și în laboratorul trecut, vom folosi ca punct de plecare [[http://lxr.free-electrons.com/source/fs/minix?v=4.9|implementarea sistemului de fișiere minix]]. |
+ | |||
+ | Vom folosi utilitarul de formatare ''mkfs.minfs'' din directorul ''minfs/user'' care este compilat automat automat la rularea comenzii ''make build'' și copiat pe mașina virtuală la ''make copy''. | ||
- | Vom folosi utilitarul de formatare ''mkfs.minfs'' compilabil folosind fișierul Makefile aferent cu ajutorul comenzii<code bash> | ||
- | make -f Makefile.format | ||
- | </code> | ||
Utilitarul de formatare se aplică asupra unui disc al mașinii virtuale cu o comandă de forma<code> | Utilitarul de formatare se aplică asupra unui disc al mașinii virtuale cu o comandă de forma<code> | ||
- | # ./mkfs.minfs /dev/sdb | + | # ./mkfs.minfs /dev/vdb |
</code> | </code> | ||
În urma formatării, discul capătă o structură precum cea din diagrama de mai jos: | În urma formatării, discul capătă o structură precum cea din diagrama de mai jos: | ||
Line 193: | Line 251: | ||
Așa cum reiese din diagramă, ''minfs'' este un sistem de fișiere minimalist. ''minfs'' conține maxim 32 de inode-uri, fiecare inode având alocat un singur bloc; adică dimensiunea intrărilor este limitată la dimensiunea blocului. Superblocul conține o mască (''imap'') de 32 biți, fiecare bit indicând utilizarea inode-ului respectiv. | Așa cum reiese din diagramă, ''minfs'' este un sistem de fișiere minimalist. ''minfs'' conține maxim 32 de inode-uri, fiecare inode având alocat un singur bloc; adică dimensiunea intrărilor este limitată la dimensiunea blocului. Superblocul conține o mască (''imap'') de 32 biți, fiecare bit indicând utilizarea inode-ului respectiv. | ||
- | |||
- | Rezolvarea exercițiilor este grupată în două seturi de pași. Pentru primul set de pași (exercițiile 3 și 4), vom folosi subdirectorul ''minfs/stage1/'', iar pentru al doilea set de pași (exercițiul 5), vom folosi subdirectorul ''minfs/stage2/''. | ||
<note important> | <note important> | ||
- | Înainte de a începe să lucrați parcurgeți fișierul header ''minfs/stage1/minfs.h''. În acest fișier se găsesc structurile și macro-urile care vor fi folosite în cadrul exercițiilor. Aceste structuri și macro-uri definesc sistemul de fișiere, așa cum este descris în diagrama de mai sus. | + | Înainte de a începe să lucrați parcurgeți fișierul header ''minfs/kernel/minfs.h''. În acest fișier se găsesc structurile și macro-urile care vor fi folosite în cadrul exercițiilor. Aceste structuri și macro-uri definesc sistemul de fișiere, așa cum este descris în diagrama de mai sus. |
</note> | </note> | ||
Line 204: | Line 260: | ||
În primă fază ne dorim să putem lista conținutul directorului rădăcină. Pentru aceasta trebuie să putem citi intrările din directorul rădăcină, adică să implementăm operația ''iterate''. Operația ''iterate'' este un câmp în cadrul structurii ''minfs_dir_operations'' (de tipul [[|file_operations]] și este implmenentată de funcția ''minfs_readdir''. Această funcție trebuie să o implementăm. | În primă fază ne dorim să putem lista conținutul directorului rădăcină. Pentru aceasta trebuie să putem citi intrările din directorul rădăcină, adică să implementăm operația ''iterate''. Operația ''iterate'' este un câmp în cadrul structurii ''minfs_dir_operations'' (de tipul [[|file_operations]] și este implmenentată de funcția ''minfs_readdir''. Această funcție trebuie să o implementăm. | ||
- | Urmăriți indicațiile marcate cu ''TODO 3'' care vă vor ghida pașii pe care trebuie să îi faceți. | + | Urmăriți indicațiile marcate cu ''TODO 5'' care vă vor ghida pașii pe care trebuie să îi faceți. |
<note tip> | <note tip> | ||
Parcurgeți secțiunea [[:so2:laboratoare:lab09#operatii_asupra_inode-urilor_de_tip_director|Operații asupra inode-urilor de tip director]]. | Parcurgeți secțiunea [[:so2:laboratoare:lab09#operatii_asupra_inode-urilor_de_tip_director|Operații asupra inode-urilor de tip director]]. | ||
- | Ca puncte de plecare, urmăriți funcția [[http://lxr.free-electrons.com/source/fs/minix/dir.c?v=3.13#L85|minix_readdir]]. Funcția este destul de complicată, dar vă oferă o perspectivă a pașilor pe care îi aveți de făcut. | + | Ca puncte de plecare, urmăriți funcția [[http://lxr.free-electrons.com/source/fs/minix/dir.c?v=4.9#L80|minix_readdir]]. Funcția este destul de complicată, dar vă oferă o perspectivă a pașilor pe care îi aveți de făcut. |
Urmăriți în ''minfs.c'' și ''minfs.h'' definițiile structurilor ''struct minfs_inode_info'', ''struct minfs_inode'' și ''struct minfs_dir_entry''. Le veți folosi pe parcursul implementării funcției ''minfs_readdir''. | Urmăriți în ''minfs.c'' și ''minfs.h'' definițiile structurilor ''struct minfs_inode_info'', ''struct minfs_inode'' și ''struct minfs_dir_entry''. Le veți folosi pe parcursul implementării funcției ''minfs_readdir''. | ||
Line 218: | Line 274: | ||
<note tip> | <note tip> | ||
- | Pentru obținerea structurii ''struct minfs_inode_info'' folosiți [[http://lxr.free-electrons.com/source/scripts/kconfig/list.h?v=3.13#L33|list_entry]] sau [[http://lxr.free-electrons.com/source/scripts/kconfig/list.h?v=3.13#L11|container_of]]. | + | Pentru obținerea structurii ''struct minfs_inode_info'' folosiți [[http://lxr.free-electrons.com/source/include/linux/list.h?v=4.9#L345|list_entry]] sau [[http://lxr.free-electrons.com/source/tools/include/linux/kernel.h?v=4.9#L18|container_of]]. |
</note> | </note> | ||
- | Folosiți [[http://lxr.free-electrons.com/source/include/linux/buffer_head.h?v=3.13#L297|sb_bread]] pentru citirea blocului de date al directorului. | + | Folosiți [[http://lxr.free-electrons.com/source/include/linux/buffer_head.h?v=4.9#L298|sb_bread]] pentru citirea blocului de date al directorului. |
<note tip> | <note tip> | ||
Blocul de date al directorului este indicat de câmpul ''data_block'' al structurii ''struct minfs_inode_info'' aferentă directorului. | Blocul de date al directorului este indicat de câmpul ''data_block'' al structurii ''struct minfs_inode_info'' aferentă directorului. | ||
- | Datele din bloc sunt referite de câmpul ''b_data'' al structurii [[http://lxr.free-electrons.com/source/include/linux/buffer_head.h?v=3.13#L53|struct buffer_head]] (codul uzual va fi ''%%bh->b_data%%''). Acest bloc (fiind blocul de date al unui director) conține un vector de cel mult ''MINFS_NUM_ENTRIES'' intrări de tipul ''struct minfs_dir_entry'' (intrări de tip director (//dentry//-uri) specifice ''minfs''). Folosiți casting la ''struct minfs_dir_entry *'' pentru a lucra cu datele din bloc. | + | Datele din bloc sunt referite de câmpul ''b_data'' al structurii [[http://lxr.free-electrons.com/source/include/linux/buffer_head.h?v=4.9#L53|struct buffer_head]] (codul uzual va fi ''%%bh->b_data%%''). Acest bloc (fiind blocul de date al unui director) conține un vector de cel mult ''MINFS_NUM_ENTRIES'' intrări de tipul ''struct minfs_dir_entry'' (intrări de tip director (//dentry//-uri) specifice ''minfs''). Folosiți casting la ''struct minfs_dir_entry *'' pentru a lucra cu datele din bloc. |
</note> | </note> | ||
Line 238: | Line 294: | ||
Pentru fiecare intrare validă se apelează funcția ''dir_emit'' cu parametrii corespunzători. | Pentru fiecare intrare validă se apelează funcția ''dir_emit'' cu parametrii corespunzători. | ||
- | Urmăriți modul de apel din [[http://lxr.free-electrons.com/source/fs/qnx6/dir.c?v=3.13#L117|qnx6_readdir]] și [[http://lxr.free-electrons.com/source/fs/minix/dir.c?v=3.13#L85|minix_readdir]]. | + | Urmăriți modul de apel din [[http://lxr.free-electrons.com/source/fs/qnx6/dir.c?v=4.9#L111|qnx6_readdir]] și [[http://lxr.free-electrons.com/source/fs/minix/dir.c?v=4.9#L80|minix_readdir]]. |
</note> | </note> | ||
=== Testare === | === Testare === | ||
- | O dată realizat modulul putem testa listarea conținutului directorului rădăcină. Pentru aceasta, compilăm modulul de kernel și copiem fișierul rezultat (''minfs.ko''), scripturile de testare (''test-minfs-{0,1}.sh'') și utilitarul de formatare (''mkfs.minfs'') în directorul aferent mașinii virtuale, apoi pornim mașina. După ce pornim mașina, formatăm discul ''/dev/sdb'', creăm punctul de montare și montăm sistemul de fișiere:<code> | + | O dată realizat modulul putem testa listarea conținutului directorului rădăcină. Pentru aceasta, compilăm modulul de kernel și copiem rezultatul pe mașina virtuală împreună cu scripturile de testare (''minfs/user/test-minfs-{0,1}.sh'') și utilitarul de formatare (''minfs/user/mkfs.minfs'') folosind ''make copy'', apoi pornim mașina. Scripturile de testare sunt copiate pe mașina virtuală doar dacă sunt executabile: |
- | # ./mkfs.minfs /dev/sdb | + | <code bash> |
+ | student@eg106:~/so2/linux/tools/labs$ chmod +x skels/filesystems/minfs/user/test-minfs*.sh | ||
+ | </code> | ||
+ | |||
+ | După ce pornim mașina, formatăm discul ''/dev/vdb'', creăm punctul de montare și montăm sistemul de fișiere:<code> | ||
+ | # ./mkfs.minfs /dev/vdb | ||
# mkdir -p /mnt/minfs | # mkdir -p /mnt/minfs | ||
- | # mount -t minfs /dev/sdb /mnt/minfs | + | # mount -t minfs /dev/vdb /mnt/minfs |
</code> | </code> | ||
Line 265: | Line 326: | ||
==== 4. [1.5p] Operația lookup (minfs) ==== | ==== 4. [1.5p] Operația lookup (minfs) ==== | ||
- | Pentru listarea corespunzătoare a conținutului unui director este nevoie să implementăm funcționalitatea de căutare, adică operația ''lookup''. Operația ''lookup'' este un câmp în cadrul structurii ''minfs_dir_inode_operations'' (de tipul [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=3.13#L1552|inode_operations]]) și este implementată de funcția ''minfs_lookup''. Această funcție (''minfs_lookup'') trebuie să o implementăm. De fapt vom implementa funcția ''minfs_find_entry'' apelată de funcția ''minfs_lookup''. | + | Pentru listarea corespunzătoare a conținutului unui director este nevoie să implementăm funcționalitatea de căutare, adică operația ''lookup''. Operația ''lookup'' este un câmp în cadrul structurii ''minfs_dir_inode_operations'' (de tipul [[http://lxr.free-electrons.com/source/include/linux/fs.h?v=4.9#L1736|inode_operations]]) și este implementată de funcția ''minfs_lookup''. Această funcție (''minfs_lookup'') trebuie să o implementăm. De fapt vom implementa funcția ''minfs_find_entry'' apelată de funcția ''minfs_lookup''. |
- | Urmăriți indicațiile marcate cu ''TODO 4'' care vă vor ghida pașii pe care trebuie să îi faceți. | + | Urmăriți indicațiile marcate cu ''TODO 6'' care vă vor indica pașii pe care trebuie să îi faceți. |
<note tip> | <note tip> | ||
Parcurgeți secțiunea [[:so2:laboratoare:lab09#operatii_asupra_inode-urilor_de_tip_director|Operații asupra inode-urilor de tip director]]. | Parcurgeți secțiunea [[:so2:laboratoare:lab09#operatii_asupra_inode-urilor_de_tip_director|Operații asupra inode-urilor de tip director]]. | ||
- | Ca punct de plecare, urmăriti funcțiile [[http://lxr.free-electrons.com/source/fs/qnx6/dir.c?v=3.13#L218|qnx6_find_entry]] și [[http://lxr.free-electrons.com/source/fs/minix/dir.c?v=3.13#L147|minix_find_entry]]. | + | Ca punct de plecare, urmăriti funcțiile [[http://lxr.free-electrons.com/source/fs/qnx6/dir.c?v=4.9#L212|qnx6_find_entry]] și [[http://lxr.free-electrons.com/source/fs/minix/dir.c?v=4.9#L142|minix_find_entry]]. |
</note> | </note> | ||
Line 306: | Line 367: | ||
<note> | <note> | ||
După ce montăm sistemul de fișiere folosind comanda<code> | După ce montăm sistemul de fișiere folosind comanda<code> | ||
- | # mount -t minfs /dev/sdb /mnt/minfs | + | # mount -t minfs /dev/vdb /mnt/minfs |
</code> | </code> | ||
încercăm să creăm un fișier folosind comanda<code> | încercăm să creăm un fișier folosind comanda<code> | ||
Line 316: | Line 377: | ||
==== 5. [3.5p] Operația create (minfs) ==== | ==== 5. [3.5p] Operația create (minfs) ==== | ||
- | Pentru a permite crearea unui fișier într-un director trebuie să implementăm operația de tip ''create''. Operația ''create'' este un câmp în cadrul structurii ''minfs_dir_inode_operations'' (de tipul [[|inode_operations]] și este implmenentată de funcția ''minfs_create''. Această funcție trebuie să o implementăm. De fapt vom implementa funcțiile ''minfs_new_inode'' (care creează și inițializează un inode) și ''minfs_add_link'' care adaugă un link (sau nume sau //dentry//) inode-ului creat. | + | Pentru a permite crearea unui fișier într-un director trebuie să implementăm operația de tip ''create''. Operația ''create'' este un câmp în cadrul structurii ''minfs_dir_inode_operations'' (de tipul [[|inode_operations]] și este implmenentată de funcția ''minfs_create''. Trebuie să o implementăm această funcție. De fapt vom implementa funcțiile ''minfs_new_inode'' (care creează și inițializează un inode) și ''minfs_add_link'' care adaugă un link (sau nume sau //dentry//) inode-ului creat. |
- | Urmăriți indicațiile marcate cu ''TODO 5'' care vă vor ghida pașii pe care trebuie să îi faceți. | + | Urmăriți indicațiile marcate cu ''TODO 7'' care vă vor ghida pașii pe care trebuie să îi faceți. |
<note tip> | <note tip> | ||
Line 328: | Line 389: | ||
Completați funcțiile ''minfs_readdir'' și ''minfs_find_entry'' cu implementarea de la exercițiul anterior. | Completați funcțiile ''minfs_readdir'' și ''minfs_find_entry'' cu implementarea de la exercițiul anterior. | ||
- | Implementați funcția ''minfs_new_inode''. În cadrul funcției veți crea ([[http://lxr.free-electrons.com/source/fs/inode.c?v=3.13#L880|new_inode]]) și veți inițializa un inode. Inițializarea se face cu datele de pe disc. | + | Implementați funcția ''minfs_new_inode''. În cadrul funcției veți crea ([[http://lxr.free-electrons.com/source/fs/inode.c?v=4.9#L900|new_inode]]) și veți inițializa un inode. Inițializarea se face cu datele de pe disc. |
<note tip> | <note tip> | ||
- | Parcurgeți ca model funcția [[http://lxr.free-electrons.com/source/fs/minix/bitmap.c?v=3.13#L212|minix_new_inode]]. | + | Parcurgeți ca model funcția [[http://lxr.free-electrons.com/source/fs/minix/bitmap.c?v=4.9#L212|minix_new_inode]]. |
- | Găsiți primul inode liber din imap (''%%sbi->imap%%''). Folosiți operații de lucru pe biți ([[http://lxr.free-electrons.com/source/lib/find_next_bit.c?v=3.13#L139|find_first_zero_bit]] și [[http://lxr.free-electrons.com/source/include/asm-generic/bitops/non-atomic.h?v=3.13#L6|__set_bit]]). Parcurgeți secțiunea [[:so2:laboratoare:lab09#operatii_pe_bitmap-uri|Operații pe bitmap-uri]]. | + | Găsiți primul inode liber din imap (''%%sbi->imap%%''). Folosiți operații de lucru pe biți ([[http://lxr.free-electrons.com/source/include/asm-generic/bitops/find.h?v=4.9#L45|find_first_zero_bit]] și [[http://lxr.free-electrons.com/source/include/asm-generic/bitops/atomic.h?v=4.9#L50|set_bit]]). Parcurgeți secțiunea [[:so2:laboratoare:lab09#operatii_pe_bitmap-uri|Operații pe bitmap-uri]]. |
Buffer-ul aferent supernodului (''%%sbi->sbh%%'') trebuie marcat //dirty//. | Buffer-ul aferent supernodului (''%%sbi->sbh%%'') trebuie marcat //dirty//. | ||
Line 343: | Line 404: | ||
<note tip> | <note tip> | ||
- | Parcurgeți ca model funcția [[http://lxr.free-electrons.com/source/fs/minix/dir.c?v=3.13#L204|minix_add_link]]. | + | Parcurgeți ca model funcția [[http://lxr.free-electrons.com/source/fs/minix/dir.c?v=4.9#L199|minix_add_link]]. |
</note> | </note> | ||
Line 349: | Line 410: | ||
<note tip> | <note tip> | ||
- | Pentru a putea lucra cu directorul, obțineți inode-ul ''struct minfs_inode_info'' aferente directorului părinte (inode-ul ''dir''). Pentru obținerea structurii ''struct minfs_inode_info'' folosiți [[http://lxr.free-electrons.com/source/scripts/kconfig/list.h?v=3.13#L33|list_entry]] sau [[http://lxr.free-electrons.com/source/scripts/kconfig/list.h?v=3.13#L11|container_of]]. | + | Pentru a putea lucra cu directorul, obțineți inode-ul ''struct minfs_inode_info'' aferente directorului părinte (inode-ul ''dir''). **Nu** folosiți inode-ul ''inode'' pentru obținerea ''struct_minfs_inode_info''; acel inode este inode-ul fișierului, nu al directorului părinte (cum este ''dir'') în conținutul căruia trebuie să adăugați link-ul/dentry-ul. Pentru obținerea structurii ''struct minfs_inode_info'' folosiți [[http://lxr.free-electrons.com/source/tools/include/linux/kernel.h?v=4.9#L18|container_of]]. |
- | Structura ''struct minfs_inode_info'' este utilă pentru a afla blocul de date al directorului (cel indicat de inode-ul ''%%dentry->d_parent->d_inode%%''. Din cadrul acestei structuri obțineți câmpul ''data_block'', reprezentând indexul blocului de date pe disc. Acest bloc conține intrări în director. Folosiți [[http://lxr.free-electrons.com/source/include/linux/buffer_head.h?v=3.13#L292|sb_bread]] pentru citirea blocului dat și apoi construcția ''%%bh->b_data%%'' pentru a referi datele din bloc. Blocul conține un vector de cel mult ''MINFS_NUM_ENTRIES'' intrări de tipul ''struct minfs_dir_entry''. | + | Structura ''struct minfs_inode_info'' este utilă pentru a afla blocul de date al directorului (cel indicat de inode-ul ''%%dentry->d_parent->d_inode%%'', adică de variabila ''dir''). Din cadrul acestei structuri obțineți câmpul ''data_block'', reprezentând indexul blocului de date pe disc. Acest bloc conține intrări în director. Folosiți [[http://lxr.free-electrons.com/source/include/linux/buffer_head.h?v=4.9#L298|sb_bread]] pentru citirea blocului dat și apoi construcția ''%%bh->b_data%%'' pentru a referi datele din bloc. Blocul conține un vector de cel mult ''MINFS_NUM_ENTRIES'' intrări de tipul ''struct minfs_dir_entry''. |
Dacă toate intrările sunt ocupate, se întoarce ''-ENOSPC''. | Dacă toate intrările sunt ocupate, se întoarce ''-ENOSPC''. |