Jak znaleźć implementacje wywołań systemowych jądra systemu Linux?


375

Próbuję zrozumieć, jak działa, powiedzmy mkdir, funkcja, patrząc na źródło jądra. Jest to próba zrozumienia wewnętrznych elementów jądra i nawigacji między różnymi funkcjami. Wiem, że mkdirjest zdefiniowany w sys/stat.h. Znalazłem prototyp:

/* Create a new directory named PATH, with permission bits MODE.  */
extern int mkdir (__const char *__path, __mode_t __mode)
     __THROW __nonnull ((1));

Teraz muszę zobaczyć, w którym pliku C ta funkcja jest zaimplementowana. Próbowałem z katalogu źródłowego

ack "int mkdir"

który się wyświetlał

security/inode.c
103:static int mkdir(struct inode *dir, struct dentry *dentry, int mode)

tools/perf/util/util.c
4:int mkdir_p(char *path, mode_t mode)

tools/perf/util/util.h
259:int mkdir_p(char *path, mode_t mode);

Ale żadne z nich nie pasuje do definicji w sys/stat.h.

pytania

  1. Który plik ma mkdirimplementację?
  2. W przypadku definicji funkcji takiej jak powyżej, jak mogę dowiedzieć się, który plik ma implementację? Czy istnieje jakiś wzorzec, który jądro stosuje podczas definiowania i wdrażania metod?

UWAGA: Używam jądra 2.6.36-rc1 .


2
Nawiasem mówiąc, sprawdź to: voinici.ceata.org/~tct/resurse/utlk.pdf
Tom Brito

Odpowiedzi:


386

Wywołania systemowe nie są obsługiwane jak zwykłe wywołania funkcji. Przejście z przestrzeni użytkownika do przestrzeni jądra wymaga specjalnego kodu, w zasadzie trochę wbudowanego kodu asemblera wprowadzonego do twojego programu w miejscu wywołania. Kod po stronie jądra, który „łapie” wywołanie systemowe, to także rzeczy niskiego poziomu, których prawdopodobnie nie musisz dogłębnie rozumieć, przynajmniej na początku.

W include/linux/syscalls.hkatalogu źródłowym jądra znajdziesz:

asmlinkage long sys_mkdir(const char __user *pathname, int mode);

Następnie /usr/include/asm*/unistd.hznajdziesz:

#define __NR_mkdir                              83
__SYSCALL(__NR_mkdir, sys_mkdir)

Ten kod mówi, że mkdir(2)to wywołanie systemowe nr 83. Innymi słowy, wywołania systemowe są wywoływane przez numer, a nie przez adres, jak w przypadku zwykłego wywołania funkcji w twoim własnym programie lub funkcji w bibliotece powiązanej z twoim programem. Wspomniany powyżej kod kleju do montażu wbudowanego wykorzystuje to do przejścia od przestrzeni użytkownika do przestrzeni jądra, biorąc parametry razem z nim.

Kolejnym dowodem na to, że jest tu trochę dziwnie, jest to, że nie zawsze istnieje ścisła lista parametrów dla wywołań systemowych: open(2)na przykład może przyjmować 2 lub 3 parametry. Oznacza to, że open(2)jest przeciążony , funkcja C ++, a nie C, ale interfejs syscall jest kompatybilny z C. (To nie jest to samo, co funkcja varargs języka C , która pozwala jednej funkcji na przyjęcie zmiennej liczby argumentów.)

Aby odpowiedzieć na pierwsze pytanie, nie ma jednego pliku, w którym mkdir()istnieje. Linux obsługuje wiele różnych systemów plików i każdy z nich ma własną implementację operacji „mkdir”. Warstwa abstrakcji, która pozwala jąderowi ukryć to wszystko za jednym wywołaniem systemowym, nazywa się VFS . Prawdopodobnie chcesz zacząć się w to zagłębiać fs/namei.c, używając vfs_mkdir(). Rzeczywiste implementacje kodu modyfikującego system plików niskiego poziomu znajdują się gdzie indziej. Na przykład wywoływana jest implementacja ext4 ext4_mkdir()zdefiniowana w fs/ext4/namei.c.

Jeśli chodzi o twoje drugie pytanie, tak, są w tym wszystkim wzorce, ale nie ma jednej reguły. To, czego naprawdę potrzebujesz, to dość szerokie zrozumienie działania jądra, aby dowiedzieć się, gdzie powinieneś szukać jakiegoś konkretnego wywołania systemowego. Nie wszystkie wywołania systemowe dotyczą VFS, więc ich łańcuchy wywołań po stronie jądra nie zaczynają się fs/namei.c. mmap(2), na przykład, zaczyna się od mm/mmap.c, ponieważ jest to część podsystemu zarządzania pamięcią („mm”) jądra.

Polecam ci kopię „ Understanding the Linux Kernel ” autorstwa Boveta i Cesati.


Bardzo dobra odpowiedź. Jeden punkt o książce, o której wspominasz, „Zrozumieć jądro Linuksa”. Nie mam tego, ale wydaje mi się, że od daty wydania (2000) i TOC (na stronie oreilly) jest to około 2,2 jądra plus pewne spostrzeżenia z jądra 2.4 (ale mylę się). Moje pytanie brzmi: istnieje odpowiednik książki, która obejmuje elementy wewnętrzne jądra 2.6? (lub nawet lepiej, że obejmują 2.2, 2.4 i 2.6)?
DavAlPi

2
@DavAlPi: O ile mi wiadomo, Bovet i Cesati to wciąż najlepsza pojedyncza książka na ten temat. Kiedy muszę uzupełnić go o bardziej aktualny materiał, zaczynam kopać w Documentationpodkatalogu drzewa źródłowego jądra, z którym pracuję.
Warren Young

1
W rzeczywistości open (2) jest funkcją varargs. Są tylko dwa sposoby, aby to nazwać, więc strona man dokumentuje to w ten sposób, a rzeczywisty prototyp ma ...w nim dowolną funkcję varargs. Oczywiście jest to realizowane na poziomie libc. Może przekazać 0 lub wartość śmieci do jądra ABI, gdy trzeci parametr nie jest używany.
Random832

„To coś, czego nie musisz rozumieć”. Świat byłby lepszym miejscem, gdyby tego rodzaju zdania nie było nigdzie w sieci stosów wymiany.
Petr

84

To prawdopodobnie nie odpowiada bezpośrednio na twoje pytanie, ale okazało stracesię, że naprawdę fajnie jest próbować zrozumieć podstawowe wywołania systemowe, w akcji, które są tworzone dla nawet najprostszych poleceń powłoki. na przykład

strace -o trace.txt mkdir mynewdir

Wywołania systemowe dla polecenia mkdir mynewdirzostaną zrzucone do trace.txt dla twojej przyjemności oglądania.


5
+1 fajna sztuczka! Nie użyłem tego wcześniej
David Oneill

3
Jeszcze lepiej, stwórz plik wyjściowy trace.strace i otwórz go w VIM. VIM podświetli go, co znacznie ułatwi jego czytanie.
Marcin,

55

Dobrym miejscem do czytania źródła jądra Linux jest odnośnik do systemu Linux (LXR) ¹. Wyszukiwania zwracają wpisane dopasowania (prototypy funkcji, deklaracje zmiennych itp.) Oprócz wyników wyszukiwania dowolnego tekstu, więc jest to wygodniejsze niż zwykłe grep (i także szybsze).

LXR nie rozwija definicji preprocesora. We wszystkich połączeniach systemowych ich nazwa jest zniekształcana przez preprocesora. Jednak większość (wszystkich?) Wywołań systemowych jest definiowana za pomocą jednej z SYSCALL_DEFINExrodzin makr. Ponieważ mkdirwymaga dwóch argumentów, wyszukiwanie SYSCALL_DEFINE2(mkdirprowadzi do deklaracjimkdir wywołania systemowego :

SYSCALL_DEFINE2(mkdir, const char __user *, pathname, int, mode)
{
    return sys_mkdirat(AT_FDCWD, pathname, mode);
}

ok, sys_mkdiratoznacza to, że jest to mkdiratwywołanie systemowe, więc kliknięcie go prowadzi tylko do deklaracji w include/linux/syscalls.h, ale definicja jest tuż powyżej.

Głównym zadaniem mkdiratjest wywoływanie vfs_mkdir(VFS to ogólna warstwa systemu plików). Kliknięcie tego powoduje wyświetlenie dwóch wyników wyszukiwania: deklaracji w include/linux/fs.hi definicji kilka wierszy powyżej. Głównym zadaniem vfs_mkdirjest wywołanie wdrożenie systemu plików specyficzne: dir->i_op->mkdir. Aby dowiedzieć się, jak to jest zaimplementowane, musisz przejść do implementacji pojedynczego systemu plików, a nie ma twardej i szybkiej reguły - może to być nawet moduł spoza drzewa jądra.

¹ LXR to program indeksujący. Istnieje kilka stron internetowych, które zapewniają interfejs do LXR, z nieco innymi zestawami znanych wersji i nieco innymi interfejsami internetowymi. Zwykle przychodzą i odchodzą, więc jeśli ten, do którego jesteś przyzwyczajony, nie jest dostępny, wyszukaj w Internecie „linux cross-reference”, aby znaleźć inny.


To jeden cholerny zasób. Świetna odpowiedź.
Stabledog

„Błąd wewnętrznego serwera” w linku linux.no .
Fredrick Gauss

@FredrickGauss Przez pewien czas lxr.linux.no był najfajniejszym interfejsem do LXR, ale często miał przestoje. Teraz myślę, że zniknęło na dobre. Pierwszy link zamieniłem na inny interfejs LXR.
Gilles

21

Wywołania systemowe są zwykle pakowane w SYSCALL_DEFINEx()makro, dlatego prosty grepnie może ich znaleźć:

fs/namei.c:SYSCALL_DEFINE2(mkdir, const char __user *, pathname, int, mode)

Ostateczna nazwa funkcji po rozwinięciu makra kończy się jako sys_mkdir. SYSCALL_DEFINEx()Makro dodaje szablonowe rzeczy jak kod, który każda definicja syscall musi mieć śledzenia.


17

Uwaga: plik .h nie definiuje funkcji. Jest zadeklarowany w tym pliku .h i zdefiniowany (zaimplementowany) gdzie indziej. Pozwala to kompilatorowi na dołączenie informacji o sygnaturze funkcji (prototypie), aby umożliwić sprawdzenie typu argumentów i dopasowanie typów zwracanych do dowolnych kontekstów wywoływania w kodzie.

Ogólnie pliki .h (nagłówek) w C są używane do deklarowania funkcji i definiowania makr.

mkdirw szczególności jest wywołaniem systemowym. Wokół tego wywołania systemowego może znajdować się opakowanie GNU libc (prawie na pewno tak jest). Prawdziwą implementację jądra mkdirmożna znaleźć, przeszukując źródła jądra, aw szczególności wywołania systemowe.

Zauważ, że będzie także implementacja pewnego rodzaju kodu do tworzenia katalogu dla każdego systemu plików. Warstwa VFS (wirtualny system plików) zapewnia wspólny interfejs API, do którego może wywoływać się warstwa wywołania systemowego. Każdy system plików musi zarejestrować funkcje, aby warstwa VFS mogła się do niego wywoływać. Pozwala to różnym systemom plików na implementację własnej semantyki dotyczącej struktury katalogów (na przykład, jeśli są one przechowywane przy użyciu jakiegoś schematu haszującego, aby usprawnić wyszukiwanie określonych pozycji). Wspominam o tym, ponieważ podczas przeszukiwania drzewa źródeł jądra Linux prawdopodobnie potkniesz się o funkcje tworzenia katalogów specyficzne dla systemu plików.


8

Żadna ze znalezionych implementacji nie pasuje do prototypu w sys / stat.h Może wyszukiwanie instrukcji include z tym plikiem nagłówkowym byłoby bardziej skuteczne?


1
Wdrożenie (zgodnie z opisem w sys / stat.h) jest domeną użytkownika i libc. Wewnętrzne rzeczy jądra (jak to się naprawdę robi) to wewnętrzna sprawa jądra. W trosce o wszystkich hakerów jądra funkcję wewnętrzną można nazwać xyzzy i przyjmować 5 parametrów. Zadaniem libc jest przejęcie wywołania użytkownika, przetłumaczenie go na wymagane inkantacje jądra, wysłanie go i zebranie wszelkich wyników.
vonbrand

6

Oto kilka naprawdę świetnych postów na blogu opisujących różne techniki poszukiwania niskiego poziomu kodu źródłowego jądra.


12
Nie zamieszczaj tylko linków do blogów lub forów, streszczaj ich zawartość, aby czytelnicy mogli zobaczyć, o czym są, i mieć coś do zrobienia, jeśli witryny znikną. Ponadto twój pierwszy link dotyczy libc, co jest nie na temat tego pytania.
Gilles
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.