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.
la source
Réponses:
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.
Correct.
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}/exe
lien symbolique (ou, de manière équivalente, lalsof
sortie) 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
df
avant 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.
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.
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é.
la source
rename
est à 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 puisrename
" 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.rename
fait 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à.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]: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_DENYWRITE
drapeau àmmap(2)
, mais ne vous y trompez pas - cela n'a aucun effet.la source
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
).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.
la source