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:
asmlinkage long sys_mkdir(const char __user *pathname, int mode);
Następnie /usr/include/asm*/unistd.h
znajdziesz:
#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.