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:
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
filesystems
.
Similar, putem genera și scheletul pentru un singur exercițiu, atribuind valoarea <lab_name>/<task_name>
variabilei LABS
.
tools/labs/skels
.
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
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ă.
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
Ctrl+Shift+t
. Cele trei tab-uri de terminal îndeplinesc următoarele roluri:
~/so2/linux/tools/labs
.~/so2/linux/
cu sursele nucleului unde putem folosi Vim și cscope pentru parcurgerea codului sursă.student@eg106-pc:~ 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 simple_statfs.
Î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/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 laboratorul următor.
Urmăriți diagrama de mai jos pentru a clarifica rolul structurilor din cadrul sistemului de fișiere minfs
.
dd if=/dev/zero of=qemu/mydisk.img bs=1M count=100
ș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
).
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
.
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 Funcțiile mount, kill_sb; este vorba de funcția 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 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 Înregistrarea și deînregistrarea sistemelor de fișiere.
Funcția de completare a superblocului este minfs_fill_super
.
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
, din directorul minfs/user
. Utilitarul se compilează automat la comanda
make build
și se copiază pe mașina virtuală la
make copy
.
După compilare, copiere și pornirea mașinii virtuale, formatăm discul /dev/vdb
folosind utilitarul de formatare:
# ./mkfs.minfs /dev/vdb
Încărcăm modulul de kernel
# insmod minfs.ko
creăm punctul de montare /mnt/minfs/
# mkdir -p /mnt/minfs/
și montăm sistemul de fișiere
# mount -t minfs /dev/vdb /mnt/minfs/
Operaţia eşuează din cauză că inode-ul rădăcină nu este iniţializat.
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 minix_fill_super.
minfs.h
.
Pentu informații legate de lucrul cu buffere, parcurgeți secțiunea Buffer cache-ul.
Citiți primul bloc de pe disc (blocul cu indexul 0). Pentru a citi blocul, folosiți funcția 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
.
Pentru verificarea funcționalității avem nevoie de o funcţie pentru citirea inode-ului rădăcină. Pe moment folosiți funcția myfs_get_inode
de la exercițiile cu sistemul de fișiere myfs
. Copiați funcția în codul sursă şi apelaţi-o la fel ca în cazul myfs
. Al doilea argument în cazul apelării funcției myfs_get_inode
îl reprezintă permisiunile de creare ale inode-ului, similar exercițiului cu sistem de fișiere virtual (myfs
).
Validaţi implementarea executând comenzile de la exerciţiul anterior.
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 minix_alloc_inode și minix_destroy_inode.
În implementare urmăriți macro-urile și structurile din fișierul minfs.h
.
minfs_alloc_inode
și minfs_destroy_inode
recomandăm folosirea kzalloc și 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 de minfs_alloc_inode
apelați funcția 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 container_of.
minfs_alloc_inode
şi minfs_destroy_inode
, dar ele nu sunt încă apelate. Corectitudinea implementării o veţi verifica la sfârşitul exerciţiului următor.
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 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
).
În cadrul funcției minfs_fill_super
înlocuiți apelul funcției myfs_get_inode
cu apelul funcției minfs_iget
.
minfs_iget
urmăriți implementarea funcției V1_minix_iget.
Pentru a citi un bloc folosiți funcția 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
).
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.
Inițializați câmpurile i_atime
, i_ctime
și i_mtime
ale inode-ului VFS la valoarea întoarsă de funcția current_time.
Va trebui să inițializați operațiile pentru inode-ul de tip director. Pentru aceasta urmați pașii:
i_op
și i_fop
, folosiți funcții din kernel deja implementate:i_op
: simple_dir_inode_operations.i_fop
: simple_dir_operations
Acum putem să montăm sistemul de fișiere. Urmați pașii indicați mai sus pentru a compila modulul de kernel, copia pe mașina virtuală și porni mașina virtuală și apoi inserați modulul de kernel, creați punctul de montare /mnt/minfs/
și montați sistemul de fișiere. Verificăm că sistemul de fișiere a fost montat investigând fișierul /proc/mounts
.
Verificăm că totul este în regulă prin listarea conținutului punctului de montare /mnt/minfs/
:
# ls /mnt/minfs/
După montare și verificare, demontăm sistemul de fișiere și descărcăm modulul din kernel.
test-minfs.sh
:
# ./test-minfs.sh
Scriptul este copiat pe mașina virtuală la rularea comenzii make copy
doar dacă este executabil.
student@workstation:~/so2/linux/tools/labs$ chmod +x skels/filesystems/minfs/user/test-minfs.sh