Ich versuche zu verstehen, wie eine Funktion funktioniert, mkdir
indem ich mir die Kernelquelle anschaue. Dies ist ein Versuch, die Kernel-Interna zu verstehen und zwischen verschiedenen Funktionen zu navigieren. Ich weiß, mkdir
ist definiert in sys/stat.h
. 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 es 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
- Welche Datei hat die
mkdir
Implementierung? - Wie kann ich bei einer Funktionsdefinition wie der obigen herausfinden, welche Datei die Implementierung hat? Gibt es ein Muster, nach dem der Kernel Methoden definiert und implementiert?
ANMERKUNG: Ich verwende den Kernel 2.6.36-rc1 .
linux-kernel
source
system-calls
Navaneeth KN
quelle
quelle
Antworten:
Systemaufrufe werden nicht wie normale Funktionsaufrufe behandelt. Für den Übergang vom User-Space zum Kernel-Space wird spezieller Code benötigt, im Grunde ein bisschen Inline-Assembler-Code, der an der aufrufenden Site in Ihr Programm eingefügt wird. Der Kernel-Side-Code, der den Systemaufruf "abfängt", ist ebenfalls ein Teil auf niedriger Ebene, den Sie wahrscheinlich zumindest auf den ersten Blick nicht genau verstehen müssen.
In
include/linux/syscalls.h
Ihrem Kernel-Quellverzeichnis finden Sie Folgendes:Dann
/usr/include/asm*/unistd.h
finden Sie in:Dieser Code besagt, dass
mkdir(2)
es sich um den Systemaufruf Nr. 83 handelt. Das heißt, Systemaufrufe werden nach Nummer und nicht nach Adresse aufgerufen, wie bei einem normalen Funktionsaufruf in Ihrem eigenen Programm oder bei einer Funktion in einer Bibliothek, die mit Ihrem Programm verknüpft ist. Der oben erwähnte Inline-Assembler-Code verwendet diesen Code, um den Übergang vom Benutzer- zum Kernel-Space durchzuführen, wobei Ihre Parameter mitgeführt werden.Ein weiterer Beweis dafür, dass die Dinge hier etwas seltsam sind, ist, dass es nicht immer eine strikte Parameterliste für Systemaufrufe gibt:
open(2)
Beispielsweise können 2 oder 3 Parameter verwendet werden. Das heißt, esopen(2)
ist überladen , eine Funktion von C ++, nicht von C, aber die Syscall-Schnittstelle ist C-kompatibel. (Dies ist nicht dasselbe wie die varargs-Funktion von C , mit der eine einzelne Funktion eine variable Anzahl von Argumenten annehmen kann.)Zur Beantwortung Ihrer ersten Frage existiert keine einzige Datei
mkdir()
. Linux unterstützt viele verschiedene Dateisysteme und jedes hat eine eigene Implementierung der Operation "mkdir". Die Abstraktionsschicht, die es dem Kernel ermöglicht, alles, was sich hinter einem einzelnen Systemaufruf verbirgt, wird als VFS bezeichnet . Also möchten Sie wahrscheinlich anfangenfs/namei.c
, mit zu grabenvfs_mkdir()
. Die tatsächlichen Implementierungen des Änderungscodes für das Dateisystem auf niedriger Ebene befinden sich an anderer Stelle. Zum Beispiel heißt die ext4-Implementierungext4_mkdir()
, definiert infs/ext4/namei.c
.Bei Ihrer zweiten Frage gibt es zwar Muster, aber keine einzige Regel. Was Sie tatsächlich brauchen, ist ein ziemlich umfassendes Verständnis der Funktionsweise des Kernels, um herauszufinden, wo Sie nach einem bestimmten Systemaufruf suchen sollten. Nicht alle Systemaufrufe beziehen das VFS mit ein, sodass ihre kernelseitigen Aufrufketten nicht alle in beginnen
fs/namei.c
.mmap(2)
Beginnt beispielsweise inmm/mmap.c
, weil es Teil des Speicherverwaltungssubsystems ("mm") des Kernels ist.Ich empfehle Ihnen eine Kopie von " Understanding the Linux Kernel " von Bovet und Cesati.
quelle
Documentation
Unterverzeichnis des Quellbaums für den Kernel, mit dem ich arbeite....
enthält die Funktion varargs. Dies wird natürlich auf libc-Ebene implementiert. Es kann entweder 0 oder einen Garbage-Wert an die Kernel-ABI übergeben, wenn der dritte Parameter nicht verwendet wird.Dies beantwortet Ihre Frage wahrscheinlich nicht direkt, aber ich fand
strace
es wirklich cool, zu versuchen, die zugrunde liegenden Systemaufrufe in Aktion zu verstehen, die selbst für die einfachsten Shell-Befehle gemacht sind. z.BDie Systemaufrufe für den Befehl
mkdir mynewdir
werden zu Ihrer Freude in die Datei trace.txt geschrieben.quelle
Ein guter Ort, um die Linux -Kernelquelle zu lesen, ist der Linux-Querverweis (LXR) ¹. Suchanfragen liefern zusätzlich zu den Ergebnissen der Freitextsuche typisierte Übereinstimmungen (Funktionsprototypen, Variablendeklarationen usw.). Sie sind also handlicher als ein Grep (und auch schneller).
LXR erweitert keine Präprozessordefinitionen. Bei Systemaufrufen wird der Name vom Präprozessor überall verfälscht. Die meisten (alle?) Systemaufrufe werden jedoch mit einer
SYSCALL_DEFINEx
der Makrofamilien definiert. Da esmkdir
zwei Argumente braucht, führt eine SucheSYSCALL_DEFINE2(mkdir
nach zur Deklaration desmkdir
Syscalls :OK, das
sys_mkdirat
heißt, es ist dermkdirat
Syscall. Wenn Sie also darauf klicken, gelangen Sie nur zur Deklaration ininclude/linux/syscalls.h
, aber die Definition befindet sich direkt darüber.Die Hauptaufgabe von
mkdirat
ist das Aufrufenvfs_mkdir
(VFS ist die generische Dateisystemebene). Wenn Sie darauf klicken, werden zwei Suchergebnisse angezeigt: die Deklaration ininclude/linux/fs.h
und die Definition einige Zeilen darüber. Die Hauptaufgabevfs_mkdir
ist es, das Dateisystem-spezifische Implementierung zu nennen:dir->i_op->mkdir
. Um herauszufinden, wie dies implementiert wird, müssen Sie sich an die Implementierung des einzelnen Dateisystems wenden, und es gibt keine feste Regel - es könnte sogar ein Modul außerhalb des Kernelbaums sein.¹ LXR ist ein Indexierungsprogramm. Es gibt mehrere Websites, die eine Schnittstelle zu LXR bieten, mit geringfügig unterschiedlichen Sätzen bekannter Versionen und geringfügig unterschiedlichen Webschnittstellen. Sie neigen dazu, zu kommen und zu gehen. Wenn die von Ihnen verwendete also nicht verfügbar ist, führen Sie eine Websuche nach "Linux-Querverweis" durch, um eine andere zu finden.
quelle
Systemaufrufe werden normalerweise in das
SYSCALL_DEFINEx()
Makro eingebunden, weshalb ein einfachergrep
Benutzer sie nicht findet:Der endgültige Funktionsname nach dem Erweitern des Makros lautet
sys_mkdir
. DasSYSCALL_DEFINEx()
Makro fügt Boilerplate-Elemente wie Trace-Code hinzu, den jede Syscall-Definition haben muss.quelle
Hinweis: Die .h-Datei definiert die Funktion nicht. Es wird erklärt , dass H - Datei und (implementiert) an anderer Stelle definiert. Auf diese Weise kann der Compiler Informationen zur Funktionssignatur (Prototyp) einschließen, um die Typüberprüfung von Argumenten zu ermöglichen und die Rückgabetypen mit beliebigen aufrufenden Kontexten in Ihrem Code abzugleichen.
Im Allgemeinen werden .h (Header) -Dateien in C verwendet, um Funktionen zu deklarieren und Makros zu definieren.
mkdir
Insbesondere handelt es sich um einen Systemaufruf. Möglicherweise gibt es einen GNU libc- Wrapper um diesen Systemaufruf (mit ziemlicher Sicherheit sogar). Die wahre Kernel-Implementierung vonmkdir
kann durch Durchsuchen der Kernel-Quellen 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 zugreifen kann. Jedes Dateisystem muss Funktionen registrieren, in die die VFS-Ebene aufgerufen werden kann. Auf diese Weise können verschiedene Dateisysteme ihre eigene Semantik für die Struktur von Verzeichnissen implementieren (z. B. wenn sie mithilfe eines Hash-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.
quelle
Keine der gefundenen Implementierungen stimmt mit dem Prototyp in sys / stat.h überein. Wäre es möglicherweise erfolgreicher, nach einer Include-Anweisung mit dieser Header-Datei zu suchen?
quelle
Hier sind ein paar wirklich großartige Blog-Posts, die verschiedene Techniken zum Aufspüren von Kernel-Quellcode auf niedriger Ebene beschreiben.
quelle