Bună ziua tuturor, vă împărtășim a doua parte a publicației „Sisteme de fișiere virtuale în Linux: de ce sunt necesare și cum funcționează?” Puteți citi prima parte
Cum se monitorizează VFS folosind instrumentele eBPF și bcc
Cel mai simplu mod de a înțelege cum funcționează nucleul pe fișiere sysfs
este să-l vezi în practică, iar cel mai simplu mod de a viziona ARM64 este să folosești eBPF. eBPF (prescurtare de la Berkeley Packet Filter) constă dintr-o mașină virtuală care rulează query
) din linia de comandă. Sursele nucleului spun cititorului ce poate face nucleul; rularea instrumentelor eBPF pe un sistem încărcat arată ce face de fapt nucleul.
Din fericire, începerea utilizării eBPF este destul de ușoară cu ajutorul instrumentelor bcc
sunt scripturi Python cu mici inserții de cod C, ceea ce înseamnă că oricine familiarizat cu ambele limbi le poate modifica cu ușurință. ÎN bcc/tools
Există 80 de scripturi Python, ceea ce înseamnă că cel mai probabil un dezvoltator sau un administrator de sistem va putea alege ceva potrivit pentru rezolvarea problemei.
Pentru a vă face cel puțin o idee superficială despre ceea ce lucrează VFS-urile pe un sistem care rulează, încercați vfscount
sau vfsstat
. Acest lucru va arăta, să spunem, că zeci de apeluri vfs_open()
iar „prietenii lui” se întâmplă literalmente în fiecare secundă.
vfsstat.py
este un script Python cu inserții de cod C care pur și simplu numără apelurile de funcții VFS.
Să dăm un exemplu mai banal și să vedem ce se întâmplă când introducem o unitate flash USB într-un computer și sistemul o detectează.
Folosind eBPF puteți vedea ce se întâmplă în
/sys
când este introdusă o unitate flash USB. Un exemplu simplu și complex este prezentat aici.
În exemplul prezentat mai sus, bcc
instrument sysfs_create_files()
. Noi vedem asta sysfs_create_files()
a fost lansat folosind kworker
stream ca răspuns la faptul că unitatea flash a fost introdusă, dar ce fișier a fost creat? Al doilea exemplu arată puterea eBPF. Aici trace.py
Tipărește un backtrace al nucleului (opțiunea -K) și numele fișierului care a fost creat sysfs_create_files()
. Inserarea unei singure instrucțiuni este un cod C care include un șir de format ușor de recunoscut furnizat de scriptul Python care rulează LLVM compilator just-in-time. Compilează această linie și o execută într-o mașină virtuală din interiorul nucleului. Semnătură cu funcții complete sysfs_create_files ()
trebuie reprodus în a doua comandă pentru ca șirul de format să se poată referi la unul dintre parametri. Erorile din această bucată de cod C au ca rezultat erori de recunoscut de la compilatorul C. De exemplu, dacă parametrul -l este omis, veți vedea „Failed to compilation BPF text”. Dezvoltatorii care sunt familiarizați cu C și Python vor găsi instrumentele bcc
ușor de extins și schimbat.
Când unitatea USB este introdusă, backtraceul nucleului va arăta că PID 7711 este un fir kworker
care a creat fișierul «events»
в sysfs
. În consecință, apelul de la sysfs_remove_files()
va arăta că eliminarea unității a dus la ștergerea fișierului events
, care corespunde conceptului general de numărare a referințelor. În același timp, vizionarea sysfs_create_link ()
cu eBPF în timp ce introduceți unitatea USB va arăta că au fost create cel puțin 48 de legături simbolice.
Deci, ce rost are dosarul evenimentelor? Utilizare disk_add_events ()
, si nici "media_change"
Sau "eject_request"
poate fi înregistrată într-un fișier eveniment. Aici stratul bloc al nucleului informează spațiul utilizatorului că un „disc” a apărut și a fost scos. Rețineți cât de informativă este această metodă de cercetare prin introducerea unei unități USB, în comparație cu încercarea de a afla cum funcționează lucrurile doar de la sursă.
Sistemele de fișiere rădăcină numai pentru citire permit dispozitivele încorporate
Desigur, nimeni nu oprește serverul sau computerul trăgând ștecherul din priză. Dar de ce? Acest lucru se datorează faptului că sistemele de fișiere montate pe dispozitivele de stocare fizice pot avea scrieri întârziate, iar structurile de date care înregistrează starea lor pot să nu fie sincronizate cu scrierile în stocare. Când se întâmplă acest lucru, proprietarii de sistem trebuie să aștepte până la următoarea pornire pentru a lansa utilitarul. fsck filesystem-recovery
și, în cel mai rău caz, pierderea datelor.
Cu toate acestea, știm cu toții că multe dispozitive IoT, precum și routere, termostate și mașini, rulează acum Linux. Multe dintre aceste dispozitive au interfață cu utilizatorul puțin sau deloc și nu există nicio modalitate de a le opri „curat”. Imaginați-vă că porniți o mașină cu o baterie descărcată când unitatea de control este alimentată fsck
cand in sfarsit porneste motorul? Și răspunsul este simplu. Dispozitivele încorporate se bazează pe sistemul de fișiere rădăcină ro-rootfs
(sistem de fișiere rădăcină numai pentru citire)).
ro-rootfs
oferă multe beneficii care sunt mai puțin evidente decât autenticitatea. Un avantaj este că malware-ul nu poate scrie /usr
sau /lib
, dacă niciun proces Linux nu poate scrie acolo. O alta este că un sistem de fișiere în mare măsură imuabil este esențial pentru suportul pe teren al dispozitivelor de la distanță, deoarece personalul de asistență se bazează pe sisteme locale care sunt nominal identice cu sistemele de teren. Poate cel mai important (dar și cel mai insidios) beneficiu este că ro-rootfs obligă dezvoltatorii să decidă ce obiecte de sistem vor fi imuabile în faza de proiectare a sistemului. Lucrul cu ro-rootf-uri poate fi ciudat și dureros, deoarece variabilele const sunt adesea în limbaje de programare, dar beneficiile lor justifică cu ușurință costul suplimentar.
creație rootfs
Numai citirea necesită un efort suplimentar pentru dezvoltatorii încorporați și aici intervine VFS. Linux necesită ca fișierele să fie în /var
erau inscriptibile și, în plus, multe aplicații populare care rulează sisteme încorporate vor încerca să creeze configurații dot-files
в $HOME
. O soluție pentru fișierele de configurare din directorul principal este, de obicei, să le pre-generați și să le construiți rootfs
. Pentru /var
O abordare posibilă este să-l montezi pe o partiție de scriere separată, în timp ce /
montat numai în citire. O altă alternativă populară este utilizarea suporturilor de legătură sau de suprapunere.
Suporturi legabile și stivuibile, utilizarea lor de către containere
Executarea unei comenzi man mount
este cea mai bună modalitate de a afla despre monturile care se pot lega și care se pot suprapune, care oferă dezvoltatorilor și administratorilor de sistem posibilitatea de a crea un sistem de fișiere într-o cale și apoi de a-l expune aplicațiilor din alta. Pentru sistemele încorporate, aceasta înseamnă capacitatea de a stoca fișiere /var
pe o unitate flash numai pentru citire, dar o cale de montare suprapusă sau conectabilă de la tmpfs
в /var
la încărcare, va permite aplicațiilor să scrie note acolo (scrawl). Data viitoare când activați modificările la /var
va fi pierdut. Un suport de suprapunere creează o unire între tmpfs
și sistemul de fișiere de bază și vă permite să faceți modificări vizibile la fișierele existente în ro-tootf
în timp ce o montură care poate fi legată le poate face pe altele noi goale tmpfs
foldere vizibile ca inscriptibile în ro-rootfs
moduri. In timp ce overlayfs
acesta este cel potrivit (proper
) tip de sistem de fișiere, montarea care poate fi legată este implementată în
Pe baza descrierii suprapunerii și a monturii care poate fi conectată, nimeni nu este surprins de asta mountsnoop
din bcc
.
apel system-nspawn
pornește containerul în timpul rulării mountsnoop.py
.
Să vedem ce s-a întâmplat:
lansa mountsnoop
în timp ce containerul „pornește” arată că timpul de rulare al containerului depinde foarte mult de montarea care este legată (este afișat doar începutul ieșirii lungi).
Aici systemd-nspawn
furnizează fișierele selectate în procfs
и sysfs
gazdă la container ca căi către acesta rootfs
... in afara de asta MS_BIND
steag care setează montarea legăturii, alți indicatori de pe montare definesc relația dintre modificările la spațiile de nume gazdă și container. De exemplu, o montură conectată poate sări peste modificări /proc
и /sys
în container sau ascundeți-le în funcție de apel.
Concluzie
Înțelegerea funcționării interioare a Linuxului poate părea o sarcină imposibilă, deoarece nucleul în sine conține o cantitate imensă de cod, lăsând deoparte aplicațiile pentru spațiul utilizatorului Linux și interfețele de apel de sistem din bibliotecile C, cum ar fi glibc
. O modalitate de a face progres este să citiți codul sursă al unui subsistem al nucleului, cu accent pe înțelegerea apelurilor de sistem și a antetelor spațiului utilizator, precum și a principalelor interfețe interne ale nucleului, cum ar fi tabelul file_operations
. Operațiunile cu fișiere asigură principiul „totul este un fișier”, ceea ce le face deosebit de plăcut de gestionat. Fișierele sursă ale nucleului C în directorul de nivel superior fs/
prezintă o implementare a sistemelor de fișiere virtuale, care sunt un strat de înveliș care oferă o compatibilitate largă și relativ simplă între sistemele de fișiere populare și dispozitivele de stocare. Conectarea și montarea suprapunerii prin spații de nume Linux este magia VFS care face posibilă crearea de containere numai pentru citire și sisteme de fișiere rădăcină. Combinat cu o examinare a codului sursă, a instrumentului de bază eBPF și a interfeței sale bcc
făcând explorarea de bază mai ușoară ca niciodată.
Prieteni, scrieți, v-a fost util acest articol? Poate aveți comentarii sau observații? Și cei care sunt interesați de cursul de Administrator Linux sunt invitați
Sursa: www.habr.com