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

Я пытаюсь понять, как работает функция, например 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 .

368 голосов | спросил Navaneeth K N 19 PM00000060000000031 2010, 18:26:00

7 ответов


384

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

В 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-совместим. (Это не то же самое, что и функция 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 , поскольку это часть подсистемы управления памятью (" мм ") ядра.

Я рекомендую вам получить копию « Понимание ядра Linux » от Bovet и Cesati.

ответил Warren Young 19 PM00000070000003531 2010, 19:28:35
83

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

strace -o trace.txt mkdir mynewdir

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

ответил Banjer 19 PM000000110000001431 2010, 23:37:14
54

Хорошим местом для чтения источника ядра Linux является перекрестная ссылка Linux (LXR) . Поиски возвращают типизированные соответствия (функции prototypes, объявления переменных и т. Д.) В дополнение к результатам бесплатного текстового поиска, поэтому они более удобны, чем просто 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);
}

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

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

ответил Gilles 5 Jam1000000amWed, 05 Jan 2011 00:09:29 +030011 2011, 00:09:29
20

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

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

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

ответил stefanha 20 AM000000100000004831 2010, 10:16:48
17

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

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

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

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

ответил Jim Dennis 21 AM000000110000003431 2010, 11:31:34
8

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

ответил greg0ire 19 PM00000070000004531 2010, 19:19:45
6

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

ответил An̲̳̳drew 14 Jam1000000amFri, 14 Jan 2011 01:04:21 +030011 2011, 01:04:21

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132