HA Clustering (SAF based)
1: Prepare modified load module as shared object using standard compiler
3.4 ライブパッチ方式の実装
本項ではライブパッチ方式の実装について示す.なおライブパッチ方式の実装のベースに Linuxカーネルバージョン2.6.9を用いた.
3.3に示したとおりライブパッチの処理は三つの段階に分かれる.第1段階の修正用ロード モジュールの作成は通常のコンパイラを使用する.第2段階は修正用ロードモジュールを修正 対象プロセス及びカーネルのメモリ領域にロードする処理である.第3段階は修正対象プロセ ス及びカーネルの修正対象関数の先頭に修正関数へのjump命令を書き込む処理である(図 3.11).
以下にこの第2及び第3の段階の実装を,プロセスライブパッチ及びカーネルライブパッチ それぞれについて示す.
system New call
Live patching process The new system call that enables atomic overwriting of branch instruction to the head of kernel function.
Time
CPU0 CPU1 CPU2 CPU3
Overwrite branch instruction Kernel
(Non Operation Instruction)Nop
Assign NOP to other
CPUs Disable interruptions Release NOP Operations
Enable interruptions
図3.10. カーネルライブパッチでのカーネルの停止と分岐命令の上書き
図3.11.ライブパッチ方式のシーケンス
3.4.1 プロセスライブパッチの実装
修正対象プロセスへの修正用ロードモジュールのロード
プロセスライブパッチはカーネルの仮想記憶管理から修正対象プロセスのメモリ空間にアク セスし,修正用ロードモジュールをロードする.
本機能の実装として,修正対象プロセスのリアルタイム性を阻害しないよう,修正対象プロ セスを停止することなく,修正用ロードモジュールを修正対象プロセスの空メモリ領域にマッ
プ可能なmmap3()システムコールを実装した.また修正対象プロセスの使用済みメモリ領域
にアクセス(Read/Write)するaccesspvm()システムコールを実装した.
具体的にはmmap3()は,既存のmmap() 及びmmap2()システムコールを元に,引数に 任意のプロセスを指定できるよう拡張を行った.またaccesspvm()では,任意のプロセスの アドレスに仮想記憶管理を介してメモリのセグメントを意識せず,同時に複数ワード単位で アクセスできるよう実装した.このmmap3()を用いて修正用ロードモジュールのロード,
accesspvm()を用いてjump命令の書込みを行う.
またLinuxのシステムコールとしてptrace()システムコール[54]が存在し,mmap3()及
びaccesspvm()と同様に修正対象プロセスのメモリ領域にアクセスすることが可能である.
しかしptrace()では修正用ロードモジュールをロード・コピーする間,修正対象プロセスを
停止する必要がある.またptrace()を使用してのデータコピーは,1回のシステムコールご とに1ワードサイズしかできない.このため修正個所が多数に上る場合,修正対象プロセスが 長時間停止する問題があり,リアルタイム性を要求するネットワークサービスへの適用は困難 である.これについては3.5にて評価する.
なお我々のライブパッチ方式をもとにした,ptraceを用いたオンライン修正実装[55]も存 在するが,上記リアルタイム性への影響と,適切な異常系の処理をもたないため実用性に乏 しい.
jump命令上書き処理と修正対象プロセスの停止
修正対象関数の先頭にjump命令を上書きする際,プロセスをいったん停止して上書きを行 う.具体的にはプロセスを停止するためのCPUスケジューラ上のプロセス状態変更の実装と
して,Linuxの既存の機能であるシグナルのSIGSTOP/SIGCONTによるプロセスの実行状
態変更機能を適用する.また上述したaccesspvm()を用いてjump命令を書き込む.
修正対象プロセスを停止させるシグナルはプロセスに信号を通知するカーネルが有するプリ ミティブな通信手段である.ライブパッチプロセスがSIGSTOPを修正対象プロセスに送信 することで,修正対象プロセス及びそのプロセスに属するタスクは停止状態となる.その後
SIGCONTを修正対象プロセスに送信することで修正対象プロセスは実行を再開する.
またPOSIXの仕様としてSIGSTOPを受信したプロセスの親プロセスは,SIGCHLDが
通知される.このため修正対象プロセスの親プロセスはSIGCHLDにより特殊な状態遷移を 行わないことが必要である.
次にプロセスライブパッチのリトライ処理を示す.ライブパッチプロセスはSIGSTOPの 送信を行った後,停止したプロセスの実行アドレスをチェックする.実行アドレスと修正アド レスの範囲が一致する場合,ライブパッチプロセスはSIGCONTの送信を実施後,リトライ 用の情報を更新し再度SIGSTOPの送信を試みる.
なおSIGSTOPを使用したサンプルプログラムに対する停止処理の予備評価を行った結果,
スレッド数が100の場合は,全スレッド及びプロセスを停止するのにかかる時間は10ミリ秒 程度である[50].プロセス停止が許容される時間はサービスに要求されるリアルタイム性に よって異なるが,前述のリトライ回数を要求されるリアルタイム性に応じた回数とすることで 十分適用可能である.
3.4.2 カーネルライブパッチの実装
カーネルへの修正用ロードモジュールのロード
カーネルライブパッチでは,まず修正用ロードモジュールをカーネルのメモリ領域内に ロードする.本機能の実装としては,既存のカーネルモジュールの読み込み機構である load module()を適用する.load module()を用いることで,カーネルの動作を停止せずに,
空メモリ領域に修正用ロードモジュールをロードすることが可能である.本機能の動作はライ ブパッチが所望する,サービスの可用性低下を最小限にすることに合致している.
jump命令上書き処理とカーネルの停止
カーネルライブパッチでは,jump命令を上書きする間はカーネルの実行を停止させ,jump 命令を上書きする間に,他のカーネル実行タスクや割込みに修正アドレスを実行させない.具 体的にはカーネル内の既存処理であるstop machine run() 関数を使用しカーネルの実行を停 止する.その後各タスクの実行アドレスを確認し,jump命令を上書きする.
このstop machine run()関数は,引数にて指定された処理のみを単一CPUで実施し,指 定された処理が終了するまでの間,それ以外のCPUにおいてはnop命令を実行する.この nop命令は他のCPUにおいて極めて高い優先度のリアルタイムスケジューリングで割り当て られるため,他のCPUは次回のタイマ割込み時である1ms後にnop命令が実行され停止状 態となる.
上述のstop machine run() 関数を呼び出し,各タスクの実行アドレスを確認後,jump命 令を上書きする処理をpatch kpannus() システムコールとして実装した.
次にカーネルライブパッチのリトライ処理を示す.ライブパッチ処理はstop machine run() により書込み処理を行う各CPU以外を割込み不可の停止状態に遷移した後,停止した各カー ネル実行タスクの実行アドレスをチェックする.実行アドレスと修正アドレスの範囲が一致す る場合,ライブパッチ処理はstop machine run()の実行を終了,割込みを許容する.その後 リトライ用の情報を更新し再度stop machine run()のからの処理を行う.
表3.2.評価環境
CPU Pentium Xeon 2.8GHz ×2 (HT により4SMT)
Memory 2GByte
HDD 160GByte SATA-1
カーネル 2.6.9にライブパッチ方式を実装