Witam wszystkich, udostępniamy Państwu drugą część publikacji „Wirtualne systemy plików w systemie Linux: po co są potrzebne i jak działają?” Możesz przeczytać pierwszą część
Jak monitorować VFS za pomocą narzędzi eBPF i bcc
Najłatwiejszy sposób zrozumienia, jak jądro działa na plikach sysfs
jest zobaczenie tego w praktyce, a najłatwiejszym sposobem obejrzenia ARM64 jest użycie eBPF. eBPF (skrót od Berkeley Packet Filter) składa się z działającej maszyny wirtualnej query
) z wiersza poleceń. Źródła jądra mówią czytelnikowi, co jądro może zrobić; uruchomienie narzędzi eBPF na załadowanym systemie pokazuje, co faktycznie robi jądro.
Na szczęście rozpoczęcie korzystania z eBPF jest dość łatwe przy pomocy narzędzi bcc
to skrypty w języku Python z małymi wstawkami kodu C, co oznacza, że każdy znający oba języki może je łatwo modyfikować. W bcc/tools
Istnieje 80 skryptów Pythona, co oznacza, że najprawdopodobniej programista lub administrator systemu będzie mógł wybrać coś odpowiedniego do rozwiązania problemu.
Aby uzyskać przynajmniej powierzchowne pojęcie o tym, jaką pracę wykonują VFS w działającym systemie, spróbuj vfscount
lub vfsstat
. To pokaże, powiedzmy, dziesiątki połączeń vfs_open()
i „jego przyjaciele” zdarzają się dosłownie co sekundę.
vfsstat.py
to skrypt w języku Python z wstawkami kodu C, który po prostu zlicza wywołania funkcji VFS.
Podajmy bardziej banalny przykład i zobaczmy, co się stanie, gdy włożymy pendrive'a do komputera, a system go wykryje.
Korzystając z eBPF możesz zobaczyć co dzieje się w
/sys
po włożeniu dysku flash USB. Tutaj pokazano prosty i złożony przykład.
W przykładzie pokazanym powyżej bcc
инструмент sysfs_create_files()
. Widzimy to sysfs_create_files()
został uruchomiony za pomocą kworker
stream w odpowiedzi na fakt, że pendrive został włożony, ale jaki plik został utworzony? Drugi przykład pokazuje siłę eBPF. Tutaj trace.py
Drukuje ślad jądra (opcja -K) i nazwę utworzonego pliku sysfs_create_files()
. Wstawienie pojedynczej instrukcji to kod C zawierający łatwo rozpoznawalny ciąg formatu dostarczony przez skrypt Pythona uruchamiający LLVM kompilator just-in-time. Kompiluje tę linię i wykonuje ją na maszynie wirtualnej wewnątrz jądra. Pełny podpis funkcji sysfs_create_files ()
musi zostać odtworzony w drugim poleceniu, aby ciąg formatujący mógł odnosić się do jednego z parametrów. Błędy w tym fragmencie kodu C powodują rozpoznawalne błędy kompilatora C. Na przykład, jeśli pominięto parametr -l, zostanie wyświetlony komunikat „Nie udało się skompilować tekstu BPF”. Programiści znający C i Python znajdą te narzędzia bcc
łatwy w rozbudowie i zmianie.
Po włożeniu dysku USB śledzenie jądra pokaże, że PID 7711 jest wątkiem kworker
który utworzył plik «events»
в sysfs
. W związku z tym wezwanie z sysfs_remove_files()
pokaże, że usunięcie dysku spowodowało usunięcie pliku events
, co odpowiada ogólnej koncepcji liczenia referencji. Jednocześnie oglądam sysfs_create_link ()
z eBPF podczas wkładania napędu USB pokaże, że utworzono co najmniej 48 dowiązań symbolicznych.
Jaki jest więc sens pliku zdarzeń? Stosowanie disk_add_events ()
, i albo "media_change"
Lub "eject_request"
można zapisać w pliku zdarzenia. Tutaj warstwa bloków jądra informuje przestrzeń użytkownika, że „dysk” pojawił się i został wyrzucony. Zwróć uwagę, jak pouczająca jest ta metoda badawcza polegająca na włożeniu dysku USB w porównaniu z próbą dowiedzenia się, jak wszystko działa wyłącznie na podstawie źródła.
Główne systemy plików tylko do odczytu obsługują urządzenia wbudowane
Oczywiście nikt nie wyłącza serwera ani swojego komputera poprzez wyciągnięcie wtyczki z gniazdka. Ale dlaczego? Dzieje się tak dlatego, że zamontowane systemy plików na fizycznych urządzeniach pamięci masowej mogą mieć opóźnione zapisy, a struktury danych rejestrujące ich stan mogą nie być zsynchronizowane z zapisami w pamięci masowej. Kiedy tak się dzieje, właściciele systemów muszą poczekać do następnego uruchomienia, aby uruchomić narzędzie. fsck filesystem-recovery
a w najgorszym przypadku utratę danych.
Jednak wszyscy wiemy, że wiele urządzeń IoT, a także routery, termostaty i samochody, działa obecnie na systemie Linux. Wiele z tych urządzeń ma niewielki interfejs użytkownika lub nie ma go wcale i nie ma możliwości ich „czystego” wyłączenia. Wyobraź sobie uruchamianie samochodu z rozładowanym akumulatorem, gdy jednostka sterująca nie ma zasilania fsck
kiedy silnik w końcu zacznie pracować? A odpowiedź jest prosta. Urządzenia wbudowane korzystają z głównego systemu plików ro-rootfs
(główny system plików tylko do odczytu)).
ro-rootfs
oferują wiele korzyści, które są mniej oczywiste niż autentyczność. Jedną z zalet jest to, że złośliwe oprogramowanie nie może zapisywać danych /usr
lub /lib
, jeśli żaden proces Linuksa nie może tam pisać. Innym jest to, że w dużej mierze niezmienny system plików ma kluczowe znaczenie dla obsługi urządzeń zdalnych w terenie, ponieważ personel pomocniczy polega na systemach lokalnych, które są nominalnie identyczne z systemami obiektowymi. Być może najważniejszą (ale także najbardziej podstępną) korzyścią jest to, że ro-rootfs zmusza programistów do decydowania, które obiekty systemowe będą niezmienne na etapie projektowania systemu. Praca z ro-rootfs może być niewygodna i bolesna, ponieważ zmienne const często występują w językach programowania, ale ich zalety z łatwością uzasadniają dodatkowy narzut.
tworzenie rootfs
Tryb tylko do odczytu wymaga od programistów systemów wbudowanych dodatkowego wysiłku i tu z pomocą przychodzi VFS. Linux wymaga, aby pliki znajdowały się w /var
można było zapisywać, a ponadto wiele popularnych aplikacji obsługujących systemy wbudowane będzie próbowało utworzyć konfigurację dot-files
в $HOME
. Jednym z rozwiązań dla plików konfiguracyjnych w katalogu domowym jest zwykle ich wstępne wygenerowanie i wbudowanie rootfs
. Dla /var
Jednym z możliwych podejść jest zamontowanie go na osobnej zapisywalnej partycji, podczas gdy /
zamontowany w trybie tylko do odczytu. Inną popularną alternatywą jest użycie uchwytów wiążących lub nakładkowych.
Uchwyty łączone i ustawiane jeden na drugim, ich zastosowanie przy kontenerach
Wykonanie polecenia man mount
to najlepszy sposób na poznanie montowań z możliwością powiązania i nakładania, które dają programistom i administratorom systemów możliwość tworzenia systemu plików w jednej ścieżce, a następnie udostępniania go aplikacjom w innej. W przypadku systemów wbudowanych oznacza to możliwość przechowywania plików /var
na dysku flash tylko do odczytu, ale na nakładce lub możliwej do połączenia ścieżce montowania tmpfs
в /var
podczas ładowania umożliwi aplikacjom zapisywanie tam notatek (bazgranie). Następnym razem, gdy włączysz zmiany w /var
będzie zgubiony. Montaż nakładkowy tworzy połączenie pomiędzy tmpfs
i bazowego systemu plików oraz umożliwia dokonywanie pozornych zmian w istniejących plikach ro-tootf
podczas gdy wierzchowiec z możliwością wiązania może sprawić, że nowe będą puste tmpfs
foldery widoczne jako przeznaczone do zapisu ro-rootfs
sposoby. Chwila overlayfs
to jest właściwe (proper
) typ systemu plików, w którym zaimplementowano montowanie z możliwością powiązania
Sądząc po opisie nakładki i łączonego mocowania, nikogo to nie dziwi mountsnoop
od bcc
.
Zadzwoń system-nspawn
uruchamia kontener podczas działania mountsnoop.py
.
Zobaczmy co się stało:
szalupa mountsnoop
podczas „ładowania” kontenera pokazuje, że czas działania kontenera jest w dużym stopniu zależny od podłączonego uchwytu (pokazany jest tylko początek długiego wyjścia).
Tutaj systemd-nspawn
udostępnia wybrane pliki w formacie procfs
и sysfs
hosta do kontenera jako ścieżki do niego rootfs
. Z wyjątkiem MS_BIND
flaga, która konfiguruje montowanie powiązania, niektóre inne flagi na montowaniu definiują relację pomiędzy zmianami w przestrzeniach nazw hosta i kontenera. Na przykład połączone mocowanie może pominąć zmiany /proc
и /sys
do kontenera lub ukryj je w zależności od wywołania.
wniosek
Zrozumienie wewnętrznego działania Linuksa może wydawać się zadaniem niemożliwym, ponieważ samo jądro zawiera ogromną ilość kodu, pomijając aplikacje przestrzeni użytkownika Linuksa i interfejsy wywołań systemowych w bibliotekach C, takich jak glibc
. Jednym ze sposobów osiągnięcia postępu jest przeczytanie kodu źródłowego jednego podsystemu jądra, z naciskiem na zrozumienie wywołań systemowych i nagłówków przestrzeni użytkownika, a także głównych wewnętrznych interfejsów jądra, takich jak tabele file_operations
. Operacje na plikach działają zgodnie z zasadą „wszystko jest plikiem”, dzięki czemu zarządzanie nimi jest szczególnie przyjemne. Pliki źródłowe jądra C w katalogu najwyższego poziomu fs/
przedstawiają implementację wirtualnych systemów plików, które stanowią warstwę otaczającą zapewniającą szeroką i stosunkowo prostą kompatybilność pomiędzy popularnymi systemami plików i urządzeniami pamięci masowej. Łączenie i montowanie nakładek poprzez przestrzenie nazw Linuksa to magia VFS, która umożliwia tworzenie kontenerów tylko do odczytu i głównych systemów plików. W połączeniu z badaniem kodu źródłowego, podstawowego narzędzia eBPF i jego interfejsu bcc
dzięki czemu eksploracja rdzeni jest łatwiejsza niż kiedykolwiek.
Przyjaciele, napiszcie, czy ten artykuł był dla Was przydatny? Być może mają Państwo jakieś uwagi lub uwagi? A zainteresowanych kursem Administratora Linuksa zapraszam
Źródło: www.habr.com