Ciò è causato da un livelock quando ntpd chiama adjtimex (2) per dire al kernel di inserire un secondo di salto. Vedi i post di lkml http://lkml.indiana.edu/hypermail/linux/kernel/1203.1/04598.html
Red Hat dovrebbe anche aggiornare anche l'articolo KB. https://access.redhat.com/knowledge/articles/15145
AGGIORNAMENTO: Red Hat ha un secondo articolo KB solo per questo problema qui: https://access.redhat.com/knowledge/solutions/154713 - l'articolo precedente riguarda un problema precedente non correlato
La soluzione è semplicemente disattivare ntpd. Se ntpd ha già emesso la chiamata adjtimex (2), potrebbe essere necessario disabilitare ntpd e riavviare per essere sicuri al 100%.
Ciò riguarda RHEL 6 e altre distro che eseguono kernel più recenti (più recenti di circa 2.6.26), ma non RHEL 5.
Il motivo per cui ciò sta accadendo prima che il secondo salto sia effettivamente programmato è che ntpd consente al kernel di gestire il secondo salto a mezzanotte, ma deve avvisare il kernel di inserire il salto prima di mezzanotte. ntpd quindi chiama adjtimex (2) qualche volta durante il giorno del secondo bisestile, a quel punto questo bug viene attivato.
Se hai installato adjtimex (8), puoi usare questo script per determinare se il flag 16 è impostato. Flag 16 è "inserimento secondo salto":
adjtimex -p | perl -p -e 'undef $_, next unless m/status: (\d+)/; (16 & $1) && print "leap second flag is set:\n"'
AGGIORNARE:
Red Hat ha aggiornato il loro articolo KB per notare: "I clienti di RHEL 6 potrebbero essere interessati da un problema noto che fa sì che NMI Watchdog rilevi un blocco durante la ricezione dell'annuncio del secondo bisestile NTP. Questo problema viene risolto in modo tempestivo. Se i sistemi hanno ricevuto l'annuncio del secondo e non ha riscontrato questo problema, quindi non sono più interessati. "
AGGIORNAMENTO: la lingua sopra è stata rimossa dall'articolo di Red Hat; e una seconda soluzione KB è stata aggiunta in dettaglio il problema di crash di adjtimex (2): https://access.redhat.com/knowledge/solutions/154713
Tuttavia, la modifica del codice nel post LKML dell'ingegnere IBM John Stultz nota che potrebbe esserci anche un deadlock quando viene effettivamente applicato il secondo bisestile, quindi potresti voler disabilitare il secondo bisestile riavviando o usando adjtimex (8) dopo aver disabilitato ntpd.
AGGIORNAMENTO FINALE:
Bene, non sono uno sviluppatore del kernel, ma ho rivisto di nuovo la patch di John Stultz qui: https://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h = 6b43ae8a619d17c4935c3320d2ef9e92bdeed05d
Se sto leggendo bene questa volta, mi sbagliavo sul fatto che ci fosse un altro deadlock quando viene applicato il secondo bisestile. Anche questa sembra essere l'opinione di Red Hat, basata sulla loro voce KB. Tuttavia, se hai disabilitato ntpd, mantienilo disabilitato per altri 10 minuti, in modo da non colpire il deadlock quando ntpd chiama adjtimex (2).
Scopriremo presto se ci saranno altri bug :)
SECONDO AGGIORNAMENTO POST-LEAP:
Ho passato le ultime ore a leggere il codice del kernel ntpd e pre-patch (buggy), e mentre potrei sbagliarmi qui, cercherò di spiegare cosa penso stia succedendo:
Innanzitutto, ntpd chiama adjtimex (2) sempre. Lo fa come parte del suo "filtro loop clock", definito in local_clock in ntp_loopfilter.c. Puoi vedere quel codice qui: http://www.opensource.apple.com/source/ntp/ntp-70/ntpd/ntp_loopfilter.c (dalla versione 4.2.6 di ntp).
Il filtro del loop di clock viene eseguito abbastanza spesso: viene eseguito ogni volta che ntpd esegue il polling dei suoi server upstream, che per impostazione predefinita è ogni 17 minuti o più. Il bit rilevante del filtro del loop di clock è:
if (sys_leap == LEAP_ADDSECOND)
ntv.status |= STA_INS;
E poi:
ntp_adjtime(&ntv)
In altre parole, nei giorni in cui c'è un balzo in secondo, ntpd imposta il flag "STA_INS" e chiama adjtimex (2) (tramite il suo portabilità-wrapper).
Quella chiamata di sistema arriva al kernel. Ecco il codice kernel rilevante: https://github.com/mirrors/linux/blob/a078c6d0e6288fad6d83fb6d5edd91ddb7b6ab33/kernel/time/ntp.c
Il codepath del kernel è approssimativamente questo:
- riga 663 - inizio della routine do_adjtimex.
- riga 691 - annulla qualsiasi timer esistente dei secondi saltati.
- linea 709 - prendi lo spinlock ntp_lock (questo lock è coinvolto nel possibile crash del livelock)
- linea 724 - chiama process_adjtimex_modes.
- linea 616 - chiama process_adj_status.
- riga 590 - imposta la variabile globale time_status, basata sui flag impostati nella chiamata adjtimex (2)
- riga 592 - controlla la variabile globale time_state. nella maggior parte dei casi, chiama ntp_start_leap_timer.
- riga 554 - controlla la variabile globale time_status. Verrà impostato STA_INS, quindi imposta time_state su TIME_INS e chiama hrtimer_start (un'altra funzione del kernel) per avviare il secondo del salto. nel processo di creazione di un timer, questo codice prende xtime_lock. se ciò accade mentre un'altra CPU ha già catturato xtime_lock e ntp_lock, allora i kernel livelock. questo è il motivo per cui John Stultz ha scritto la patch per evitare di usare hrtimer. Questo è ciò che stava causando problemi a tutti oggi.
- riga 598 - se ntp_start_leap_timer non ha effettivamente avviato un timer di salto, impostare time_state su TIME_OK
- riga 751 - supponendo che il kernel non si blocchi, lo stack viene srotolato e lo spinlock ntp_lock viene rilasciato.
Ci sono un paio di cose interessanti qui.
Innanzitutto, la riga 691 annulla il timer esistente ogni volta che viene chiamato adjtimex (2). Quindi, 554 ricrea quel timer. Ciò significa che ogni volta che ntpd ha eseguito il suo filtro loop clock, è stato invocato il codice buggy.
Quindi credo che Red Hat si sbagliasse quando affermarono che una volta che ntpd aveva impostato la bandiera del secondo bisestile, il sistema non si sarebbe bloccato. Credo che ogni sistema che esegue ntpd avesse il potenziale di legarsi in blocco ogni 17 minuti (o più) per il periodo di 24 ore prima del secondo bisestile. Credo che ciò possa anche spiegare perché così tanti sistemi si sono schiantati; una possibilità di crash di una volta sarebbe molto meno probabile che colpisse rispetto a 3 possibilità all'ora.
AGGIORNAMENTO: Nella soluzione KB di Red Hat all'indirizzo https://access.redhat.com/knowledge/solutions/154713 , gli ingegneri di Red Hat sono giunti alla stessa conclusione (che l'esecuzione di ntpd avrebbe colpito continuamente il codice errato). E infatti lo hanno fatto diverse ore prima di me. Questa soluzione non era collegata all'articolo principale su https://access.redhat.com/knowledge/articles/15145 , quindi non me ne sono accorto fino ad ora.
In secondo luogo, questo spiega perché i sistemi caricati avevano maggiori probabilità di arrestarsi in modo anomalo. I sistemi caricati gestiranno un numero maggiore di interruzioni, facendo sì che la funzione del kernel "do_tick" venga chiamata più spesso, dando più possibilità a questo codice di essere eseguito e catturare ntp_lock durante la creazione del timer.
Terzo, c'è la possibilità che il sistema si blocchi quando si verifica effettivamente il secondo bisestile? Non lo so per certo, ma forse sì, perché il timer che spara ed esegue effettivamente la regolazione del secondo bisestile (ntp_leap_second, sulla linea 388) prende anche lo spinlock ntp_lock e ha una chiamata a hrtimer_add_expires_ns. Non so se quella chiamata potrebbe anche essere in grado di causare un livelock, ma non sembra impossibile.
Infine, cosa causa la disabilitazione del flag del secondo intercalare dopo l'esecuzione del secondo intercalare? La risposta è ntpd smette di impostare il flag del secondo bisestile ad un certo punto dopo la mezzanotte quando chiama adjtimex (2). Poiché il flag non è impostato, il controllo sulla riga 554 non sarà vero e non verrà creato alcun timer e la riga 598 reimposterà la variabile globale time_state su TIME_OK. Questo spiega perché se si controlla la bandiera con adjtimex (8) subito dopo il secondo bisestile, si vedrebbe comunque impostato il flag bisestile.
In breve, il miglior consiglio per oggi sembra essere il primo che ho dato dopo tutto: disabilitare ntpd e disabilitare il flag del secondo bisestile.
E alcuni pensieri finali:
- nessuno dei fornitori di Linux ha notato la patch di John Stultz e l'ha applicata ai loro kernel :(
- perché John Stultz non ha avvisato alcuni dei venditori che ciò era necessario? forse la possibilità che il livelock sembrasse abbastanza basso facendo rumore non era giustificata.
- Ho sentito rapporti di processi Java bloccarsi o girare quando è stato applicato il secondo bisestile. Forse dovremmo seguire l'esempio di Google e ripensare il modo in cui applichiamo i secondi intercalari ai nostri sistemi: http://googleblog.blogspot.com/2011/09/time-technology-and-leaping-seconds.html
06/02 Aggiornamento da John Stultz:
https://lkml.org/lkml/2012/7/1/203
Il post conteneva una spiegazione dettagliata del motivo per cui il secondo balzo ha fatto scadere prematuramente e continuamente i timer futex, aumentando il carico della CPU.