これは、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には、この問題に関する2番目のKB記事があります:https : //access.redhat.com/knowledge/solutions/154713-以前の記事は、以前の無関係な問題に関するものです
回避策は、ntpdをオフにすることです。ntpdがすでにadjtimex(2)呼び出しを発行している場合は、ntpdを無効にして再起動して100%安全にする必要がある場合があります。
これは、RHEL 6および新しいカーネル(約2.6.26より新しい)を実行している他のディストリビューションに影響しますが、RHEL 5には影響しません。
うるう秒が実際に発生するようにスケジュールされる前にこれが発生する理由は、ntpdがカーネルに深夜にうるう秒を処理させるが、深夜の前にうるう秒を挿入するようカーネルに警告する必要があるためです。したがって、ntpdはうるう秒の間にadjtimex(2)を呼び出し、この時点でこのバグがトリガーされます。
adjtimex(8)がインストールされている場合、このスクリプトを使用してフラグ16が設定されているかどうかを判断できます。フラグ16は「うるう秒の挿入」です。
adjtimex -p | perl -p -e 'undef $_, next unless m/status: (\d+)/; (16 & $1) && print "leap second flag is set:\n"'
更新:
Red HatはKB記事を更新して、「RHEL 6のお客様は、NTPうるう秒のアナウンスを受信するとNMI Watchdogがハングを検出するという既知の問題の影響を受ける可能性があります。この問題はタイムリーに対処されています。うるう秒の発表であり、この問題は発生していなかったため、影響を受けなくなりました。」
更新:上記の言語はRed Hatの記事から削除されました。また、adjtimex(2)クラッシュの問題の詳細を示す2番目のKBソリューションが追加されました:https : //access.redhat.com/knowledge/solutions/154713
ただし、IBMエンジニアJohn StultzによるLKML投稿のコード変更では、実際にうるう秒が適用されるときにデッドロックが発生する場合があるため、ntpdを無効にした後、リブートするかadjtimex(8)を使用してうるう秒を無効にすることができます。
最終更新:
まあ、私はカーネル開発者ではありませんが、John Stultzのパッチをここでもう一度レビューしました:https ://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h = 6b43ae8a619d17c4935c3320d2ef9e92bdeed05d
今回正しく読んでいると、うるう秒が適用されたときに別のデッドロックが発生するのは間違っていました。KBエントリに基づくと、これもRed Hatの意見のようです。ただし、ntpdを無効にしている場合は、ntpdがadjtimex(2)を呼び出したときにデッドロックが発生しないように、さらに10分間無効のままにします。
もうすぐバグがあるかどうかを確認します:)
ポストラップ2回目の更新:
私はここ数時間、ntpdとpre-patch(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)
言い換えると、うるう秒がある日に、ntpdは「STA_INS」フラグを設定し、adjtimex(2)を(そのポータビリティラッパーを介して)呼び出します。
そのシステムコールはカーネルに到達します。関連するカーネルコードは次のとおりです。https://github.com/mirrors/linux/blob/a078c6d0e6288fad6d83fb6d5edd91ddb7b6ab33/kernel/time/ntp.c
カーネルのコードパスはおおよそ次のとおりです。
- 663行目-do_adjtimexルーチンの開始。
- 691行目-既存のうるう秒タイマーをキャンセルします。
- 709行目-ntp_lockスピンロックを取得します(このロックは、可能性のあるライブロッククラッシュに関与しています)
- 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(別のカーネル関数)を呼び出してうるう秒タイマーを開始します。タイマーを作成するプロセスで、このコードはxtime_lockを取得します。別のCPUがすでにxtime_lock と ntp_lockを取得している間にこれが発生した場合、カーネルはライブロックします。これが、John Stultzがhrtimersの使用を避けるためにパッチを作成した理由です。これが今日、誰もがトラブルを引き起こした原因です。
- 598行目-ntp_start_leap_timerが実際にリープタイマーを開始しなかった場合、time_stateをTIME_OKに設定します
- 751行目-カーネルがライブロックしないと仮定すると、スタックは巻き戻され、ntp_lockスピンロックが解放されます。
ここにはいくつか面白いことがあります。
まず、行691は、adjtimex(2)が呼び出されるたびに既存のタイマーをキャンセルします。次に、554はそのタイマーを再作成します。これは、ntpdがクロックループフィルターを実行するたびに、バグのあるコードが呼び出されたことを意味します。
したがって、ntpdがうるう秒フラグを設定するとシステムがクラッシュしないと言ったとき、Red Hatは間違っていたと思います。ntpdを実行している各システムは、うるう秒の前の24時間の間、17分(またはそれ以上)ごとにライブロックする可能性があると思います。これにより、多くのシステムがクラッシュした理由も説明できると思います。1回のクラッシュの可能性は、1時間に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を取得する機会が増えます。
第三に、実際にうるう秒が発生したときにシステムがクラッシュする可能性はありますか?確かにわかりませんが、恐らくはい、うるう秒調整を実行して実際に実行するタイマー(388行目のntp_leap_second)もntp_lockスピンロックを取得し、hrtimer_add_expires_nsを呼び出します。その呼び出しがライブロックを引き起こす可能性があるかどうかはわかりませんが、不可能ではないようです。
最後に、うるう秒の実行後にうるう秒フラグが無効になる原因は何ですか?ntpdの答えは、adjtimex(2)を呼び出す深夜0時以降のある時点でうるう秒フラグの設定を停止します。フラグが設定されていないため、554行目のチェックは真にならず、タイマーは作成されず、598行目はtime_stateグローバル変数をTIME_OKにリセットします。これは、うるう秒の直後にadjtimex(8)でフラグをチェックした場合に、うるう秒フラグが設定されたままである理由を説明しています。
要するに、今日の最良のアドバイスは、結局私が最初に出したもののようです。ntpdを無効にし、うるう秒フラグを無効にします。
そしていくつかの最終的な考え:
06/02 John Stultzからの更新:
https://lkml.org/lkml/2012/7/1/203
この投稿には、うるう秒が原因でfutexタイマーが時期尚早に継続的に期限切れになり、CPU負荷が急上昇する理由が段階的に説明されています。