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 mkdir
jest 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
- Który plik ma
mkdir
implementację? - 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 .
linux-kernel
source
system-calls
Navaneeth KN
źródło
źródło
Odpowiedzi:
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.h
katalogu źródłowym jądra znajdziesz:Następnie
/usr/include/asm*/unistd.h
znajdziesz: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, żeopen(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ącvfs_mkdir()
. Rzeczywiste implementacje kodu modyfikującego system plików niskiego poziomu znajdują się gdzie indziej. Na przykład wywoływana jest implementacja ext4ext4_mkdir()
zdefiniowana wfs/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ę odmm/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.
źródło
Documentation
podkatalogu drzewa źródłowego jądra, z którym pracuję....
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.To prawdopodobnie nie odpowiada bezpośrednio na twoje pytanie, ale okazało
strace
się, ż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ładWywołania systemowe dla polecenia
mkdir mynewdir
zostaną zrzucone do trace.txt dla twojej przyjemności oglądania.źródło
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_DEFINEx
rodzin makr. Ponieważmkdir
wymaga dwóch argumentów, wyszukiwanieSYSCALL_DEFINE2(mkdir
prowadzi do deklaracjimkdir
wywołania systemowego :ok,
sys_mkdirat
oznacza to, że jest tomkdirat
wywołanie systemowe, więc kliknięcie go prowadzi tylko do deklaracji winclude/linux/syscalls.h
, ale definicja jest tuż powyżej.Głównym zadaniem
mkdirat
jest wywoływanievfs_mkdir
(VFS to ogólna warstwa systemu plików). Kliknięcie tego powoduje wyświetlenie dwóch wyników wyszukiwania: deklaracji winclude/linux/fs.h
i definicji kilka wierszy powyżej. Głównym zadaniemvfs_mkdir
jest 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.
źródło
Wywołania systemowe są zwykle pakowane w
SYSCALL_DEFINEx()
makro, dlatego prostygrep
nie może ich znaleźć: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.źródło
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.
mkdir
w 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ądramkdir
moż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.
źródło
Ż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?
źródło
Oto kilka naprawdę świetnych postów na blogu opisujących różne techniki poszukiwania niskiego poziomu kodu źródłowego jądra.
źródło