Як я можу знайти реалізацію системних викликів ядра 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. (Це не те саме, що функція varargs C , яка дозволяє одній функції приймати змінну кількість аргументів.)

Щоб відповісти на ваше перше запитання, там не існує жодного файлу 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 " Бовета та Чезаті.


Дуже гарна відповідь. Один момент згаданої вами книги "Розуміння ядра Linux". Я цього не маю, але мені здається, що з дати виходу (2000) та TOC (на сайті oreilly) приблизно 2,2 ядра плюс деякі відомості з 2,4 ядер (але я помиляюся). Моє запитання: чи існує рівнозначна книга, яка охоплює 2,6 внутрішніх ядер? (а ще краще, що охоплюють 2.2, 2.4 та 2.6)?
DavAlPi

2
@DavAlPi: Наскільки я знаю, Bovet & Cesati як і раніше є найкращою єдиною книгою на цю тему. Коли мені потрібно доповнити його більш сучасними матеріалами, Documentationя переконуюсь у підкаталозі вихідного дерева для ядра, з яким я працюю.
Warren Young

1
Фактично open (2) - це функція varargs. Існує лише два способи його виклику, тому manpage документує це таким чином, власне прототип має ...в ньому як і будь-яку функцію varargs. Звичайно, це реалізується на рівні libc. Він може передавати або 0, або значення сміття до ядра ABI, коли третій параметр не використовується.
Випадково832

"Це те, що вам не потрібно розуміти". Світ був би кращим місцем, якби такого речення ніде не було знайти в мережі stackexchange.
Петро

84

Це, ймовірно, не відповідає безпосередньо на ваше запитання, але я виявив, straceщо це дуже круто, намагаючись зрозуміти основні системні виклики в дії, які зроблені навіть для найпростіших команд оболонки. напр

strace -o trace.txt mkdir mynewdir

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


5
+1 Охайний трюк! Я раніше цим не користувався
Девід Онелл

3
А ще краще зробити вихідний файл trace.strace та відкрити його у VIM. VIM виділить його, полегшивши його читання.
Марцін

55

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

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

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

Ок, sys_mkdiratозначає, що це mkdiratsscall, тому натискання на нього приводить вас лише до декларації include/linux/syscalls.h, але це визначення трохи вище.

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

¹ LXR - програма індексації. Існує кілька веб-сайтів, які надають інтерфейс до LXR, з дещо різними наборами відомих версій та трохи іншими веб-інтерфейсами. Вони, як правило, приходять і йдуть, тому якщо той, до якого ви звикли, недоступний, виконайте в Інтернеті пошук "перехресного посилання на Linux", щоб знайти інший.


Це одна біса ресурсу. Чудова відповідь.
Stabledog

"Внутрішня помилка сервера" у посиланні 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()Макрос додає шаблонних речі , як трасування коду, кожне визначення системних викликів необхідно мати.


17

Примітка: .h файл не визначає функцію. Це задекларовано у тому .h-файлі та визначено (реалізовано) в іншому місці. Це дозволяє компілятору включати інформацію про підпис функції (прототип), щоб дозволити перевірку аргументів типу та відповідати типам повернення будь-яким контекстам виклику у вашому коді.

Загалом .h (заголовки) файли в C використовуються для оголошення функцій та визначення макросів.

mkdirзокрема, це системний виклик. Навколо цього системного виклику може бути обгортка GNU libc (майже напевно це насправді). Справжню реалізацію ядра mkdirможна знайти, шукаючи джерела ядра та зокрема системні виклики.

Зауважте, що також буде реалізований якийсь код створення каталогу для кожної файлової системи. Шар VFS (віртуальна файлова система) забезпечує загальний API, на який може зателефонувати рівень системного виклику. Кожна файлова система повинна реєструвати функції для рівня VFS для виклику. Це дозволяє різним файловим системам реалізувати власну семантику щодо структуризованих каталогів (наприклад, якщо вони зберігаються за допомогою якоїсь схеми хешування, щоб зробити пошук конкретних записів більш ефективним). Я згадую про це, тому що ви, швидше за все, переходите через ці функції створення файлів для певної файлової системи, якщо ви шукаєте дерево джерела ядра Linux.


8

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


1
Реалізація (як описано в sys / stat.h) - справа користувача userland та libc. Внутрішній матеріал ядра (як це реально ) - це внутрішній бізнес ядра. При догляді за хакерами ядра внутрішня функція може бути названа xyzzy та приймати 5 параметрів. Завдання libc - приймати виклик userland, переводити його на необхідні заклики ядра, відправляти його та збирати будь-які результати.
фонбранд

6

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


12
Будь ласка, не публікуйте лише посилання на блоги чи форуми, підсумовуйте їхній вміст, щоб читачі могли бачити, про що вони йдуть, і щось залишати, якщо сайти зникають. Крім того, ваше перше посилання стосується libc, що поза темою для цього питання.
Жиль
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.