Я пытаюсь понять, как работает, скажем 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
.
Вопросов
- Какой файл имеет
mkdir
реализацию? - С помощью определения функции, подобного приведенному выше, как я могу узнать, какой файл имеет реализацию? Есть ли какая-то схема, которой придерживается ядро при определении и реализации методов?
ПРИМЕЧАНИЕ: я использую ядро 2.6.36-rc1 .
linux-kernel
source
system-calls
Наванет К.Н.
источник
источник
Ответы:
Системные вызовы не обрабатываются как обычные вызовы функций. Для перехода из пользовательского пространства в пространство ядра требуется специальный код, в основном немного встроенного ассемблерного кода, внедренного в вашу программу на сайте вызовов. Код на стороне ядра, который «ловит» системный вызов, - это тоже низкоуровневый материал, который вам, вероятно, не нужно глубоко понимать, по крайней мере, сначала.
В
include/linux/syscalls.h
вашей директории с исходным кодом ядра вы найдете это:Затем
/usr/include/asm*/unistd.h
вы найдете это:Этот код говорит,
mkdir(2)
что системный вызов # 83. То есть системные вызовы вызываются по номеру, а не по адресу, как при обычном вызове функции в вашей собственной программе или функции в библиотеке, связанной с вашей программой. Код связывания встроенной сборки, о котором я упоминал выше, использует это для перехода от пользователя к пространству ядра, принимая ваши параметры вместе с ним.Еще одно свидетельство того, что здесь немного странно, заключается в том, что не всегда существует строгий список параметров для системных вызовов:
open(2)
например, он может принимать 2 или 3 параметра. Это означает,open(2)
что перегружен , особенность C ++, а не C, но интерфейс syscall является C-совместимым. (Это не то же самое, что функция C varargs , которая позволяет одной функции принимать переменное число аргументов.)Чтобы ответить на ваш первый вопрос, нет ни одного файла, где бы он ни был
mkdir()
. Linux поддерживает множество различных файловых систем, и у каждой есть своя реализация операции «mkdir». Уровень абстракции, который позволяет ядру скрывать все, что за одним системным вызовом, называется VFS . Итак, вы, вероятно, хотите начать копатьсяfs/namei.c
, сvfs_mkdir()
. Реальные реализации низкоуровневого кода, модифицирующего файловую систему, находятся в другом месте. Например, вызывается реализация ext4ext4_mkdir()
, определенная вfs/ext4/namei.c
.Что касается вашего второго вопроса, да, есть шаблоны для всего этого, но нет единого правила. Что вам действительно нужно, так это достаточно широкое понимание того, как работает ядро, чтобы выяснить, где вы должны искать какой-либо конкретный системный вызов. Не все системные вызовы включают VFS, поэтому их цепочки вызовов на стороне ядра не все начинаются с
fs/namei.c
.mmap(2)
Например, запускается из-за тогоmm/mmap.c
, что является частью подсистемы управления памятью ("mm") ядра.Я рекомендую вам получить копию « Понимание ядра Linux » Бове и Цезати.
источник
Documentation
подкаталоге дерева исходных текстов для ядра, с которым я работаю....
любая функция varargs. Конечно, это реализовано на уровне libc. Он может передать либо 0, либо значение мусора в ABI ядра, когда третий параметр не используется.Это, вероятно, не отвечает на ваш вопрос напрямую, но я обнаружил,
strace
что это действительно здорово, когда пытаемся понять базовые системные вызовы в действии, которые сделаны даже для самых простых команд оболочки. напримерСистемные вызовы для команды
mkdir mynewdir
будут выгружены в файл trace.txt для вашего удобства просмотра.источник
Хорошее место для чтения исходного кода ядра Linux - перекрестная ссылка Linux (LXR) ¹. Поиски возвращают типизированные совпадения (прототипы функций, объявления переменных и т. Д.) В дополнение к результатам поиска в свободном тексте, так что это удобнее, чем просто grep (и тоже быстрее).
LXR не расширяет определения препроцессора. Системные вызовы имеют название, искаженное препроцессором повсюду. Однако большинство (все?) Системных вызовов определяются с одним из
SYSCALL_DEFINEx
семейств макросов. Так какmkdir
принимает два аргумента, поискSYSCALL_DEFINE2(mkdir
приводит к объявлениюmkdir
системного вызова :Хорошо ,
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», чтобы найти другой.
источник
Системные вызовы обычно заключаются в
SYSCALL_DEFINEx()
макрос, поэтому простойgrep
не находит их:Окончательное имя функции после раскрытия макроса заканчивается
sys_mkdir
.SYSCALL_DEFINEx()
Макрос добавляет шаблонных вещи , как трассировку кода, каждое определение системных вызовов необходимо иметь.источник
Примечание. Файл .h не определяет функцию. Он объявлен в этом файле .h и определен (реализован) в другом месте. Это позволяет компилятору включать информацию о сигнатуре (прототипе) функции, чтобы разрешить проверку типов аргументов и сопоставить типы возврата с любым контекстом вызова в вашем коде.
В общем случае .h (заголовочные) файлы в C используются для объявления функций и определения макросов.
mkdir
в частности это системный вызов. Вокруг этого системного вызова может быть оболочка libc GNU (почти наверняка). Реальная реализация ядраmkdir
может быть найдена путем поиска источников ядра и, в частности, системных вызовов.Обратите внимание, что для каждой файловой системы также будет реализован некоторый код создания каталога. Уровень VFS (виртуальная файловая система) предоставляет общий API, к которому может обращаться уровень системных вызовов. Каждая файловая система должна зарегистрировать функции для вызова уровня VFS. Это позволяет различным файловым системам реализовывать свою собственную семантику для структуры каталогов (например, если они хранятся с использованием некоторой схемы хеширования, чтобы сделать поиск конкретных записей более эффективным). Я упоминаю об этом, потому что вы, скорее всего, отключите эти специфические для файловой системы функции создания каталогов, если будете искать в дереве исходных кодов ядра Linux.
источник
Ни одна из найденных реализаций не соответствует прототипу в sys / stat.h. Может быть, поиск оператора включения с этим заголовочным файлом будет более успешным?
источник
Вот пара действительно хороших постов в блоге, описывающих различные методы поиска низкоуровневого исходного кода ядра.
источник