Comment Linux fait-il la différence entre les fichiers réels et inexistants (par exemple: périphérique)?

28

Il s'agit d'une question de bas niveau, et je comprends que ce n'est peut-être pas le meilleur endroit à poser. Mais, il semblait plus approprié que tout autre site SE, alors voilà.

Je sais que sur le système de fichiers Linux, certains fichiers existent réellement , par exemple: /usr/bin/bashest celui qui existe. Cependant, (pour autant que je le comprends), certains aussi n'existent pas réellement en tant que tels et sont plus virtuels des fichiers, par exemple: /dev/sda, /proc/cpuinfo, etc. Mes questions sont (ils sont deux, mais trop étroitement liés comme des questions distinctes):

  • Comment le noyau Linux fonctionne-t-il pour savoir si ces fichiers sont réels (et donc les lire depuis le disque) ou non lorsqu'une commande de lecture (ou autre) est émise?
  • Si le fichier n'est pas réel: à titre d'exemple, une lecture de /dev/randomretournera des données aléatoires et une lecture de /dev/nullretournera EOF. Comment fonctionne-t-il quelles données lire à partir de ce fichier virtuel (et donc quoi faire quand / si des données écrites dans le fichier virtuel aussi) - existe-t-il une sorte de carte avec des pointeurs pour séparer les commandes de lecture / écriture appropriées pour chaque fichier, ou même pour le répertoire virtuel lui-même? Ainsi, une entrée pour /dev/nullpourrait simplement retourner un EOF.
Joe
la source
1
Lorsque le fichier est créé, le noyau enregistre son type. Les fichiers de disque ordinaires sont ensuite traités différemment des liens symboliques, des périphériques de bloc, des périphériques de caractères, des répertoires, des sockets, des FIFO, etc. C'est le travail du noyau de savoir.
Jonathan Leffler
voir l'homme pge pour mknod
Jasen
C'est un peu comme demander "comment un interrupteur d'éclairage sait-il si la lumière est allumée?" L'interrupteur d'éclairage est chargé de décider si l'éclairage est allumé.
Courses de légèreté avec Monica

Réponses:

25

Il y a donc essentiellement deux types de choses ici:

  1. Les systèmes de fichiers normaux, qui contiennent des fichiers dans des répertoires contenant des données et des métadonnées, de la manière habituelle (y compris les liens logiciels, les liens matériels, etc.). Ceux-ci sont souvent, mais pas toujours, soutenus par un périphérique bloc pour un stockage persistant (un tmpfs vit uniquement dans la RAM, mais est par ailleurs identique à un système de fichiers normal). La sémantique de ceux-ci est familière; lire, écrire, renommer, etc., tout fonctionne comme vous vous y attendez.
  2. Systèmes de fichiers virtuels, de divers types. /procet /syssont des exemples ici, tout comme les systèmes de fichiers personnalisés FUSE comme sshfsou ifuse. Il y a beaucoup plus de diversité dans ceux-ci, car en réalité, ils se réfèrent simplement à un système de fichiers avec une sémantique qui est en quelque sorte «personnalisée». Ainsi, lorsque vous lisez à partir d'un fichier sous /proc, vous n'accédez pas réellement à un élément de données spécifique qui a été stocké par quelque chose d'autre l'écrivant plus tôt, comme sous un système de fichiers normal. Vous effectuez essentiellement un appel au noyau, demandant des informations générées à la volée. Et ce code peut faire tout ce qu'il veut, car ce n'est qu'une fonction implémentant quelque part la readsémantique. Ainsi, vous avez le comportement étrange des fichiers sous /proc, comme par exemple faire semblant d'être des liens symboliques lorsqu'ils ne sont pas '

La clé est qu'en /devfait, c'est généralement l'un des premiers. Il est normal dans les distributions modernes d'avoir /devquelque chose comme un tmpfs, mais dans les systèmes plus anciens, il était normal que ce soit un simple répertoire sur le disque, sans aucun attribut spécial. La clé est que les fichiers sous /devsont des nœuds de périphériques, un type de fichier spécial similaire aux FIFO ou aux sockets Unix; un nœud de périphérique a un nombre majeur et mineur, et leur lecture ou leur écriture fait un appel à un pilote du noyau, tout comme la lecture ou l'écriture d'un FIFO appelle le noyau pour mettre en mémoire tampon votre sortie dans un canal. Ce pilote peut faire tout ce qu'il veut, mais il touche généralement le matériel, par exemple pour accéder à un disque dur ou lire du son dans les haut-parleurs.

Pour répondre aux questions originales:

  1. Il y a deux questions pertinentes pour savoir si le «fichier existe» ou non; il s'agit de savoir si le fichier de nœud de périphérique existe littéralement et si le code du noyau le soutenant est significatif. Le premier est résolu comme n'importe quoi sur un système de fichiers normal. Les systèmes modernes utilisent udevou quelque chose du genre pour surveiller les événements matériels et créer et détruire automatiquement les nœuds de périphérique en /devconséquence. Mais les systèmes plus anciens, ou les versions personnalisées légères, peuvent simplement avoir tous leurs nœuds de périphérique sur le disque, créés à l'avance. Pendant ce temps, lorsque vous lisez ces fichiers, vous faites un appel au code du noyau qui est déterminé par les numéros de périphérique majeurs et mineurs; si ceux-ci ne sont pas raisonnables (par exemple, vous essayez de lire un périphérique bloc qui n'existe pas), vous obtiendrez simplement une sorte d'erreur d'E / S.

  2. La façon dont il détermine quel code de noyau appeler pour quel fichier de périphérique varie. Pour les systèmes de fichiers virtuels comme /proc, ils implémentent leurs propres fonctions readet write; le noyau appelle simplement ce code en fonction du point de montage dans lequel il se trouve et l'implémentation du système de fichiers s'occupe du reste. Pour les fichiers de périphérique, il est distribué en fonction des numéros de périphérique majeurs et mineurs.

Tom Hunt
la source
Donc, si, disons, un ancien système avait été /devmis hors tension, les fichiers seraient toujours là, mais je suppose qu'ils seraient effacés au démarrage du système?
Joe
2
Si un ancien système (un sans création de périphérique dynamique) était arrêté, normalement ou anormalement, les nœuds de périphérique resteraient sur le disque comme n'importe quel fichier. Ensuite, au prochain démarrage, ils resteraient également sur le disque et vous pourriez les utiliser normalement. Ce n'est que dans les systèmes modernes que quelque chose de spécial se produit lors de la création et de la destruction des nœuds de périphériques.
Tom Hunt
Ainsi, un système plus moderne n'utilisant pas un tmpfsles créerait et les supprimerait dynamiquement au besoin, par exemple: démarrage et arrêt?
Joe
3
devtmpfs, le /devsystème de fichiers sous Linux moderne, est similaire à a tmpfs, mais a quelques différences à supporterudev . (Le noyau effectue lui-même une création de nœud automatisée avant de le transférer udev, afin de rendre le démarrage moins compliqué.) Dans tous ces cas, les nœuds de périphérique ne vivent que dans la RAM et sont créés et détruits dynamiquement selon les besoins du matériel. Vraisemblablement, vous pouvez également l'utiliser udevsur un disque ordinaire /dev, mais je n'ai jamais vu cela faire et il ne semble pas y avoir de bonnes raisons de le faire.
Tom Hunt
17

Voici une liste de fichiers /dev/sda1sur mon serveur Arch Linux presque à jour:

% ls -li /dev/sda1
1294 brw-rw---- 1 root disk 8, 1 Nov  9 13:26 /dev/sda1

Ainsi, l'entrée de répertoire /dev/pour sdaa un numéro d'inode, 1294. C'est un vrai fichier sur le disque.

Regardez où la taille du fichier apparaît généralement. "8, 1" apparaît à la place. Il s'agit d'un numéro d'appareil majeur et mineur. Notez également le «b» dans les autorisations de fichier.

Le fichier /usr/include/ext2fs/ext2_fs.hcontient cette (fragment) structure C:

/*
 * Structure of an inode on the disk
 */
struct ext2_inode {
    __u16   i_mode;     /* File mode */

Cette structure nous montre la structure sur disque de l'inode d'un fichier. Beaucoup de choses intéressantes sont dans cette structure; regardez-le longuement.

L' i_modeélément de struct ext2_inodea 16 bits et n'utilise que 9 pour l'utilisateur / groupe / autre, les autorisations de lecture / écriture / exécution et 3 autres pour setuid, setgid et sticky. Il dispose de 4 bits pour différencier les types tels que "fichier simple", "lien", "répertoire", "canal nommé", "socket de famille Unix" et "périphérique de bloc".

Le noyau Linux peut suivre l'algorithme de recherche de répertoire habituel, puis prendre une décision en fonction des autorisations et des drapeaux de l' i_modeélément. Pour 'b', bloquer les fichiers de périphériques, il peut trouver les numéros de périphériques majeurs et mineurs et, traditionnellement, utiliser le numéro de périphérique principal pour rechercher un pointeur vers une fonction du noyau (un pilote de périphérique) qui traite des disques. Le numéro de périphérique mineur est généralement utilisé, par exemple, le numéro de périphérique de bus SCSI, ou le numéro de périphérique EIDE ou quelque chose comme ça.

Quelques autres décisions sur la façon de traiter un fichier comme /proc/cpuinfo sont prises en fonction du type de système de fichiers. Si vous faites:

% mount | grep proc 
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)

vous pouvez voir que /procle type de système de fichiers est "proc". La lecture d'un fichier dans /procfait que le noyau fait quelque chose de différent en fonction du type du système de fichiers, tout comme l'ouverture d'un fichier sur un système de fichiers ReiserFS ou DOS obligerait le noyau à utiliser différentes fonctions pour localiser les fichiers et localiser les données du des dossiers.

Bruce Ediger
la source
Êtes-vous certain que seuls les "vrais fichiers sur disque" ont un numéro d'inode affiché? Je reçois 4026531975 -r--r--r-- 1 root root 0 Nov 14 18:41 /proc/mdstatce qui n'est clairement pas un "vrai fichier".
guntbert
7

À la fin de la journée, ce sont tous des fichiers pour Unix, c'est la beauté de l'abstraction.

La façon dont les fichiers sont gérés par le noyau, maintenant c'est une histoire différente.

/ proc et de nos jours / dev et / run (alias / var / run) sont des systèmes de fichiers virtuels en RAM. / proc est une interface / windows pour les variables et les structures du noyau.

Je recommande de lire le noyau Linux http://tldp.org/LDP/tlk/tlk.html et les pilotes de périphériques Linux, troisième édition https://lwn.net/Kernel/LDD3/ .

J'ai également apprécié la conception et la mise en œuvre du système d'exploitation FreeBSD http://www.amazon.com/Design-Implementation-FreeBSD-Operating-System/dp/0321968972/ref=sr_1_1

Jetez un oeil à la page pertinente qui se rapporte à votre question.

http://www.tldp.org/LDP/tlk/dd/drivers.html

Rui F Ribeiro
la source
merci, j'ai légèrement changé la première question après avoir commenté cela.
Joe
Lisez le dernier commentaire s'il vous plaît.
Rui F Ribeiro
5

En plus des réponses de @ RuiFRibeiro et @ BruceEdiger, la distinction que vous faites n'est pas exactement la distinction que fait le noyau. En fait, vous avez différents types de fichiers: fichiers normaux, répertoires, liens symboliques, périphériques, sockets (et j'en oublie toujours quelques-uns donc je n'essaierai pas de faire une liste complète). Vous pouvez avoir les informations sur le type d'un fichier avec ls: c'est le premier caractère de la ligne. Par exemple:

$ls -la /dev/sda
brw-rw---- 1 root disk 8, 0 17 nov.  08:29 /dev/sda

Le «b» au tout début signale que ce fichier est un périphérique bloc. Un tiret, signifie un fichier normal, 'l' un lien symbolique et ainsi de suite. Ces informations sont stockées dans les métadonnées du fichier et sont accessibles via l'appel systèmestat par exemple, afin que le noyau puisse lire différemment un fichier et un lien symbolique par exemple.

Ensuite, vous faites une autre distinction entre les "vrais fichiers" /bin/bashet les "fichiers virtuels" /proc/cpuinfomais lssignalez les deux comme des fichiers normaux, la différence est donc d'un autre type:

ls -la /proc/cpuinfo /bin/bash
-rwxr-xr-x 1 root root  829792 24 août  10:58 /bin/bash
-r--r--r-- 1 root wheel      0 20 nov.  16:50 /proc/cpuinfo

Ce qui se passe, c'est qu'ils appartiennent à différents systèmes de fichiers. /procest le point de montage d'un pseudo-système de fichiers procfsalors qu'il se /bin/bashtrouve sur un système de fichiers sur disque normal. Lorsque Linux ouvre un fichier (il le fait différemment selon le système de fichiers), il remplit une structure de donnéesfile qui a, entre autres attributs, une structure de plusieurs pointeurs de fonction qui décrivent comment utiliser ce fichier. Par conséquent, il peut implémenter des comportements distincts pour différents types de fichiers.

Par exemple, ce sont les opérations annoncées par /proc/meminfo:

static int meminfo_proc_open(struct inode *inode, struct file *file)
{
    return single_open(file, meminfo_proc_show, NULL);
}

static const struct file_operations meminfo_proc_fops = {
    .open       = meminfo_proc_open,
    .read       = seq_read,
    .llseek     = seq_lseek,
    .release    = single_release,
};

Si vous regardez la définition de meminfo_proc_open, vous pouvez voir que cette fonction remplit un tampon en mémoire avec les informations renvoyées par la fonction meminfo_proc_show, dont la tâche est de collecter des données sur l'utilisation de la mémoire. Ces informations peuvent ensuite être lues normalement. Chaque fois que vous ouvrez le fichier, la fonction meminfo_proc_openest appelée et les informations sur la mémoire sont actualisées.

lgeorget
la source
3

Tous les fichiers d'un système de fichiers sont "réels" dans le sens où ils autorisent les E / S sur les fichiers. Lorsque vous ouvrez un fichier, le noyau crée un descripteur de fichier, qui est un objet (au sens d'une programmation orientée objet) qui agit comme un fichier. Si vous lisez le fichier, le descripteur de fichier exécute sa méthode de lecture, qui à son tour demandera au système de fichiers (sysfs, ext4, nfs, etc.) les données du fichier. Les systèmes de fichiers présentent une interface uniforme vers l'espace utilisateur et savent quoi faire pour gérer les lectures et les écritures. Les systèmes de fichiers demandent à leur tour à d'autres couches de gérer leurs demandes. Pour un fichier normal sur un système de fichiers ext4 par exemple, cela impliquera des recherches dans les structures de données du système de fichiers (ce qui peut impliquer des lectures sur disque), et éventuellement une lecture à partir du disque (ou du cache) pour copier les données dans le tampon de lecture. Pour un fichier dans disons sysfs, il suffit généralement de sprintf () quelque chose dans le tampon. Pour un nœud de développement de blocs, il demandera au pilote de disque de lire certains blocs et de les copier dans le tampon (les nombres majeurs et mineurs indiquent au système de fichiers à quel pilote adresser les requêtes).

jpkotta
la source