it-swarm.com.de

Wie finde ich die Implementierungen von Linux-Kernel-Systemaufrufen?

Ich versuche zu verstehen, wie eine Funktion, z. B. mkdir, funktioniert, indem ich mir die Kernelquelle anschaue. Dies ist ein Versuch, die Kernel-Interna zu verstehen und zwischen verschiedenen Funktionen zu navigieren. Ich weiß, dass mkdir in sys/stat.h Definiert ist. Ich habe den Prototyp gefunden:

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

Jetzt muss ich sehen, in welcher C-Datei diese Funktion implementiert ist. Aus dem Quellverzeichnis habe ich versucht

ack "int mkdir"

welche angezeigt

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

Aber keiner von ihnen entspricht der Definition in sys/stat.h.

Fragen

  1. Welche Datei hat die Implementierung von mkdir?
  2. Wie kann ich bei einer Funktionsdefinition wie oben herausfinden, welche Datei die Implementierung hat? Gibt es ein Muster, dem der Kernel beim Definieren und Implementieren von Methoden folgt?

HINWEIS: Ich verwende den Kernel 2.6.36-rc1 .

376
Navaneeth K N

Systemaufrufe werden nicht wie normale Funktionsaufrufe behandelt. Für den Übergang vom Benutzerbereich zum Kernelbereich ist spezieller Code erforderlich, im Grunde genommen ein bisschen Inline-Assembly-Code, der am Aufrufstandort in Ihr Programm eingefügt wird. Der kernelseitige Code, der den Systemaufruf "abfängt", ist ebenfalls ein Low-Level-Code, den Sie wahrscheinlich zumindest zunächst nicht genau verstehen müssen.

In include/linux/syscalls.h unter Ihrem Kernel-Quellverzeichnis finden Sie Folgendes:

asmlinkage long sys_mkdir(const char __user *pathname, int mode);

Dann finden Sie in /usr/include/asm*/unistd.h Folgendes:

#define __NR_mkdir                              83
__SYSCALL(__NR_mkdir, sys_mkdir)

Dieser Code sagt, dass mkdir(2) der Systemaufruf # 83 ist. Das heißt, Systemaufrufe werden nach Nummer aufgerufen, nicht nach Adresse wie bei einem normalen Funktionsaufruf in Ihrem eigenen Programm oder zu einer Funktion in einer Bibliothek, die mit Ihrem Programm verknüpft ist. Der oben erwähnte Inline-Assembly-Klebercode verwendet diesen Code, um den Übergang vom Benutzer zum Kernel-Speicherplatz durchzuführen und Ihre Parameter mitzunehmen.

Ein weiterer Beweis dafür, dass die Dinge hier etwas seltsam sind, ist, dass es für Systemaufrufe nicht immer eine strenge Parameterliste gibt: open(2) kann beispielsweise entweder 2 oder 3 Parameter annehmen. Das heißt, open(2) ist überladen , eine Funktion von C++, nicht von C, aber die Syscall-Schnittstelle ist C-kompatibel. (Dies ist nicht dasselbe wie Cs varargs feature , wodurch eine einzelne Funktion eine variable Anzahl von Argumenten annehmen kann.)

Um Ihre erste Frage zu beantworten, gibt es keine einzelne Datei, in der mkdir() vorhanden ist. Linux unterstützt viele verschiedene Dateisysteme und jedes hat seine eigene Implementierung der "mkdir" -Operation. Die Abstraktionsschicht, mit der der Kernel alles hinter einem einzelnen Systemaufruf verbergen kann, heißt VFS . Sie möchten also wahrscheinlich mit vfs_mkdir() in fs/namei.c Graben. Die tatsächlichen Implementierungen des Codes zur Änderung des Dateisystems auf niedriger Ebene befinden sich an anderer Stelle. Zum Beispiel heißt die ext4-Implementierung ext4_mkdir(), definiert in fs/ext4/namei.c .

Was Ihre zweite Frage betrifft, ja, es gibt Muster für all dies, aber keine einzige Regel. Was Sie tatsächlich benötigen, ist ein ziemlich umfassendes Verständnis der Funktionsweise des Kernels, um herauszufinden, wo Sie nach einem bestimmten Systemaufruf suchen sollten. Nicht alle Systemaufrufe betreffen das VFS, daher beginnen ihre kernelseitigen Aufrufketten nicht alle in fs/namei.c. mmap(2) startet beispielsweise in mm/mmap.c , da es Teil des Speichermanagementsubsystems ("mm") des Kernels ist.

Ich empfehle Ihnen, eine Kopie von " nderstanding the Linux Kernel " von Bovet und Cesati zu erhalten.

388
Warren Young

Dies beantwortet Ihre Frage wahrscheinlich nicht direkt, aber ich habe festgestellt, dass strace wirklich cool ist, wenn ich versuche, die zugrunde liegenden Systemaufrufe in Aktion zu verstehen, die selbst für die einfachsten Shell-Befehle erstellt wurden. z.B.

strace -o trace.txt mkdir mynewdir

Das System ruft den Befehl mkdir mynewdir wird für Ihr Sehvergnügen in trace.txt gespeichert.

86
Banjer

Ein guter Ort, um die Linux-Kernelquelle zu lesen, ist der Linux-Querverweis (LXR) ¹. Suchvorgänge geben zusätzlich zu den Freitextsuchergebnissen typisierte Übereinstimmungen (Funktionsprototypen, Variablendeklarationen usw.) zurück, sodass sie handlicher sind als nur ein Grep (und auch schneller).

LXR erweitert keine Präprozessordefinitionen. Bei Systemaufrufen wird der Name vom Präprozessor überall entstellt. Die meisten (alle?) Systemaufrufe werden jedoch mit einer der Makrofamilien SYSCALL_DEFINEx definiert. Da mkdir zwei Argumente akzeptiert, führt eine Suche nach SYSCALL_DEFINE2(mkdir zum Deklaration des mkdir syscall :

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

ok, sys_mkdirat bedeutet, dass es sich um den mkdirat -Syscall handelt. Wenn Sie also darauf klicken, gelangen Sie nur zur Deklaration in include/linux/syscalls.h, aber die Definition befindet sich direkt darüber.

Die Hauptaufgabe von mkdirat besteht darin, vfs_mkdir aufzurufen (VFS ist die generische Dateisystemschicht). Wenn Sie darauf klicken, werden zwei Suchergebnisse angezeigt: die Deklaration in include/linux/fs.h Und die Definition einige Zeilen darüber. Die Hauptaufgabe von vfs_mkdir Ist das Aufrufen der dateisystemspezifischen Implementierung: dir->i_op->mkdir. Um herauszufinden, wie this implementiert ist, müssen Sie sich der Implementierung des einzelnen Dateisystems zuwenden, und es gibt keine feste Regel - es könnte sich sogar um ein Modul außerhalb des Kernelbaums handeln.

¹ LXR ist ein Indexierungsprogramm. Es gibt mehrere Websites, die eine Schnittstelle zu LXR bieten, mit leicht unterschiedlichen Sätzen bekannter Versionen und leicht unterschiedlichen Webschnittstellen. Sie neigen dazu zu kommen und zu gehen. Wenn also die gewohnte nicht verfügbar ist, suchen Sie im Internet nach „Linux-Querverweisen“, um eine andere zu finden.

Systemaufrufe werden normalerweise in das Makro SYSCALL_DEFINEx() eingeschlossen, weshalb ein einfaches grep sie nicht findet:

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

Der endgültige Funktionsname nach dem Erweitern des Makros lautet sys_mkdir. Das Makro SYSCALL_DEFINEx() fügt Boilerplate-Dinge wie den Ablaufverfolgungscode hinzu, den jede Syscall-Definition haben muss.

22
stefanha

Hinweis: Die .h-Datei definiert die Funktion nicht . Es ist in dieser .h-Datei deklariert und an anderer Stelle definiert (implementiert). Auf diese Weise kann der Compiler Informationen zur Signatur (Prototyp) der Funktion einschließen, um die Typprüfung von Argumenten zu ermöglichen und die Rückgabetypen mit allen aufrufenden Kontexten in Ihrem Code abzugleichen.

Im Allgemeinen werden .h (Header) -Dateien in C verwendet, um Funktionen zu deklarieren und Makros zu definieren.

mkdir ist insbesondere ein Systemaufruf. Möglicherweise gibt es einen GNU libc - Wrapper um diesen Systemaufruf (mit ziemlicher Sicherheit). Der wahre Kernel Die Implementierung von mkdir kann durch Durchsuchen der Kernelquellen und insbesondere der Systemaufrufe gefunden werden.

Beachten Sie, dass für jedes Dateisystem auch eine Art Verzeichniserstellungscode implementiert wird. Die VFS-Schicht (Virtual Filesystem) bietet eine gemeinsame API, in die die Systemaufrufschicht aufrufen kann. Jedes Dateisystem muss Funktionen registrieren, die von der VFS-Schicht aufgerufen werden können. Auf diese Weise können verschiedene Dateisysteme ihre eigene Semantik für die Struktur von Verzeichnissen implementieren (z. B. wenn sie mithilfe eines Hashing-Schemas gespeichert werden, um die Suche nach bestimmten Einträgen effizienter zu gestalten). Ich erwähne dies, weil Sie wahrscheinlich über diese dateisystemspezifischen Verzeichniserstellungsfunktionen stolpern, wenn Sie den Linux-Kernel-Quellbaum durchsuchen.

17
Jim Dennis

Keine der gefundenen Implementierungen stimmt mit dem Prototyp in sys/stat.h überein. Vielleicht wäre die Suche nach einer include-Anweisung mit dieser Header-Datei erfolgreicher?

8
greg0ire

Hier sind ein paar wirklich großartige Blog-Beiträge, die verschiedene Techniken für die Suche nach Kernel-Quellcode auf niedriger Ebene beschreiben.

6
An̲̳̳drew