Laborator 9: Exerciții

Pregătirea laboratorului

Pentru rezolvarea laboratorului, vom lucra în același director din care pornim mașina virtuală (~/so2/linux/tools/labs).

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:

tools/labs $ make skels

Pentru a genera scheletul pentru un singur laborator, vom folosi variabila de mediu LABS:

tools/labs $ make clean
tools/labs $ LABS=<lab name> make skels

Numele laboratorului curent este filesystems.

Similar, putem genera și scheletul pentru un singur exercițiu, atribuind valoarea <lab_name>/<task_name> variabilei LABS.

Scheletul este generat în directorul tools/labs/skels.

Compilarea modulelor

Comanda make build compilează toate modulele din directorul skels.

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

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ă.

student@eg106:~/so2/linux/tools/labs$ make copy
student@eg106:~/so2/linux/tools/labs$ make boot

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 Interacțiunea cu mașina virtuală.

Testarea modulelor

Modulele generate sunt copiate pe mașina virtuală în directorul /home/root/skels/<lab_name>.

root@qemux86:~/skels/filesystems# ls
minfs  myfs
root@qemux86:~/skels/filesystems# ls myfs/
myfs.ko       test-myfs.sh

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:

root@qemux86:~# insmod skels/<lab_name>/<task_name>/<module_name>.ko
root@qemux86:~# rmmod skels/<lab_name>/<task_name>/<module_name>.ko

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:

  1. Î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.
  2. Î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.
  3. În al treilea tab de terminal accesăm directorul ~/so2/linux/ cu sursele nucleului unde putem folosi Vim și cscope pentru parcurgerea codului sursă.

student@eg106-pc:~$ netcat -lup 6666
</code>

</note>

===== 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.

Î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>

===== [4p] myfs =====

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=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 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) ====

Pentru început vom implementa operațiile de lucru cu directoare. Operația de creare a unui fișier sau ștergere a unui fișier este tot operație de lucru cu directoare; aceste operații duc la adăugarea sau ștergerea unei intrări în director (//dentry// -- //directory entry//).

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 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:
  * creare de fișier (''create'')
  * căutare (''lookup'')
  * link (''link'')
  * creare de director (''mkdir'')
  * ștergere (''rmdir'' și ''unlink'')
  * creare de nod (''mknod'')
  * redenumire (''rename'')

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>
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=4.9#L140|ramfs_dir_inode_operations]].
</note>

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>
Recomandăm modularizarea codului folosind o funcție ''mknod'', pe care o veți putea folosi și la exercițiul următor.

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=4.9|sistemul de fișiere ramfs]]:
  * [[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=4.9#L108|ramfs_mkdir]]
  * [[http://lxr.free-electrons.com/source/fs/ramfs/inode.c?v=4.9#L116|ramfs_create]]
</note>

Pentru celelalte funcții folosiți apeluri generice (''simple_*'') deja definite în VFS.

Î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_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>
''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=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>

=== Testare ===

O dată realizată modulul putem testa crearea de fișiere și directoare. Pentru aceasta, compilăm modulul de kernel și copiem fișierul rezultat (''myfs.ko'') și scripturile de testare (''test-myfs-{1,2}.sh'') în directorul aferent mașinii virtuale, apoi pornim mașina virtuală .

După ce pornim mașinavirtuală, inserăm modulul, creăm punctul de montare și montăm sistemul de fișiere:<code>
# insmod myfs.ko
# mkdir -p /mnt/myfs
# mount -t myfs none /mnt/myfs
</code>

Acum putem crea ierarhii de fișiere și subdirectoare în directorul montat (''/mnt/myfs''). Folosim comenzi precum cele de mai jos:<code>
# touch /mnt/myfs/peanuts.txt
# mkdir -p /mnt/myfs/mountain/forest
# touch /mnt/myfs/mountain/forest/tree.txt
# rm /mnt/myfs/mountain/forest/tree.txt
# rmdir /mnt/myfs/mountain/forest
</code>

În acest moment nu putem însă citi sau scrie în fișiere. La rularea comenzilor<code>
# echo "chocolate" > /mnt/myfs/peanuts.txt
# cat /mnt/myfs/peanuts.txt
</code>
vom obține eroare. Aceasta se întâmplă pentru că nu am implementat operațiile pentru lucrul cu fișiere; vom face acest lucru în continuare.

Pentru a descărca modulul din kernel folosim comanda<code>
rmmod myfs
</code>

Pentru testarea funcționalităților oferite de modul putem folosi scriptul dedicat:<code>
# ./test-myfs-1.sh
</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.

==== 2. [2p] Operații pentru lucrul cu fișiere (myfs) ====

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=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 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''.

<note tip>
Parcurgeți secțiunea [[:so2:laboratoare:lab09#operatii_asupra_inode-urilor_de_tip_fisier|Operații asupra inode-urilor de tip fișier]].

Folosiți funcțiile generice oferite de VFS.

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>

În cadrul funcției ''myfs_get_inode'' inițializați câmpurile de operații ale inode-urilor de tip fișier (//regular file//):
  * ''i_op'' inițializat la ''myfs_file_inode_operations'';
  * ''i_fop'' inițializat la ''myfs_file_operations''.

Continuați cu definirea structurii ''myfs_aops''.

<note tip>
Parcurgeți secțiunea [[:so2:laboratoare:lab09#operatii_asupra_inode-urilor_de_tip_fisier|Operații asupra inode-urilor de tip fișier]].

Folosiți funcțiile generice oferite de VFS.

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''.
</note>

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 ===

Pentru testare, folosim pașii descriși la exercițiul anterior. În plus față de acei pași acum vom putea citi, scrie și modifica un fișier folosind comenzi precum cele de mai jos:<code>
# echo "chocolate" > /mnt/myfs/peanuts.txt
# cat /mnt/myfs/peanuts.txt
</code>

Pentru testarea funcționalităților oferite de modul putem folosi scriptul dedicat:<code>
# ./test-myfs-2.sh
</code>

Dacă implementarea este validă, nu vor fi afișate mesaje de eroare în urma rulării scriptului de mai sus.

===== [7p] minfs =====

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=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/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''.

Utilitarul de formatare se aplică asupra unui disc al mașinii virtuale cu o comandă de forma<code>
# ./mkfs.minfs /dev/vdb
</code>
În urma formatării, discul capătă o structură precum cea din diagrama de mai jos:
{{ :so2:laboratoare:lab10:minfs_arch.png | Layout MinFS}}

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.

<note important>
Î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>

==== 3. [2p] Operația iterate (minfs) ====

Î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 5'' care vă vor ghida pașii pe care trebuie să îi faceți.

<note tip>
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=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''.
</note>

Obțineți inode-ul și structura ''struct minfs_inode_info'' aferente directorului. Structura ''struct minfs_inode_info'' este utilă pentru a afla blocul de date al directorului.
Din cadrul acestei structuri obțineți câmpul ''data_block'', reprezentând indexul blocului de date pe disc.

<note tip>
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>

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>
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=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>

Parcurgeți toate intrările din blocul de date și completați datele în buffer-ul utilizatorului în cadrul buclei ''for'' definite.

<note tip>
Pentru fiecare index obțineți intrarea aferentă de tipul ''struct minfs_dir_entry'' prin folosirea aritmeticii de pointeri pe câmpul ''%%bh->b_data%%''.

Ignorați dentry-urile care au câmpul ''ino'' egal cu ''0''. Un astfel de dentry este un slot liber în lista de dentry-uri a directorului.

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=4.9#L111|qnx6_readdir]] și [[http://lxr.free-electrons.com/source/fs/minix/dir.c?v=4.9#L80|minix_readdir]].
</note>

=== Testare ===

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:
<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:

# ./mkfs.minfs /dev/vdb
# mkdir -p /mnt/minfs
# mount -t minfs /dev/vdb /mnt/minfs

Acum putem lista conținutul directorului rădăcină:

# ls -l /mnt/minfs

Observăm că există deja un fișier (a.txt); acesta este creat de utilitarul de formatare.

Observăm, de asemenea, că nu ne este permisă afișerea de informații folosind comanda ls. Aceasta se întâmplă pentru că nu avem implementată funcția de lookup. O vom implementa în exercițiul următor.

Pentru testarea funcționalităților oferite de modul putem folosi scriptul dedicat:

# ./test-minfs-0.sh
# ./test-minfs-1.sh

Dacă implementarea este validă, nu vor fi afișate mesaje de eroare în urma rulării scripturilor de mai sus.

==== 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 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 6 care vă vor indica pașii pe care trebuie să îi faceți.

Parcurgeți secțiunea Operații asupra inode-urilor de tip director.

Ca punct de plecare, urmăriti funcțiile qnx6_find_entry și minix_find_entry.

În cadrul funcției minfs_find_entry, parcurgeți directorul în care se află intrarea dentry: dentry->d_parent->d_inode. Parcurgere înseamnă parcurgerea intrărilor din blocul de date al directorului și localizarea, dacă există, a intrării căutate.

Din structura de tip struct minfs_inode_info aferent directorului, aflați indexul blocului și citiți-l. Veți accesa conținutul blocului folosind construcția bh->b_data.

Blocul de date al directorului conține un vector de cel mult MINFS_NUM_ENTRIES intrări de tipul struct minfs_dir_entry. Folosiți aritmetică de pointeri pentru a obține intrări de tipul struct minfs_dir_entry din blocul de date (bh->b_data).

Verificați prezența numelui (stocat în variabila locală name) în director; adică dacă există o intrare în blocul de date al cărei nume să un șir egal cu șirul name. Folosiți strcmp pentru verificare.

Ignorați dentry-urile care au câmpul ino egal cu 0. Acele dentry-uri reprezintă slot-uri liber în lista de dentry-uri a directorului.

Rețineți în variabila final_de dentry-ul găsit. Dacă nu găsiți nici un dentry, atunci variabila final_de va avea valoarea NULL, valoare cu care a fost inițializată.

Actualizați câmpul lookup al structurii minfs_dir_inode_operations, structură de tipul inode_operations.

=== Testare ===

Pentru testare, folosim pașii descriși la exercițiul anterior. La listarea în format lung (ls -l) a conținutului unui director (directorul rădăcină) vor fi afișate permiuni și alte informații specifice fișierului:

# ls -l /mnt/minfs

Pentru testarea funcționalităților oferite de modul putem folosi scriptul dedicat:

# ./test-minfs-0.sh
# ./test-minfs-1.sh

Dacă implementarea este validă, nu vor fi afișate mesaje de eroare în urma rulării scripturilor de mai sus.

După ce montăm sistemul de fișiere folosind comanda

# mount -t minfs /dev/vdb /mnt/minfs

încercăm să creăm un fișier folosind comanda

# touch /mnt/minfs/peanuts.txt

Observăm că primi eroare pentru că nu am implementat operațiile de lucru pe directoare care permit crearea unui fișier. Vom face acest lucru la exercițiul următor.

==== 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. 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 7 care vă vor ghida pașii pe care trebuie să îi faceți.

Parcurgeți secțiunea Operații asupra inode-urilor de tip director.

Parcurgeți codul funcției minfs_create și scheletul funcțiilor minfs_new_inode și minfs_add_link.

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 (new_inode) și veți inițializa un inode. Inițializarea se face cu datele de pe disc.

Parcurgeți ca model funcția minix_new_inode.

Găsiți primul inode liber din imap (sbi->imap). Folosiți operații de lucru pe biți (find_first_zero_bit și set_bit). Parcurgeți secțiunea Operații pe bitmap-uri.

Buffer-ul aferent supernodului (sbi->sbh) trebuie marcat dirty.

Trebuie să inițializați câmpurile uzuale, așa cum este inițializat și pentru sistemul de fișiere myfs. Inițializați câmpul i_mode la 0. Va fi inițializat ulterior în apelant.

Implementați funcția minfs_add_link. Funcția adaugă un nou dentry (struct minfs_dir_entry) în blocul de date al directorului părinte (dentry->d_parent->d_inode).

Parcurgeți ca model funcția minix_add_link.

În cadrul funcției minfs_add_link doriți să găsiți primul loc liber pentru dentry. Pentru aceasta veți parcurge blocul de date aferente directorului și veți găsi primul loc liber, adică acel dentry pentru care câmpul ino are valoarea 0.

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 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, 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 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.

Obțineți numele intrării în forma unui șir de caractere (char *) în variabila name.

Parcurgeți intrările din bloc folosind variabila de și extrageți prima intrare liberă (cea pentru care câmpul ino este 0). Dacă ați găsit loc liber, completați intrarea corespunzătoare: câmpul ino și câmpul name din variabila de. Puteți folosi strcpy sau memcpy pentru inițializarea numelui la conținutul variabilei name.

=== Testare ===

Pentru testare, folosim pașii descriși la exercițiul anterior. Acum vom putea crea fișiere în cadrul sistemului de fișiere:

# touch /mnt/minfs/peanuts.txt

Pentru testarea funcționalităților oferite de modul putem folosi scriptul dedicat:

# ./test-minfs-2.sh

Dacă implementarea este validă, nu vor fi afișate mesaje de eroare în urma rulării scriptului de mai sus.

Implementarea curentă nu este definitivă pentru sistemul de fișiere minfs. Pentru a fi completă, implementarea are nevoie de funcții de șters fișiere, create și șters directoare, redumit intrări și alterat conținutul unui fișier.

===== Soluții =====

so2/laboratoare/lab09/exercitii.txt · Last modified: 2019/04/16 23:19 by ionel.ghita
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0