togotoday
2015年4月14日 13時13分
アットマークテクノ様
いつも大変お世話になっております。坂本です。
Armadillo-840に置きまして4回に1回くらいの高頻度で
起動できない現象が発生しております。以前からも
起きていた現象で、現象発生時には起動できるまで
再起動を繰り返す形で対処しておりました。
ですが、客先納入の段階になって
品質上捨て置けない状況となりました。
====== 起動OK時のブートログ(抜粋) ==========
[ ok ] Starting rpcbind daemon....
[ ok ] Cleaning up temporary files....
INIT: Entering runlevel: 2
[info] Using makefile-style concurrent boot in runlevel 2.
[ ok ] Starting rpcbind daemon...[....] Already running..
[....] Starting Tomcat servlet engine: tomcat7PHY: sh-eth-ffffffff:00 - Link is Up - 100/Full
====== 起動NG時のブートログ(抜粋) ==========
[ ok ] Starting rpcbind daemon....
[ ok ] Cleaning up temporary files....
PHY: sh-eth-ffffffff:00 - Link is Up - 100/Full
※ 「INIT: Entering runlevel: 2」 というログが出力される前に
「PHY: sh-eth-ffffffff:00 - Link is Up - 100/Full」という
ログが出力されるとそれ以上ログが表示されずに
起動シーケンスがストップするパターンが多いようです。
上記に関してコメントを頂けますようよろしくお願い申し上げます。
コメント
togotoday
togotoday
at_daisuke.sasaki
at_yashi
原因がわかりました。
Linux 3.4 の MMU のコードに不具合がありました。https://git.kernel.org/linus/26ffd0d4 をあてると、直ります。このコミットには不具合の修正という感じに書かれていませんが、論理的にも正しく直ります。
パッチを添付しますので、お試しください。このパッチには、以下のコミットが含まれます。
- ARM: mm: introduce L_PTE_VALID for page table entries
- commit dbf62d50067e55a782583fe53c3d2a3d98b1f6f3
- url https://git.kernel.org/linus/dbf62d5
- ARM: mm: introduce present, faulting entries for PAGE_NONE
- commit 26ffd0d43b186b0d5186354da8714a1c2d360df0
- url https://git.kernel.org/linus/26ffd0d4
修正版のカーネルは、次の製品アップデートでリリース予定です。
以下、技術的な話:
ARMv7のMMUのコードに、Hardware PTEの nGビットを意図せず落す不具合がありました。この不具合は、あるページをアクセス禁止にするために mprotect(2)
で「PROT_NONE
」に設定すると、そのページのHardware PTEの nGビットを落し、グローバル設定にしてしまいます。
ARM の MMU は、通常 Address Space Identifier (ASID) と仮想アドレスによって、対象の Page Table Entry (PTE) を確定させますが、nGビットがグローバルに設定されている PTEでは、ASIDが比較対象となりません。このためグローバル設定になっている PTEが TLBに格納されている状態で別プロセスが偶然同じ仮想アドレスにアクセスすると、異なるプロセスの PTE にもかかわらずグローバル設定になっている PTEが使われてしまいます。
ハードウェアとしては設定された通りに動作しているのですが、Linux 側では想定外の動作のために齟齬が発生します。
グローバルに設定されたページは、PROT_NONE つまり「ユーザープロセスからのアクセスを許可しない」という設定に変更する過程で作られます。ページの設定はアクセス不許可となるので、別プロセスがアクセスした場合でもアクセス許可フォルトが発生します。しかし、Linux 側はアクセス可能であるはずと思うために、アクセス許可フォルトのハンドラーは、なにもせずに処理を終ります。そして、またフォルトが発生するという無限ループに入ります。
アクセス許可フォルトなどの例外を処理するハンドラーは、高速に動作することが求められているため、このような齟齬を拾うコードは含まれていません。正しく動作することが、そもそも前提となっています。
グローバルに設定されたページは、設定したプロセスが終了される時にも消されることはありません。最終的にグローバルに設定したプロセスが終了したとしても、この問題は解決せずに永遠に無限ループの中に入ったままになります。
今回の修正では、ページを「PAGE_NONE」に設定した場合にも、誤ってグローバルの設定にはせずに PTE 自体を削除するように修正されています。
Atmark Dist を使った場合にグローバルに設定されるページは確認されていません。しかし、標準イメージを使った場合のみの確認であり、mprotect()
はだれでも使えるシステムコールですので、Atmark Dist をお使いの場合でも不具合が発生する可能性があります。そのため、Atmark Distをお使いでもカーネルのアップデートをお勧めします。
ファイル | ファイルの説明 |
---|---|
0001-a840-Debian-Page-Fault.patch |
at_yashi
2015年4月14日 14時40分
ご連絡ありがとうございます。
こちらでも症状を確認できました。
とりあえずのワークアラウンドですが、
/etc/init.d/.legacy-bootordering
を作成し startpar を並列実行から逐次処理に変更することで、問題を回避または軽減できることまで確認できました。根本原因は調査中です。お手数をおかけして申し訳ないのですが、ご確認いただけますか?