This is caused by a livelock when ntpd calls adjtimex(2) to tell the kernel to insert a leap second. See lkml posting http://lkml.indiana.edu/hypermail/linux/kernel/1203.1/04598.html
Red Hat should also be updating their KB article as well. https://access.redhat.com/knowledge/articles/15145
UPDATE: Red Hat has a second KB article just for this issue here: https://access.redhat.com/knowledge/solutions/154713 - the previous article is for an earlier, unrelated problem
The work-around is to just turn off ntpd. If ntpd already issued the adjtimex(2) call, you may need to disable ntpd and reboot to be 100% safe.
This affects RHEL 6 and other distros running newer kernels (newer than approx 2.6.26), but not RHEL 5.
The reason this is occurring before the leap second is actually scheduled to occur is that ntpd lets the kernel handle the leap second at midnight, but needs to alert the kernel to insert the leap second before midnight. ntpd therefore calls adjtimex(2) sometime during the day of the leap second, at which point this bug is triggered.
If you have adjtimex(8) installed, you can use this script to determine if flag 16 is set. Flag 16 is "inserting leap second":
adjtimex -p | perl -p -e 'undef $_, next unless m/status: (\d+)/; (16 & $1) && print "leap second flag is set:\n"'
UPDATE:
Red Hat has updated their KB article to note: "RHEL 6 customers may be affected by a known issue that causes NMI Watchdog to detect a hang when receiving the NTP leapsecond announcement. This issue is being addressed in a timely manner. If your systems received the leapsecond announcement and did not experience this issue, then they are no longer affected."
UPDATE: The above language was removed from the Red Hat article; and a second KB solution was added detailing the adjtimex(2) crash issue: https://access.redhat.com/knowledge/solutions/154713
However, the code change in the LKML post by IBM Engineer John Stultz notes there may also be a deadlock when the leap second is actually applied, so you may want to disable the leap second by rebooting or using adjtimex(8) after disabling ntpd.
FINAL UPDATE:
Well, I'm no kernel dev, but I reviewed John Stultz's patch again here: https://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=6b43ae8a619d17c4935c3320d2ef9e92bdeed05d
If I'm reading it right this time, I was wrong about there being another deadlock when the leap second is applied. That seems to be Red Hat's opinion as well, based on their KB entry. However, if you have disabled ntpd, keep it disabled for another 10 minutes, so that you don't hit the deadlock when ntpd calls adjtimex(2).
We'll find out if there are any more bugs soon :)
POST-LEAP SECOND UPDATE:
I spent the last few hours reading through the ntpd and pre-patch (buggy) kernel code, and while I may be very wrong here, I'll attempt to explain what I think was going on:
First, ntpd calls adjtimex(2) all the time. It does this as part of its "clock loop filter", defined in local_clock in ntp_loopfilter.c. You can see that code here: http://www.opensource.apple.com/source/ntp/ntp-70/ntpd/ntp_loopfilter.c (from ntp version 4.2.6).
The clock loop filter runs quite often -- it runs every time ntpd polls its upstream servers, which by default is every 17 minutes or more. The relevant bit of the clock loop filter is:
if (sys_leap == LEAP_ADDSECOND)
ntv.status |= STA_INS;
And then:
ntp_adjtime(&ntv)
In other words, on days when there's a leap second, ntpd sets the "STA_INS" flag and calls adjtimex(2) (via its portability-wrapper).
That system call makes its way to the kernel. Here's the relevant kernel code: https://github.com/mirrors/linux/blob/a078c6d0e6288fad6d83fb6d5edd91ddb7b6ab33/kernel/time/ntp.c
The kernel codepath is roughly this:
- line 663 - start of do_adjtimex routine.
- line 691 - cancel any existing leap-second timer.
- line 709 - grab the ntp_lock spinlock (this lock is involved in the possible livelock crash)
- line 724 - call process_adjtimex_modes.
- line 616 - call process_adj_status.
- line 590 - set time_status global variable, based on flags set in adjtimex(2) call
- line 592 - check time_state global variable. in most cases, call ntp_start_leap_timer.
- line 554 - check time_status global variable. STA_INS will be set, so set time_state to TIME_INS and call hrtimer_start (another kernel function) to start the leap second timer. in the process of creating a timer, this code grabs the xtime_lock. if this happens while another CPU has already grabbed the xtime_lock and the ntp_lock, then the kernel livelocks. this is why John Stultz wrote the patch to avoid using hrtimers. This is what was causing everyone trouble today.
- line 598 - if ntp_start_leap_timer did not actually start a leap timer, set time_state to TIME_OK
- line 751 - assuming the kernel does not livelock, the stack is unwound and the ntp_lock spinlock is released.
There are a couple interesting things here.
First, line 691 cancels the existing timer every time adjtimex(2) is called. Then, 554 re-creates that timer. This means each time ntpd ran its clock loop filter, the buggy code was invoked.
Therefore I believe Red Hat was wrong when they said that once ntpd had set the leap-second flag, the system would not crash. I believe each system running ntpd had the potential to livelock every 17 minutes (or more) for the 24-hour period before the leap-second. I believe this may also explain why so many systems crashed; a one-time chance of crashing would be much less likely to hit as compared to 3 chances an hour.
UPDATE: In Red Hat's KB solution at https://access.redhat.com/knowledge/solutions/154713 , Red Hat engineers did come to the same conclusion (that running ntpd would continuously hit the buggy code). And indeed they did so several hours before I did. This solution wasn't linked to the main article at https://access.redhat.com/knowledge/articles/15145 , so I didn't notice it until now.
Second, this explains why loaded systems were more likely to crash. Loaded systems will be handling more interrupts, causing the "do_tick" kernel function to be called more often, giving more of a chance for this code to run and grab the ntp_lock while the timer was being created.
Third, is there a chance of the system crashing when the leap-second actually occurs? I don't know for sure, but possibly yes, because the timer that fires and actually executes the leap-second adjustment (ntp_leap_second, on line 388) also grabs the ntp_lock spinlock, and has a call to hrtimer_add_expires_ns. I don't know if that call might also be able to cause a livelock, but it doesn't seem impossible.
Finally, what causes the leap-second flag to be disabled after the leap-second has run? The answer there is ntpd stops setting the leap-second flag at some point after midnight when it calls adjtimex(2). Since the flag isn't set, the check on line 554 will not be true, and no timer will be created, and line 598 will reset the time_state global variable to TIME_OK. This explains why if you checked the flag with adjtimex(8) just after the leap second, you would still see the leap-second flag set.
In short, the best advice for today seems to be the first I gave after all: disable ntpd, and disable the leap-second flag.
And some final thoughts:
- none of the Linux vendors noticed John Stultz's patch and applied it to their kernels :(
- why didn't John Stultz alert some of the vendors this was needed? perhaps the chance of the livelock seemed low enough making noise wasn't warranted.
- I've heard reports of Java processes locking up or spinning when the leap-second was applied. Perhaps we should follow Google's lead and rethink how we apply leap-seconds to our systems: http://googleblog.blogspot.com/2011/09/time-technology-and-leaping-seconds.html
06/02 Update from John Stultz:
https://lkml.org/lkml/2012/7/1/203
The post contained a step-by-step walk-through of why the leap second caused the futex timers to expire prematurely and continuously, spiking the CPU load.
This is what I ended up doing and what I assume is sound:
Hyper-V host (physical server) is set to synchronize against a selection of time servers and each Hyper-V guest is set to synchronize against the host alone. The changes below are differences from default.
Host setup
First stop the time service with:
net stop w32time
Registry changes (base HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\
):
w32time\Config\AnnounceFlags
= 10
w32time\Parameters\NtpServers
= 0.dk.pool.ntp.org,0x1 1.dk.pool.ntp.org,0x1 2.dk.pool.ntp.org,0x1 3.dk.pool.ntp.org,0x1
w32time\TimeProviders\NtpClient\SpecialPollInterval
= 900
(15 minutes)
w32time\TimeProviders\NtpServer\Enabled
= 1
Some use AnnounceFlags=5 but the correlation with a domain controller (which is not setup in this case) causes the ntp server to not announce itself (observation; not fact) hence AnnounceFlags is set to 10 (more on AnnounceFlags)
0x1 on the ntpservers = use special poll interval (instead of standard ntp poll intervals). (more on 0x1, 0x2, 0x4 and 0x8). Using SpecialPollInterval is not required, but it seems to be recommended (perhaps mostly for guests and not so much for hosts). If you decide not to use SpecialPollInterval, you have to limit MinPollInterval and MaxPollInterval instead. Their defaults are 10 (1024 seconds) and 15 (32768 seconds); I suggest 6 (64 seconds) and 10 (1024 seconds)) instead.
Make sure the time service is started when the server has network connection:
sc triggerinfo w32time start/networkon stop/networkoff
The default is to start (and stop) the time service with the domain controller (which is not present in this setup). Forgetting this step will stop your time server on every boot (shortly after it is started automatically). This problem was a difficult one to track.
And start the service again:
net start w32time
Now the host will poll one of the ntp time servers every 15 minutes and offer to be a ntp server for other clients. I have firewalled udp:123 to make sure only the guests are allowed in.
The server may take up to 15 minutes (SpecialPollInterval) until it announces its capabilities as a reliable time server to the world (guests). This means the guests may be free-running for 15-20 minutes after start of the service.
Guest setup
The guests drift (much) more than the host (also compared to each other) and require a relatively short poll interval. Due to this, using remote ntp servers is not ideal and as we have a reliable ntp server at hand (just configured), we are going to use this (and only this). The guests can all access the host using a virtual network.
Make sure the Hyper-V Time Integration service is installed and running. With this setup, it will be used when the virtual server is booted but also when resuming from save. It will not be used as a time source.
Stop the time service with:
net stop w32time
Make the necessary registry changes (base HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\
):
w32time\Config\AnnounceFlags
= 10
w32time\Parameters\NtpServers
= 192.168.0.100,0x9
w32time\TimeProviders\NtpClient\SpecialPollInterval
= 300
(5 minutes)
w32time\TimeProviders\NtpServer\Enabled
= 0
w32time\TimeProviders\VMICTimeProvider\Enabled
= 0
Make sure the time service is started when the server has network connection:
sc triggerinfo w32time start/networkon stop/networkoff
And start the service again:
net start w32time
Conclusion
With this setup, time should be in good control on both the host and the guests.
Best Answer
Virtual Machines can't track time. You may want to try setting up the DC up as an NTP client. This blog might be useful.
http://www.aperture.ro/index.php/2009/01/windows-time-sync-hyper-v-enabled-domain-controller-dilemma/
The guy waffles for a bit, but scroll down and you will get the necessary registry entries. This KB article seems a bit more authorative.
http://support.microsoft.com/kb/223184
There is also a Technet article on configuring a DC to use NTP:
http://technet.microsoft.com/en-us/library/cc784553(WS.10).aspx
As for why this happens, VMware has a writeup about timekeeping with VMs (not HyperV, but the concepts still apply).
http://www.vmware.com/pdf/vmware_timekeeping.pdf