Comment mettre à niveau la bibliothèque partagée sans crash?

18

Ici, il est dit que vous pouvez réécrire un fichier exécutable et le processus se déroulera très bien - il sera relu au redémarrage d'un processus.

Cependant, lorsque j'essaie de remplacer un fichier binaire pendant que le processus est en cours (avec scp, du développeur au serveur de test), il dit «fichier occupé». Et si je remplace un fichier de bibliothèque partagée (* .so), tous les processus qui le lient se bloquent.

Pourquoi Suis-je en train de manquer quelque chose? Comment puis-je remplacer les fichiers binaires sans arrêter / planter un processus?

Sam
la source
Vous pouvez vérifier le .sofichier à l'aide de ldd filename.sopour vérifier les dépendances
Rahul Patil
Je connais les dépendances. Je veux un moyen de remplacer ces fichiers sans affecter les processus en cours. Comme l'indique la question liée
Sam
un temps d'arrêt est nécessaire .. ou vous pouvez faire comme stop app && create symlink of .so && start app
Rahul Patil

Réponses:

21

Comme mentionné dans Pourquoi un progiciel fonctionne-t-il très bien même lorsqu'il est mis à niveau? , le verrou est placé sur l'inode et non sur le nom de fichier. Lorsque vous chargez et exécutez un fichier binaire, le fichier est marqué comme occupé - c'est pourquoi vous obtenez une erreur ETXTBSY (fichier occupé) lorsque vous essayez d'écrire dessus.

Maintenant, pour les bibliothèques partagées, c'est légèrement différent: les bibliothèques obtiennent de la mémoire mappée dans l'espace d'adressage du processus avec mmap(). Bien que cela MAP_DENYWRITEpuisse être spécifié, au moins Glibc sur Linux l'ignore silencieusement (selon la page de manuel, n'hésitez pas à vérifier les sources) - vérifiez ce fil . Par conséquent, vous êtes réellement autorisé à écrire le fichier et, comme il est mappé en mémoire, toutes les modifications sont visibles presque immédiatement - ce qui signifie que si vous essayez assez fort, vous pouvez réussir à briquer votre machine en écrasant la bibliothèque.

La bonne façon de mettre à jour est donc:

  1. supprimer le fichier, ce qui supprime la référence aux données du système de fichiers, de sorte qu'il n'est pas accessible pour les applications nouvellement générées qui pourraient vouloir l'utiliser, tout en gardant les données accessibles pour toute personne qui les a déjà ouvertes (ou mappées) ;

  2. créer un nouveau fichier avec un contenu mis à jour.

Les processus nouvellement créés utiliseront le contenu mis à jour, les applications en cours d'exécution accéderont à l'ancienne version. C'est ce que fait n'importe quel utilitaire de gestion de packages. Notez que ce n'est pas complètement sans danger - par exemple, les applications qui chargent dynamiquement du code (en utilisant dlsym()et amis) rencontreront des problèmes si l'API de la bibliothèque change silencieusement.

Si vous voulez être vraiment sûr, arrêtez le système, montez le système de fichiers à partir d'une autre instance de système d'exploitation, mettez à jour et réactivez le système mis à jour.

peterph
la source
6

Une mise à niveau rpm fait de même - avec l'exécution de binaires et de bibliothèques alors que rien ne plante.

Alors, quelle est la difference:

  1. dissocier le fichier
  2. écrire un nouveau fichier avec le même nom

Cela ne remplacera PAS le fichier sur place: l'inode faisant référence au binaire en cours d'utilisation est toujours "occupé" jusqu'à ce que le dernier objet le maintenant ouvert se termine. Le nouveau fichier sera créé avec un nouveau numéro d'inode.

Maintenant scpou cpva essayer de remplacer le fichier sur place - ce qui changerait le contenu auquel l'inode fait référence. Cela ne fonctionne pas - comme vous l'avez décrit.

Nils
la source