Darmowy fragment publikacji:
Tytuł oryginału: Linux Kernel Development (3rd Edition)
Tłumaczenie: Przemysław Szeremiota
ISBN: 978-83-246-4273-1
Authorized translation from the English edition, entitled: LINUX KERNEL DEVELOPMENT, Third
Edition; ISBN 0672329468; by Robert Love; published by Pearson Education, Inc, publishing as Addison
Wesley.
Copyright © 2010 by Pearson Education, Inc.
All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means,
electronic or mechanical, including photocopying, recording or by any information storage retrieval system,
without permission from Pearson Education, Inc.
Polish language edition published by HELION S.A., Copyright © 2014.
Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości lub fragmentu niniejszej
publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii metodą kserograficzną,
fotograficzną, a także kopiowanie książki na nośniku filmowym, magnetycznym lub innym powoduje
naruszenie praw autorskich niniejszej publikacji.
Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi bądź towarowymi ich
właścicieli.
Autor oraz Wydawnictwo HELION dołożyli wszelkich starań, by zawarte w tej książce informacje były
kompletne i rzetelne. Nie bierze jednak żadnej odpowiedzialności ani za ich wykorzystanie, ani za
związane z tym ewentualne naruszenie praw patentowych lub autorskich. Wydawnictwo HELION nie
ponosi również żadnej odpowiedzialności za ewentualne szkody wynikłe z wykorzystania informacji
zawartych w książce.
Wydawnictwo HELION
ul. Kościuszki 1c, 44-100 GLIWICE
tel. 32 231 22 19, 32 230 98 63
e-mail: helion@helion.pl
WWW: http://helion.pl (księgarnia internetowa, katalog książek)
Drogi Czytelniku!
Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres
http://helion.pl/user/opinie/jadlin
Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję.
Printed in Poland.
• Kup książkę
• Poleć książkę
• Oceń książkę
• Księgarnia internetowa
• Lubię to! » Nasza społeczność
Spis treści
Przedmowa ........................................................................17
Wst(cid:246)p ...............................................................................19
Rozdzia(cid:228) 1. J(cid:241)dro systemu Linux — wprowadzenie ................................25
Historia Uniksa .............................................................................25
Wprowadzenie do systemu Linux ....................................................27
Przegl(cid:241)d systemów operacyjnych ....................................................29
J(cid:241)dro Linuksa a j(cid:241)dro klasycznego systemu uniksowego ..................31
Oznaczenia wersji j(cid:241)dra Linuksa .....................................................34
Spo(cid:228)eczno(cid:264)(cid:232) programistów j(cid:241)dra Linuksa ........................................35
Zanim zaczniemy ...........................................................................36
Rozdzia(cid:228) 2. Linux — zaczynamy ............................................................37
Kod (cid:274)ród(cid:228)owy j(cid:241)dra ........................................................................37
Git ..........................................................................................37
Instalowanie (cid:274)róde(cid:228) j(cid:241)dra z archiwum .........................................38
Aplikowanie (cid:228)at ........................................................................39
Struktura katalogów kodu (cid:274)ród(cid:228)owego j(cid:241)dra .....................................39
Kompilowanie j(cid:241)dra .......................................................................40
Konfigurowanie j(cid:241)dra ................................................................41
Minimalizacja szumu podczas kompilacji ...................................43
Kompilacja na wielu frontach ....................................................43
Instalowanie nowego j(cid:241)dra .......................................................44
Odmienno(cid:264)(cid:232) j(cid:241)dra .........................................................................45
Brak implementacji i nag(cid:228)ówków biblioteki standardowej C ..........45
GNU C ....................................................................................47
Brak mechanizmu ochrony pami(cid:246)ci ............................................49
Niemo(cid:276)no(cid:264)(cid:232) ((cid:228)atwego) korzystania
z operacji zmiennoprzecinkowych ............................................50
Ograniczony co do rozmiaru (i sta(cid:228)y) stos ...................................50
Synchronizacja i wspó(cid:228)bie(cid:276)no(cid:264)(cid:232) .................................................50
Znaczenie przeno(cid:264)no(cid:264)ci ...........................................................51
Podsumowanie .............................................................................51
Kup książkęPoleć książkę
6
J(cid:241)dro Linuksa. Przewodnik programisty
Rozdzia(cid:228) 3. Zarz(cid:241)dzanie procesami .......................................................53
Proces .........................................................................................53
Deskryptor procesu i struktura zadania ...........................................55
Przydzia(cid:228) deskryptora procesu ...................................................55
Przechowywanie deskryptora procesu ........................................57
Stan procesu ...........................................................................58
Manipulowanie bie(cid:276)(cid:241)cym stanem procesu .................................59
Kontekst procesu ....................................................................60
Drzewo procesów .....................................................................60
Tworzenie procesu ........................................................................62
Kopiowanie przy zapisie ............................................................62
Rozwidlanie procesu ................................................................63
Wywo(cid:228)anie vfork() .....................................................................64
W(cid:241)tki w systemie Linux .................................................................65
Tworzenie w(cid:241)tków ....................................................................66
W(cid:241)tki j(cid:241)dra ..............................................................................67
Zako(cid:254)czenie procesu .....................................................................68
Usuwanie deskryptora procesu .................................................70
Problem zada(cid:254) osieroconych .....................................................71
Podsumowanie .............................................................................73
Rozdzia(cid:228) 4. Szeregowanie zada(cid:254) ...........................................................75
Wielozadaniowo(cid:264)(cid:232) .........................................................................75
Planista zada(cid:254) w Linuksie ..............................................................77
Strategia post(cid:246)powania .................................................................77
Procesy ograniczone wej(cid:264)ciem-wyj(cid:264)ciem
a procesy ograniczone procesorem .........................................78
Priorytet procesu .....................................................................79
Kwant czasu procesora ............................................................80
Strategia szeregowania w dzia(cid:228)aniu ...........................................81
Algorytm szeregowania zada(cid:254) w Linuksie ........................................82
Klasy szeregowania ..................................................................82
Szeregowanie procesów w systemach klasy Unix ........................82
Sprawiedliwe szeregowanie zada(cid:254) .............................................85
Implementacja szeregowania zada(cid:254) w Linuksie ...............................87
Zliczanie czasu wykonania ........................................................87
Wybór procesu .........................................................................89
Punkt wej(cid:264)cia do planisty CFS ...................................................94
Zawieszanie i wybudzanie procesów ..........................................95
Wyw(cid:228)aszczanie i prze(cid:228)(cid:241)czanie kontekstu ..........................................99
Wyw(cid:228)aszczanie procesu u(cid:276)ytkownika ........................................100
Wyw(cid:228)aszczenie j(cid:241)dra ..............................................................101
Szeregowanie czasu rzeczywistego ...............................................102
Kup książkęPoleć książkę
Spis tre(cid:264)ci
7
Wywo(cid:228)ania systemowe zwi(cid:241)zane z szeregowaniem .........................103
Wywo(cid:228)ania wp(cid:228)ywaj(cid:241)ce na strategi(cid:246) szeregowania
i warto(cid:264)ci priorytetów ...........................................................104
Wywo(cid:228)ania systemowe steruj(cid:241)ce kojarzeniem procesów
z procesorami .....................................................................105
Odst(cid:241)pienie procesora ...........................................................105
Podsumowanie ...........................................................................106
Rozdzia(cid:228) 5. Wywo(cid:228)ania systemowe .....................................................107
Komunikacja z j(cid:241)drem systemu ....................................................107
API, POSIX i biblioteka C ..............................................................108
Wywo(cid:228)ania systemowe .................................................................109
Numery wywo(cid:228)a(cid:254) systemowych ................................................111
Wydajno(cid:264)(cid:232) wywo(cid:228)ania systemowego ........................................111
Procedura obs(cid:228)ugi wywo(cid:228)a(cid:254) systemowych .....................................111
Oznaczanie w(cid:228)a(cid:264)ciwego wywo(cid:228)ania systemowego ......................112
Przekazywanie argumentów ....................................................113
Implementacja wywo(cid:228)ania systemowego ........................................113
Implementowanie wywo(cid:228)a(cid:254) systemowych .................................114
Weryfikacja argumentów .........................................................114
Kontekst wywo(cid:228)ania systemowego ................................................118
Wi(cid:241)zanie wywo(cid:228)ania systemowego ...........................................119
Inicjowanie wywo(cid:228)ania systemowego
z przestrzeni u(cid:276)ytkownika .....................................................120
Sze(cid:264)(cid:232) powodów,
aby nie implementowa(cid:232) wywo(cid:228)a(cid:254) systemowych ......................121
Podsumowanie ...........................................................................122
Rozdzia(cid:228) 6. Struktury danych j(cid:241)dra .....................................................123
Listy ...........................................................................................123
Listy jedno- i dwukierunkowe ...................................................124
Listy cykliczne .......................................................................124
Implementacja list w j(cid:241)drze Linuksa ........................................126
Operacje na listach ................................................................128
Przegl(cid:241)danie list ....................................................................131
Inne operacje na listach .........................................................134
Kolejki ........................................................................................135
kfifo ......................................................................................135
Tworzenie kolejki ...................................................................136
Zakolejkowanie ......................................................................137
Wyci(cid:241)ganie danych .................................................................137
Okre(cid:264)lanie rozmiaru kolejki .....................................................137
Zerowanie i usuwanie kolejki ..................................................138
Przyk(cid:228)ad u(cid:276)ycia kolejki kfifo .....................................................138
Kup książkęPoleć książkę
8
J(cid:241)dro Linuksa. Przewodnik programisty
Mapy ..........................................................................................139
Inicjalizowanie mapy idr ..........................................................140
Przydzia(cid:228) nowego identyfikatora UID .........................................140
Odwzorowanie UID na wska(cid:274)nik ..............................................141
Usuwanie UID ........................................................................142
Usuwanie idr .........................................................................142
Drzewa binarne ...........................................................................143
Drzewa BST ...........................................................................143
Zrównowa(cid:276)one drzewa BST .....................................................144
Drzewa czerwono-czarne .........................................................145
rbtree ...................................................................................146
Kiedy i jakiej struktury u(cid:276)y(cid:232)? ........................................................148
Z(cid:228)o(cid:276)ono(cid:264)(cid:232) obliczeniowa ...............................................................149
Algorytmy ..............................................................................149
Notacja O ..............................................................................149
Notacja theta ........................................................................150
Z(cid:228)o(cid:276)ono(cid:264)(cid:232) czasowa ................................................................150
Podsumowanie ...........................................................................151
Rozdzia(cid:228) 7. Przerwania i procedury obs(cid:228)ugi przerwa(cid:254) ...........................153
Przerwania ..................................................................................154
Procedury obs(cid:228)ugi przerwa(cid:254) ..........................................................155
Po(cid:228)ówki górne i dolne ..................................................................156
Rejestrowanie procedury obs(cid:228)ugi przerwania ..................................157
Znaczniki procedury obs(cid:228)ugi przerwa(cid:254) ......................................158
Przyk(cid:228)adowe przerwanie ..........................................................159
Zwalnianie procedury obs(cid:228)ugi przerwania ..................................160
Tworzenie procedury obs(cid:228)ugi przerwa(cid:254) ..........................................160
Procedury obs(cid:228)ugi przerwa(cid:254) wspó(cid:228)u(cid:276)ytkowanych .......................162
Prawdziwa procedura obs(cid:228)ugi przerwania ..................................163
Kontekst przerwania ....................................................................165
Implementacja obs(cid:228)ugi przerwa(cid:254) ...................................................166
/proc/interrupts ..........................................................................168
Kontrola przerwa(cid:254) .......................................................................169
Wy(cid:228)(cid:241)czanie i w(cid:228)(cid:241)czanie przerwa(cid:254) .............................................170
Blokowanie konkretnej linii przerwania .....................................172
Stan systemu przerwa(cid:254) ..........................................................173
Podsumowanie ...........................................................................174
Rozdzia(cid:228) 8. Dolne po(cid:228)ówki i czynno(cid:264)ci odroczone ................................175
Po(cid:228)ówki dolne .............................................................................176
Po co dolne po(cid:228)ówki? .............................................................177
(cid:263)wiat dolnych po(cid:228)ówek ...........................................................178
Kup książkęPoleć książkę
Spis tre(cid:264)ci
9
Przerwania programowe ...............................................................181
Implementacja przerwa(cid:254) programowych ...................................181
Korzystanie z przerwa(cid:254) programowych .....................................183
Tasklety .....................................................................................186
Implementacja taskletów ........................................................186
Korzystanie z taskletów ..........................................................189
W(cid:241)tek j(cid:241)dra ksoftirqd .............................................................191
Dawny mechanizm BH ............................................................193
Kolejki prac ................................................................................194
Implementacja kolejek prac ....................................................195
Korzystanie z kolejek prac ......................................................199
Dawny mechanizm kolejkowania zada(cid:254) ....................................201
Jak wybra(cid:232) implementacj(cid:246) dolnej po(cid:228)ówki? ....................................202
Blokowanie pomi(cid:246)dzy dolnymi po(cid:228)ówkami ......................................204
Wy(cid:228)(cid:241)czanie dolnych po(cid:228)ówek ........................................................204
Podsumowanie ...........................................................................206
Rozdzia(cid:228) 9. Wprowadzenie do synchronizacji j(cid:241)dra ..............................207
Sekcje krytyczne i przeplot operacji ...............................................208
Po co ta ochrona? ..................................................................208
Zmienna globalna ..................................................................210
Blokowanie .................................................................................211
(cid:273)ród(cid:228)a wspó(cid:228)bie(cid:276)no(cid:264)ci ............................................................213
Co wymaga zabezpieczania? ...................................................215
Zakleszczenia .............................................................................216
Rywalizacja a skalowalno(cid:264)(cid:232) ..........................................................218
Podsumowanie ...........................................................................220
Rozdzia(cid:228) 10. Metody synchronizacji j(cid:241)dra .............................................221
Operacje niepodzielne .................................................................221
Niepodzielne operacje na liczbach ca(cid:228)kowitych .........................222
64-bitowe operacje niepodzielne .............................................226
Niepodzielne operacje bitowe ..................................................228
Rygle p(cid:246)tlowe .............................................................................230
Interfejs rygli p(cid:246)tlowych ..........................................................231
Inne metody blokowania ryglami p(cid:246)tlowymi ..............................234
Rygle p(cid:246)tlowe a dolne po(cid:228)ówki ................................................234
Rygle p(cid:246)tlowe R-W .......................................................................235
Semafory ....................................................................................238
Semafory binarne i zliczaj(cid:241)ce ..................................................239
Tworzenie i inicjalizowanie semaforów .....................................240
Korzystanie z semaforów ........................................................240
Semafory R-W .............................................................................241
Kup książkęPoleć książkę 10
J(cid:241)dro Linuksa. Przewodnik programisty
Muteksy .....................................................................................243
Muteksy czy semafory? ..........................................................245
Muteksy czy rygle p(cid:246)tlowe? .....................................................245
Zmienne sygna(cid:228)owe .....................................................................245
Blokada BKL (Big Kernel Lock) .....................................................246
Blokady sekwencyjne ...................................................................247
Blokowanie wyw(cid:228)aszczania ...........................................................249
Bariery pami(cid:246)ciowe .....................................................................251
Podsumowanie ...........................................................................255
Rozdzia(cid:228) 11. Liczniki i zarz(cid:241)dzanie czasem ............................................257
Czas z punktu widzenia j(cid:241)dra .......................................................258
Cz(cid:246)stotliwo(cid:264)(cid:232) taktowania — HZ ...................................................259
Optymalna warto(cid:264)(cid:232) HZ ...........................................................260
Zalety wysokich warto(cid:264)ci HZ ...................................................261
Wady wysokich warto(cid:264)ci HZ ....................................................262
Chwilki .......................................................................................263
Wewn(cid:246)trzna reprezentacja zmiennej jiffies ...............................264
Zawijanie zmiennej jiffies ........................................................266
HZ a przestrze(cid:254) u(cid:276)ytkownika ...................................................267
Zegary i liczniki sprz(cid:246)towe ............................................................268
Zegar czasu rzeczywistego ......................................................268
Zegar systemowy ...................................................................269
Procedura obs(cid:228)ugi przerwania zegarowego .....................................269
Data i godzina .............................................................................272
Liczniki .......................................................................................274
Korzystanie z liczników ...........................................................275
Liczniki i sytuacje hazardowe ..................................................277
Implementacja licznika ...........................................................277
Opó(cid:274)nianie wykonania .................................................................278
Oczekiwanie w p(cid:246)tli aktywnej ..................................................278
Krótkie opó(cid:274)nienia .................................................................280
Funkcja schedule_timeout() ....................................................281
Implementacja funkcji schedule_timeout() ...............................282
Podsumowanie ...........................................................................284
Rozdzia(cid:228) 12. Zarz(cid:241)dzanie pami(cid:246)ci(cid:241) .......................................................285
Strony ........................................................................................285
Strefy .........................................................................................287
Pozyskiwanie stron pami(cid:246)ci .........................................................290
Pozyskiwanie czystych stron pami(cid:246)ci .......................................291
Zwalnianie stron ....................................................................291
Funkcja kmalloc() ........................................................................292
Znaczniki gfp_mask ...............................................................293
Funkcja kfree() .......................................................................298
Kup książkęPoleć książkę
Spis tre(cid:264)ci
11
Funkcja vmalloc() ........................................................................299
Alokator plastrowy .......................................................................301
Zadania alokatora plastrowego ...............................................302
Interfejs alokatora plastrowego ...............................................305
Przydzia(cid:228) z pami(cid:246)ci podr(cid:246)cznej ................................................307
Statyczne przydzia(cid:228)y na stosie ......................................................309
Jednostronicowy stos procesów j(cid:241)dra ......................................309
Ostro(cid:276)nie ze stosem ..............................................................310
Odwzorowanie pami(cid:246)ci wysokiej ...................................................310
Odwzorowanie trwa(cid:228)e ..............................................................311
Odwzorowania czasowe ..........................................................311
Przydzia(cid:228)y lokalne wzgl(cid:246)dem procesora .........................................312
Interfejs percpu ...........................................................................313
Statyczne dane lokalne wzgl(cid:246)dem procesora ............................313
Dynamiczne dane lokalne wzgl(cid:246)dem procesora ........................314
Przydatno(cid:264)(cid:232) danych lokalnych wzgl(cid:246)dem procesora ........................315
Wybór metody przydzia(cid:228)u pami(cid:246)ci w kodzie j(cid:241)dra ............................316
Podsumowanie ...........................................................................317
Rozdzia(cid:228) 13. Wirtualny system plików ..................................................319
Wspólny interfejs systemu plików .................................................320
Warstwa abstrakcji systemu plików ..............................................320
Uniksowy system plików ..............................................................322
Obiekty VFS i ich struktury danych ................................................323
Obiekt bloku g(cid:228)ównego ................................................................325
Operacje bloku g(cid:228)ównego .............................................................326
Obiekt i-w(cid:246)z(cid:228)a .............................................................................329
Operacje i-w(cid:246)z(cid:228)a ..........................................................................331
Obiekt wpisu katalogowego ..........................................................334
Stan wpisu katalogowego .......................................................335
Bufor wpisów katalogowych ....................................................336
Operacje na wpisach katalogowych ...............................................337
Obiekt pliku ................................................................................339
Operacje na plikach .....................................................................340
Struktury danych systemu plików ..................................................343
Struktury danych procesu ............................................................345
Podsumowanie ...........................................................................347
Rozdzia(cid:228) 14. Blokowe urz(cid:241)dzenia wej(cid:264)cia-wyj(cid:264)cia .................................349
Anatomia urz(cid:241)dzenia blokowego ...................................................350
Bufory i nag(cid:228)ówki buforów ............................................................351
Struktura bio ..............................................................................354
Wektory wej(cid:264)cia-wyj(cid:264)cia ..........................................................355
Stare a nowe .........................................................................357
Kup książkęPoleć książkę 12
J(cid:241)dro Linuksa. Przewodnik programisty
Kolejki zlece(cid:254) .............................................................................357
Zawiadywanie operacjami wej(cid:264)cia-wyj(cid:264)cia ......................................358
Zadania planisty operacji wej(cid:264)cia-wyj(cid:264)cia .................................359
Winda Linusa ........................................................................360
Terminowy planista operacji wej(cid:264)cia-wyj(cid:264)cia .............................361
Przewiduj(cid:241)cy planista operacji wej(cid:264)cia-wyj(cid:264)cia ..........................363
Sprawiedliwy planista kolejkowania operacji wej(cid:264)cia-wyj(cid:264)cia ....364
Nieingeruj(cid:241)cy planista operacji wej(cid:264)cia-wyj(cid:264)cia .........................365
Wybór planisty operacji wej(cid:264)cia-wyj(cid:264)cia ....................................366
Podsumowanie ...........................................................................366
Rozdzia(cid:228) 15. Przestrze(cid:254) adresowa procesu ...........................................367
Przestrzenie adresowe .................................................................367
Deskryptor pami(cid:246)ci .....................................................................369
Przydzia(cid:228) deskryptora pami(cid:246)ci .................................................371
Zwalnianie deskryptora pami(cid:246)ci ..............................................371
Struktura mm_struct i w(cid:241)tki j(cid:241)dra ............................................372
Obszary pami(cid:246)ci wirtualnej ...........................................................372
Znaczniki VMA .......................................................................374
Operacje VMA ........................................................................375
Obszary pami(cid:246)ci na listach i w drzewach ..................................376
Obszary pami(cid:246)ci w praktyce ....................................................377
Manipulowanie obszarami pami(cid:246)ci ...............................................379
Funkcja find_vma() .................................................................379
Funkcja find_vma_prev() .........................................................381
Funkcja find_vma_intersection() ..............................................381
Tworzenie interwa(cid:228)u adresów
— wywo(cid:228)ania mmap() i do_mmap() .............................................381
Usuwanie interwa(cid:228)u adresów
— wywo(cid:228)ania munmap() i do_munmap() ......................................383
Tablice stron ...............................................................................384
Podsumowanie ...........................................................................386
Rozdzia(cid:228) 16. Pami(cid:246)(cid:232) podr(cid:246)czna stron i opó(cid:274)niony zapis stron w tle .......387
Modele pami(cid:246)ci podr(cid:246)cznych .......................................................387
Buforowanie zapisów ..............................................................388
Eksmisja z pami(cid:246)ci podr(cid:246)cznej ................................................389
Pami(cid:246)(cid:232) podr(cid:246)czna stron w Linuksie ..............................................391
Obiekt address_space ............................................................391
Operacje na obiektach address_space ....................................392
Drzewo pozycyjne ...................................................................395
Tablica skrótów stron .............................................................395
Pami(cid:246)(cid:232) podr(cid:246)czna buforów ..........................................................396
Kup książkęPoleć książkę
Spis tre(cid:264)ci
13
W(cid:241)tki zapisu w tle .......................................................................396
Tryb laptopowy .......................................................................398
Rys historyczny — bdflush, kupdated i pdflush .........................399
Eliminowanie obci(cid:241)(cid:276)enia operacjami wej(cid:264)cia-wyj(cid:264)cia .................400
Podsumowanie ...........................................................................401
Rozdzia(cid:228) 17. Sterowniki i modu(cid:228)y .........................................................403
Typy urz(cid:241)dze(cid:254) .............................................................................403
Modu(cid:228)y .......................................................................................404
Hello, world! ..........................................................................405
Kompilowanie modu(cid:228)ów ..........................................................406
Instalowanie modu(cid:228)ów ............................................................409
Generowanie zale(cid:276)no(cid:264)ci mi(cid:246)dzymodu(cid:228)owych .............................409
(cid:227)adowanie modu(cid:228)ów ...............................................................410
Zarz(cid:241)dzanie opcjami konfiguracji j(cid:241)dra .....................................411
Parametry modu(cid:228)ów ...............................................................413
Symbole eksportowane ..........................................................415
Model sterowników .....................................................................416
Obiekty j(cid:241)dra .........................................................................417
Typy obiektów j(cid:241)dra ................................................................418
Grupy obiektów j(cid:241)dra ..............................................................419
Powi(cid:241)zania pomi(cid:246)dzy obiektami, typami
i grupami obiektów j(cid:241)dra ......................................................419
Zarz(cid:241)dzanie i operowanie obiektami j(cid:241)dra ................................420
Zliczanie odwo(cid:228)a(cid:254) ..................................................................421
System plików sysfs ....................................................................423
Dodawanie i usuwanie obiektów j(cid:241)dra w sysfs ..........................426
Dodawanie plików do sysfs .....................................................427
Kernel Event Layer .................................................................430
Podsumowanie ...........................................................................431
Rozdzia(cid:228) 18. Diagnostyka b(cid:228)(cid:246)dów j(cid:241)dra ................................................433
Od czego zacz(cid:241)(cid:232)? ........................................................................433
B(cid:228)(cid:246)dy w j(cid:241)drze .............................................................................434
Diagnostyka komunikatami ..........................................................435
Niezawodno(cid:264)(cid:232) printk() ............................................................435
Poziomy diagnostyczne ...........................................................436
Bufor komunikatów ................................................................437
Demony syslogd i klogd ..........................................................438
printf(), printk() — (cid:228)atwo o pomy(cid:228)k(cid:246) .........................................438
B(cid:228)(cid:241)d oops ...................................................................................438
Polecenie ksymoops ..............................................................440
kallsyms ...............................................................................441
Opcje diagnostyczne j(cid:241)dra ...........................................................441
Kup książkęPoleć książkę 14
J(cid:241)dro Linuksa. Przewodnik programisty
Asercje i wypisywanie informacji o b(cid:228)(cid:246)dach ....................................442
Funkcja Magic SysRq Key ............................................................443
Saga debugera j(cid:241)dra ...................................................................444
gdb .......................................................................................445
kgdb .....................................................................................446
Stymulowanie i sondowanie systemu ............................................446
Uzale(cid:276)nianie wykonania kodu od identyfikatora UID ..................446
Korzystanie ze zmiennych warunkowych ...................................447
Korzystanie ze statystyk .........................................................447
Ograniczanie cz(cid:246)stotliwo(cid:264)ci
i liczby komunikatów diagnostycznych ....................................448
Szukanie winowajcy — wyszukiwanie binarne ................................449
Binarne wyszukiwanie wersji za pomoc(cid:241) Gita .................................450
Koledzy — kiedy wszystko inne zawiedzie .....................................451
Podsumowanie ...........................................................................451
Rozdzia(cid:228) 19. Przeno(cid:264)no(cid:264)(cid:232) ....................................................................453
Przeno(cid:264)ne systemy operacyjne .....................................................453
Historia przeno(cid:264)no(cid:264)ci systemu Linux ............................................455
Rozmiar s(cid:228)owa i typy danych .........................................................456
Typy nieprzejrzyste .................................................................459
Typy specjalne .......................................................................459
Typy o zadanych rozmiarach ....................................................460
Znak typu char .......................................................................461
Wyrównanie danych .....................................................................462
Unikanie problemów wyrównywania .........................................462
Wyrównanie typów niestandardowych ......................................463
Dope(cid:228)nienie struktury .............................................................463
Wzajemny porz(cid:241)dek bajtów ..........................................................465
Pomiar up(cid:228)ywu czasu ...................................................................467
Rozmiar strony ............................................................................468
Kolejno(cid:264)(cid:232) wykonywania instrukcji .................................................469
Tryb SMP, wyw(cid:228)aszczanie j(cid:241)dra i pami(cid:246)(cid:232) wysoka ............................469
Podsumowanie ...........................................................................470
Rozdzia(cid:228) 20. Kodowanie, (cid:228)aty i spo(cid:228)eczno(cid:264)(cid:232) ..........................................471
Spo(cid:228)eczno(cid:264)(cid:232) ...............................................................................471
Obowi(cid:241)zuj(cid:241)cy styl kodowania .......................................................472
Wci(cid:246)cia .................................................................................472
Instrukcje switch ....................................................................473
Odst(cid:246)py ................................................................................473
Nawiasy klamrowe .................................................................475
D(cid:228)ugo(cid:264)(cid:232) wiersza kodu ............................................................476
Nazewnictwo .........................................................................476
Kup książkęPoleć książkę
Spis tre(cid:264)ci
15
Funkcje .................................................................................477
Komentarze ...........................................................................477
Definicje typów ......................................................................478
Korzystanie z gotowców ..........................................................478
Unikanie definicji ifdef w ciele funkcji ......................................478
Inicjalizacja struktur ...............................................................479
Poprawianie z(cid:228)ego stylu ..........................................................479
(cid:227)a(cid:254)cuch polece(cid:254) .........................................................................480
Przesy(cid:228)anie raportów o b(cid:228)(cid:246)dach ....................................................480
(cid:227)aty ...........................................................................................481
Generowanie (cid:228)at ....................................................................481
Generowanie (cid:228)at za pomoc(cid:241) Gita .............................................482
Rozsy(cid:228)anie (cid:228)at ........................................................................483
Podsumowanie ...........................................................................484
Dodatek A Bibliografia ......................................................................485
Ksi(cid:241)(cid:276)ki o projektowaniu systemów operacyjnych ............................485
Ksi(cid:241)(cid:276)ki o j(cid:241)drze systemu Unix ......................................................486
Ksi(cid:241)(cid:276)ki o j(cid:241)drze systemu Linux .....................................................486
Ksi(cid:241)(cid:276)ki o j(cid:241)drach innych systemów operacyjnych ...........................487
Ksi(cid:241)(cid:276)ki o interfejsie programowym Uniksa .....................................487
Ksi(cid:241)(cid:276)ki o programowaniu w j(cid:246)zyku C .............................................487
Inne ksi(cid:241)(cid:276)ki ................................................................................488
Witryny WWW ..............................................................................488
Skorowidz.........................................................................489
Kup książkęPoleć książkę 16
J(cid:241)dro Linuksa. Przewodnik programisty
Kup książkęPoleć książkę18
Diagnostyka błędów jądra
J
edną z podstawowych miar odróżniających programowanie jądra od programowania
przestrzeni użytkownika jest stopień trudności diagnostyki błędów. Diagnostyka jądra
nie jest łatwa, zwłaszcza w porównaniu z przestrzenią użytkownika. Problem komplikuje
jeszcze wysokość stawki — błąd w jądrze może załamać cały system komputerowy.
Rosnąca umiejętność diagnozowania błędów w jądrze — a co za tym idzie, coraz
większa swoboda programowania jądra — jest w dużej mierze funkcją doświadczenia
i stopnia zrozumienia systemu operacyjnego. Podziałać mogą zapewne również zaklęcia
i czary, ale do udanej diagnostyki jądra konieczna jest jego pełna znajomość. Niniejszy
rozdział poświęcony będzie właśnie zagadnieniom związanym z diagnostyką błędów jądra.
Od czego zacz(cid:241)(cid:232)?
Diagnostyka błędów w jądrze bywa uciążliwym i żmudnym procesem. Niektóre z błędów
całymi miesiącami myliły tropy, choć śledzone były przez wielu programistów. Na szczęście
na dosłownie każdy tak pracochłonny błąd przypada wiele błędów bardziej oczywistych,
z równie oczywistymi poprawkami. Przy odrobinie szczęścia wszystkie błędy, jakie
popełnimy, będą błędami prostymi. Tego jednak przed rozpoczęciem poszukiwań
nie będzie wiadomo na pewno. Dlatego warto zaopatrzyć się w:
(cid:132) Błąd. To może brzmi śmiesznie, ale potrzebny będzie dobrze zdefiniowany
i bardzo konkretny błąd. Dobrze, jeżeli jest to błąd powtarzalny, który można
sprowokować w określonych warunkach. Niestety, błędy rzadko bywają
stabilne i powtarzalne.
(cid:132) Wersję jądra, w której występuje rzeczony błąd (na przykład najnowszą wersję,
bo inaczej nikt nie zawracałby sobie głowy błędem). Najlepiej, jeżeli uda się
wytypować najwcześniejszą wersję jądra, w której pojawił się błąd. W rozdziale
będzie omawiana technika polowania na popsutą wersję jądra.
(cid:132) Znajomość odpowiedniej części jądra albo szczęście. Diagnozowanie błędów
jądra jest śledztwem, które daje tym lepsze wyniki, im lepsza jest znajomość
otoczenia.
Kup książkęPoleć książkę434
Rozdzia(cid:228) 18. Diagnostyka b(cid:228)(cid:246)dów j(cid:241)dra
Większość bieżącego rozdziału będzie poświęcona technikom reprodukcji błędów.
Skuteczność w ich poprawianiu jest bowiem wypadkową umiejętności prowokowania
wystąpienia błędu. Niemożność sprowokowania błędu ogranicza możliwości jego usunięcia,
zmuszając do jedynie koncepcyjnego określenia problemu i odnalezienia odpowiadającej
mu luki w kodzie źródłowym. Często zdarza się zresztą i tak, ale szansa powodzenia jest
znacznie większa przy możliwości obserwacji błędu.
Istnienie błędu, którego wpływu na system nie da się ujawnić, może być nieco wątpliwe.
W programach przestrzeni użytkownika błędy są najczęściej bardziej dokuczliwe — na
przykład „wywołanie funkcji bla() w takim a takim kroku pętli powoduje awaryjne
zamknięcie programu”. W kodzie jądra sprawy są zazwyczaj znacznie bardziej
zagmatwane. Interakcje pomiędzy jądrem, przestrzenią użytkownika i sprzętem potrafią
być bardzo delikatne. Niekiedy będące przyczyną błędu sytuacje hazardowe pojawiają się
raz na milion iteracji jakiegoś algorytmu. Słabo zaprojektowany albo nawet źle skompilowany
kod może dawać w niektórych systemach oczekiwane rezultaty, pogarszając wydajność
systemów o innych konfiguracjach. Niejednokrotnie zdarza się wywołać błąd jedynie
w określonej konfiguracji jądra, na pewnej przypadkowej maszynie, przy obciążeniu
systemu nietypowymi operacjami itd. Dlatego kluczowe znaczenie ma ilość informacji
o środowisku, w jakim wystąpił błąd. Zazwyczaj jednak możliwość powtórnego
sprowokowania błędu to więcej niż połowa sukcesu.
B(cid:228)(cid:246)dy w j(cid:241)drze
Błędy w jądrze bywają bardzo różnorodne. Zdarzają się one z niezliczonych powodów
i objawiają się w równie niezliczonych formach. Błędy od jawnie błędnego kodu
(na przykład niezachowania poprawnej wartości w odpowiednim miejscu), przez błędy
synchronizacji (wynikające z braku właściwego blokowania dostępu do współdzielonej
zmiennej), po nieprawidłowe zarządzanie sprzętem (wysyłanie nieprawidłowej wartości
do nieodpowiedniego rejestru sterującego) objawiają się pod wszelkimi postaciami,
od niezadowalającej wydajności systemu po jego niewłaściwe działanie w skrajnych
przypadkach powodujące utratę danych albo zawieszanie systemu.
Błąd w postaci objawiającej się użytkownikowi nieraz może dzielić od jego przyczyny
tkwiącej w kodzie jądra długi łańcuch zdarzeń. Na przykład współużytkowana struktura
pozbawiona licznika odwołań może prowokować sytuacje hazardowe. Wobec braku
poprawnego zliczania odwołań może dojść do zwolnienia przez jeden proces struktury
używanej jeszcze przez inny proces. Ów inny proces może próbować odwołać się
do zwolnionej już struktury za pośrednictwem przetrzymywanego lokalnie,
nieprawidłowego już wskaźnika. Może to zaowocować wyłuskaniem wskaźnika pustego,
odczytem „śmieci” czy też czymś zupełnie niewinnym (kiedy obszar zwolnionej struktury
nie został jeszcze niczym nadpisany). Wyłuskanie wskaźnika pustego daje w efekcie błąd
„oops”, podczas gdy odwołanie do przypadkowych danych („śmieci”) w pamięci może
prowadzić do naruszenia spójności danych (a w jej wyniku do niewłaściwego zachowania
Kup książkęPoleć książkęDiagnostyka komunikatami
435
programu, a w dalekiej konsekwencji do błędu „oops”). Użytkownik zgłasza więc albo
błąd „oops”, albo wyłącznie niepoprawne działanie systemu. Programista jądra musi
wyśledzić przyczynę błędu, wykryć, że nastąpił dostęp do zwolnionych wcześniej
danych, że wcześniej niewłaściwie współużytkowana była zawierająca te dane struktura
i wreszcie zaaplikować łatę w postaci poprawnego zliczania odwołań do współużytkowanej
struktury (i być może jakiegoś rygla chroniącego ją przed współbieżnym dostępem).
Diagnostyka błędów jądra może sprawiać wrażenie zadania dla magików, ale
w rzeczywistości jądro systemu nie różni się niczym od innych dużych projektów
programowych. Co prawda w jądrze należy brać pod uwagę elementy specyficzne, takie
jak ograniczenia czasowe wykonania kodu czy sytuacje hazardowe będące konsekwencją
działania wielu wątków w ramach jądra.
Diagnostyka komunikatami
Funkcja jądra printk() działa niemal identycznie jak podobnie nazwana funkcja biblioteczna
języka C, printf(). Podobieństwo działania jest tak duże, że jak na razie w książce nie
wystąpiło zastosowanie funkcji printk() znacząco odbiegające od zastosowań printf().
Tak więc printk() to nazwa funkcji jądra generującej sformatowany wydruk znakowy. Nie
jest to jednak tak do końca zwykła funkcja formatująca.
Niezawodno(cid:264)(cid:232) printk()
Jedną z tych właściwości wywołania printk(), które szybko przyjmuje się za oczywistość,
jest jej niezawodność i wszechstronność. Funkcja printk() daje się wywołać z dowolnego
miejsca jądra w dowolnym momencie jego wykonania. Można ją wywołać z kontekstu
procesu i kontekstu przerwania. Można ją wywoływać, przetrzymując równocześnie
blokadę dowolnego rodzaju. Można też wywoływać ją współbieżnie na wielu procesorach,
przy czym wywołujący nie musi pozyskiwać żadnej blokady.
To funkcja naprawdę nie do zdarcia. To bardzo ważne, ponieważ przydatność
funkcji printk() wynika w dużej mierze właśnie z możliwości jej wywołania dosłownie
zewsząd i z gwarancji jej działania w każdych warunkach.
Istnieje jednak luka we wszechstronności wywołania printk(). Nie da się jej bowiem
zastosować przed określonym momentem rozruchu jądra, a ściśle mówiąc, przed momentem
zainicjowania konsoli. To oczywiste, bo gdzie niby miałyby być wcześniej kierowane
komunikaty? Zwykle nie jest to problemem, chyba że chodzi o diagnozowanie bardzo
wczesnej fazy rozruchu (na przykład diagnostykę błędów działania funkcji setup_arch()
odpowiedzialnej za operacje inicjalizacji zależne od architektury systemu). Taka diagnostyka
to prawdziwe wyzwanie — a brak jakichkolwiek narzędzi wyprowadzania komunikatów
dodatkowo je komplikuje.
Nawet diagnostyka wczesnych faz rozruchu daje jednak pewne możliwości. Niektórzy
programiści wykorzystują do wyprowadzania komunikatów sprzęt, który działa zawsze,
Kup książkęPoleć książkę436
Rozdzia(cid:228) 18. Diagnostyka b(cid:228)(cid:246)dów j(cid:241)dra
na przykład port szeregowy. Nie jest to jednak przyjemna zabawa. Rozwiązaniem jest
wariant wywołania printk() przystosowany do wyprowadzania komunikatów na konsolę
we wczesnych fazach rozruchu — early_printk(). Działa ona identycznie jak printk()
— funkcje te różnią się wyłącznie nazwami i możliwością operowania w pierwszych
fazach rozruchu. Nie jest to jednak rozwiązanie przenośne, gdyż funkcja early_printk()
nie jest implementowana we wszystkich architekturach. Dobrze, żeby diagnozowana
architektura ją posiadała — a większość (z architekturą x86 na czele) posiada.
Podsumowując, o ile nie zachodzi potrzeba sygnalizacji na bardzo wczesnym etapie
rozruchu, można polegać na wszechstronności i niezawodności funkcji printk().
Poziomy diagnostyczne
Główna różnica pomiędzy wywołaniami printk() i printf() tkwi w zdolności tej pierwszej
do określania tak zwanego poziomu diagnostycznego (ang. loglevel). Jądro określa poziom
diagnostyczny, decydując tym samym, czy komunikat powinien zostać wyświetlony
na konsoli czy też przekierowany gdzieś indziej. Jądro wyświetla na konsoli wszystkie
komunikaty o poziomie diagnostycznym ustalonym na poziomie niższym od pewnego progu.
Poziom diagnostyczny określa się następująco:
printk(KERN_WARNING To jest ostrzezenie!
);
printk(KERN_DEBUG To jest komunikat diagnostyczny!
);
printk( Brak okreslenia poziomu diagnostycznego!
);
Ciągi KERN_WARNING i KERN_DEBUG to po prostu definicje występujące w pliku
linux/printk.h . Rozwijane są one odpowiednio do ciągów 4 i 7 i dołączane na początek
komunikatu przekazywanego do printk(). Jądro na podstawie tych przedrostków
decyduje o tym, które z komunikatów powinny być wyświetlane na konsoli, porównując
określony poziom diagnostyczny z bieżącym poziomem diagnostycznym konsoli określonym
parametrem console_loglevel. Pełny wykaz dostępnych poziomów diagnostycznych funkcji
printk() został przedstawiony w tabeli 18.1.
Tabela 18.1. Poziomy diagnostyczne funkcji printk()
Poziom diagnostyczny
KERN_EMERG
KERN_ALERT
KERN_CRIT
KERN_ERR
KERN_WARNING
KERN_NOTICE
KERN_INFO
KERN_DEBUG
Opis
Sytuacja awaryjna.
Problem wymagający natychmiastowej interwencji.
Sytuacja krytyczna.
Błąd.
Ostrzeżenie.
Sytuacja normalna, ale warta odnotowania.
Komunikat informacyjny.
Komunikat diagnostyczny — najprawdopodobniej zbyteczny.
Kup książkęPoleć książkęDiagnostyka komunikatami
437
W przypadku nieokreślenia poziomu rejestrowania jego wartość jest przyjmowana
przez domniemanie jako DEFAULT_MESSAGE_LOGLEVEL, która to stała jest z kolei rozwijana
do stałej KERN_WARNING. Jednak z uwagi na to, że ustawienie domyślne może w kolejnych
wersjach jądra ulec zmianie, warto jawnie opatrywać komunikaty stałymi poziomów
rejestrowania.
Najwyższy poziom rejestrowania definiuje stała KERN_EMERG rozwijana do literału
znakowego 0 . Poziom najniższy określa zaś stała KERN_DEBUG rozwijana do ciągu 7 .
Na przykład po zakończenia fazy przetwarzania pliku kodu źródłowego przez preprocesor
zamieszczone wcześniej wywołania będą miały postać:
printk( 4 To jest ostrzezenie!
);
printk( 7 To jest komunikat diagnostyczny!
);
printk( 4 Brak okreslenia poziomu diagnostycznego!
);
Strategia przyjmowania poziomów rejestrowania w różnych sytuacjach leży
całkowicie w gestii programisty. Rzecz jasna, zwykłe komunikaty należałoby opatrywać
odpowiednim dla nich poziomem rejestrowania. Ale już komunikaty, którymi szpikuje
się kod w poszukiwaniu źródła problemu — wypada się do tego przyznać, wszyscy tak
robią — można opatrywać dowolnym poziomem rejestrowania. Jedną z możliwości jest
pozostawienie w spokoju domyślnego poziomu rejestrowania konsoli i generowania
wszystkich komunikatów diagnostycznych z poziomem KERN_CRIT lub wyższym. Można
też generować komunikaty na poziomie KERN_DEBUG i w zamian zmodyfikować poziom
rejestrowania konsoli, tak aby komunikaty były widoczne. Każda z metod ma swoje wady
i zalety. Decyzję pozostawiam Czytelnikowi.
Bufor komunikatów
Komunikaty jądra umieszczane są w cyklicznym buforze o rozmiarze LOG_BUF_LEN.
Rozmiar ten daje się konfigurować na etapie kompilacji przez ustawienie opcji
CONFIG_LOG_BUF_SHIFT. Domyślny rozmiar bufora dla komputerów jednoprocesorowych
to 16 kB. Innymi słowy, jądro może przechowywać do 16 kB komunikatów jądra. Jeżeli
kolejka komunikatów jest zapełniona i dojdzie do kolejnego wywołania printk(), nowy
komunikat nadpisze najstarszy z komunikatów w buforze. Bufor komunikatów nosi
nazwę cyklicznego, ponieważ jego zapis i odczyt następują w sposób cykliczny.
Korzystanie z bufora cyklicznego ma szereg zalet. Z racji dużej łatwości równoczesnego
zapisywania i odczytywania z takiego bufora funkcja printk() może być wywoływana
nawet z poziomu kontekstu. Co więcej, cykliczność upraszcza zarządzanie buforem.
W obliczu zbyt dużej liczby komunikatów najstarsze komunikaty są po prostu zastępowane
nowymi. Jeżeli zdarzy się problem, w wyniku którego wygenerowana zostanie większa
liczba komunikatów, cykliczność obsługi bufora wyeliminuje część z nich, nie dopuszczając
do zwiększenia zapotrzebowania na pamięć. Jedyną wadą takiego rozwiązania jest
prawdopodobieństwo utraty komunikatów, ale jest to niewielka cena za wszechstronność
bufora.
Kup książkęPoleć książkę438
Rozdzia(cid:228) 18. Diagnostyka b(cid:228)(cid:246)dów j(cid:241)dra
Demony syslogd i klogd
W klasycznym systemie Linux za pobieranie komunikatów jądra z bufora odpowiedzialny
jest demon przestrzeni użytkownika o nazwie klogd — demon ten wypełnia pobieranymi
komunikatami systemowy plik dziennika, korzystając przy tym z pomocy demona syslogd.
W celu odczytu rejestru komunikatów klogd może odczytywać plik /proc/kmsg bądź
korzystać z wywołania systemowego syslog(). Domyślnie wykorzystuje jednak system
plików /proc. Niezależnie od sposobu odczytywania komunikatów klogd ulega zawieszeniu
aż do momentu pojawienia się nowych komunikatów. W obliczu zgłoszenia nowych
komunikatów demon jest pobudzany, odczytuje nowe komunikaty i przetwarza je.
Domyślnie przetwarzanie to polega na przekazaniu ich do demona syslogd.
Demon syslogd dołącza otrzymywane komunikaty do pliku, którym przez domniemanie
jest plik /var/log/messages. Działanie demona da się konfigurować za pośrednictwem
pliku /etc/syslog.conf.
Za pośrednictwem demona klogd można zmieniać poziom rejestrowania konsoli —
wystarczy w wywołaniu demona określić argument -c.
printf(), printk() — (cid:228)atwo o pomy(cid:228)k(cid:246)
Każdemu początkującemu programiście jądra zdarza się mylić wywołania printk()
z wywołaniami printf(). To całkiem naturalne, ponieważ nie sposób zignorować lata
doświadczeń i nawyku wykorzystywania funkcji printf() w programach przestrzeni
użytkownika. Na szczęście takie pomyłki są szybko wychwytywane, jako że powodują
przy kompilacji zalew komunikatami z protestami ze strony konsolidatora.
Pewnego dnia być może zdarzy się Czytelnikowi zastosować w wyniku wyniesionych
z programowania jądra nawyków wywołanie printk() w programie przestrzeni użytkownika.
Wtedy będzie on mógł o sobie powiedzieć, że jest prawdziwym hakerem jądra.
B(cid:228)(cid:241)d oops
Błąd oops to normalny sposób powiadamiania użytkownika o nieprawidłowościach
działania jądra. Jako że jądro to nadzorca całego systemu, nie ma możliwości samodzielnego
usunięcia usterki czy wykonania samounicestwienia, tak jak unicestwia się błędne procesy
przestrzeni użytkownika. Jądro w takich sytuacjach zgłasza błąd oops. Polega to na
wyświetleniu na konsoli komunikatu o błędzie wraz z zawartością rejestrów i śladem
wykonania (ang. back trace). Błąd jądra jest trudny do obejścia, więc jądro w celu obsłużenia
błędu musi się nieźle napracować. Niekiedy po zakończeniu obsługi pojawia się niespójność
jądra. Jądro w momencie pojawienia się błędu mogło być na przykład w trakcie przetwarzania
istotnych danych. Mogło przetrzymywać blokadę albo prowadzić komunikację ze sprzętem.
W obliczu błędu konieczne jest natomiast ostrożne wycofanie się od poprzedniego
kontekstu i w miarę możliwości przywrócenie kontroli nad systemem. W wielu przypadkach
powrót taki jest niemożliwy. Jeżeli błąd wystąpi w kontekście przerwania, jądro nie może
Kup książkęPoleć książkęB(cid:228)(cid:241)d oops
439
kontynuować działania i „panikuje”. Błąd „paniczny” (ang. panic error) powoduje zaś
trwałe unieruchomienie systemu. Również pojawienie się błędu oops w trakcie wykonywania
zadania jałowego (o numerze pid równym zero) bądź zadania init (pid równy jeden)
oznacza błąd paniczny — jądro nie może kontynuować działania bez tych dwóch
ważnych procesów. Jedynie wystąpienie błędu oops w kontekście jednego ze zwykłych
procesów użytkownika daje możliwość unicestwienia tego procesu i kontynuowania
działania reszty systemu.
Przyczyny błędu oops mogą być rozmaite, z nieuprawnionym dostępem do pamięci
bądź próbą wykonania niedozwolonej instrukcji włącznie. Programista jądra jest skazany
na diagnostykę takich błędów (nie mówiąc o tym, że sam przyczynia się do ich powstawania).
Poniższy wydruk to komunikat towarzyszący błędowi oops zaobserwowanemu
w komputerze PPC w procedurze obsługi zegara karty sieciowej:
Oops: Exception in kernel mode, sig: 4
Unable to handle kernel NULL pointer dereference at virtual address 00000001
NIP: C013A7F0 LR: C013A7F0 SP: C0685E00 REGS: c0905d10 TRAP: 0700
Not tained
MSR: 00089037 EE: 1 PR: 0 FP: 0 ME: 1 IR/DR: 11
TASK = c0712530[0] swapper Last syscall: 120
GPR00: C013A7C0 C0295E00 C0231530 0000002F 00000001 C0380CB8 C0291B80 C02D0000
GPR08: 000012A0 00000000 00000000 C0292AA0 4020A088 00000000 00000000 00000000
GPR16: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
GPR24: 00000000 00000005 00000000 00001032 C3F70000 00000032 FFFFFFFF C3F7C1C0
Call trace:
[c013ab30] tulip_timer+0x128/0x1c4
[c0020744] run_timer_softirq+0x10c/0x164
[c001b864] do_softirq+0x88/0x104
[c0007e80] timer_interrupt+0x284/0x298
[c00033c4] ret_from_except+0x0/0x34
[c0007b84] default_idle+0x20/0x60
[c0007bf8] cpu_idle+0x34/0x38
[c0003ae8] rest_init+0x24/0x34
Użytkownicy komputerów klasy PC mogą dziwić się znaczną liczbą rejestrów (aż 32!).
Błędy oops w znacznie popularniejszych systemach klasy x86-32 generują dużo krótszy
wydruk zawartości rejestrów. Najważniejsze informacje są jednak w obu architekturach
identyczne — liczy się zawartość rejestrów i ślad wykonania.
Ślad wykonania to łańcuch wywołania funkcji prowadzący do błędu. W prezentowanym
przypadku ślad zdradza dokładnie przebieg wykonania aż do momentu wystąpienia błędu —
system realizował proces jałowy w pętli cpu_idle(), w której wywoływana jest funkcja
default_idle(). Zgłoszenie przerwania zegarowego spowodowało zainicjowanie obsługi
liczników. Uruchomiona wtedy procedura obsługi takiego licznika dla karty sieciowej
tulip_timer() wykonała w ramach przetwarzania wyłuskanie wskaźnika o wartości NULL.
Na podstawie podanych na wydruku offsetów (tutaj 0x128/0x1c4) można wręcz wytypować
konkretny wiersz programu, którego wykonanie spowodowało błąd.
Kup książkęPoleć książkę440
Rozdzia(cid:228) 18. Diagnostyka b(cid:228)(cid:246)dów j(cid:241)dra
Równie przydatna jak ślad wykonania może być zawartość rejestrów. Dysponując
kopią problematycznej funkcji w postaci kodu asemblerowego, można na podstawie
zawartości rejestrów odtworzyć dokładnie stan jej wykonania w momencie wystąpienia
błędu. Obecność w jednym z rejestrów nieoczekiwanej wartości może często rzucić światło na
przyczynę błędu. W analizowanym przypadku widać, które z rejestrów zawierają wartości
NULL (zera), i na tej podstawie można wytypować argument wywołania bądź zmienną
lokalną funkcji, która przyjęła niewłaściwą wartość. Dla sytuacji podobnych do analizowanej
typowym źródłem błędu jest sytuacja hazardowa — w tym konkretnym przypadku
chodzi o rywalizację w dostępie do zasobu pomiędzy obsługą licznika a resztą kodu
obsługi karty sieciowej. Diagnostyka sytuacji hazardowych jest zresztą zawsze
problematyczna.
Polecenie ksymoops
Prezentowany wcześniej wydruk generowany w ramach obsługi błędu oops nosi nazwę
zdekodowanego, ponieważ adresy pamięci zostały na wydruku przetłumaczone na nazwy
funkcji rezydujących pod tymi adresami. Wersja niezdekodowana tego samego błędu
wyglądałaby następująco:
NIP: C013A7F0 LR: C013A7F0 SP: C0685E00 REGS: c0905d10 TRAP: 0700
Not tained
MSR: 00089037 EE: 1 PR: 0 FP: 0 ME: 1 IR/DR: 11
TASK = c0712530[0] swapper Last syscall: 120
GPR00: C013A7C0 C0295E00 C0231530 0000002F 00000001 C0380CB8 C0291B80 C02D0000
GPR08: 000012A0 00000000 00000000 C0292AA0 4020A088 00000000 00000000 000000
Pobierz darmowy fragment (pdf)