Je veux analyser /proc/net/tcp/
mais est-ce sûr ?
Comment dois-je ouvrir et lire les fichiers de /proc/
et ne pas avoir peur qu'un autre processus (ou le système d'exploitation lui-même) le modifie en même temps ?
Je veux analyser /proc/net/tcp/
mais est-ce sûr ?
Comment dois-je ouvrir et lire les fichiers de /proc/
et ne pas avoir peur qu'un autre processus (ou le système d'exploitation lui-même) le modifie en même temps ?
En général, non. (La plupart des réponses sont donc fausses). pourrait être sûr, en fonction de la propriété que vous voulez. Mais il est facile de se retrouver avec des bogues dans votre code si vous supposez trop la cohérence d'un fichier dans le fichier /proc
. Par exemple, voir ce bogue qui provenait de la supposition que /proc/mounts
était un instantané cohérent .
Par exemple :
/proc/uptime
es totalement atomique comme quelqu'un l'a mentionné dans une autre réponse, mais seulement depuis Linux 2.6.30 qui a moins de deux ans. Ainsi, même ce fichier minuscule et trivial était sujet à une condition de course jusqu'alors, et l'est toujours dans la plupart des noyaux d'entreprise. Voir fs/proc/uptime.c
pour la source de courant, ou le commit qui l'a rendu atomique . Sur un noyau pré-2.6.30, vous pouvez open
le dossier, read
un peu d'elle, puis si vous revenez plus tard et read
Encore une fois, le morceau que vous obtiendrez ne correspondra pas au premier morceau. (Je viens de le démontrer - essayez vous-même pour le plaisir).
/proc/mounts
es atomique au sein d'un seul read
appel système. Donc si vous read
l'ensemble du fichier en une seule fois, vous obtenez un instantané unique et cohérent des points de montage sur le système. Cependant, si vous utilisez plusieurs read
et si le fichier est volumineux, c'est exactement ce qui se produira si vous utilisez des bibliothèques d'E/S normales et ne prêtez pas une attention particulière à ce problème - vous serez soumis à une situation de concurrence. Non seulement vous n'obtiendrez pas un instantané cohérent, mais les points de montage qui étaient présents avant que vous ne commenciez et qui n'ont jamais cessé d'être présents pourraient être absents de ce que vous voyez. Pour voir que c'est atomique pour un read()
regardez m_start()
en fs/namespace.c
et le voir saisir un sémaphore qui garde la liste des points de montage, qu'il conserve jusqu'à ce que m_stop()
qui est appelé lorsque le read()
est fait. Pour voir ce qui peut mal tourner, voir ce bug de l'année dernière (le même que celui que j'ai mis en lien ci-dessus) dans des logiciels d'excellente qualité qui lisent allègrement /proc/mounts
.
/proc/net/tcp
qui est en fait celui que vous demandez, est encore moins cohérent que cela. C'est atomique uniquement dans chaque ligne du tableau . Pour voir cela, regardez listening_get_next()
en net/ipv4/tcp_ipv4.c
y established_get_next()
juste en dessous dans le même fichier, et voir les verrous qu'ils prennent sur chaque entrée à tour de rôle. Je n'ai pas de code de reproduction à portée de main pour démontrer le manque de cohérence d'une ligne à l'autre, mais il n'y a pas de verrous ici (ou quoi que ce soit d'autre) qui rendrait le tout cohérent. Ce qui est logique si l'on y réfléchit : le réseau est souvent une partie très occupée du système, donc cela ne vaut pas la peine de présenter une vue cohérente dans cet outil de diagnostic.
L'autre pièce qui maintient /proc/net/tcp
atomique dans chaque rangée est la mise en mémoire tampon en seq_read()
que vous pouvez lire sur fs/seq_file.c
. Cela garantit qu'une fois que vous read()
partie d'une ligne, le texte de la ligne entière est conservé dans une mémoire tampon de sorte que la suivante read()
récupérera le reste de cette ligne avant d'en commencer une nouvelle. Le même mécanisme est utilisé dans /proc/mounts
pour garder chaque ligne atomique même si vous faites de multiples read()
et c'est aussi le mécanisme par lequel /proc/uptime
dans les noyaux plus récents utilise pour rester atomique. Ce mécanisme fait no mettre en mémoire tampon l'ensemble du fichier, car le noyau est prudent quant à l'utilisation de la mémoire.
La plupart des fichiers dans /proc
sera au moins aussi cohérent que /proc/net/tcp
avec chaque ligne une image cohérente d'une entrée dans n'importe quelle information qu'ils fournissent, parce que la plupart d'entre eux utilisent le même format de données. seq_file
abstraction. Comme le /proc/uptime
Cependant, comme l'illustre l'exemple, certains fichiers étaient encore en train d'être migrés afin d'utiliser seq_file
pas plus tard qu'en 2009 ; je parie qu'il en existe encore qui utilisent des mécanismes plus anciens et n'ont même pas ce niveau d'atomicité. Ces mises en garde sont rarement documentées. Pour un fichier donné, votre seule garantie est de lire la source.
Dans le cas de /proc/net/tcp
vous pouvez le lire et analyser chaque ligne sans crainte. Mais si vous essayez de tirer des conclusions de plusieurs lignes à la fois -- attention, d'autres processus et le kernel sont Si vous le modifiez pendant que vous le lisez, vous créez probablement un bug.
Bien que les fichiers dans /proc
apparaissent comme des fichiers normaux dans l'espace utilisateur, ils ne sont pas vraiment des fichiers mais plutôt des entités qui prennent en charge les opérations de fichier standard de l'espace utilisateur ( open
, read
, close
). Notez que c'est très différent que d'avoir un fichier ordinaire sur le disque qui est modifié par le noyau.
Tout ce que le noyau fait, c'est imprimer son état interne dans sa propre mémoire en utilisant un fichier sprintf
-et que la mémoire est copiée dans l'espace utilisateur chaque fois que vous émettez une fonction de type read(2)
appel système.
Le noyau traite ces appels d'une manière totalement différente de celle utilisée pour les fichiers ordinaires, ce qui peut signifier que l'intégralité de l'instantané des données que vous allez lire peut être prêt au moment où vous open(2)
tandis que le noyau s'assure que les appels concurrents sont cohérents et atomiques. Je n'ai lu cela nulle part, mais cela n'a pas vraiment de sens qu'il en soit autrement.
Je vous conseille de jeter un coup d'oeil à l'implémentation d'un fichier proc dans votre version particulière d'Unix. Il s'agit vraiment d'une question d'implémentation (tout comme le format et le contenu de la sortie) qui n'est pas régie par un standard.
L'exemple le plus simple serait l'implémentation de la fonction uptime
proc sous Linux : http://lxr.free-electrons.com/source/fs/proc/uptime.c . Notez comment le tampon entier est produit dans la fonction de rappel fournie à single_open
.
/proc est un système de fichiers virtuel : en fait, il donne juste une vue pratique de l'intérieur du noyau. Il est tout à fait sûr de le lire (c'est pourquoi il est ici) mais c'est risqué sur le long terme, car l'interne de ces fichiers virtuels peut évoluer avec une nouvelle version du noyau.
EDITAR
Plus d'informations disponibles dans documentation du proc dans le doc du noyau Linux chapitre 1.4 Mise en réseau Je n'arrive pas à trouver si l'information comment l'information évolue dans le temps. Je pensais qu'elle était figée sur l'ouverture, mais je ne peux pas avoir de réponse définitive.
EDIT2
Selon Sco doc (pas linux, mais je suis presque sûr que toutes les versions de *nix se comportent comme ça)
Bien que l'état du processus et par conséquent le contenu des fichiers /proc peuvent changer d'un instant à l'autre instant, une seule lecture(2) d'un fichier /proc est garantie pour retourner une représentation ``sane'' de l'état, c'est-à-dire que c'est-à-dire que la lecture sera un instantané instantané de l'état du processus. Une telle garantie ne s'applique pas aux lectures successives appliquées à un fichier /proc d'un processus en cours d'exécution. Sur En outre, l'atomicité n'est garantie pour toute entrée/sortie appliquée à le fichier as (espace d'adressage) ; le contenu de l'espace d'adressage d'un processus peut être modifié simultanément simultanément par un LWP de ce processus ou de tout autre processus du système.
L'API procfs du noyau Linux fournit une interface permettant de s'assurer que les lectures renvoient des données cohérentes. Lisez les commentaires dans __proc_file_read
. Le point 1) dans le grand bloc de commentaires explique cette interface.
Cela dit, c'est bien sûr à l'implémentation d'un fichier proc spécifique d'utiliser correctement cette interface pour s'assurer que les données retournées sont cohérentes. Donc, pour répondre à votre question : non, le noyau ne garantit pas la cohérence des fichiers proc lors d'une lecture mais il fournit les moyens aux implémentations de ces fichiers d'assurer la cohérence.
J'ai les sources de Linux 2.6.27.8 à portée de main car je développe actuellement des pilotes sur une cible ARM embarquée.
Le fichier ... linux-2.6.27.8-lpc32xx/net/ipv4/raw.c
à la ligne 934 contient, par exemple
seq_printf(seq, "%4d: %08X:%04X %08X:%04X"
" %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n",
i, src, srcp, dest, destp, sp->sk_state,
atomic_read(&sp->sk_wmem_alloc),
atomic_read(&sp->sk_rmem_alloc),
0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp),
atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops));
qui produit
[wally@zenetfedora ~]$ cat /proc/net/tcp
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 017AA8C0:0035 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 15160 1 f552de00 299
1: 00000000:C775 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 13237 1 f552ca00 299
...
en fonction raw_sock_seq_show()
qui fait partie d'une hiérarchie de procfs les fonctions de manutention. Le texte n'est pas généré avant qu'un read()
la demande est faite auprès du /proc/net/tcp
un mécanisme raisonnable puisque procfs Les lectures sont sûrement beaucoup moins courantes que la mise à jour des informations.
Certains pilotes (comme le mien) implémentent la fonction proc_read avec une seule fonction sprintf()
. La complication supplémentaire dans l'implémentation des pilotes de base est de gérer les sorties potentiellement très longues qui peuvent ne pas tenir dans le tampon intermédiaire de l'espace noyau lors d'une seule lecture.
J'ai testé cela avec un programme utilisant un tampon de lecture de 64K mais il en résulte un tampon d'espace noyau de 3072 octets dans mon système pour que proc_read renvoie les données. Plusieurs appels avec des pointeurs avancés sont nécessaires pour obtenir plus que cette quantité de texte retourné. Je ne sais pas quelle est la bonne façon de rendre cohérentes les données retournées lorsque plusieurs entrées/sorties sont nécessaires. Il est certain que chaque entrée dans /proc/net/tcp
est cohérent avec lui-même. Il y a une certaine probabilité que les lignes côte à côte soient prises à des moments différents.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.