J'essaie de comprendre comment une fonction, disons mkdir
, fonctionne en regardant la source du noyau. Il s'agit d'une tentative de comprendre les composants internes du noyau et de naviguer entre les différentes fonctions. Je connais mkdir
est 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, je dois voir dans quel fichier C cette fonction est implémentée. Depuis le répertoire source, j'ai essayé
ack "int mkdir"
qui s'affiche
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 dans sys/stat.h
.
Questions
- Quel fichier contient le
mkdir
? mise en œuvre ? - Avec une définition de fonction comme ci-dessus, comment puis-je savoir quel fichier contient l'implémentation ? Existe-t-il un modèle suivi par le noyau pour définir et implémenter des méthodes ?
REMARQUE :J'utilise le noyau 2.6.36-rc1.
Réponse acceptée :
Les appels système ne sont pas traités comme des appels de fonction normaux. Il faut un code spécial pour effectuer la transition de l'espace utilisateur à l'espace noyau, essentiellement un peu de code d'assemblage en ligne injecté dans votre programme sur le site d'appel. Le code côté noyau qui "attrape" 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.h
sous le répertoire source de votre noyau, vous trouverez ceci :
asmlinkage long sys_mkdir(const char __user *pathname, int mode);
Puis dans /usr/include/asm*/unistd.h
, vous trouvez ceci :
#define __NR_mkdir 83
__SYSCALL(__NR_mkdir, sys_mkdir)
Ce code dit mkdir(2)
est l'appel système #83. C'est-à-dire que les appels système sont appelés par numéro, et non 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 colle d'assemblage en ligne que j'ai mentionné ci-dessus l'utilise pour effectuer la transition de l'espace utilisateur à l'espace noyau, en emportant vos paramètres avec lui.
Une autre preuve que les choses sont un peu bizarres ici est qu'il n'y a pas toujours une liste stricte de paramètres pour les appels système :open(2)
, par exemple, peut prendre 2 ou 3 paramètres. Cela signifie open(2)
est surchargé, une fonctionnalité de C++, pas de C, mais l'interface syscall est compatible C. (Ce n'est pas la même chose que la fonctionnalité varargs de C, qui permet à une seule fonction de prendre un nombre variable d'arguments.)
Pour répondre à votre première question, il n'y a pas de fichier unique où mkdir()
existe. Linux prend en charge 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 cacher tout cela derrière un seul appel système s'appelle le VFS. Donc, vous voulez probablement commencer à creuser dans fs/namei.c
, avec vfs_mkdir()
. Les implémentations réelles du code de modification du système de fichiers de bas niveau sont ailleurs. Par exemple, l'implémentation ext4 s'appelle ext4_mkdir()
, défini dans fs/ext4/namei.c
.
Quant à votre deuxième question, oui, il y a des modèles dans tout cela, mais pas une seule règle. Ce dont vous avez réellement besoin, c'est d'une compréhension assez large du fonctionnement du noyau afin de déterminer où vous devez rechercher un appel système particulier. Tous les appels système n'impliquent pas le VFS, donc leurs chaînes d'appels côté noyau ne commencent pas toutes dans 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 un exemplaire de "Comprendre le noyau Linux" de Bovet et Cesati.