Comment trouver les implémentations des appels système du noyau Linux?


375

J'essaie de comprendre comment une fonction, disons mkdir, fonctionne en regardant la source du noyau. Ceci est une tentative de comprendre les éléments internes du noyau et de naviguer entre différentes fonctions. Je sais mkdirest défini dans sys/stat.h. J'ai trouvé le prototype:

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

Maintenant, j'ai besoin de voir dans quel fichier C cette fonction est implémentée. Depuis le répertoire source, j'ai essayé

ack "int mkdir"

qui a affiché

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

Mais aucun d’entre eux ne correspond à la définition de sys/stat.h.

Des questions

  1. Quel fichier a l' mkdirimplémentation?
  2. Avec une définition de fonction comme ci-dessus, comment puis-je savoir quel fichier est implémenté? Le noyau utilise-t-il un modèle pour définir et mettre en œuvre des méthodes?

NOTE: J'utilise le noyau 2.6.36-rc1 .


2
À propos, regardez ceci: voinici.ceata.org/~tct/resurse/utlk.pdf
Tom Brito

Réponses:


386

Les appels système ne sont pas traités comme des appels de fonction normaux. Il faut un code spécial pour passer de l’espace utilisateur à l’espace noyau, c’est-à-dire un peu de code d’assemblage en ligne injecté dans votre programme sur le site d’appel. Le code du noyau qui "intercepte" l'appel système est également un élément de bas niveau que vous n'avez probablement pas besoin de comprendre en profondeur, du moins au début.

Dans include/linux/syscalls.hle répertoire source de votre noyau, vous trouvez ceci:

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

Ensuite /usr/include/asm*/unistd.h, vous trouvez ceci:

#define __NR_mkdir                              83
__SYSCALL(__NR_mkdir, sys_mkdir)

Ce code dit qu'il mkdir(2)s'agit de l'appel système n ° 83. C'est-à-dire que les appels système sont appelés par numéro, pas par adresse comme avec un appel de fonction normal dans votre propre programme ou vers une fonction dans une bibliothèque liée à votre programme. Le code de collage d'assemblage en ligne que j'ai mentionné ci-dessus l'utilise pour effectuer la transition de l'espace utilisateur vers l'espace noyau, en prenant en compte vos paramètres.

Une autre preuve que les choses sont un peu bizarres ici est qu’il n’existe pas toujours de liste de paramètres stricte pour les appels système: open(2)par exemple, elle peut prendre 2 ou 3 paramètres. Cela signifie open(2)est surchargé , une caractéristique de C ++, C pas, mais l'interface syscall est C-compatible. (Ce n'est pas la même chose que la fonction varargs de C , qui permet à une seule fonction de prendre un nombre variable d'arguments.)

Pour répondre à votre première question, il n’existe pas de fichier unique mkdir(). Linux supporte de nombreux systèmes de fichiers différents et chacun a sa propre implémentation de l'opération "mkdir". La couche d'abstraction qui permet au noyau de masquer tout ce qui se cache derrière un seul appel système s'appelle VFS . Donc, vous voulez probablement commencer à creuser fs/namei.c, avec vfs_mkdir(). Les implémentations réelles du code modifiant le système de fichiers de bas niveau sont ailleurs. Par exemple, l'implémentation ext4 est appelée ext4_mkdir(), définie dans fs/ext4/namei.c.

En ce qui concerne votre deuxième question, oui, il y a des tendances à tout cela, mais pas une seule règle. Ce dont vous avez réellement besoin est une compréhension assez large du fonctionnement du noyau afin de déterminer où rechercher un appel système particulier. Tous les appels système n’impliquent pas le système VFS. Par conséquent, leurs chaînes d’appel côté noyau ne démarrent pas fs/namei.c. mmap(2), par exemple, commence par mm/mmap.c, car il fait partie du sous-système de gestion de la mémoire ("mm") du noyau.

Je vous recommande de vous procurer une copie de " Comprendre le noyau Linux " de Bovet et Cesati.


Très bonne réponse. Un point sur le livre que vous mentionnez, "Comprendre le noyau Linux". Je ne l’ai pas, mais à partir de la date de parution (2000) et TOC (sur le site d’Ouilly), il me semble qu’il s’agit d’environ 2,2 noyaux plus quelques informations tirées des noyaux 2.4 (mais je me trompe). Ma question est la suivante: y at-il un livre équivalent qui couvre les internes de 2,6 noyaux? (ou mieux encore qui couvrent 2.2, 2.4 et 2.6)?
DavAlPi

2
@DavAlPi: Autant que je sache, Bovet & Cesati est toujours le meilleur livre sur ce sujet. Lorsque je dois le compléter avec du matériel plus à jour, je vais creuser dans le Documentationsous - répertoire de l'arbre source du noyau avec lequel je travaille.
Warren Young

1
En fait open (2) est une fonction varargs. Il n’existe que deux façons de l’appeler, aussi la page de manuel la documente-t-elle de la manière suivante: le prototype actuel a la ...fonction Varargs. Bien sûr, cela est implémenté au niveau de la libc. Il se peut que la valeur ABI du noyau soit transmise à 0 ou à une valeur résiduelle lorsque le troisième paramètre n'est pas utilisé.
Random832

"C'est quelque chose que vous n'avez pas besoin de comprendre". World serait un meilleur endroit si ce genre de phrase n’était nulle part ailleurs sur le réseau stackexchange.
Petr le

84

Cela ne répond probablement pas directement à votre question, mais j’ai trouvé stracetrès bon d’essayer de comprendre les appels système sous-jacents, en action, conçus pour les commandes shell les plus simples. par exemple

strace -o trace.txt mkdir mynewdir

Les appels système de la commande mkdir mynewdirseront sauvegardés dans trace.txt pour votre plus grand plaisir.


5
+1 astuce! Je n'avais jamais utilisé ça auparavant
David Oneill

3
Mieux encore, créez le fichier de sortie trace.strace et ouvrez-le dans VIM. VIM le mettra en évidence, ce qui facilitera grandement sa lecture.
Marcin

55

La référence croisée Linux (LXR) ¹ est un bon endroit pour lire la source du noyau Linux . Les recherches renvoient des résultats typés (prototypes de fonctions, déclarations de variables, etc.) en plus des résultats de recherche de texte libre, ce qui est plus pratique qu'un simple grep (et plus rapide également).

LXR ne développe pas les définitions du préprocesseur. Les appels système ont leur nom mutilé par le préprocesseur. Cependant, la plupart des appels système (tous?) Sont définis avec l'une des SYSCALL_DEFINExfamilles de macros. Puisque mkdirprend deux arguments, une recherche de SYSCALL_DEFINE2(mkdirconduit à la déclaration du mkdirsyscall :

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

ok, sys_mkdiratça veut dire que c'est l' mkdiratappel système, donc cliquer dessus ne conduit qu'à la déclaration include/linux/syscalls.h, mais la définition est juste au dessus.

Le travail principal de mkdiratest d'appeler vfs_mkdir(VFS est la couche de système de fichiers générique). En cliquant dessus, vous obtenez deux résultats de recherche: la déclaration dans include/linux/fs.het la définition quelques lignes plus haut. Le travail principal vfs_mkdirest d'appeler la mise en œuvre spécifique au système de fichiers: dir->i_op->mkdir. Pour savoir comment cela est implémenté, vous devez passer à l'implémentation du système de fichiers individuel, et il n'y a pas de règle absolue - il pourrait même s'agir d'un module situé en dehors de l'arborescence du noyau.

¹ LXR est un programme d'indexation. Plusieurs sites Web fournissent une interface à LXR, avec des ensembles de versions connues légèrement différentes et des interfaces Web légèrement différentes. Ils ont tendance à aller et venir, alors si celui auquel vous êtes habitué n’est pas disponible, lancez une recherche Web sur «référence croisée Linux» pour en trouver une autre.


C'est une sacrée ressource. Très bonne réponse.
Stabledog

"Erreur interne du serveur" dans le lien de linux.no .
Fredrick Gauss

@FredrickGauss Pendant un certain temps, lxr.linux.no était l'interface la plus agréable pour LXR, mais il y avait des temps d'arrêt fréquents. Maintenant, je pense que c'est parti pour de bon. J'ai remplacé le premier lien vers une autre interface LXR.
Gilles le

21

Les appels système sont généralement intégrés à la SYSCALL_DEFINEx()macro. C'est pourquoi un simple grepne les trouve pas:

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

Le nom de la fonction finale après la macro est étendue finit par être sys_mkdir. La SYSCALL_DEFINEx()macro ajoute des éléments standard, tels que le code de traçage, nécessaires à chaque définition d'appel système.


17

Remarque: le fichier .h ne définit pas la fonction. Il est déclaré dans ce fichier .h et défini (implémenté) ailleurs. Cela permet au compilateur d'inclure des informations sur la signature de la fonction (prototype) afin de permettre la vérification du type des arguments et de faire correspondre les types de retour à tous les contextes d'appel de votre code.

En général, les fichiers .h (en-tête) en C sont utilisés pour déclarer des fonctions et définir des macros.

mkdiren particulier est un appel système. Il peut y avoir un wrapper GNU libc autour de cet appel système (presque certainement, en fait). La véritable implémentation du noyau de mkdirpeut être trouvée en recherchant les sources du noyau et les appels système en particulier.

Notez qu'il y aura également une implémentation d'une sorte de code de création de répertoire pour chaque système de fichiers. La couche VFS (système de fichiers virtuel) fournit une API commune à laquelle la couche d'appels système peut appeler. Chaque système de fichiers doit enregistrer des fonctions pour que la couche VFS appelle. Cela permet à différents systèmes de fichiers d'implémenter leur propre sémantique pour la structure des répertoires (par exemple, s'ils sont stockés à l'aide d'une sorte de schéma de hachage pour rendre plus efficace la recherche d'entrées spécifiques). Je le mentionne parce que vous risquez de trébucher sur ces fonctions de création de répertoires spécifiques au système de fichiers si vous effectuez une recherche dans l’arborescence des sources du noyau Linux.


8

Aucune des implémentations que vous avez trouvées ne correspond au prototype dans sys / stat.h Peut-être que la recherche d'une instruction include avec ce fichier d'en-tête aurait plus de succès?


1
L’implémentation (décrite dans sys / stat.h) est l’activité de userland et de libc. Le truc interne du noyau (comment c'est vraiment fait) est le business interne du noyau. Pour tous les hackers du noyau, la fonction interne pourrait s’appeler xyzzy et prendre 5 paramètres. C'est le travail de la libc de prendre l'appel de l'utilitaire utilisateur, de le traduire en une incantation du noyau requise, de l'expédier et de collecter tous les résultats.
vonbrand

6

Voici quelques articles de blog décrivant diverses techniques permettant de rechercher le code source du noyau de bas niveau.


12
Ne postez pas uniquement des liens vers des blogs ou des forums, résumez leur contenu afin que les lecteurs puissent voir de quoi ils parlent et qu'il reste quelque chose si les sites disparaissent. En outre, votre premier lien concerne la libc, qui est hors sujet pour cette question.
Gilles le
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.