GNU/Linux >> Tutoriels Linux >  >> Linux

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

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

C'est la partie la plus importante.

Un nouveau fichier est publié en créant un nouveau fichier (par exemple, /apps/EXE.tmp.20190907080000 ), écrire le contenu, définir les autorisations et la propriété et enfin le renommer (2) en le nom final /apps/EXE , 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, qu'il s'agit d'un fichier différent.)

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

Donc, la clé ici est que lorsque nous parlons de "fichiers" sous Linux, nous parlons le plus souvent 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 avec un descripteur de fichier faisant référence à l'ancien exécutable) continuera à utiliser l'ancien, en mémoire /apps/EXE sans problème, et tout nouveau processus qui tente d'exécuter ce chemin obtiendra le nouveau exécutable.

Exact.

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

Incorrect. L'ancien inode est toujours là, donc les défauts de page du processus utilisant l'ancien binaire pourront toujours trouver ces pages sur le disque.

Vous pouvez en voir certains effets en regardant le /proc/${pid}/exe lien symbolique (ou, de manière équivalente, lsof output) pour le processus exécutant l'ancien binaire, qui affichera /app/EXE (deleted) pour indiquer 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 mort du processus (en supposant que c'est le seul processus avec cet inode ouvert.) Vérifiez la sortie de df avant et après avoir tué le processus, vous le verrez diminuer de la taille de cet ancien binaire que vous pensiez ne plus exister.

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). le pilote du système de fichiers (dans le noyau Linux) conserve un compteur du nombre de références existantes à 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 verrouillez toutes les pages du fichier avec quelque chose comme vmtouch, est-ce que cela change 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)

C'est signifié fonctionner de la même manière et la plupart du temps, mais il y a quelques "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 "remaniés" lorsque le serveur NFS redémarre.

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) tant que l'inode est toujours référencé.


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

Non, cela n'arrivera 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) 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 descripteurs ouverts vers l'ancien fichier continueront à l'utiliser sans problème.

[1] le ETXBUSY la protection n'est pas étendue aux autres fichiers qui peuvent aussi être considérés comme "texte" (=live code / exécutable) :bibliothèques partagées, classes java, etc; modifier un tel fichier alors qu'il est mappé par un autre processus va faire planter le processus. Sous linux, l'éditeur de liens dynamique passe consciencieusement le MAP_DENYWRITE indicateur à mmap(2) , mais ne vous méprenez pas, cela n'a aucun effet. Exemple :

$ cc -xc - <<<'void lib(){}' -shared -o lib.so
$ cc -Wl,-rpath=. lib.so -include unistd.h -xc - <<<'
   extern void lib();
   int main(){ truncate("lib.so", 0); lib(); }
'
./a.out
Bus error

La réponse de filbranden est correcte en supposant que le processus de publication continue effectue un remplacement atomique correct 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 est encore erroné.

Il n'y a aucune possibilité que des choses soient modifiées sur le disque et soient incohérentes avec le cache de la page, car le cache de la page est la version canonique et celui qui est modifié. 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. S'il n'est pas encore présent, 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à en cache. Les écritures qui s'étendent sur une page entière ou plus peuvent (et le font 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 plus d'un, et généralement (selon lequel et quelles options de montage et côté serveur sont utilisées) 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 défectueux et refusent de les utiliser dans des situations où il y aura des écritures simultanées à l'utilisation.


Linux
  1. Comment récupérer un sémaphore lorsque le processus qui l'a décrémenté à zéro plante ?

  2. Qu'advient-il d'un descripteur de fichier ouvert sous Linux si le fichier pointé est déplacé ou supprimé

  3. Quel fichier dans /proc est lu par le noyau lors du processus de démarrage ?

  4. Qu'advient-il d'un processus Linux multithread s'il reçoit un signal ?

  5. Quel est le concept de création d'un fichier avec zéro octet sous Linux ?

Qu'advient-il de la sortie d'un processus qui a été désavoué et a perdu son terminal ?

Linux - Que se passe-t-il lorsque vous vous synchronisez sans chemin de destination ? ?

SIGTERM vs SIGKILL :Quelle est la différence ?

Que sont les inodes sous Linux ?

Que se passe-t-il lorsqu'un thread bifurque ?

Qu'est-ce qu'anon_inode dans la sortie de ls -l /proc/[PID]/fd ?