Ingo Molnar wysłał na LKML wiadomość w której poinformował o stworzeniu nowego drzewa, którego celem będzie usunięcie BKL z jądra Linux. Kiedyś opisałem do czego są używane blokady i dlaczego są ważne — różnica pomiędzy Big Kernel Lock a innymi mechanizmami blokad jest taka, że BKL, jak sama nazwa wskazuje, blokuje całe jądro nie pozwalając innym procesom na działanie dopóki nie zostanie zwolniona.
Robert Love w swojej książce o programowaniu Linuksa napisał “Blokada BKL to czyste zło”, poniżej zamieszczam tłumaczenie wiadomości Ingo w której opisał co chce zrobić temu czystemu złu ;).
Jak niektórzy fani niskich opóźnień wiedzą, commit 8e3e076 (“BKL: revert back to the old spinlock implementation”) w 2.6.26-rc2 usunął funkcję wywłaszczania BKL i zamienił ją w spinlock (W Polsce szerzej znany jako blokada wirująca lub rygiel pętlowy, ale obie nazwy mi się nie podobają i będę używał angielskiej. przyp. tłum.) przez co kod jest ponownie niewywłaszczalny. Ta łatka przywróciła stan BKL z jądra 2.6.7.
Linus również wskazał, że jedynym akceptowalnym (dla nas, ludzi od -rt, raczej mało szczęśliwym) sposobem na usunięcie źródeł opóźnień i niewywłaszczalnych blokad jest wyrzucenie BKL.
To zadanie wcale nie jest łatwe. Dwanaście lat po tym, jak Linux zaczął wykorzystywać SMP, ciągle mamy powyżej 1300 sytuacji wykorzystujących BKL. Jest powyżej 400 krytycznych sekcji z lock_kernel() oraz powyżej 800 w ioctl. Są porozrzucane w różnych, przeważnie trudnych obszarach starego kodu, który niewiele osób rozumie i niewielu odważa się go modyfikować.
Zadaniem powinni się zająć ludzie tacy jak Alan Cox, nawet dla niego (Alan wyrzuca BKL z kodu TTY) jest to trudne i czasochłonne.
Zgodnie z moimi szybkimi analizami w oparciu o git-log, przy aktualnym tempie wyrzucania krytycznych sekcji BKL z jądra, powrót do akceptowalnych opóźnień zajmie ponad dziesięć lat.
Największym technicznym problemem jest to, że BKL w przeciwieństwie do innych blokad zostaje automatycznie zwolniona po wywołaniu funkcji schedule(). To czyni spinlock BKL bardzo “lepkim”, “niewidocznym” i “wirusowym” – bardzo łatwo jest go dodać do kawałka kodu (nawet nieświadomie) i nigdy tak naprawdę nie wiesz czy jest przetrzymywany czy nie. PREEMPT_BKL uczyniło go jeszcze bardziej niewidocznym, ponieważ jego efekty były jeszcze mniej widoczne dla zwykłych użytkowników.
Poza tym BKL jest nieobsługiwana przez lockdep (mechanizm sprawdzania poprawności użycia blokad w systemie przyp. tłum.) a więc jej zależności są w dużej mierze niewidzialne i nieznane, a to wszystko gdzieś w pyle ostatnich piętnastu lat zmian w kodzie. Wszystko to się złożyło na FUD (Fear, Uncertainty and Doubt) o BKL: nikt jej tak naprawdę nie zna, nikt nie jest dość odważny aby ją zmienić a kod może subtelnie i dyskretnie popsuć jeśli blokowanie BKL jest niepoprawne.
A więc przy aktualnych zasadach gry, nie możemy naprawdę naprawić kodu używającego BKL. Ludzie nie będą w stanie zmienić 1300 bardzo trudnych i delikatnych ścieżek kodu jądra w ciągu jednej nocy, tylko po to, aby zmniejszyć opóźnienia.
Więc… ponieważ uważam, że więcej niż dziesięć lat czekania na poprawę sytuacji jest raczej nie do zaakceptowania, proponuję inne rozwiązanie – spróbujmy zmienić zasady gry 🙂
Celem jest uczynienie usunięcia BKL bardziej prostym i naturalnym – uczynienie BKL bardziej widoczną i usunięcie elementu FUD.
Aby osiągnąć te cele utworzyłem gałąź “kill-the-BKL” w drzewie -tip. Aktualnie gałąź zawiera dziewiętnaście różnych łatek:
git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip.git kill-the-BKL
Ta gałąź (na podstawie najnowszego -git) implementuje największe (i najbardziej krytyczne) zmiany w jądrze mające na celu usunięcie BKL:
- naprawia wszystkie “automatyczne zwolnienia BKL podczas wywołania schedule()” jakie mogłem namierzyć na moich testowych maszynach
- dodaje funkcje debugowania ostrzegającą o niezgodnym z nowym modelem blokowania użyciu BKL
- zamienia BKL w zwykły mutex i usuwa cały kod automatycznie zwalniający blokady BKL z planisty zadań
- zapewnia wsparcie dla BKL w lockdep (mechanizmie sprawdzania poprawności blokad)
- włącza BKL na maszynach jedno procesorowych z wyłączonym wywłaszczeniem – czyni to kod prostszym i bardziej uniwersalnym i miejmy nadzieję, że skłoni to więcej ludzi do pracy nad usunięciem BKL
- czyni sekcje BKL ponownie wywłaszczalnymi
- … poważnie upraszcza kod BKL i przenosi go poza centralną część jądra
Innymi słowy drzewo kill-the-BKL zamienia BKL w zwykły, duży mutex z ekscentrycznym interfejsem nazywanym “lock_kernel()” i “unlock_kernel()”.
Najbardziej interesującym commitem jest aa3187000:
“remove the BKL: remove it from the core kernel!”.
Gdy to drzewo się ustabilizuje, eliminacja BKL może zostać przeprowadzona zwyczajną i dobrze znaną metodą eliminacji wielkich blokad przez: przeniesienie jej do podsystemów i zamianę na blokady w nich używane, rozdzielenie i eliminację blokad. Robiliśmy to już wiele razy w przeszłości i jest wielu deweloperów potrafiących radzić sobie z takimi problemami.
W przyszłości możemy również spróbować wyeliminować funkcję rekurencji (zagnieżdżonego blokowania) BKL – to uczyni kod BKL bardziej oczywisty.
Shortlog, diffstat i łatki są poniżej. Przetestowałem je na 32 i 64 bitowych x86.
Uwaga: kod jest bardzo eksperymentalny – zalecane jest używanie go z włączonymi PROVE_LOCKING i SOFTLOCKUP_DEBUG. Jeśli znajdziesz jakieś ostrzeżenie od lockdep lub softlockup, proszę o jego zgłoszenie. (..)
Dodaj komentarz