สิ่งนี้เกิดจาก livelock เมื่อ ntpd เรียก adjtimex (2) เพื่อบอกเคอร์เนลให้แทรกวินาทีกระโดด ดูการโพสต์ lkml http://lkml.indiana.edu/hypermail/linux/kernel/1203.1/04598.html
Red Hat ควรอัพเดตบทความ KB ของพวกเขาด้วย https://access.redhat.com/knowledge/articles/15145
อัปเดต: Red Hat มีบทความ KB ที่สองสำหรับปัญหานี้ที่นี่: https://access.redhat.com/knowledge/solutions/154713 - บทความก่อนหน้านี้สำหรับปัญหาก่อนหน้านี้ที่ไม่เกี่ยวข้อง
วิธีแก้ไขคือปิด ntpd หาก ntpd ออกการเรียก adjtimex (2) แล้วคุณอาจต้องปิดการใช้งาน ntpd และเริ่มระบบใหม่เพื่อให้ปลอดภัย 100%
สิ่งนี้มีผลต่อ RHEL 6 และ distros อื่น ๆ ที่ใช้เมล็ดที่ใหม่กว่า (ใหม่กว่าประมาณ 2.6.26) แต่ไม่ใช่ RHEL 5
เหตุผลนี้เกิดขึ้นก่อนการกระโดดครั้งที่สองจะเกิดขึ้นจริงคือ ntpd ให้เคอร์เนลจัดการการกระโดดครั้งที่สองในเวลาเที่ยงคืน แต่ต้องแจ้งเตือนเคอร์เนลให้แทรกการกระโดดครั้งที่สองก่อนเที่ยงคืน ntpd จึงเรียก adjtimex (2) บางครั้งในระหว่างวันของ leap วินาที ณ จุดนี้จุดบกพร่องนี้จะถูกเรียก
หากคุณติดตั้ง adjtimex (8) คุณสามารถใช้สคริปต์นี้เพื่อพิจารณาว่าตั้งค่าสถานะ 16 ไว้หรือไม่ ค่าสถานะ 16 คือ "การแทรกการก้าวกระโดดครั้งที่สอง":
adjtimex -p | perl -p -e 'undef $_, next unless m/status: (\d+)/; (16 & $1) && print "leap second flag is set:\n"'
UPDATE:
Red Hat ได้อัปเดตบทความ KB ของพวกเขาเพื่อให้ทราบ: "ลูกค้า RHEL 6 อาจได้รับผลกระทบจากปัญหาที่ทราบที่ทำให้ NMI Watchdog ตรวจพบสถานะแฮงค์เมื่อได้รับการประกาศ leapsecond NTP ปัญหานี้กำลังได้รับการแก้ไขในเวลาที่เหมาะสม การประกาศ leapsecond และไม่พบปัญหานี้จากนั้นจะไม่มีผลกระทบอีกต่อไป "
ปรับปรุง: ภาษาข้างต้นถูกลบออกจากบทความ Red Hat; และโซลูชัน KB ที่สองถูกเพิ่มเข้ามาโดยมีรายละเอียดปัญหาความผิดพลาดของ adjtimex (2): https://access.redhat.com/knowledge/solutions/154713
อย่างไรก็ตามการเปลี่ยนรหัสในการโพสต์ LKML โดย IBM Engineer John Stultz อาจมีการหยุดชะงักเมื่อมีการใช้ leap วินาทีดังนั้นคุณอาจต้องการปิดใช้งาน leap วินาทีโดยการรีบูตหรือใช้ adjtimex (8) หลังจากปิดใช้งาน ntpd
การปรับปรุงครั้งสุดท้าย:
ฉันไม่มีเคอร์เนล dev แต่ฉันตรวจสอบแพทช์ของ John Stultz อีกครั้งที่นี่: https://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h = 6b43ae8a619d17c4935c3320d2ef9e92bdeed05d
ถ้าฉันอ่านมันในเวลานี้ฉันผิดเกี่ยวกับการหยุดชะงักอีกครั้งเมื่อมีการใช้งานการก้าวกระโดดครั้งที่สอง นั่นเป็นความเห็นของ Red Hat เช่นกันตามรายการ KB ของพวกเขา อย่างไรก็ตามหากคุณปิดใช้งาน ntpd ให้ปิดการใช้งานไว้เป็นเวลา 10 นาทีเพื่อไม่ให้คุณหยุดชะงักเมื่อ ntpd เรียก adjtimex (2)
เราจะตรวจสอบว่ามีข้อผิดพลาดอื่น ๆ อีกหรือไม่ :)
POST-LEAP อัปเดตครั้งที่สอง:
ฉันใช้เวลาสองสามชั่วโมงสุดท้ายอ่าน ntpd และ pre-patch (buggy) รหัสเคอร์เนลและในขณะที่ฉันอาจจะผิดมากฉันจะพยายามอธิบายสิ่งที่ฉันคิดว่าเกิดขึ้น:
ก่อนอื่น ntpd เรียก adjtimex (2) ตลอดเวลา มันทำเช่นนี้เป็นส่วนหนึ่งของ "clock loop filter" ซึ่งกำหนดไว้ใน local_clock ใน ntp_loopfilter.c คุณสามารถดูรหัสได้ที่นี่: 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)
กล่าวอีกนัยหนึ่งในวันที่มีวินาทีกระโดด ntpd ตั้งค่าสถานะ "STA_INS" และเรียก adjtimex (2) (ผ่าน portability-wrapper)
การเรียกระบบนั้นทำให้มันไปถึงเคอร์เนล นี่คือรหัสเคอร์เนลที่เกี่ยวข้อง: https://github.com/mirrors/linux/blob/a078c6d0e6288fad6d83fb6d5edd91ddb7b6ab33/kernel/time/ntp.c
เคอร์เนล codepath ประมาณนี้:
- บรรทัด 663 - เริ่มต้นรูทีน do_adjtimex
- บรรทัด 691 - ยกเลิกตัวจับเวลากระโดดวินาทีใด ๆ ที่มีอยู่
- บรรทัด 709 - คว้า ntp_lock spinlock (ล็อคนี้เกี่ยวข้องกับความผิดพลาดของ livelock ที่เป็นไปได้)
- บรรทัด 724 - เรียก process_adjtimex_modes
- บรรทัด 616 - เรียก process_adj_status
- บรรทัด 590 - ตั้งค่าตัวแปรโกลบอล time_status ตามแฟล็กที่ตั้งค่าในการเรียก adjtimex (2)
- บรรทัด 592 - ตรวจสอบตัวแปรโกลบอล time_state ในกรณีส่วนใหญ่โทร ntp_start_leap_timer
- บรรทัด 554 - ตรวจสอบตัวแปรโกลบอล time_status STA_INS จะถูกตั้งค่าดังนั้นให้ตั้งค่า time_state เป็น TIME_INS และโทร hrtimer_start (ฟังก์ชั่นเคอร์เนลอื่น) เพื่อเริ่มจับเวลาตัวจับเวลาครั้งที่สอง ในกระบวนการสร้างตัวจับเวลารหัสนี้จะคว้า xtime_lock หากสิ่งนี้เกิดขึ้นในขณะที่ CPU ตัวอื่นคว้า xtime_lock และ ntp_lock แล้วเคอร์เนลก็มีชีวิตชีวา นี่คือเหตุผลที่ John Stultz เขียนโปรแกรมแก้ไขเพื่อหลีกเลี่ยงการใช้ hrtimers นี่คือสิ่งที่ทำให้ทุกคนเดือดร้อนในวันนี้
- บรรทัด 598 - หาก ntp_start_leap_timer ไม่ได้เริ่มตัวจับเวลากระโดดจริงตั้ง time_state เป็น TIME_OK
- บรรทัดที่ 751 - สมมติว่าเคอร์เนลไม่ได้เป็นแบบหมุนได้สแต็กจะคลายออกและจะปล่อย ntp_lock spinlock
มีบางสิ่งที่น่าสนใจอยู่ที่นี่
อันดับแรกบรรทัด 691 ยกเลิกตัวจับเวลาที่มีอยู่ทุกครั้งที่เรียก adjtimex (2) จากนั้น 554 จะสร้างตัวจับเวลาอีกครั้ง ซึ่งหมายความว่าในแต่ละครั้งที่ ntpd เรียกใช้ตัวกรองลูปของนาฬิการหัส buggy จะถูกเรียกใช้
ดังนั้นฉันเชื่อว่า Red Hat ผิดเมื่อพวกเขาพูดว่าเมื่อ ntpd ตั้งค่าสถานะการก้าวกระโดดครั้งที่สองระบบจะไม่ผิดพลาด ฉันเชื่อว่าแต่ละระบบที่รัน ntpd มีศักยภาพในการหมุนทุก 17 นาที (หรือมากกว่า) เป็นระยะเวลา 24 ชั่วโมงก่อนการก้าวกระโดดครั้งที่สอง ฉันเชื่อว่านี่อาจอธิบายได้ว่าทำไมระบบจำนวนมากจึงล่ม โอกาสครั้งเดียวในการกระแทกจะมีโอกาสน้อยกว่ามากเมื่อเปรียบเทียบกับ 3 โอกาสต่อชั่วโมง
อัปเดต: ในโซลูชัน KB ของ Red Hat ที่https://access.redhat.com/knowledge/solutions/154713วิศวกรของ Red Hat ได้ข้อสรุปเดียวกัน (การรัน ntpd จะกดรหัส buggy อย่างต่อเนื่อง) และแน่นอนพวกเขาทำไปหลายชั่วโมงก่อนฉัน วิธีการแก้ปัญหานี้ไม่ได้เชื่อมโยงกับบทความหลักที่https://access.redhat.com/knowledge/articles/15145ดังนั้นฉันจึงไม่ได้สังเกตจนกว่าจะถึงตอนนี้
ประการที่สองนี่อธิบายว่าทำไมระบบที่โหลดมีแนวโน้มที่จะผิดพลาดมากกว่า ระบบที่โหลดจะจัดการกับอินเตอร์รัปต์มากขึ้นทำให้เรียกใช้ฟังก์ชันเคอร์เนล "do_tick" บ่อยขึ้นทำให้มีโอกาสมากขึ้นที่รหัสนี้จะเรียกใช้และคว้า ntp_lock ในขณะที่ตัวจับเวลาถูกสร้างขึ้น
ประการที่สามมีโอกาสที่ระบบจะหยุดทำงานเมื่อการกระโดดครั้งที่สองเกิดขึ้นจริงหรือไม่? ฉันไม่รู้แน่ชัด แต่อาจเป็นเพราะตัวจับเวลาที่ใช้ไฟและดำเนินการปรับการเผ่นวินาที (ntp_leap_second, บรรทัด 388) ยังคว้า ntp_lock spinlock และมีการเรียกไปยัง hrtimer_add_expires_ns ฉันไม่รู้ว่าการโทรนั้นอาจทำให้เกิดการเคลื่อนไหวได้หรือไม่ แต่ดูเหมือนจะเป็นไปไม่ได้
ในที่สุดสิ่งที่ทำให้การตั้งค่าเผ่นวินาทีถูกปิดใช้งานหลังจากเผ่นวินาทีทำงาน คำตอบที่นั่นคือ ntpd หยุดตั้งค่าสถานะเผ่นวินาทีในบางจุดหลังเที่ยงคืนเมื่อเรียก adjtimex (2) เนื่องจากไม่ได้ตั้งค่าสถานะการตรวจสอบที่บรรทัด 554 จะไม่เป็นจริงและจะไม่มีการสร้างตัวจับเวลาและบรรทัด 598 จะรีเซ็ตตัวแปรโกลบอล time_state เป็น TIME_OK สิ่งนี้อธิบายว่าทำไมถ้าคุณตรวจสอบการตั้งค่าสถานะด้วย adjtimex (8) หลังจากการกระโดดครั้งที่สองคุณจะยังคงเห็นชุดการตั้งค่าวินาทีที่ก้าวกระโดด
ในระยะสั้นคำแนะนำที่ดีที่สุดสำหรับวันนี้น่าจะเป็นคำตอบแรกที่ฉันได้รับ: ปิดการใช้งาน ntpd และปิดใช้งานการตั้งค่าสถานะเผ่นวินาที
และความคิดสุดท้าย:
- ไม่มีผู้ขาย Linux รายใดที่สังเกตเห็นแพทช์ของ John Stultz และนำไปใช้กับเมล็ดของพวกเขา :(
- ทำไม John Stultz ถึงไม่แจ้งเตือนผู้ขายบางรายว่าเป็นสิ่งจำเป็น? บางทีโอกาสของการเคลื่อนไหวดูเหมือนจะต่ำพอที่จะทำให้เสียงไม่ได้รับประกัน
- ฉันได้ยินรายงานเกี่ยวกับกระบวนการของ Java ที่ล็อคหรือหมุนเมื่อมีการใช้งานการก้าวกระโดดครั้งที่สอง บางทีเราควรปฏิบัติตามคำแนะนำของ Google และคิดใหม่เกี่ยวกับวิธีการที่เราใช้ leap-วินาทีกับระบบของเรา: http://googleblog.blogspot.com/2011/09/time-technology-and-leaping-seconds.html
06/02 อัพเดตจาก John Stultz:
https://lkml.org/lkml/2012/7/1/203
โพสต์มีการเดินผ่านทีละขั้นตอนของเหตุผลที่ก้าวกระโดดครั้งที่สองทำให้ตัวนับ futex จะหมดอายุก่อนกำหนดและอย่างต่อเนื่อง spiking โหลด CPU