Системные вызовы не обрабатываются как обычные вызовы функций. Для перехода из пользовательского пространства в пространство ядра требуется специальный код, в основном немного встроенного ассемблерного кода, внедренного в вашу программу на сайте вызовов. Код на стороне ядра, который «ловит» системный вызов, - это тоже низкоуровневый материал, который вам, вероятно, не нужно глубоко понимать, по крайней мере, сначала.
В include/linux/syscalls.h
вашей директории с исходным кодом ядра вы найдете это:
asmlinkage long sys_mkdir(const char __user *pathname, int mode);
Затем /usr/include/asm*/unistd.h
вы найдете это:
#define __NR_mkdir 83
__SYSCALL(__NR_mkdir, sys_mkdir)
Этот код говорит, mkdir(2)
что системный вызов # 83. То есть системные вызовы вызываются по номеру, а не по адресу, как при обычном вызове функции в вашей собственной программе или функции в библиотеке, связанной с вашей программой. Код связывания встроенной сборки, о котором я упоминал выше, использует это для перехода от пользователя к пространству ядра, принимая ваши параметры вместе с ним.
Еще одно свидетельство того, что здесь немного странно, заключается в том, что не всегда существует строгий список параметров для системных вызовов: open(2)
например, он может принимать 2 или 3 параметра. Это означает, open(2)
что перегружен , особенность C ++, а не C, но интерфейс syscall является C-совместимым. (Это не то же самое, что функция C varargs , которая позволяет одной функции принимать переменное число аргументов.)
Чтобы ответить на ваш первый вопрос, нет ни одного файла, где бы он ни был mkdir()
. Linux поддерживает множество различных файловых систем, и у каждой есть своя реализация операции «mkdir». Уровень абстракции, который позволяет ядру скрывать все, что за одним системным вызовом, называется VFS . Итак, вы, вероятно, хотите начать копаться fs/namei.c
, с vfs_mkdir()
. Реальные реализации низкоуровневого кода, модифицирующего файловую систему, находятся в другом месте. Например, вызывается реализация ext4 ext4_mkdir()
, определенная в fs/ext4/namei.c
.
Что касается вашего второго вопроса, да, есть шаблоны для всего этого, но нет единого правила. Что вам действительно нужно, так это достаточно широкое понимание того, как работает ядро, чтобы выяснить, где вы должны искать какой-либо конкретный системный вызов. Не все системные вызовы включают VFS, поэтому их цепочки вызовов на стороне ядра не все начинаются с fs/namei.c
. mmap(2)
Например, запускается из-за того mm/mmap.c
, что является частью подсистемы управления памятью ("mm") ядра.
Я рекомендую вам получить копию « Понимание ядра Linux » Бове и Цезати.