Jak zalogować błędy podczas zamykania systemu Debian Linux

Spis treści

By wyłączyć komputer, jego system operacyjny musi pierw zatrzymać (lub też ubić siłowo) wszystkie działające usługi za wyjątkiem tego mającego PID z numerkiem 1. Zwykle proces zamykania się systemu Debian Linux nie trwa więcej niż parę sekund ale czasami pojawiają się dziwne problemy, które mogą to zadanie utrudnić lub też całkowicie uniemożliwić. Nawet jeśli system będzie się w stanie zresetować, to zanim to nastąpi, to na konsoli mogą pojawić się komunikaty mogące pomóc nam w zdiagnozowaniu dolegliwości, która doskwiera naszej maszynie. Problem w tym, że część tych wiadomości nie zostanie nigdy zalogowana do pliku, gdzie moglibyśmy ich poszukać. Dzieje się tak dlatego, że w pewnym określonym momencie zamykania się systemu trzeba wyłączyć usługę logowania, co zwykle widać w logu jako systemd-journald[]: Journal stopped . Gdy dziennik zostanie zatrzymany, żadna wiadomość, która od tego momentu pojawi się na ekranie, nie zostanie już zalogowana do pliku. Jeśli teraz pojawią nam się ostrzeżenia lub błędy, a po chwili komputer się zresetuje, to możemy mieć nie lada problem z ustaleniem przyczyny mimo, że system nam ją zgłasza. Przydałoby się zapisać te komunikaty, tylko jak to zrobić, skoro usługa logowania jest już nieaktywna?

Jak Linux wyłącza komputer

Z chwilą, gdy w działającym Debianie wpiszemy na konsoli reboot/poweroff , systemd zaczyna zamykać usługi (zwykle w kolejności odwrotnej niż zostały one uruchomione). Gdy wszystko idzie według planu, to spora część procesów zostaje zatrzymana zgodnie z określonymi w plikach usług wytycznymi. Gdy procesy są już zatrzymane, to synchronizowane są bufory dysków, a po chwili następuje próba odmontowania wszystkich systemów plików, które do tej pory jeszcze nie zostały odmontowane. Warto tutaj zaznaczyć, że system plików, który jest zamontowany w miejsce / , nie zostanie nigdy odmontowany z racji, że działają na nim procesy, min. ten mający PID 1, a system plików może być odmontowany jedynie w sytuacji, gdy nie jest wykorzystywany przez żaden proces. Systemd doskonale zdaje sobie z tego faktu sprawę i dlatego tuż przed zresetowaniem/wyłączeniem maszyny, montuje / w trybie ro , czyli tylko do odczytu. Zanim to jednak nastąpi, to do każdego procesu (za wyjątkiem PID1), który jeszcze działa w systemie, są wysyłane sygnały SIGTERM oraz SIGKILL W ten sposób pod koniec fazy zamykania systemu działa nam w zasadzie tylko jeden proces i mamy podmontowany z reguły jeden system plików w trybie tylko do odczytu.

Poniżej jest końcówka logu z zamykania systemu:

$  journalctl -b-1
...
systemd[1]: Reached target Unmount All Filesystems.
systemd[1]: Reached target Final Step.
systemd[1]: systemd-reboot.service: Succeeded.
systemd[1]: Started Reboot.
systemd[1]: Reached target Reboot.
systemd[1]: Shutting down.
systemd[1]: Hardware watchdog 'iTCO_wdt', version 0
systemd[1]: Set hardware watchdog to 10min.
kernel: watchdog: watchdog0: watchdog did not stop!
systemd-shutdown[1]: Syncing filesystems and block devices.
systemd-shutdown[1]: Sending SIGTERM to remaining processes...
systemd-journald[396]: Journal stopped

Z komunikatu wyżej widać, że usługa logowania systemd-journald została ubita po tym jak systemd-shutdown posłał jej sygnał SIGTERM umożliwiając jej tym samym zapisanie danych na dysk. System jednak działa dalej, choć nie wyczytamy tego z powyższego logu.

Logi kernela (dmesg) oraz logi systemd

Może i już nie jesteśmy w stanie zalogować komunikatów do pliku, bo stosowna usługa umożliwiająca nam to nie działa ale kernel posiada swój własny mechanizm logowania, tj. dmesg . Dane w dmesg są przechowywane w buforze zlokalizowanym w pamięci RAM, którego rozmiar można dostosować przez dopisanie do linijki kernela w bootloaderze parametru log_buf_len , np. log_buf_len=24M . Domyślnie jednak, w tym buforze znajdą się jedynie logi kernela, przez co niewiele się z nich dowiemy, gdy problem będzie tkwił w jakiejś usłudze systemowej. By zalogować nie tylko komunikaty kernela ale również i te pochodzące od systemd (oraz jego usług), trzeba również użyć parametru systemd.log_target=kmsg . Jeśli w dalszym ciągu logi nic nam nie powiedzą, to możemy przełączyć systemd w tryb debugowania za pomocą parametru systemd.log_level=debug , z tym, że tutaj przydałoby się również wyłączyć ratelimit logów przez określenie printk.devkmsg=on . Zatem do linijki kernela w bootloaderze powinniśmy dodać to poniższe:

APPEND root=... systemd.log_level=debug systemd.log_target=kmsg log_buf_len=24M printk.devkmsg=on ...

Poniżej znajduje się przykład tego, co zostaje zalogowane od momentu, gdy usługa systemd-journald zostaje zatrzymana:

[97745.444190] systemd-shutdown[1]: Sending SIGTERM to remaining processes...
[97745.451446] systemd-journald[482]: Received SIGTERM from PID 1 (systemd-shutdow).
[97745.649032] systemd-shutdown[1]: Sending SIGKILL to remaining processes...
[97745.656809] systemd-shutdown[1]: Hardware watchdog 'iTCO_wdt', version 0
[97745.659726] systemd-shutdown[1]: Unmounting file systems.
[97745.663229] [47842]: Remounting '/' read-only in with options 'errors=remount-ro'.
[97745.755769] EXT4-fs (dm-4): re-mounted. Opts: errors=remount-ro
[97745.791525] systemd-shutdown[1]: All filesystems unmounted.
[97745.794368] systemd-shutdown[1]: Deactivating swaps.
[97745.796662] systemd-shutdown[1]: All swaps deactivated.
[97745.798859] systemd-shutdown[1]: Detaching loop devices.
[97745.806223] systemd-shutdown[1]: All loop devices detached.
[97745.807701] systemd-shutdown[1]: Detaching DM devices.
[97745.812357] systemd-shutdown[1]: Detaching DM 253:9.
[97745.833097] systemd-shutdown[1]: Detaching DM 253:8.
[97745.835815] systemd-shutdown[1]: Could not detach DM /dev/dm-8: Device or resource busy
[97745.838396] systemd-shutdown[1]: Detaching DM 253:7.
[97745.855184] systemd-shutdown[1]: Detaching DM 253:6.
[97745.878200] systemd-shutdown[1]: Detaching DM 253:5.
[97745.896543] systemd-shutdown[1]: Detaching DM 253:3.
[97745.908330] systemd-shutdown[1]: Detaching DM 253:2.
[97745.926478] systemd-shutdown[1]: Detaching DM 253:12.
[97745.947184] systemd-shutdown[1]: Detaching DM 253:11.
[97745.964219] systemd-shutdown[1]: Detaching DM 253:10.
[97745.977158] systemd-shutdown[1]: Detaching DM 253:1.
[97745.989103] systemd-shutdown[1]: Detaching DM 253:0.
[97745.991164] systemd-shutdown[1]: Could not detach DM /dev/dm-0: Device or resource busy
[97745.993165] systemd-shutdown[1]: Not all DM devices detached, 3 left.
[97745.995581] systemd-shutdown[1]: Detaching DM devices.
[97745.998183] systemd-shutdown[1]: Detaching DM 253:8.
[97746.012280] systemd-shutdown[1]: Detaching DM 253:0.
[97746.013710] systemd-shutdown[1]: Could not detach DM /dev/dm-0: Device or resource busy
[97746.015103] systemd-shutdown[1]: Not all DM devices detached, 2 left.
[97746.016793] systemd-shutdown[1]: Detaching DM devices.
[97746.019221] systemd-shutdown[1]: Detaching DM 253:0.
[97746.020676] systemd-shutdown[1]: Could not detach DM /dev/dm-0: Device or resource busy
[97746.022143] systemd-shutdown[1]: Not all DM devices detached, 2 left.
[97746.023867] systemd-shutdown[1]: Detaching DM devices.
[97746.026179] systemd-shutdown[1]: Detaching DM 253:0.
[97746.027658] systemd-shutdown[1]: Could not detach DM /dev/dm-0: Device or resource busy
[97746.028776] systemd-shutdown[1]: Not all DM devices detached, 2 left.
[97746.029878] systemd-shutdown[1]: Cannot finalize remaining DM devices, continuing.
[97746.205732] EXT4-fs (dm-4): re-mounted. Opts: errors=remount-ro

Tych komunikatów naturalnie może być więcej, choć jak widać, to w zasadzie tylko systemd-shutdown i kernel na tym etapie zamykania systemu są jeszcze w stanie coś powiedzieć.

Jak zrzucić dmesg przy zamykaniu systemu do pliku

By te powyższe wiadomości zapisać do pliku, potrzebny jest nam krótki skrypt, który zamontuje nam na chwilę partycję / w trybie do zapisu ( rw ), zrzuci bufor dmesg do pliku (przykładowo /shutdown-log.txt ), zsynchronizuje bufor dysku i przemontuje z powrotem system plików w tryb tylko do odczytu ( ro ). Poniżej jest taki skrypt:

#!/bin/sh
mount -o remount,rw /
dmesg > /shutdown-log.txt
sync
mount -o remount,ro /

Ten skrypt trzeba zapisać w katalogu /lib/systemd/system-shutdown/ i nadać mu prawa do wykonywania:

# chmod +x /lib/systemd/system-shutdown/debug.sh

Teraz już wystarczy zrestartować system i po ponownym jego uruchomieniu zajrzeć w plik /shutdown-log.txt . Warto tutaj zaznaczyć, że w tym pliku znajdą się również logi z wcześniejszego etapu pracy systemu i trzeba w nich odszukać moment, w którym proces wyłączania maszyny zostaje zainicjowany ale to zadanie nie powinno już sprawić problemu.

Mikhail Morfikov avatar
Mikhail Morfikov
Po ponad 10 latach spędzonych z różnej maści linux'ami (Debian/Ubuntu, OpenWRT, Android) mogę śmiało powiedzieć, że nie ma rzeczy niemożliwych i problemów, których nie da się rozwiązać. Jedną umiejętność, którą ludzki umysł musi posiąść, by wybrnąć nawet z tej najbardziej nieprzyjemniej sytuacji, to zdolność logicznego rozumowania.