Cela est dû à un livelock lorsque ntpd appelle adjtimex (2) pour dire au noyau d’insérer une seconde intercalaire. Voir la publication de lkml http://lkml.indiana.edu/hypermail/linux/kernel/1203.1/04598.html
Red Hat devrait également mettre à jour son article de base de connaissances. https://access.redhat.com/knowledge/articles/15145
MISE À JOUR: Red Hat a publié un deuxième article sur la base de connaissances pour ce problème: https://access.redhat.com/knowledge/solutions/154713 - l'article précédent concerne un problème antérieur, sans rapport avec ce dernier.
La solution consiste simplement à désactiver ntpd. Si ntpd a déjà émis l'appel adjtimex (2), vous devrez peut-être désactiver ntpd et redémarrer pour être sûr à 100%.
Cela concerne RHEL 6 et les autres distributions utilisant des noyaux plus récents (plus récents que les 2.6.26 environ), mais pas RHEL 5.
La raison pour laquelle cela se produit avant que la seconde intercalaire ne soit réellement programmée est que ntpd permet au noyau de gérer la seconde intercalaire à minuit, mais il doit en avertir le noyau d'insérer la seconde intercalaire avant minuit. ntpd appelle donc adjtimex (2) à un moment quelconque de la journée de la seconde intercalaire, moment auquel ce bogue est déclenché.
Si vous avez installé adjtimex (8), vous pouvez utiliser ce script pour déterminer si l'indicateur 16 est défini. Le drapeau 16 est "insertion d'une seconde intercalaire":
adjtimex -p | perl -p -e 'undef $_, next unless m/status: (\d+)/; (16 & $1) && print "leap second flag is set:\n"'
MISE À JOUR:
Red Hat a mis à jour son article de la base de connaissances pour indiquer: "Les clients de RHEL 6 peuvent être affectés par un problème connu qui permet à NMI Watchdog de détecter un blocage lors de la réception de l'annonce NTP en une seconde. Ce problème est résolu rapidement. Si vos systèmes sont reçus l'annonce de la seconde de saut et n'a pas rencontré ce problème, alors ils ne sont plus affectés. "
MISE À JOUR: La langue ci-dessus a été supprimée de l'article de Red Hat. et une deuxième solution de base de connaissances a été ajoutée, détaillant le problème de crash adjtimex (2): https://access.redhat.com/knowledge/solutions/154713.
John Stultz, ingénieur chez IBM, a cependant ajouté qu'il y avait peut-être un blocage lorsque la seconde intercalaire est réellement appliquée. Vous pouvez donc désactiver cette dernière en la redémarrant ou en utilisant adjtimex (8) après avoir désactivé ntpd.
MISE À JOUR FINALE:
Bien, je ne suis pas un développeur de noyau, mais j’ai revu le correctif de John Stultz ici: https://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h = 6b43ae8a619d17c4935c3320d2ef9e92bdeed05d
Si je le lis bien cette fois, je me suis trompé sur le fait qu'il y avait une autre impasse lorsque la seconde intercalaire est appliquée. Cela semble également être l'opinion de Red Hat, basée sur son entrée dans la base de connaissances. Cependant, si vous avez désactivé ntpd, maintenez-le désactivé pendant 10 minutes supplémentaires afin d'éviter tout blocage lorsque ntpd appelle adjtimex (2).
Nous verrons s'il y a bientôt d'autres bugs :)
DEUXIÈME MISE À JOUR POST-LEAP:
J'ai passé les dernières heures à lire le code du noyau ntpd et pre-patch (buggy) et, même si je me trompe peut-être, je vais tenter d'expliquer ce qui se passait:
Premièrement, ntpd appelle adjtimex (2) tout le temps. Cela fait partie de son "filtre de boucle d'horloge", défini dans local_clock dans ntp_loopfilter.c. Vous pouvez voir ce code ici: http://www.opensource.apple.com/source/ntp/ntp-70/ntpd/ntp_loopfilter.c (à partir de la version 4.2.6 de ntp).
Le filtre de boucle d'horloge fonctionne assez souvent - il s'exécute chaque fois que ntpd interroge ses serveurs en amont, ce qui correspond par défaut toutes les 17 minutes ou plus. Le bit pertinent du filtre de boucle d'horloge est:
if (sys_leap == LEAP_ADDSECOND)
ntv.status |= STA_INS;
Puis:
ntp_adjtime(&ntv)
En d'autres termes, les jours où il y a une seconde intercalaire, ntpd définit l'indicateur "STA_INS" et appelle adjtimex (2) (via son gestionnaire de portabilité).
Cet appel système se rend au noyau. Voici le code du noyau approprié: https://github.com/mirrors/linux/blob/a078c6d0e6288fad6d83fb6d5edd91ddb7b6ab33/kernel/time/ntp.c
Le codepath du noyau est à peu près ceci:
- ligne 663 - début de la routine do_adjtimex.
- ligne 691 - annule toute minuterie en secondes intercalaires existante.
- ligne 709 - récupère le spinlock ntp_lock (ce verrou est impliqué dans un possible crash de livelock)
- ligne 724 - appelez process_adjtimex_modes.
- ligne 616 - appelez process_adj_status.
- ligne 590 - définit la variable globale time_status, en fonction des indicateurs définis dans l'appel adjtimex (2)
- ligne 592 - vérifie la variable globale time_state. dans la plupart des cas, appelez ntp_start_leap_timer.
- ligne 554 - Vérifiez la variable globale time_status. STA_INS sera défini, donc définissez time_state sur TIME_INS et appelez hrtimer_start (une autre fonction du noyau) pour démarrer le temporisateur par seconde intercalaire. en train de créer une minuterie, ce code récupère le xtime_lock. si cela se produit alors qu'un autre processeur a déjà saisi les clés xtime_lock et ntp_lock, le noyau livelocks. C'est pourquoi John Stultz a écrit le correctif pour éviter d'utiliser des horloges. C'est ce qui causait des problèmes à tout le monde aujourd'hui.
- ligne 598 - si ntp_start_leap_timer n'a pas démarré un retardateur, définissez time_state sur TIME_OK
- ligne 751 - en supposant que le noyau ne fonctionne pas, la pile est déroulée et le verrou tournant ntp_lock est libéré.
Il y a quelques choses intéressantes ici.
Premièrement, la ligne 691 annule la minuterie existante chaque fois que adjtimex (2) est appelé. Ensuite, 554 recrée ce minuteur. Cela signifie que chaque fois que ntpd a exécuté son filtre de boucle d’horloge, le code du buggy a été appelé.
C’est pourquoi je pense que Red Hat avait tort quand ils ont déclaré qu’une fois que ntpd aurait défini le drapeau de la seconde intercalaire, le système ne planterait plus. Je pense que chaque système exécutant ntpd pouvait potentiellement survivre toutes les 17 minutes (ou plus) pendant les 24 heures précédant le saut de seconde. Je crois que cela peut aussi expliquer pourquoi autant de systèmes se sont écrasés. une chance unique de chute serait beaucoup moins susceptible de frapper que 3 chances par heure.
MISE À JOUR: Dans la solution de base de connaissances de Red Hat à l’ adresse https://access.redhat.com/knowledge/solutions/154713 , les ingénieurs de Red Hat sont parvenus à la même conclusion (l’exécution de ntpd ne cesserait de frapper le code du buggy). Et en effet, ils l'ont fait plusieurs heures avant moi. Cette solution n'était pas liée à l'article principal à l' adresse https://access.redhat.com/knowledge/articles/15145 , je ne l'avais donc pas remarquée jusqu'à présent.
Deuxièmement, cela explique pourquoi les systèmes chargés étaient plus susceptibles de tomber en panne. Les systèmes chargés gèrent davantage d'interruptions, ce qui entraîne l'appel de la fonction de noyau "do_tick" plus souvent, ce qui donne une chance supplémentaire à ce code de s'exécuter et de récupérer le ntp_lock pendant la création du temporisateur.
Troisièmement, y a-t-il une chance que le système se bloque lorsque la seconde intercalaire se produit réellement? Je ne sais pas avec certitude, mais peut-être que oui, car le minuteur qui déclenche et exécute le réglage en secondes (ntp_leap_second, ligne 388) saisit également le spinlock ntp_lock et effectue un appel à hrtimer_add_expires_ns. Je ne sais pas si cet appel pourrait également causer un délai de livraison, mais cela ne semble pas impossible.
Enfin, pourquoi le drapeau de seconde intercalaire est-il désactivé une fois la seconde intercalaire écoulée? La réponse est que ntpd cesse de définir l'indicateur de seconde intercalaire à partir de minuit, lorsqu'il appelle adjtimex (2). Comme l'indicateur n'est pas défini, la vérification de la ligne 554 ne sera pas vraie, aucune minuterie ne sera créée et la ligne 598 réinitialisera la variable globale time_state en TIME_OK. Cela explique pourquoi, si vous avez coché le drapeau avec adjtimex (8) juste après la seconde de saut, vous verriez toujours le drapeau défini.
En bref, le meilleur conseil pour aujourd'hui semble être le premier que j'ai donné après tout: désactiver ntpd et désactiver l'indicateur de saut de seconde.
Et quelques réflexions finales:
- aucun des vendeurs de Linux n'a remarqué le correctif de John Stultz et l'a appliqué à leurs noyaux :(
- pourquoi John Stultz n'a-t-il pas averti certains des fournisseurs que c'était nécessaire? peut-être que la chance du livelock semblait assez faible pour que le bruit ne soit pas garanti.
- J'ai entendu parler de processus Java bloqués ou en rotation lorsque la seconde intercalaire était appliquée. Peut-être devrions-nous suivre l'exemple de Google et repenser la manière dont nous appliquons des secondes intercalaires à nos systèmes: http://googleblog.blogspot.com/2011/09/time-technology-and-leaping-seconds.html
06/02 Mise à jour de John Stultz:
https://lkml.org/lkml/2012/7/1/203
Le message contenait une explication pas à pas des raisons pour lesquelles la seconde intercalaire avait provoqué une expiration prématurée et continue des minuteries futex, alourdissant ainsi la charge du processeur.