Que se passe-t-il lorsqu'un fichier paginé à 100% dans le cache de pages est modifié par un autre processus


14

Je sais que lorsqu'une page de cache de page est modifiée, elle est marquée comme sale et nécessite une réécriture, mais que se passe-t-il lorsque:

Scénario: le fichier / apps / EXE, qui est un fichier exécutable, est paginé complètement dans le cache de pages (toutes ses pages sont dans le cache / mémoire) et exécuté par le processus P

La version continue remplace ensuite / apps / EXE par un tout nouvel exécutable.

Hypothèse 1: je suppose que le processus P (et toute autre personne ayant un descripteur de fichier référençant l'ancien exécutable) continuera à utiliser l'ancien, dans la mémoire / applications / EXE sans problème, et tout nouveau processus qui tentera d'exécuter ce chemin obtiendra le nouvel exécutable.

Hypothèse 2: Je suppose que si toutes les pages du fichier ne sont pas mappées en mémoire, les choses iront bien jusqu'à ce qu'il y ait une erreur de page nécessitant des pages du fichier qui ont été remplacées, et probablement une erreur de segmentation se produira?

Question 1: Si vous bloquez toutes les pages du fichier avec quelque chose comme vmtouch, cela change-t-il le scénario?

Question 2: Si / apps / EXE est sur un NFS distant, cela ferait-il une différence? (Je suppose que non)

Veuillez corriger ou valider mes 2 hypothèses et répondre à mes 2 questions.

Supposons qu'il s'agit d'une boîte CentOS 7.6 avec une sorte de noyau 3.10.0-957.el7

Mise à jour: En y réfléchissant plus, je me demande si ce scénario n'est pas différent de tout autre scénario de page sale.

Je suppose que le processus qui écrit le nouveau binaire fera une lecture et obtiendra toutes les pages de cache car il est paginé, puis toutes ces pages seront marquées comme sales. S'ils sont verrouillés, ce ne seront que des pages inutiles occupant la mémoire centrale une fois que le compte de références sera à zéro.

Je soupçonne qu'à la fin des programmes en cours d'exécution, tout le reste utilisera le nouveau binaire. En supposant que tout est correct, je suppose que ce n'est intéressant que si une partie du fichier est paginée.


Juste pour le rendre explicite, le remplacement d'un fichier ne sera pas une grosse chose (selon qu'il est rouvert par l'application et comment l'application réagit au contenu modifié), mais la modification des fichiers mmapés peut entraîner une grave panne des applications (c'est un problème courant dans le monde java lorsqu'un fichier zip qui a une entrée de répertoire mmaped est modifié). Cela dépend cependant de la plate-forme, il n'est pas garanti que les régions mmapées voient le changement ou non.
vérifie le

Réponses:


12

La version continue remplace ensuite / apps / EXE par un tout nouvel exécutable.

C'est la partie importante.

La façon dont un nouveau fichier est publié consiste à créer un nouveau fichier (par exemple /apps/EXE.tmp.20190907080000), à en écrire le contenu, à définir les autorisations et la propriété et enfin à le renommer (2) en lui donnant le nom final /apps/EXE, en remplaçant l'ancien fichier.

Le résultat est que le nouveau fichier a un nouveau numéro d'inode (ce qui signifie, en fait, c'est un fichier différent.)

Et l'ancien fichier avait son propre numéro d'inode, qui est en fait toujours là même si le nom de fichier ne le pointe plus (ou il n'y a plus de nom de fichier pointant vers cet inode.)

Donc, la clé ici est que lorsque nous parlons de "fichiers" sous Linux, nous parlons le plus souvent vraiment d '"inodes" car une fois qu'un fichier a été ouvert, l'inode est la référence que nous gardons pour le fichier.

Hypothèse 1 : je suppose que le processus P (et toute autre personne ayant un descripteur de fichier référençant l'ancien exécutable) continuera à utiliser l'ancien, dans la mémoire / apps / EXE sans problème, et tout nouveau processus qui tentera d'exécuter ce chemin obtiendra le nouvel exécutable.

Correct.

Hypothèse 2 : Je suppose que si toutes les pages du fichier ne sont pas mappées en mémoire, les choses iront bien jusqu'à ce qu'il y ait une erreur de page nécessitant des pages du fichier qui ont été remplacées, et probablement une erreur de segmentation se produira?

Incorrect. L'ancien inode est toujours là, donc les erreurs de page du processus utilisant l'ancien binaire seront toujours en mesure de trouver ces pages sur le disque.

Vous pouvez voir certains effets de cela en regardant le /proc/${pid}/exelien symbolique (ou, de manière équivalente, la lsofsortie) pour le processus exécutant l'ancien binaire, qui montrera /app/EXE (deleted)que le nom n'est plus là mais que l'inode est toujours là.

Vous pouvez également voir que l'espace disque utilisé par le binaire ne sera libéré qu'après la fin du processus (en supposant que c'est le seul processus avec cet inode ouvert.) Vérifiez la sortie dfavant et après avoir tué le processus, vous le verrez diminuer de la taille de ce vieux binaire que vous pensiez ne plus être là.

BTW, ce n'est pas seulement avec les binaires, mais avec tous les fichiers ouverts. Si vous ouvrez un fichier dans un processus et supprimez le fichier, le fichier sera conservé sur le disque jusqu'à ce que ce processus ferme le fichier (ou meurt.) De la même manière que les liens physiques gardent un compteur du nombre de noms pointant vers un inode sur le disque, le Le pilote du système de fichiers (dans le noyau Linux) conserve un compteur du nombre de références à cet inode en mémoire et ne libérera l'inode du disque qu'une fois que toutes les références du système en cours d'exécution auront également été libérées.

Question 1 : Si vous bloquez toutes les pages du fichier avec quelque chose comme vmtouch, cela change-t-il le scénario

Cette question est basée sur l'hypothèse incorrecte 2 selon laquelle le fait de ne pas verrouiller les pages entraînera des erreurs de segmentation. Ce ne sera pas le cas.

Question 2 : Si / apps / EXE est sur un NFS distant, cela ferait-il une différence? (Je suppose que non)

Il est censé fonctionner de la même manière et la plupart du temps, mais il existe des "pièges" avec NFS.

Parfois, vous pouvez voir les artefacts de la suppression d'un fichier qui est toujours ouvert dans NFS (apparaît comme un fichier caché dans ce répertoire.)

Vous avez également un moyen d'attribuer des numéros de périphérique aux exportations NFS, pour vous assurer que ceux-ci ne seront pas "réorganisés" au redémarrage du serveur NFS.

Mais l'idée principale est la même. Le pilote client NFS utilise toujours des inodes et essaiera de conserver les fichiers (sur le serveur) pendant que l'inode est toujours référencé.


1
Rename (2) bloque-t-il jusqu'à ce que le nombre de références du fichier oldname atteigne zéro?
Gregg Leventhal

2
Non, renommer (2) ne bloquera pas. L'ancien inode est conservé pendant potentiellement très longtemps.
filbranden

1
Voir la réponse de @ mosvy pour savoir pourquoi vous ne pouvez pas écrire dans un fichier en cours d'exécution (vous obtenez ETXTBSY). Dissocier et créer un nouveau a le même effet de renommer: vous vous retrouvez avec un nouvel inode. (Renommer est meilleur car il n'y a pas de moment où le nom de fichier n'existe pas, c'est une opération atomique remplaçant le nom pour pointer vers le nouvel inode.)
filbranden

4
@GreggLeventhal: "Quelle supposition faites-vous sur le processus de publication continue que j'utilise qui vous garantit qu'il utilise des fichiers temporaires?" - Parce que depuis aussi longtemps qu'Unix existe, c'est et a été la seule façon sensée de le faire. renameest à peu près la seule opération de fichier et de système de fichiers qui est garantie d'être atomique (en supposant que nous ne traversons pas les limites du système de fichiers ou du périphérique), donc "créer un fichier temporaire puis rename" est le modèle standard pour la mise à jour des fichiers. C'est aussi ce que chaque éditeur de texte sous Unix utilise, par exemple.
Jörg W Mittag

1
@ grahamj42: renamefait partie de POSIX. Certes, il est inclus par référence à l'ISO C (section 7.21.4.2 dans le projet actuel), mais il est là.
Jörg W Mittag

6

Hypothèse 2: Je suppose que si toutes les pages du fichier ne sont pas mappées en mémoire, les choses iront bien jusqu'à ce qu'il y ait une erreur de page nécessitant des pages du fichier qui ont été remplacées, et probablement une erreur de segmentation se produira?

Non, cela ne se produira pas, car le noyau ne vous laissera pas ouvrir pour écrire et remplacer quoi que ce soit à l'intérieur d'un fichier en cours d'exécution. Une telle action échouera avec ETXTBSY[1]:

cp /bin/sleep sleep; ./sleep 3600 & echo none > ./sleep
[9] 5332
bash: ./sleep: Text file busy

Lorsque dpkg, etc. met à jour un binaire, il ne l'écrase pas, mais utilise rename(2)ce qui pointe simplement l'entrée du répertoire vers un fichier complètement différent, et tous les processus qui ont encore des mappages ou des poignées ouvertes vers l'ancien fichier continueront de l'utiliser sans problème .

[1] cette protection n'est pas étendue à d'autres fichiers qui peuvent également être considérés comme du "texte" (code live / exécutable): bibliothèques partagées, classes java, etc; la modification d'un tel fichier pendant qu'il est mappé par un autre processus le fera planter. Sous Linux, l'éditeur de liens dynamique passe consciencieusement le MAP_DENYWRITEdrapeau à mmap(2), mais ne vous y trompez pas - cela n'a aucun effet.


1
Dans le scénario dpkg, à quel moment le renommage se termine-t-il de sorte que la dentry pour / apps / EXE fasse référence à l'inode du nouveau binaire? Quand il n'y a plus de références à l'ancien? Comment ça marche?
Gregg Leventhal

2
rename(2)est atomique; dès qu'elle est terminée, l'entrée dir fait référence au nouveau fichier. Les processus qui utilisaient encore l'ancien fichier à ce moment-là ne pourraient y accéder que via des mappages existants, ou via des poignées ouvertes (qui peuvent référencer une dentisterie orpheline, qui n'est plus accessible autrement que via /proc/PID/fd).
mosvy

1
J'aime mieux votre réponse parce que votre mention ETXTBSY m'a conduit à ce utcc.utoronto.ca/~cks/space/blog/unix/WhyTextFileBusyError qui répond à toutes mes questions.
Gregg Leventhal

4

la réponse de filbranden est correcte en supposant que le processus de libération continue effectue le remplacement atomique approprié des fichiers via rename. Si ce n'est pas le cas, mais modifie le fichier sur place, les choses sont différentes. Cependant, votre modèle mental se trompe toujours.

Il n'y a aucune possibilité que les choses soient modifiées sur le disque et incompatibles avec le cache de page, car le cache de page est la version canonique et celle qui est modifiée. Toute écriture dans un fichier s'effectue via le cache de pages. S'il y est déjà présent, les pages existantes sont modifiées. Si elle n'est pas encore présente, les tentatives de modification d'une page partielle entraîneront la mise en cache de la page entière, suivie d'une modification comme si elle était déjà mise en cache. Les écritures qui s'étendent sur une page entière ou plus peuvent (et presque sûrement) optimiser l'étape de lecture en les paginant. Dans tous les cas, il n'existe qu'une seule version canonique modifiable d'un fichier (*), celle du cache de page .

(*) J'ai légèrement menti. Pour NFS et d'autres systèmes de fichiers distants, il peut y en avoir plusieurs, et ils (généralement en fonction de celui et des options de montage et côté serveur utilisés) n'implémentent pas correctement l'atomicité et la sémantique de commande pour les écritures. C'est pourquoi beaucoup d'entre nous les considèrent comme fondamentalement cassés et refusent de les utiliser dans des situations où il y aura des écritures en même temps que leur utilisation.

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.