Esto es causado por un livelock cuando ntpd llama a adjtimex (2) para decirle al kernel que inserte un segundo intercalar. Consulte la publicación de lkml http://lkml.indiana.edu/hypermail/linux/kernel/1203.1/04598.html
Red Hat también debería actualizar su artículo de KB también. https://access.redhat.com/knowledge/articles/15145
ACTUALIZACIÓN: Red Hat tiene un segundo artículo de KB solo para este problema aquí: https://access.redhat.com/knowledge/solutions/154713 : el artículo anterior es para un problema anterior no relacionado
La solución es simplemente desactivar ntpd. Si ntpd ya emitió la llamada adjtimex (2), es posible que deba deshabilitar ntpd y reiniciar para que sea 100% seguro.
Esto afecta a RHEL 6 y otras distribuciones que ejecutan núcleos más nuevos (más nuevos que aproximadamente 2.6.26), pero no RHEL 5.
La razón por la que esto ocurre antes de que el segundo intercalar esté realmente programado es que ntpd permite que el núcleo maneje el segundo intercalar a la medianoche, pero necesita alertar al núcleo para que inserte el segundo intercalar antes de la medianoche. Por lo tanto, ntpd llama a adjtimex (2) en algún momento durante el día del segundo intercalario, momento en el que se activa este error.
Si tiene instalado adjtimex (8), puede usar este script para determinar si el marcador 16 está configurado. El indicador 16 está "insertando un segundo intercalar":
adjtimex -p | perl -p -e 'undef $_, next unless m/status: (\d+)/; (16 & $1) && print "leap second flag is set:\n"'
ACTUALIZAR:
Red Hat ha actualizado su artículo de KB para tener en cuenta: "Los clientes de RHEL 6 pueden verse afectados por un problema conocido que hace que NMI Watchdog detecte un bloqueo al recibir el anuncio de segundo salto de NTP. Este problema se está solucionando de manera oportuna. Si sus sistemas recibieron el anuncio del segundo salto y no experimentó este problema, entonces ya no se ven afectados ".
ACTUALIZACIÓN: El idioma anterior se eliminó del artículo de Red Hat; y se agregó una segunda solución KB que detalla el problema de bloqueo adjtimex (2): https://access.redhat.com/knowledge/solutions/154713
Sin embargo, el cambio de código en la publicación LKML del ingeniero de IBM John Stultz señala que también puede haber un punto muerto cuando se aplica el segundo intercalario, por lo que es posible que desee deshabilitar el segundo intercalar reiniciando o usando adjtimex (8) después de deshabilitar ntpd.
ACTUALIZACIÓN FINAL:
Bueno, no soy un desarrollador de kernel, pero revisé el parche de John Stultz nuevamente aquí: https://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h = 6b43ae8a619d17c4935c3320d2ef9e92bdeed05d
Si lo estoy leyendo bien esta vez, me equivoqué acerca de que hay otro punto muerto cuando se aplica el segundo intercalar. Esa parece ser también la opinión de Red Hat, basada en su entrada KB. Sin embargo, si ha deshabilitado ntpd, manténgalo deshabilitado durante otros 10 minutos, para que no llegue al punto muerto cuando ntpd llame a adjtimex (2).
Descubriremos si hay más errores pronto :)
SEGUNDA ACTUALIZACIÓN POSTERIOR AL SALTO:
Pasé las últimas horas leyendo el código del kernel ntpd y pre-patch (buggy), y aunque pueda estar muy equivocado aquí, intentaré explicar lo que creo que estaba sucediendo:
Primero, ntpd llama a adjtimex (2) todo el tiempo. Lo hace como parte de su "filtro de bucle de reloj", definido en local_clock en ntp_loopfilter.c. Puede ver ese código aquí: http://www.opensource.apple.com/source/ntp/ntp-70/ntpd/ntp_loopfilter.c (de la versión ntp 4.2.6).
El filtro de bucle de reloj se ejecuta con bastante frecuencia: se ejecuta cada vez que ntpd sondea sus servidores ascendentes, que por defecto es cada 17 minutos o más. El bit relevante del filtro de bucle de reloj es:
if (sys_leap == LEAP_ADDSECOND)
ntv.status |= STA_INS;
Y entonces:
ntp_adjtime(&ntv)
En otras palabras, en los días en que hay un segundo intercalar, ntpd establece el indicador "STA_INS" y llama a adjtimex (2) (a través de su contenedor de portabilidad).
Esa llamada al sistema llega al núcleo. Aquí está el código de kernel relevante: https://github.com/mirrors/linux/blob/a078c6d0e6288fad6d83fb6d5edd91ddb7b6ab33/kernel/time/ntp.c
El codepath del kernel es más o menos esto:
- línea 663 - inicio de la rutina do_adjtimex.
- línea 691 - cancela cualquier temporizador de segundo intercalar existente.
- línea 709: tome el spinlock ntp_lock (este bloqueo está involucrado en el posible bloqueo del livelock)
- línea 724: llame a process_adjtimex_modes.
- línea 616: llame a process_adj_status.
- línea 590 - establece la variable global time_status, basada en las banderas establecidas en la llamada adjtimex (2)
- línea 592: verifique la variable global time_state. en la mayoría de los casos, llame a ntp_start_leap_timer.
- línea 554: verifique la variable global time_status. STA_INS se establecerá, por lo tanto, establezca time_state en TIME_INS y llame a hrtimer_start (otra función del kernel) para iniciar el segundo temporizador. En el proceso de creación de un temporizador, este código toma el xtime_lock. Si esto sucede mientras otra CPU ya ha capturado el xtime_lock y el ntp_lock, entonces el núcleo se activa. Es por eso que John Stultz escribió el parche para evitar el uso de hrtimers. Esto es lo que estaba causando problemas a todos hoy.
- línea 598: si ntp_start_leap_timer no inició realmente un temporizador de salto, establezca time_state en TIME_OK
- línea 751: suponiendo que el kernel no tiene livelock, la pila se desenrolla y se libera el spinlock ntp_lock.
Hay un par de cosas interesantes aquí.
Primero, la línea 691 cancela el temporizador existente cada vez que se llama a adjtimex (2). Entonces, 554 recrea ese temporizador. Esto significa que cada vez que ntpd ejecutó su filtro de bucle de reloj, se invocó el código de error.
Por lo tanto, creo que Red Hat estaba equivocado cuando dijeron que una vez que ntpd había establecido el indicador de segundo intercalar, el sistema no se bloqueaba. Creo que cada sistema que ejecuta ntpd tenía el potencial de bloquear en vivo cada 17 minutos (o más) durante el período de 24 horas antes del salto de segundo. Creo que esto también puede explicar por qué tantos sistemas fallaron; una probabilidad única de estrellarse sería mucho menos probable que golpeara en comparación con 3 oportunidades por hora.
ACTUALIZACIÓN: En la solución KB de Red Hat en https://access.redhat.com/knowledge/solutions/154713 , los ingenieros de Red Hat llegaron a la misma conclusión (que ejecutar ntpd continuamente golpearía el código con errores). Y de hecho lo hicieron varias horas antes que yo. Esta solución no estaba vinculada al artículo principal en https://access.redhat.com/knowledge/articles/15145 , por lo que no lo noté hasta ahora.
En segundo lugar, esto explica por qué los sistemas cargados tenían más probabilidades de fallar. Los sistemas cargados manejarán más interrupciones, lo que provocará que la función del núcleo "do_tick" se invoque con más frecuencia, lo que brinda más posibilidades de que este código se ejecute y tome el ntp_lock mientras se crea el temporizador.
Tercero, ¿hay alguna posibilidad de que el sistema falle cuando ocurre el segundo salto? No estoy seguro, pero posiblemente sí, porque el temporizador que dispara y realmente ejecuta el ajuste del segundo intercalar (ntp_leap_second, en la línea 388) también toma el spinlock ntp_lock y tiene una llamada a hrtimer_add_expires_ns. No sé si esa llamada también podría causar un bloqueo en vivo, pero no parece imposible.
Finalmente, ¿qué causa que se deshabilite el indicador de segundo intercalar después de que se haya ejecutado el segundo intercalar? La respuesta es ntpd deja de establecer el indicador de segundo intercalar en algún momento después de la medianoche cuando llama a adjtimex (2). Como el indicador no está configurado, la verificación en la línea 554 no será verdadera y no se creará ningún temporizador, y la línea 598 restablecerá la variable global time_state a TIME_OK. Esto explica por qué si marca el indicador con adjtimex (8) justo después del segundo intercalar, aún verá el conjunto de indicadores del segundo intercalar.
En resumen, el mejor consejo para hoy parece ser el primero que di después de todo: deshabilitar ntpd y deshabilitar el indicador de segundo intercalar.
Y algunas reflexiones finales:
- ninguno de los proveedores de Linux notó el parche de John Stultz y lo aplicó a sus núcleos :(
- ¿Por qué John Stultz no alertó a algunos de los vendedores que esto era necesario? quizás la posibilidad de que el livelock pareciera lo suficientemente bajo como para hacer ruido no estaba justificada.
- He escuchado informes de procesos Java que se bloquean o giran cuando se aplica el segundo intercalario. Quizás deberíamos seguir el ejemplo de Google y repensar cómo aplicamos los segundos bisiestos a nuestros sistemas: http://googleblog.blogspot.com/2011/09/time-technology-and-leaping-seconds.html
06/02 Actualización de John Stultz:
https://lkml.org/lkml/2012/7/1/203
La publicación contenía un recorrido paso a paso de por qué el segundo salto provocó que los temporizadores futex expiraran prematura y continuamente, aumentando la carga de la CPU.