Comment Linux différencie-t-il les files réels et les files inexistants (ex: device)?

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

Je sais que sur le système de files Linux, certains files existent , par exemple: /usr/bin/bash est un file existant. Cependant, pour autant que je le comprenne, certains n'existent pas en tant que tels et sont des files plus virtuels , par exemple: /dev/sda , /proc/cpuinfo , etc. Mes questions sont (elles sont deux mais aussi étroitement liés à des questions distinctes):

  • Comment le kernel Linux détermine-t-il si ces files sont réels (et donc les lisent sur le disque) ou pas quand une command de lecture (ou telle) est émise?
  • Si le file n'est pas réel: à titre d'exemple, une lecture de /dev/random renvoie des données randoms, et une lecture de /dev/null renvoie EOF . Comment fonctionne-t-il datatables à lire à partir de ce file virtuel (et donc quoi faire quand / si datatables sont écrites dans le file virtuel) – existe-t-il une sorte de map avec des pointeurs pour séparer les commands en lecture / ou même pour le directory virtuel lui-même? Ainsi, une input pour /dev/null pourrait simplement renvoyer un EOF .

Il y a donc fondamentalement deux types de choses différents ici:

  1. Les filesystems normaux, qui contiennent des files dans des directorys contenant des données et des métadonnées, de la manière habituelle (y compris les liens logiciels, les liens physiques, etc.). Ceux-ci sont souvent, mais pas toujours, sauvegardés par un périphérique bloc pour le stockage persistant (un tmpfs ne vit que dans la RAM, mais est par ailleurs identique à un système de files normal). La sémantique de ceux-ci sont familiers; lire, écrire, renommer, et ainsi de suite, tout fonctionne comme vous l'attendez.
  2. Systèmes de files virtuels, de différents types. /proc et /sys sont des exemples ici, tout comme les filesystems personnalisés FUSE comme sshfs ou ifuse . Il y a beaucoup plus de diversité dans ces domaines, car ils se réfèrent simplement à un système de files avec une sémantique qui est en quelque sorte «personnalisée». Ainsi, lorsque vous lisez un file sous /proc , vous /proc pas réellement à une donnée spécifique stockée par quelque chose d'autre l'écrivant plus tôt, comme dans un système de files normal. Vous faites essentiellement un appel du kernel, demandant des informations générées à la volée. Et ce code peut faire tout ce qu'il veut, car c'est juste une fonction qui implémente la sémantique de la read . Ainsi, vous avez le comportement bizarre des files sous /proc , comme par exemple prétendre être des liens symboliques quand ils ne sont pas vraiment.

La key est que /dev est en fait, généralement, l'un des premiers types. Il est normal dans les dissortingbutions modernes d'avoir /dev comme quelque chose comme un tmpfs, mais dans les anciens systèmes, il était normal d'avoir un directory simple sur le disque, sans attributes spéciaux. La key est que les files sous /dev sont des nœuds de périphériques, un type de file spécial similaire aux sockets FIFO ou Unix; un nœud de périphérique possède un numéro majeur et un numéro mineur. En les lisant ou en les écrivant, il appelle un pilote du kernel, comme lire ou écrire un FIFO, appelle le kernel pour qu'il tamponne votre sortie dans un tube. Ce pilote peut faire ce qu'il veut, mais il touche généralement le matériel d'une manière ou d'une autre, par exemple pour accéder à un disque dur ou jouer du son dans les haut-parleurs.

Pour répondre aux questions d'origine:

  1. Il y a deux questions pertinentes pour savoir si le «file existe» ou non; il s'agit de savoir si le file de noeud du périphérique existe littéralement et si le code du kernel le sauvegarde. Le premier est résolu comme n'importe quoi sur un système de files normal. Les systèmes modernes utilisent udev ou quelque chose comme ça pour surveiller les events matériels et créer et détruire automatiquement les nœuds de périphériques sous /dev conséquence. Mais les systèmes plus anciens, ou les builds légers, peuvent simplement avoir tous leurs nœuds de périphériques littéralement sur le disque, créés à l'avance. Pendant ce time, lorsque vous lisez ces files, vous appelez le code du kernel qui est déterminé par les numéros de périphérique majeurs et mineurs; si ce n'est pas raisonnable (par exemple, vous essayez de lire un périphérique bloqué qui n'existe pas), vous obtiendrez simplement une sorte d'erreur d'E / S.

  2. La façon dont il fonctionne sur quel code kernel appeler pour quel file de périphérique varie. Pour les filesystems virtuels comme /proc , ils implémentent leurs propres fonctions de read et d' write ; le kernel appelle simplement ce code en fonction du sharepoint assembly dans lequel il se trouve et l'implémentation du système de files prend soin du rest. Pour les files de périphérique, il est dissortingbué en fonction des numéros de périphérique majeurs et mineurs.

Voici une list de files de /dev/sda1 sur mon server Arch Linux presque à jour:

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

Ainsi, l'input de directory dans /dev/ pour sda a un numéro d'inode, 1294. C'est un vrai file sur le disque.

Regardez où la taille du file apparaît généralement. "8, 1" apparaît à la place. C'est un numéro de périphérique majeur et mineur. Notez également le 'b' dans les permissions de file.

Le file /usr/include/ext2fs/ext2_fs.h contient ce (fragment) C struct:

 /* * 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 file. Beaucoup de choses intéressantes sont dans cette structure; jetez-y un long regard.

L'élément i_mode de struct ext2_inode a 16 bits, et il utilise seulement 9 pour l'user / groupe / autre, les permissions de lecture / écriture / exécution et 3 autres pour setuid, setgid et sticky. Il dispose de 4 bits pour différencier les types de files tels que «file ordinaire», «lien», «directory», «canal nommé», «socket de la famille Unix» et «périphérique de bloc».

Le kernel Linux peut suivre l'algorithm habituel de search d'annuaire, puis prendre une décision en fonction des permissions et des indicateurs de l'élément i_mode . Pour 'b', bloquer les files de périphériques, il peut find les numéros de périphériques majeurs et mineurs et, traditionnellement, utiliser le numéro de périphérique principal pour searchr un pointeur vers une fonction kernel (un pilote de périphérique) traitant des disques. Le numéro d'appareil mineur s'utilise habituellement comme le numéro du périphérique de bus SCSI ou le numéro de périphérique EIDE ou quelque chose comme ça.

D'autres décisions concernant la gestion d'un file comme /proc/cpuinfo sont sockets en fonction du type de système de files. Si vous faites un:

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

vous pouvez voir que /proc a le type de système de files "proc". La lecture à partir d'un file dans /proc amène le kernel à faire quelque chose de différent en fonction du type de système de files, tout comme l'ouverture d'un file sur un système de files ReiserFS ou DOS entraînerait l'utilisation de différentes fonctions pour localiser les files et localiser datatables des files.

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

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

/ proc et de nos jours / dev et / run (aka / var / run) sont des filesystems virtuels en RAM. / proc est une interface / windows pour les variables et les structures du kernel.

Je vous recommand de lire le Linux Kernel 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 design et la mise en œuvre du operating system 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

En plus des réponses de @ RuiFRibeiro et @ BruceEdiger, la distinction que vous faites n'est pas exactement la distinction faite par le kernel. En fait, vous avez différents types de files: des files réguliers, des directorys, des liens symboliques, des périphériques, des sockets (et j'en oublie toujours quelques-uns donc je n'essaierai pas de faire une list complète). Vous pouvez avoir l'information sur le type d'un file avec ls : c'est le premier caractère sur 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 indique que ce file est un périphérique de blocage. Un tiret, signifie un file régulier, 'l' un lien symbolique et ainsi de suite. Ces informations sont stockées dans les métadonnées du file et sont accessibles via l'appel système stat par exemple, de sorte que le kernel peut lire différemment un file et un lien symbolique par exemple.

Ensuite, vous faites une autre distinction entre les "files réels" comme /bin/bash et les "files virtuels" comme /proc/cpuinfo mais ls déclarent tous les deux comme des files réguliers, donc la différence est 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 est qu'ils appartiennent à différents filesystems. /proc est le sharepoint assembly d'un pseudo-système de files procfs tandis que /bin/bash trouve sur un système de files disque standard. Lorsque Linux ouvre un file (il le fait différemment selon le système de files), il remplit un file structure de données qui a, entre autres attributes, une structure de plusieurs pointeurs de fonction qui décrivent comment utiliser ce file. Par conséquent, il peut implémenter des comportements distincts pour différents types de files.

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 memory avec les informations returnnées par la fonction meminfo_proc_show , dont la tâche est de collecter des données sur l'utilisation de la memory. Cette information peut alors être lue normalement. Chaque fois que vous ouvrez le file, la fonction meminfo_proc_open est appelée et les informations sur la memory sont actualisées.

Tous les files d'un système de files sont "réels" dans la mesure où ils autorisent les E / S de files. Lorsque vous ouvrez un file, le kernel crée un descripteur de file, qui est un object (au sens de la programmation orientée object) qui agit comme un file. Si vous lisez le file, le descripteur de file exécute sa méthode de lecture, qui à son tour requestra au système de files (sysfs, ext4, nfs, etc.) datatables du file. Les filesystems présentent une interface uniforme avec l'espace user et savent ce qu'il faut faire pour gérer les lectures et les écritures. Les filesystems requestnt à leur tour à d'autres couches de traiter leurs requests. Pour un file standard, par exemple un système de files ext4, il faut searchr des data structures du système de files (qui peuvent impliquer des lectures de disque) et éventuellement une lecture du disque (ou cache) pour copyr datatables dans le tampon de lecture. Pour un file dans dis sysfs, il suffit généralement de sprintf () s quelque chose à la memory tampon. Pour un nœud de développement de bloc, il requestra au pilote de disque de lire certains blocs et de les copyr dans le tampon (les numéros majeurs et mineurs indiquent au système de files à quel pilote faire les requêtes).