这是由ntpd调用adjtimex(2)告诉内核插入a秒时的活锁引起的。请参阅lkml发布http://lkml.indiana.edu/hypermail/linux/kernel/1203.1/04598.html
红帽还应该更新其知识库文章。https://access.redhat.com/knowledge/articles/15145
更新:Red Hat在这里有第二个KB文章专门针对此问题:https : //access.redhat.com/knowledge/solutions/154713-上一篇文章是针对一个较早的,不相关的问题的
解决方法是仅关闭ntpd。如果ntpd已经发出了adjtimex(2)调用,则可能需要禁用ntpd并重新启动以确保100%安全。
这会影响运行较新内核(大约大于2.6.26的内核)的RHEL 6和其他发行版,但不会影响RHEL 5。
发生这种情况的原因是实际上计划在 the秒发生之前发生的原因是ntpd让内核在午夜处理alert秒,但是需要警告内核在午夜之前插入the秒。因此,ntpd在the秒期间的某个时间调用adjtimex(2),此时将触发此错误。
如果安装了adjtimex(8),则可以使用此脚本来确定是否设置了标志16。标志16是“插入leap秒”:
adjtimex -p | perl -p -e 'undef $_, next unless m/status: (\d+)/; (16 & $1) && print "leap second flag is set:\n"'
更新:
红帽已更新其知识库文章,以指出:“ RHEL 6客户可能受到已知问题的影响,该问题会导致NMI Watchdog在收到NTP second秒公告时检测到挂起。此问题已得到及时解决。如果您的系统收到leap秒宣布,并且没有遇到此问题,那么它们将不再受到影响。”
更新:以上语言已从Red Hat文章中删除;并添加了第二个KB解决方案,详细说明了adjtimex(2)崩溃问题:https : //access.redhat.com/knowledge/solutions/154713
但是,IBM工程师John Stultz在LKML帖子中的代码更改指出,在实际应用the秒时也可能会出现死锁,因此您可能要在禁用ntpd后重新引导或使用adjtimex(8)来禁用the秒。
最后更新:
好吧,我不是内核开发人员,但是我在这里再次查看了John Stultz的补丁:https ://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a = commit;h = 6b43ae8a619d17c4935c3320d2ef9e92bdeed05d
如果我这次没看错的话,那我错了,那就是在应用the秒时还会出现另一个死锁。根据红帽的知识库条目,这似乎也是红帽的意见。但是,如果您禁用了ntpd,请再禁用10分钟,以免在ntpd调用adjtimex(2)时造成死锁。
我们很快就会发现是否还有其他错误:)
跃迁后第二次更新:
我花了最后几个小时来阅读ntpd和预修补程序(buggy)内核代码,尽管我在这里可能很错,但我将尝试解释我的想法:
首先,ntpd始终会调用adjtimex(2)。它作为其“时钟循环过滤器”的一部分执行此操作,该过滤器在ntp_loopfilter.c中的local_clock中定义。您可以在此处看到该代码:http : //www.opensource.apple.com/source/ntp/ntp-70/ntpd/ntp_loopfilter.c(来自ntp版本4.2.6)。
时钟循环过滤器经常运行-每次ntpd轮询其上游服务器时都会运行,默认情况下每17分钟或更长时间运行一次。时钟环路滤波器的相关位为:
if (sys_leap == LEAP_ADDSECOND)
ntv.status |= STA_INS;
接着:
ntp_adjtime(&ntv)
换句话说,在a秒的日子里,ntpd设置“ STA_INS”标志并调用adjtimex(2)(通过其可移植性包装程序)。
该系统调用进入内核。这是相关的内核代码:https : //github.com/mirrors/linux/blob/a078c6d0e6288fad6d83fb6d5edd91ddb7b6ab33/kernel/time/ntp.c
内核代码路径大致如下:
- 第663行-do_adjtimex例程的开始。
- 第691行-取消所有现有的leap秒计时器。
- 第709行-抓取ntp_lock自旋锁(此锁与可能发生的livelock崩溃有关)
- 第724行-调用process_adjtimex_modes。
- 第616行-调用process_adj_status。
- 第590行-根据adjtimex(2)调用中设置的标志设置time_status全局变量
- 第592行-检查time_state全局变量。在大多数情况下,请调用ntp_start_leap_timer。
- 第554行-检查time_status全局变量。将设置STA_INS,因此将time_state设置为TIME_INS并调用hrtimer_start(另一个内核函数)以启动the秒计时器。在创建计时器的过程中,此代码捕获了xtime_lock。如果发生这种情况,而另一个CPU已经抓住了xtime_lock 和 ntp_lock,则内核活动锁。这就是John Stultz编写补丁以避免使用hrtimers的原因。这就是今天引起所有人麻烦的原因。
- 第598行-如果ntp_start_leap_timer实际未启动跳跃计时器,请将time_state设置为TIME_OK
- 第751行-假设内核没有活动锁,则取消堆栈堆栈并释放ntp_lock自旋锁。
这里有一些有趣的事情。
首先,每次调用adjtimex(2)时,第691行都会取消现有的计时器。然后,554重新创建该计时器。这意味着每当ntpd运行其时钟循环过滤器时,就会调用儿童车代码。
因此,当他们说ntpd设置了leap秒标志时,我相信Red Hat是错误的,该系统不会崩溃。我相信每个运行ntpd的系统都有潜力在the秒之前的24小时内每隔17分钟(或更长时间)进行一次活动锁定。我相信这也可以解释为什么这么多系统崩溃了。一次撞车的机会比每小时3次的机会要小得多。
更新:在位于https://access.redhat.com/knowledge/solutions/154713的 Red Hat的KB解决方案中,Red Hat工程师确实得出了相同的结论(运行ntpd会不断遇到错误代码)。实际上,他们比我早做了几个小时。该解决方案并未链接到https://access.redhat.com/knowledge/articles/15145上的主要文章,因此直到现在我都没有注意到它。
其次,这解释了为什么加载的系统更容易崩溃。加载的系统将处理更多的中断,从而导致更频繁地调用“ do_tick”内核函数,从而在创建计时器时使此代码更有机会运行并抓住ntp_lock。
第三,在实际发生actually秒时,系统是否有崩溃的可能?我不确定,但可能是肯定的,因为触发并实际执行leap秒调整的计时器(第388行的ntp_leap_second)也获取了ntp_lock自旋锁,并调用了hrtimer_add_expires_ns。我不知道该调用是否也可能导致活动锁定,但这似乎并非不可能。
最后,什么原因导致the秒运行后禁用disabled秒标志?ntpd的答案是在午夜过后的某个时间,当它调用adjtimex(2)时停止设置leap秒标志。由于未设置该标志,因此第554行的检查将不成立,也不会创建任何计时器,第598行将把time_state全局变量重置为TIME_OK。这解释了为什么如果在the秒之后使用adjtimex(8)检查了标志,仍然会看到设置了leap秒标志。
简而言之,今天最好的建议似乎是我给出的第一个建议:禁用ntpd,并禁用the秒标志。
还有一些最后的想法:
John Stultz 06/02更新:
https://lkml.org/lkml/2012/7/1/203
这篇文章分步介绍了为什么the秒导致futex计时器过早连续地超时,从而增加了CPU负载。