Как я могу найти реализации системных вызовов ядра Linux?

375

Я пытаюсь понять, как работает, скажем mkdir, функция, посмотрев на исходный код ядра. Это попытка понять внутреннее ядро ​​и перемещаться между различными функциями. Я знаю mkdir, определяется в sys/stat.h. Я нашел прототип:

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

Теперь мне нужно посмотреть, в каком C-файле эта функция реализована. Из исходного каталога я попробовал

ack "int mkdir"

который отображается

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);

Но ни один из них не соответствует определению в sys/stat.h.

Вопросов

  1. Какой файл имеет mkdirреализацию?
  2. С помощью определения функции, подобного приведенному выше, как я могу узнать, какой файл имеет реализацию? Есть ли какая-то схема, которой придерживается ядро ​​при определении и реализации методов?

ПРИМЕЧАНИЕ: я использую ядро 2.6.36-rc1 .

Наванет К.Н.
источник
2
Кстати, проверьте это: voinici.ceata.org/~tct/resurse/utlk.pdf
Том Брито,

Ответы:

386

Системные вызовы не обрабатываются как обычные вызовы функций. Для перехода из пользовательского пространства в пространство ядра требуется специальный код, в основном немного встроенного ассемблерного кода, внедренного в вашу программу на сайте вызовов. Код на стороне ядра, который «ловит» системный вызов, - это тоже низкоуровневый материал, который вам, вероятно, не нужно глубоко понимать, по крайней мере, сначала.

В 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 » Бове и Цезати.

Уоррен Янг
источник
Очень хороший ответ Одно замечание о книге, которую вы упоминаете, «Понимание ядра Linux». У меня его нет, но с даты релиза (2000) и TOC (на сайте oreilly) мне кажется, что это около 2.2 ядер плюс некоторые идеи из ядер 2.4 (но я могу ошибаться). Мой вопрос: есть ли эквивалентная книга, которая покрывает 2.6 ядра ядра? (или даже лучше, что охватывает 2.2, 2.4 и 2.6)?
DavAlPi
2
@DavAlPi: Насколько я знаю, Bovet & Cesati по-прежнему остается лучшей книгой на эту тему. Когда мне нужно дополнить его более свежим материалом, я копаюсь в Documentationподкаталоге дерева исходных текстов для ядра, с которым я работаю.
Уоррен Янг
1
Фактически open (2) является функцией varargs. Есть только два способа вызвать его, поэтому man-страница документирует это таким образом, что в самом прототипе есть ...любая функция varargs. Конечно, это реализовано на уровне libc. Он может передать либо 0, либо значение мусора в ABI ядра, когда третий параметр не используется.
Random832
«Это то, что вам не нужно понимать». Мир был бы лучше, если бы такого рода предложения нигде не было в сети stackexchange.
Петр
84

Это, вероятно, не отвечает на ваш вопрос напрямую, но я обнаружил, straceчто это действительно здорово, когда пытаемся понять базовые системные вызовы в действии, которые сделаны даже для самых простых команд оболочки. например

strace -o trace.txt mkdir mynewdir

Системные вызовы для команды mkdir mynewdirбудут выгружены в файл trace.txt для вашего удобства просмотра.

Banjer
источник
5
+1 Аккуратный трюк! Я бы не использовал это раньше
Дэвид Онеилл
3
А еще лучше, сделайте выходной файл trace.strace и откройте его в VIM. VIM выделит это, делая чтение намного проще.
Марцин
55

Хорошее место для чтения исходного кода ядра Linux - перекрестная ссылка Linux (LXR) ¹. Поиски возвращают типизированные совпадения (прототипы функций, объявления переменных и т. Д.) В дополнение к результатам поиска в свободном тексте, так что это удобнее, чем просто grep (и тоже быстрее).

LXR не расширяет определения препроцессора. Системные вызовы имеют название, искаженное препроцессором повсюду. Однако большинство (все?) Системных вызовов определяются с одним из SYSCALL_DEFINExсемейств макросов. Так как mkdirпринимает два аргумента, поиск SYSCALL_DEFINE2(mkdirприводит к объявлению mkdirсистемного вызова :

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

Хорошо , sys_mkdiratозначает, что это mkdiratсистемный вызов, поэтому нажатие на него приведет вас только к объявлению include/linux/syscalls.h, но определение чуть выше.

Основной задачей mkdiratявляется вызов vfs_mkdir(VFS - это общий уровень файловой системы). Нажав на это, вы увидите два результата поиска: объявление в include/linux/fs.hи определение несколькими строками выше. Основная задача vfs_mkdirзаключается в вызове реализации файловой системы конкретных: dir->i_op->mkdir. Чтобы выяснить, как это реализовано, вам нужно обратиться к реализации отдельной файловой системы, и нет строгого правила - это может быть даже модуль вне дерева ядра.

X LXR - это программа индексирования. Есть несколько веб-сайтов, которые предоставляют интерфейс для LXR, с немного различными наборами известных версий и немного другими веб-интерфейсами. Они имеют тенденцию приходить и уходить, поэтому, если тот, к которому вы привыкли, недоступен, выполните поиск в Интернете по запросу «перекрестные ссылки linux», чтобы найти другой.

жилль
источник
Это чертовски ресурс. Отличный ответ.
Конюшня
«Внутренняя ошибка сервера» в ссылке linux.no .
Фредрик Гаусс
@FredrickGauss Некоторое время lxr.linux.no был самым приятным интерфейсом для LXR, но у него были частые простои. Теперь я думаю, что это навсегда. Я заменил первую ссылку на другой интерфейс LXR.
Жиль
21

Системные вызовы обычно заключаются в SYSCALL_DEFINEx()макрос, поэтому простой grepне находит их:

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

Окончательное имя функции после раскрытия макроса заканчивается sys_mkdir. SYSCALL_DEFINEx()Макрос добавляет шаблонных вещи , как трассировку кода, каждое определение системных вызовов необходимо иметь.

stefanha
источник
17

Примечание. Файл .h не определяет функцию. Он объявлен в этом файле .h и определен (реализован) в другом месте. Это позволяет компилятору включать информацию о сигнатуре (прототипе) функции, чтобы разрешить проверку типов аргументов и сопоставить типы возврата с любым контекстом вызова в вашем коде.

В общем случае .h (заголовочные) файлы в C используются для объявления функций и определения макросов.

mkdirв частности это системный вызов. Вокруг этого системного вызова может быть оболочка libc GNU (почти наверняка). Реальная реализация ядра mkdirможет быть найдена путем поиска источников ядра и, в частности, системных вызовов.

Обратите внимание, что для каждой файловой системы также будет реализован некоторый код создания каталога. Уровень VFS (виртуальная файловая система) предоставляет общий API, к которому может обращаться уровень системных вызовов. Каждая файловая система должна зарегистрировать функции для вызова уровня VFS. Это позволяет различным файловым системам реализовывать свою собственную семантику для структуры каталогов (например, если они хранятся с использованием некоторой схемы хеширования, чтобы сделать поиск конкретных записей более эффективным). Я упоминаю об этом, потому что вы, скорее всего, отключите эти специфические для файловой системы функции создания каталогов, если будете искать в дереве исходных кодов ядра Linux.

Джим Деннис
источник
8

Ни одна из найденных реализаций не соответствует прототипу в sys / stat.h. Может быть, поиск оператора включения с этим заголовочным файлом будет более успешным?

greg0ire
источник
1
Реализация (как описано в sys / stat.h) является делом пользователя и libc. Внутренний материал ядра (как это действительно делается) - это внутренний бизнес ядра. Для всех хакеров ядра внутренняя функция может называться xyzzy и принимать 5 параметров. Задача libc состоит в том, чтобы принять вызов пользовательского интерфейса, перевести его в любые требуемые заклинания ядра, отправить его и собрать все результаты.
vonbrand
6

Вот пара действительно хороших постов в блоге, описывающих различные методы поиска низкоуровневого исходного кода ядра.

Андрей
источник
12
Пожалуйста, не размещайте только ссылки на блоги или форумы, суммируйте их содержание, чтобы читатели могли видеть, о чем они, и чтобы что-то осталось, если сайты исчезнут. Кроме того, ваша первая ссылка о libc, которая не по теме для этого вопроса.
Жиль