以下に、この出願の実施形態における添付の図面を参照して、この出願の実施形態における技術的解決策について説明する。記載の実施形態は、この出願の実施形態の全てではなく、単にいくつかであることは明らかである。
この出願の実施例で言及される「複数」は、2つ以上を意味する。さらに、この出願の説明において、「第1」及び「第2」のような用語は、単に区別及び説明のために使用されており、相対的重要性の指示若しくは暗示又は順序の指示若しくは暗示として理解されるべきではない。
図1は、ノード100の概略構造図である。ノード100は、アプリケーション層、オペレーティングシステム102及びハードウェア層103を含んでもよい。アプリケーション層は1つ以上のアプリケーションプログラム101を含み、オペレーティングシステム102はカーネル104を含み、ハードウェア層103は、プロセッサ106、メモリ105及び通信インタフェース107を含む。オペレーティングシステム102は、ハードウェアリソース及びソフトウェアリソースを管理するために使用されるシステムソフトウェアである。
プロセッサ106は、ノード100の制御センタであり、様々なインタフェース及びバスを通じてノード100の全てのコンポーネントに接続される。いくつかの実施形態では、プロセッサ106は1つ以上の処理ユニットを含んでもよく、或いは、物理コアと呼ばれてもよい。例えば、図1におけるプロセッサ106は、コア0及びコア1を含む。プロセッサ106はレジスタを更に含んでもよく、レジスタは、カーネル104の関数のアドレスを記憶するように構成されてもよい。プロセッサ106は中央処理装置(Central Processing Unit, CPU)でもよく、プロセッサ106は、代替として、他の汎用プロセッサ、デジタルシグナルプロセッサ(Digital Signal Processor, DSP)、特定用途向け集積回路(Application-Specific Integrated Circuit, ASIC)、フィールドプログラマブルゲートアレイ(Field-Programmable Gate Array, FPGA)若しくは他のプログラム可能論理デバイス、ディスクリートゲート若しくはトランジスタ論理デバイス、又はディスクリートハードウェアコンポーネントでもよい。汎用プロセッサはマイクロプロセッサでもよく、プロセッサ106はいずれかの従来のプロセッサ等でもよい。
コンピュータプログラムはメモリ105に記憶される。プロセッサ106は、コンピュータプログラムにより定義された関数を実現するために、メモリ105内のコンピュータプログラムを実行するように構成される。メモリ105は不揮発性記憶媒体であり、一般的に、内部記憶デバイス及び外部記憶デバイスを含む。内部記憶デバイスは、ランダムアクセスメモリ(Random Access Memory, RAM)、読み取り専用メモリ(Read-Only Memory, ROM)、キャッシュ(cache)等を含むが、これらに限定されない。外部記憶デバイスは、フラッシュメモリ(flash memory)、ハードディスク、光ディスク、ユニバーサルシリアルバス(universal serial bus, USB)フラッシュドライブ等を含むが、これらに限定されない。コンピュータプログラムは、一般的に、外部記憶デバイスに記憶される。コンピュータプログラムを実行する前に、プロセッサは、外部記憶デバイスから内部記憶デバイスにプログラムをロードする。メモリ105は独立してもよく、バスを使用することによりプロセッサ106に接続される。代替として、メモリ105及びプロセッサ106は、チップ上のサブシステムに統合されてもよい。
通信インタフェース107は、ノード100と他のデバイス又は通信ネットワークとの間の通信を実現するためのトランシーバのようなトランシーバ装置である。
この出願の実施形態において提供される方法は、ノード100のオペレーティングシステム内のカーネル104を修正するために使用されてもよい。
実現方式では、ノード100は、サーバ又は端末デバイスのような物理デバイスでもよい。端末デバイスは、無線接続機能を有するハンドヘルドデバイス、又は無線モデムに接続された他の処理デバイスでもよい。例えば、端末デバイスは、携帯電話、コンピュータ、タブレットコンピュータ、パーソナルデジタルアシスタント(personal digital assistant, PDA)、モバイルインターネットデバイス(mobile Internet device, ID)、ウェアラブルデバイス、電子書籍リーダ(e-book reader)等でもよい。代替として、モバイルデバイスは、携帯可能、ポケットサイズ、ハンドヘルド型、コンピュータ内蔵又は車載のモバイルデバイスでもよい。この実現方式では、ノード100の概略構造図が図2に示されている。ノード100は、メモリ201、プロセッサ202及び通信インタフェース203を含む。メモリ201、プロセッサ202及び通信インタフェース203は、それぞれ、図1におけるメモリ105、プロセッサ106及び通信インタフェース107に部分的に或いは完全に対応してもよい。図2におけるメモリ201、プロセッサ202及び通信インタフェース203の実現方式については、図1における対応する説明を参照する。オペレーティングシステム205及びアプリケーションプログラム204は、メモリ201に記憶され、実行プロセス中にあるオペレーティングシステム205により生成されたデータ及びアプリケーションプログラム204により生成されたデータは、メモリ201に更に記憶されてもよい。
他の実現方式では、ノード100は仮想コンピュータでもよい。仮想コンピュータは、全てのタイプの仮想化デバイス内のソフトウェアを使用することにより仮想化された実行環境の総称である。仮想コンピュータの概念は、仮想マシン及びコンテナを含む。クラウドシナリオにおけるコア技術としての仮想化は、ハードウェアリソースが仮想化された後にハードウェアリソースを複数のユーザに共有するために使用され、それにより、ユーザはセキュリティ隔離が確保されることを前提に物理リソースを便利且つ柔軟に利用でき、物理リソースの利用率が大幅に増加できる。この実現方式では、ノード100の概略構造図が図3に示されている。ノード100は、ハードウェア層312、ホストマシン層309及び仮想化層を含む。仮想化層は、仮想マシン301及び仮想マシン302を含む。ハードウェア層312は、プロセッサ314、メモリ313及び通信インタフェース315を含む。他の実施形態では、より多くの或いはより少ない仮想マシンが存在してもよい。
仮想マシン(virtual machine, VM):1つ以上の仮想マシンは、ソフトウェアを使用することにより物理コンピュータ上でシミュレーションされる。これらの仮想マシンは完全に隔離された環境で実行し、実際のコンピュータのように機能する。ゲストオペレーティングシステム(guest operating system, guest OS)(図3における305及び306)は、仮想マシン(図3における301及び302)上にインストールされてもよく、1つ以上のアプリケーションプログラム(図3における303及び304)は、ゲストオペレーティングシステム上で実行される。仮想マシンは、ネットワークリソースに更にアクセスできる。仮想マシン上で実行されるアプリケーションは、実際のコンピュータ上のように機能する。
仮想コンピュータは、全てのタイプの仮想化デバイス内でソフトウェアを使用することにより仮想化された実行環境の総称である。仮想コンピュータの概念は、仮想マシン及びコンテナを含む。
ホスト(host)マシン層309は、管理層として、ハードウェアリソースを管理及び割り当て、仮想ハードウェアプラットフォームを仮想マシンに提示し、仮想マシンをスケジューリング及び隔離するように構成される。いくつかの実施形態では、ホストマシン層309は、ホストマシンオペレーティングシステム311と、仮想マシンモニタ(virtual machine monitor, VMM)310又はhypervisorのような仮想監視装置とを含む。仮想マシンモニタ310は、ホストマシンオペレーティングシステム311の内部に配置されてもよく、或いは、ホストマシンオペレーティングシステム311の外部に配置されてもよい。いくつかの他の実現方式では、「ホストマシン層」は、1つの特権仮想マシン(例えば、仮想化アーキテクチャXen)を更に含んでもよい。仮想ハードウェアプラットフォームは、仮想ハードウェアプラットフォーム上で実行する仮想マシンのために、仮想プロセッサ、仮想メモリ、仮想ディスク、仮想ネットワークインタフェースカード等のような様々なハードウェアリソースを提供する。仮想コンピュータは、仮想コンピュータのためにホストマシン層により準備された仮想ハードウェアプラットフォーム上で実行する。この出願では、ホストマシン層は、場合によっては、略称でホストマシンと呼ばれる。
ハードウェア層312は、仮想化環境が実行されるハードウェアプラットフォームである。ハードウェア層は、複数のタイプのハードウェアを含んでもよい。例えば、物理コンピュータのハードウェア層は、プロセッサ314及びメモリ313を含んでもよく、ネットワークインタフェースカード(network interface card, NIC)のような通信インタフェース315を更に含んでもよく、割り込みコントローラ及び入出力(input/output I/O)デバイスを更に含んでもよい。プロセッサ314は、コア1及びコア0のような複数の物理コアを含んでもよい。図3に示すプロセッサ314、メモリ313及び通信インタフェース315は、それぞれ図1におけるプロセッサ106、メモリ105及び通信インタフェース107に部分的に或いは完全に対応してもよい。
仮想プロセッサ(例えば、図3における307及び308)は、仮想化技術において共有又はスライス方式で使用するために仮想コンピュータに提供される物理処理ユニット、例えば、仮想中央処理ユニット(virtual central processing unit, vCPU)の表現である。1つの仮想コンピュータについて、1つ以上の仮想プロセッサが仮想コンピュータにサービス提供してもよい。複数の仮想プロセッサが存在するとき、通常では、1つの仮想プロセッサはマスタ仮想プロセッサであり、他の仮想プロセッサはスレーブ仮想プロセッサである。
仮想コンピュータは、スタンドアロンコンピュータと同等であることが理解されるべきである。したがって、仮想コンピュータがアクションを実行することは、仮想プロセッサがアクションを実行することとして考えられてもよい。仮想プロセッサは、ソフトウェアを使用することにより実現される。したがって、仮想プロセッサがアクションを実行することは、実際には、仮想プロセッサで実行される物理プロセッサ又は物理コアがアクションを実行することである。本発明の複数の実施形態では、上記の説明は、対応するシナリオの技術的表現習慣に依存して選択的に使用される。
ホストマシンオペレーティングシステム311及びVMM310は、ホストマシン上に配置される。他の仮想化アーキテクチャでは、VMM310は、hypervisor又は他のタイプの仮想監視装置と同等である。VMM310は、ホストマシンオペレーティングシステム311の内部に配置されてもよく、或いは、ホストマシンオペレーティングシステム311から分離されて配置されてもよい。VMM310は、VMM310上で実行する1つ以上の仮想マシンを管理することを担う。ホストマシンオペレーティングシステム311は、具体的には、Linux、iOS、Microsoft又は他のオペレーティングシステムでもよい。
仮想マシン(VM)は、仮想ハードウェア層、ゲストオペレーティングシステム及び複数のタイプのアプリケーションを含む。仮想ハードウェア層は、仮想メモリ(図面に図示せず)及び仮想プロセッサのような仮想ハードウェアを含む。図3に示すように、この実施形態では、仮想マシン301及び仮想マシン302が含まれ、各仮想マシンは仮想プロセッサを含む。仮想プロセッサは、ソフトウェアとハードウェアとの組み合わせを使用することにより実現される。仮想プロセッサの実行は、実際には以下のように実現される。物理コアは、ソフトウェアプログラムを読み取って実行する。例えば、物理コアは、ソフトウェアプログラムを読み取り、仮想プロセッサを実現するために、物理コアのハードウェア支援仮想化の特定のモード(例えば、x86のnon-rootモード)でソフトウェアプログラムを実行する。
オペレーティングシステムは、通常では、古いバージョンの欠陥又は脆弱性を修正するために定期的に更新される必要がある。開発者がシステム問題を見つけたとき或いはオペレーティングシステム内の検出モジュールが修正される必要があるセキュリティ脆弱性を見つけたとき、修復関数は、パッチモジュールとして作成されてもよく、オペレーティングシステムにロードされる。このようなプロセスは、「パッチ当て」と呼ばれてもよい。オペレーティングシステムを修正することは、通常では、ユーザに認識させる必要はない。言い換えると、デバイスは、修正プロセスにおいてリブートされる必要はない。カーネルを修正することは重要な部分である。カーネルは、オペレーティングシステムの最も基本的な部分であり、複数のアプリケーションのためにコンピュータハードウェアへの安全なアクセスを提供できる。上記の要件を満たすために、通常では、ホットフィックスメカニズムがカーネルを修正するために使用される。
ホットフィックスの主な利点は、コンピュータデバイスの現在のソフトウェアバージョンにおける欠陥又は脆弱性を修正するために、コンピュータデバイスをリブートせずに、旧関数が新関数に置換されることである。旧関数が呼び出されたとき、旧関数は新関数にジャンプし、新関数が実行される。ホットフィックスは、オペレーティングシステムをリブートせずに、オペレーティングシステムの脆弱性を修正するために使用される。これには、システムのダウンタイムを低減し、システムの可用性を増加させる。ホットフィックスはまた、開発中のデバッグ及びテストにも適用可能である。例えば、ソフトウェアモジュール又はカーネルの開発中に、情報が関数に追加される必要がある場合又は特定の値が関数内の変数に割り当てられる必要がある場合、カーネルの再コンパイル、インストール及びリブートのような一連の動作を実行せずに、ホットフィックスが実現のために使用されてもよい。
カーネルは対応するソースコードパッケージを有するので、ホットフィックスモジュールは、ソースコードパッケージ及びシンボルテーブルに基づいて作成されてもよい。ホットフィックスモジュールは旧関数のアドレス及び新関数のアドレスを含んでもよい。ホットフィックスモジュールがカーネルに登録された後に、カーネルはホットフィックスモジュールから情報を抽出し、旧関数の関数ヘッダ内の元のノーオペレーション命令(nop)をジャンプ命令に置換してもよい。旧関数が呼び出されたとき、旧関数は実行されない。その代わりに、新関数を実行するために、新関数にジャンプされる。以下に、ホットフィックスメカニズムの原理を詳細に説明するために、Linuxオペレーティングシステムを例として使用する。ホットフィックスメカニズムは、2つの段階、すなわち、ホットフィックスモジュールが解析されて旧関数について対応する新関数が登録される初期化段階、及び関数ジャンプ段階に分割されてもよい。
関数は関数ヘッダ及び関数ボディを含んでもよい。関数の定義では、関数ボディの前の全ての部分が関数ヘッダと呼ばれる。関数ヘッダは関数のリターンタイプ、シーケンス及びパラメータのタイプのような関数プロトタイプ情報を提供する。関数ボディは、プログラミング言語で関数を定義する全てのコードの集合である。
関数1の対応するホットフィックス関数が登録されていない関数1が呼び出されるプロシージャが図4に示されている。関数1が呼び出されたとき、まず、関数1の関数ヘッダに記録されたプロシージャが実行される。一般的に、ノーオペレーション命令は関数ヘッダに記録されない。ノーオペレーション命令が実行された後に、関数ボディ内の関数を定義するコードが実行される。
図1におけるノード100のカーネル104は、ftraceモジュール及びlivepatchモジュールを含んでもよい。図5に示すように、ftraceモジュール及びlivepatchモジュールは、関数ジャンプを実現するように構成される。関数ジャンプを実現するための方法を説明する前に、まず、以下の関連する概念について説明する。
mcountはオペレーティングシステムにおけるメカニズムである。カーネルのコンパイル中に、関数又は関数のテスト性能をトレースするために、各関数の関数ヘッダにいくつかのバイトが予約されている。このようなメカニズムは、Linuxオペレーティングシステムではmcountと呼ばれる。
ftraceは、Linuxにおけるコードレベルの実行分析にとって最も効果的なツールの1つである。ftraceは、Linuxカーネル内の関数呼び出しをトレースするために使用できるメカニズムであり、各関数呼び出しのプロローグ(prologue)の前に特定のコードをトリガできる。ftraceは、カーネルが実行するときに実行される異なる関数呼び出しに関する情報を記録するために使用でき、カーネルイベント、コンテキスト、関数プログレッシブ関係、カーネル関数呼び出し関係又は関数スタックを分析するために、開発者及びシステム設計者が現在のカーネルの実行情報を取得するのを支援できる。ftraceはまた、関数スケジューリング又は割込みイベントのようなカーネル固有のイベントを分析でき、また、カーネル関数及びこれらの関数のコールスタックをトレースできる。コールスタックは、コンピュータプログラムのアクティブなサブルーチンに関する情報を記憶するために使用される。ftraceはまた、割り込みがマスクされる時間、プリエンプションが無効にされる時間及びプロセスが立ち上がる時点とプロセスが実行され始める時点との間の時間のような待ち時間を追跡できる。
Kpatchは、システムをリブートせずにLinuxカーネルの動的なパッチ当てを実現する技術である。Kpatchは、ユーザモードのツールkpatch tool及びカーネルモードのメカニズムlivepatchを含む。livepatchは、ホットフィックスの実現中の関数ジャンプ段階の中心的なコンポーネントである。図6に示すように、livepatchは、ftraceに基づいてカーネル関数の置換を実現し、mcountメカニズムを使用することによりカーネルコンパイル中の各関数エントリにおいていくつかのバイトを予約し、パッチ当ての間に旧関数エントリに予約されたバイトをジャンプ命令と置換する。新関数のアドレスが見つかった後に、新関数の実行プロシージャは、関数レベルのライブ置換を実現するように実行される。livepatchは、業界ではftraceと高く互換性がある唯一のホットフィックスメカニズムであり、したがって、Linuxではlivepatchが支配的である。livepatchは、Linuxオペレーティングシステムにより提供され且つホットフィックス(hotfix)のロード、アクティベーション、ロールバック及び削除をサポートするサービスコンポーネントである。livepatchは、デバイスをリブートせずに、ホットフィックスモジュールに基づいて現在のソフトウェアバージョンの欠陥を修正できる。サービスコンポーネントはまた、関数がスレッドにより呼び出されているか否かを検査して一貫性を確保することを担う。
構造体(struct)はデータ構造であり、集約データ型(aggregate data type)である。構造体は、比較的複雑なデータ構造を実現するために、変数、ポインタ又は配列として宣言されてもよい。structは要素の集合でもあり、これらの要素は構造体のメンバと呼ばれる。これらのメンバは、異なるタイプでもよく、一般的に名前を使用することによりアクセスを実行してもよい。
旧関数は新関数に対するものである。新関数は、旧関数を修正又は置換するために使用されるように登録又は構成された関数であり、新関数は、旧関数のパッチ関数とも呼ばれてもよい。旧関数のアドレスは、記憶空間における旧関数の開始アドレスを示し、新関数のアドレスは、記憶空間における新関数の開始アドレスを示す。
図5に示すように、ftraceモジュールは、旧関数のアドレスに対応する構造体について複数の構造体が記憶された単一リンクリストを検索し、構造体に記憶されたコールバック関数のポインタを抽出し、livepatchモジュールにジャンプするように構成される。livepatchモジュールは、見つかった構造体のアドレスに基づいて、旧関数に対応する新関数のスタックを取得し、旧関数に対応する新関数のアドレスを更に取得する。livepatchモジュールは、新関数のアドレスに基づいて、旧関数から新関数へのジャンプを実現する。
ホットフィックスモジュールがコンピュータシステムにリリースされた後に、コンピュータシステムは、関数1を置換するために使用される新関数(パッチ関数)を登録する。図6における関数1の関数ヘッダに予約されているいくつかのバイトは、ジャンプ命令に置換される。コンピュータシステムは、図1に示す、関数1の関数ボディ内に関数を定義するコードを実行し続けない。この場合、関数1から関数2へのジャンプの実現プロシージャが図5及び図6に示されている。関数1は旧関数であり、関数2は新関数である。
ステップS1:関数1が呼び出されたとき、関数1の関数ヘッダ内のジャンプ命令を実行し、次いで、ftraceモジュールにジャンプする。
関数1の関数ヘッダ内のジャンプ命令は、ftraceモジュールのコールバック関数のポインタである。ftraceモジュールのコールバック関数のポインタは、ftraceモジュールの実行ロジックを指すために使用される。
コールバック(callback)関数は、ポインタを使用することにより呼び出される関数である。関数Aのポインタ(アドレス)が関数Bに転送されるパラメータとして使用される場合、ポインタが指す関数Aを呼び出すためにポインタが使用されるとき、関数Aはコールバック関数である。
ステップS2:ftraceモジュールは、関数1のアドレスに基づいて単一リンクリストをトラバースし、関数1のアドレスが記録された構造体を求めて単一リンクリストを検索し、構造体に記録されたlivepatchモジュールのコールバック関数のポインタを取得し、livepatchモジュールにジャンプする。
リンクリスト(linked list)はデータ構造であり、線形テーブルであり、各ノードにおける次のノードへのポインタ(pointer)を記憶する。この構造は、ノードを求めてリンクリストを検索するか或いは特定の番号のノードにアクセスする時間の複雑さがO(n)になることを可能にする。複数の構造体が単一リンクリストに記録される。単一リンクリスト内の各ノードは、構造体と次のノードを指すポインタとを記憶する。単一リンクリスト内の複数の構造体のそれぞれは、1つの旧関数に対応する。各構造体は、旧関数のアドレスとコールバック関数のポインタとを含む。コールバック関数のポインタは、livepatchモジュールのコールバック関数のポインタでもよく、或いは、他のコールバック関数のポインタでもよい。言い換えると、1つの旧関数は複数の構造体に対応してもよく、複数の構造体に記録されたコールバック関数のポインタは異なるコールバック関数に属する。ftraceモジュールは、旧関数のアドレス及びlivepatchモジュールのコールバック関数のポインタが記録された構造体が見つかるまで、旧関数のアドレスに基づいて単一リンクリスト内の複数の構造体をトラバースし、次いで、livepatchモジュールにジャンプする。図3に示すように、4つの構造体fop1~fop4は、単一リンクリストに記憶され、各構造体は、旧関数のアドレスを記憶し、コールバック関数のアドレスが記憶される。構造体fops4に記憶されている旧関数のアドレスが関数1のアドレスであり、コールバック関数の記憶されたポインタがlivepatchモジュールのコールバック関数のポインタであると仮定する。ftraceモジュールは、関数1のアドレスに基づいて単一リンクリストをトラバースした後に、構造体fops4が旧関数Aのアドレスを記憶していることを見つけ、構造体fops4からlivepatchモジュールのコールバック関数のポインタを取得し、livepatchモジュールにジャンプする。
初期化段階の間に、livepatchモジュールが旧関数について旧関数の構造体を登録したとき、livepatchモジュールは、旧関数のアドレスと、構造体に割り当てられた記憶空間のアドレスとをftraceモジュールに送信する。したがって、旧関数に対応する構造体を見つけた後に、ftraceモジュールは、見つかった構造体のアドレスをlivepatchモジュールに送信してもよい。上記の例では、ftraceモジュールはまた、構造体fops4のアドレスをlivepatchモジュールに送信する。
ステップS3:livepatchモジュールは、旧関数に対応する関数スタックが記憶された構造体opsを直接取得するために、受信した構造体fopsのアドレスを使用し、関数スタックは、同じ旧関数についての複数のホットフィックス関数を記憶する。旧関数は複数回修正される可能性があるので、旧関数のアドレスは複数の新関数のアドレスに対応してもよい。
ステップS4:livepatchモジュールは、関数スタックから新関数のアドレスを抽出し、新関数を呼び出し、関数置換を実現する。
この解決策では、旧関数と新関数との間の対応関係は、旧関数から新関数へのジャンプを実現するために構造体fopsを使用することにより確立される。fops構造体は、ftraceモジュールがlivepatchモジュールのコールバック関数のポインタを検索するときに必要であり、fops構造体はまた、livepatchモジュールが新関数のアドレスを検索するときにも必要である。したがって、「旧関数->fops->新関数」は1対1の対応関係にある必要がある。1つの新関数が登録されたとき、1つの構造体fopsが追加される必要がある。その結果、単一リンクリストが増加し、それに従ってトラバーサル時間が増加する。修正される旧関数の数が増加するにつれて、それに従って単一リンクリストに記憶された構造体fopsの数が増加し、それに従って単一リンクリストのトラバーサル時間が増加し、すなわち、関数ジャンプ時間が増加し、高い性能オーバーヘッドを生じる。図7に示すように、関数ジャンプに必要な時間は、基本的に、ホットフィックス関数の数の増加と共に線形に増加する。カーネル内のホットスポット関数(すなわち、頻繁に呼び出される関数)が対応するホットフィックス関数を有するとき、ホットスポット関数が呼び出されたとき、関数ジャンプ時間がホットフィックス関数の実行時間よりもはるかに長くなる場合が生じる。この場合、ホットスポット関数の実行効率はかなり低減される。さらに、各関数のジャンプが実行されるとき、全体の単一リンクリストがトラバースされる必要がある。これは、全てのホットフィックス関数が互いに影響を受け、全体の性能の低下を生じることを意味する。
関数ジャンプ時間が過度に長いという問題を解決するために、業界における一般的な慣行は、関数ヘッダが新関数のヘッダを直接指すことを可能にするように旧関数の関数ヘッダを変更することである。上記の照会プロセスは、このような「旧関数-新関数」の方式で回避され、それにより、関数ジャンプ時間が低減される。しかし、この解決策はftraceと矛盾し、ftraceが利用不可能になることを生じる。
この出願は、livepatchモジュールとftraceモジュールとの間の分離を或る程度実行するための、関数ジャンプを実現するための方法を提供する。この方法は、CentOS、Red Hat及びUbuntuのような現在の主流のLinuxプラットフォームに適用されてもよい。この出願において提供される技術的解決策では、複数の旧関数のアドレスが1つの構造体に記憶され、呼び出された関数のアドレスが構造体に記憶されているか否かが検索される。呼び出された関数のアドレスが構造体に記憶されていると決定された場合、呼び出された関数のアドレスに基づいて呼び出された関数に対応する関数スタックが検索され、関数スタックに記憶された新関数のアドレスを取得する。
図8に示すように、図1におけるカーネル104は、ftraceモジュール401、livepatchモジュール402及びカーネル内の関数404を含んでもよい。1つ以上のアプリケーションプログラム406は、インタフェース205を通じてカーネル内の関数404を呼び出してもよい。アプリケーションプログラム203は、インタフェース205を通じてftraceモジュール401を更に構成してもよい。
ftraceモジュール401は、カーネル内の関数404の呼び出し状態をトレースするように構成される。この出願のこの実施形態では、第1のデータ構造408は、対応するホットフィックス関数を有する複数の旧関数のアドレスを記憶する。構造体の数が旧関数の数と同じである従来技術と比較して、この出願では、構造体の数は1に固定される。単一の項目は、従来技術における複数の構造体を含む単一リンクリストを置換するために使用される。カーネル内の関数404が呼び出されたとき、ftraceモジュール401は、関数のアドレスに基づいて関数のアドレスを求めて第1のデータ構造408を検索し、関数のアドレスが第1のデータ構造408に見つかったとき、第1のデータ構造に記憶されたlivepatchモジュール402のコールバック関数のポインタを抽出し、livepatchモジュール402にジャンプするように構成される。
livepatchモジュール402は、旧関数に対応する新関数のアドレスを検索するように構成される。ホットフィックスモジュール407を受信したとき、livepatchモジュール402は、旧関数及び旧関数に対応する関数スタックを登録し、旧関数のアドレスをftraceモジュール内の第1のデータ構造408に登録するように更に構成される。この出願のこの実施形態では、livepatchモジュール402は管理ユニット403を含む。管理ユニット403は、全ての旧関数のアドレス及び旧関数に対応する関数スタックを管理するように構成される。管理ユニット403は、アドレスの追加、削除及び照会のような動作を実行してもよい。さらに、管理ユニット403は、照会を効率的に実現するために使用できるデータ構造(例えば、ハッシュテーブル又はハッシュツリー)を使用することにより、旧関数のアドレスと関数スタックとの間の対応関係を管理してもよい。このように、livepatchモジュールとftraceモジュールとの間の分離が或る程度実行され、それにより、新関数のアドレスを照会するとき、livepatchモジュールは単一リンクリスト内の構造体に依存しない。
この出願の実施形態は、関数ジャンプを実現するための方法を提供する。図9に示すように、当該方法は以下のステップを含む。
ステップS501:第1の関数についての呼び出し命令を受信する。
呼び出し命令は、第1の関数のアドレスを含んでもよく、第1の関数のアドレスは、アドレス空間内の第1の関数の開始アドレスである。
任意選択で、第1の関数の関数ヘッダのエントリにおけるいくつかのバイトが第1のコールバック関数のポインタに置換されている場合、ポインタは第1のコールバック関数を指す。第1の関数が呼び出されたとき、第1のコールバック関数は、第1の関数の関数ヘッダに記録された第1のコールバック関数のポインタを使用することにより呼び出される。すなわち、ステップS502が実行される。
任意選択で、ノーオペレーション命令が第1の関数の関数ヘッダに記憶されてる場合、第1の関数の関数ボディに定義された関数関連の機能が実行され続ける。
任意選択で、ステップS501の前に、当該方法は、第1の関数の関数ヘッダ内のいくつかのバイトを、第1のコールバック関数のポインタで置換することを更に含む。
ステップS502:第1の関数のアドレスが第1のデータ構造に記憶されているか否かを決定する。
複数の関数のアドレスが第1のデータ構造に記憶される。第1のデータ構造に記憶された複数の関数のアドレスは、第1の関数のアドレスに基づいてトラバースされ、複数の関数のアドレスが第1の関数のアドレスを含むか否かを決定する。関数のアドレスは、記憶空間における関数の開始アドレスを示す。第2のコールバック関数のポインタ及び複数の関数のアドレスは、第1のデータ構造に記憶される。これらの関数は、修正される必要があるか或いは置換される必要があるカーネル内の関数であり、これらの関数を置換するためにこれらの関数のパッチ関数が登録されている。第2のコールバック関数は、第1の関数のアドレスに基づいて第1の関数のパッチ関数のアドレスを検索するために使用される。関数ジャンプに必要な第2のコールバック関数のポインタは不変であるので、この出願のこの実施形態では、複数の関数のアドレスは1つのデータ構造に記憶されてもよい。
第1の関数が呼び出されたとき、第1の関数のアドレスはシステムで既知である。第1の関数のアドレスが第1のデータ構造に記憶されているか否かを決定する目的は、第1の関数を置換するために使用されるパッチ関数が登録されているか否かを決定することである。言い換えると、目的は、第1の関数が対応するホットフィックス関数を有するか否かを決定することである。関数置換は、関数修正として理解されてもよい。ホットフィックス実現メカニズムにおいて、置換プロセスは、関数から関数のパッチ関数へのジャンプとして理解されてもよい。
任意選択で、ステップS502の前に、当該方法は、第1の関数のパッチ関数が登録されたとき、第1の関数のアドレスを第1のデータ構造に追加することを更に含む。従来技術では、関数のパッチ関数が登録されたとき、データ構造(struct)が新たに追加され、関数のアドレスが新たに追加された構造に記憶される。この解決策では、関数のアドレスが同じデータ構造に追加される。これは、単一リンクリストの長さを短縮する。
任意選択で、第1のデータ構造は第1のハッシュテーブルである。
任意選択で、当該方法は、第1のハッシュテーブルのアドレスが記憶された構造体を使用することにより第1のハッシュテーブルを決定することを更に含み、第1のハッシュテーブルのアドレスが記憶されている構造体を指すポインタは、第1の構造体に含まれる。
実現方式では、第1の構造体のデータ構造が図10に示されている。主なデータパラメータは以下の通りである。
funcは第2のコールバック関数のポインタである。第2のコールバック関数のポインタが第1の構造体に記憶されている場合、第2のコールバック関数は、呼び出された関数のアドレスに基づいて呼び出された関数に対応するパッチ関数を検索するために使用される。
*func_hashは少なくとも1つの構造体のポインタであり、1つのポインタが1つの構造体を指す。
ポインタが指される構造体の主なパラメータは以下の通りである。
ハッシュテーブルのアドレス(*buckets)は、記憶空間においてハッシュテーブルのアドレスを記録するために使用される。ハッシュテーブルは、複数の関数のアドレスを記憶するために使用される。ここに記載される複数の関数は、対応するパッチ関数が登録された旧関数である。これらの関数が呼び出されたとき、実行のために対応するパッチ関数にジャンプされる必要がある。図7に示すように、N個の関数のip(1)からip(N)までのアドレスが記憶されており、ip(1)~ip(N)はそれぞれ関数1のアドレス~関数Nのアドレスを示す。
rcuマーカービット: rcu (Read, Copy, Update)は、LinuxカーネルAPIのグループであり、複数のリーダ及びライタがロックなしで同時に操作を実行することを許容する同期メカニズムを実現する。この同期メカニズムは、ポインタを使用することによりアクセスされるデータを保護するために使用できる。rcuマーカービットは、第1のハッシュテーブルに対して読み取り操作が実行されるか否かをマークするために使用される。
任意選択で、第1のハッシュテーブルは、第1のハッシュテーブルのアドレスが記憶されている構造体を使用することにより決定される。第1のハッシュテーブルのアドレスが記憶されている構造体を指すポインタは、第1の構造体に含まれる。第1の関数のアドレスが第1のハッシュテーブルに記憶されているか否かは、第1の関数のアドレスに基づいて確認される。第1のハッシュテーブルのアドレスは第1の構造体に記憶され、複数の関数のアドレスは第1のハッシュテーブルに記憶される。ハッシュテーブルは、キーバリュー(key-indexed)構造を使用することによりデータが記憶される構造である。検索対象の値、すなわち、キー(key)が入力されたとき、検索対象の値に対応する値を見つけることができる。第1の関数のアドレスが第1のハッシュテーブルに記憶されているか否かは、第1の関数のアドレスのハッシュ値に基づいて迅速に確認できる。
任意選択で、複数の関数のアドレスが、第1の関数のアドレスと同じアドレスを含むとき、第1のデータ構造に記憶された複数の関数のアドレスは、第1の関数のアドレスを含むと決定される。言い換えると、第1の関数を置換するために使用されるパッチ関数が存在する。第1の関数は、対応する新関数が登録されている旧関数である。第2のコールバック関数は、第1の構造体に記憶された第2のコールバック関数のポインタに基づいて呼び出される。すなわち、ステップS503が実行される。第2のコールバック関数は、呼び出された関数に対応する新関数を検索するために使用される。
任意選択で、第1のデータ構造に記憶された複数の関数のアドレスが第1の関数のアドレスを含まないとき、第1の関数を置換するために使用されるパッチ関数は存在せず、第1の関数の関数ボディにより定義された関数関連の機能が実行され続けてもよい。
任意選択で、図10に示すように、第1の構造体内の*func_hashは2つのポインタを含み、各ポインタはハッシュテーブルのアドレスが記憶されている構造体を指す。ハッシュテーブルfilter_hashは、ftraceによりトレースされる関数のアドレスを記録するために使用され、ハッシュテーブルnotrace_hashは、ftraceによりトレースされない関数のアドレスを記録するために使用される。第1の関数のアドレスがハッシュテーブルnotrace_hashに記憶されている場合、これは、第1の関数がftraceによりトレースされないことを示し、第1の関数の関数ボディにより定義された関数関連の機能が実行され続ける。
任意選択で、ステップS502の前に、当該方法は、第1の関数のパッチ関数が登録されたとき、第1の関数のアドレスを第1のデータ構造に追加することを更に含む。具体的には、第1の関数のアドレスは、第1の構造体内の第1のハッシュテーブルに追加されてもよく、第1のハッシュテーブルは、パッチ関数を使用することにより修正される必要がある複数の関数のアドレスを記憶するために使用される。
ステップS503:第1の関数のアドレスに基づいて、第1の関数に対応するパッチ関数のアドレスを検索する。
第1の関数のアドレスに基づいて、第1の関数のパッチ関数のアドレスを求めて、第2のデータ構造が検索される。第1の関数のパッチ関数は、第1の関数を置換するために登録され、複数の関数のアドレスと複数の関数のパッチ関数との間の対応関係は、第2のデータ構造に記憶され、複数の関数のそれぞれのアドレスは、関数のパッチ関数に対応する。
任意選択で、複数の関数のそれぞれは第2の構造体に対応し、関数のパッチ関数のアドレスは、各関数の第2の構造体に記憶される。旧関数は複数回修正される可能性があるので、同じ旧関数を修正する新関数のアドレスは、全て関数スタックに記憶されてもよい。図11Aに示すように、各旧関数のアドレス及び関数の関数スタックは、第2の構造体に記憶される。1つ以上のパッチ関数のアドレスは、旧関数の関数スタックに記憶される。第4の関数のアドレス、第5の関数のアドレス及び第6の関数のアドレスは全て旧関数を修正するために使用されるパッチ関数のアドレスであり、第4の関数のアドレスは関数スタックの先頭に位置する。第1の関数の関数スタックは、第1の関数のアドレスに基づいて見つけられ、第1の関数に対応する関数スタックの先頭のアドレスが抽出される。アドレスは、第1の関数に対応するパッチ関数のアドレスである。第2のハッシュテーブルは、複数の関数のアドレスと複数の関数の第2の構造体との間の対応関係を記憶するために使用される。図11Bに示すように、第1の関数~第Nの関数のそれぞれのアドレスのハッシュ値と、関数の第2の構造体との間の対応関係は、第2のハッシュテーブルに記憶されてもよい。第1の関数のアドレスに対応する第2の構造体は、第1の関数のアドレスに基づいて第2のハッシュテーブル内で検索され、第1の関数のパッチ関数のアドレスは、見つかった第2の構造体から取得される。
任意選択で、当該方法は、第2のハッシュテーブルを変更するための命令が受信されたとき、第2のハッシュテーブルに対して実行された読み取り操作が完了した後に第3のハッシュテーブルを変更することを更に含む。
ステップS504:第1の関数のパッチ関数のアドレスに基づいて、実行のために第1の関数から第1の関数のパッチ関数にジャンプし、呼び出し命令に応答する。
第1の関数のレジスタに記憶されているアドレスは、第1の関数のパッチ関数のアドレスに置換される。呼び出し命令に応答するために、関数呼び出しがレジスタに記憶されているアドレスに基づいて実行される必要がある。第1の関数のレジスタに記憶されているアドレスは、第1の関数のパッチ関数のアドレスに置換されるので、第1の関数のパッチ関数が呼び出し命令に応答するために呼び出される。
呼び出された第1の関数のパッチ関数のアドレスを検索するために、従来技術では、複数の構造体が記憶された単一リンクリストが、第1の関数のアドレスが記憶された構造体を検索するためにトラバースされる必要があり、構造体のアドレスが取得される。次いで、第1の関数の関数スタックが構造体のアドレスに基づいて見つけられ、さらに、パッチ関数のアドレスが取得される。この出願のこの実施形態において提供される方法によれば、第1の関数のアドレスは、1つのデータ構造内で検索される。次いで、第1の関数の関数スタックが第1の関数のアドレスに基づいて見つけられ、さらに、パッチ関数のアドレスが取得される。この出願のこの実施形態において提供される方法によれば、時間の複雑さがO(N)からO(1)に低減され、それにより、関数ジャンプ時間が低減できる。さらに、ハッシュテーブルが旧関数のアドレスと旧関数の構造体との間の対応関係を記憶するために使用され、それにより、新関数のアドレスを検索するステップにおいて消費される時間が低減できる。
他の実施形態では、ロールバック命令が受信されたとき、当該方法は以下のステップを更に含む。
ステップS505:第1の関数についてのロールバック命令に応じて、第2のハッシュテーブル及び第1の関数のアドレスに基づいて、第1の関数のパッチ関数のアドレスを検索し、第1の関数のパッチ関数のアドレスを削除し、ロールバック命令は、第1の関数のパッチ関数との第1の関数の置換を元に戻すように命令するために使用される。
第1の関数の第2の構造体は、第1の関数のアドレスに基づいて第2のハッシュテーブル内で検索され、第2の構造体に記憶されている関数スタックの先頭のアドレスは削除される。
ロールバックは、修正された関数を関数が修正される前の関数に復元することを意味する。第1の関数をロールバックすることは、第1の関数を第1の関数が修正される前の関数に復元することを意味する。第1の関数の関数スタックは、第1の関数のアドレスに基づいて検索され、関数スタックの先頭のアドレスは関数スタックから削除される。複数の第2の構造体は、ハッシュテーブルを使用することにより管理され、それにより、ホットフィックス関数をロールバックするのに消費される時間が低減できる。
任意選択で、第1の関数の関数スタックの先頭のアドレスが削除された後に、関数スタックが、関数の残りのアドレスが存在しない空のスタックである場合、関数スタックが削除され、第1の関数に対応する第2の構造体が削除される。
任意選択で、第1の関数の関数スタックの先頭のアドレスが削除された後に、関数スタックに関数の残りのアドレスが存在する場合、関数スタックの先頭に現在位置するアドレスが、第1の関数のレジスタに記憶されているアドレスに置換される。
この出願の実施形態は、関数ジャンプを実現するための方法を提供する。当該方法は、ホットフィックスモジュール(例えば、図8に示すホットフィックスモジュール407)の登録の段階で実行される。図12に示すように、当該方法は以下のステップを含む。
ステップS601:ホットフィックスモジュールを受信して解析する。
カーネルの関数が修正される必要があるとき、ホットフィックスモジュールはコンピュータシステムに送信され、コンピュータシステムはホットフィックスモジュールに関する情報を受信して解析する。ホットフィックスモジュールは、1つ以上の旧関数のアドレスと、各旧関数に対応する新関数のアドレスとを含んでもよい。旧関数は修正される必要がある関数であり、新関数は旧関数を修正するために使用される関数である。関数のアドレスは、アドレス空間における関数の位置を示す。
ステップS602:旧関数の第2の構造体が登録されているか否かを決定する。
第2の構造体がホットフィックスモジュール内の1つ以上の旧関数のうちいずれか1つについて登録されているか否か。第2の構造体は、旧関数のアドレス及び旧関数のパッチ関数を記憶するために使用され、第2の構造体のデータ構造が図11Aに示されている。関数は、複数回修正されてもよく、関数の関数スタックに記憶され且つ関数を修正するために使用される1つ以上の関数のアドレスは、第2の構造体に記憶される。
任意選択で、対応する第4の構造体が旧関数について登録されている場合、これは、旧関数が現在の関数の修正の前に修正されていることを示す。最後に旧関数を修正するために使用された関数は、関数スタックに記憶されている。次いで、ステップS607がその後に実行される。
任意選択で、対応する関数スタックが旧関数について登録されていない場合、ステップS603が実行される。
ステップS603:旧関数の第2の構造体を登録する。
旧関数は、第2の構造体についてシステムに登録される。第2の構造体のデータ構造が図11Aに示されており、旧関数のアドレスと、旧関数の1つ以上のパッチ関数のアドレスを記憶するために使用される関数スタックとを含む。
任意選択で、第2のハッシュテーブルは、複数の第2の構造体を管理してもよい。言い換えると、複数の旧関数のアドレスと複数の旧関数の第2の構造体との間の対応関係は、第2のハッシュテーブルに記憶される。
ステップS604:第1の構造体が登録されているか否かを決定する。
第1の構造体は、第2のコールバック関数のポインタ及び複数の旧関数のアドレスを記憶するために使用されてもよい。第2のコールバック関数は、呼び出された関数のアドレスに基づいて、呼び出された関数を修正するために使用される新関数のアドレスを検索するために使用される。第1の構造体のデータ構造が図10に示されている。第1の構造体のデータ構造については、ステップS502における対応する説明を参照する。詳細はここでは再び説明しない。
任意選択で、第1の構造体が登録されていないとき、ステップS605が実行される。
任意選択で、第1の構造体が登録されているとき、ステップS606が実行される。
ステップS605:第1の構造体を登録する。
いくつかのアドレス空間は、第1の構造体にデータを記憶するために使用される。第2のコールバック関数のポインタ及び複数の旧関数のアドレスは、第1の構造体に記憶される。旧関数の関数ヘッダは旧関数のアドレスに基づいて見つけられ、関数ヘッダのエントリにおけるいくつかのバイトは、第1のコールバック関数のポインタに置換される。第1のコールバック関数は、呼び出された関数のアドレスを求めて第1の構造体を検索し、第2のコールバック関数のポインタを取得するように命令するために使用される。
任意選択で、第1の構造体内の第1のハッシュテーブルは、複数の旧関数のアドレスを記憶するために使用される。
ステップS606:旧関数のアドレスを第1のハッシュテーブルに追加する。
ステップS607:新関数のアドレスを関数スタックの先頭にプッシュする。
新関数のアドレスは、関数スタックのアドレス空間の開始部分に記憶される。
ホットフィックスモジュールの登録の段階では、従来技術では、旧関数のアドレスと、新関数のアドレスを検索するために使用されるコールバック関数のポインタとを記憶するために、1つの構造体が各旧関数について登録され、複数の旧関数の構造体は、単一リンクリストに記憶される。この出願のこの実施形態では、旧関数のアドレスは第1のハッシュテーブルに追加される。従来技術と比較して、単一リンクリストの長さは大幅に短縮され、それにより、旧関数のアドレスを照会するステップの時間の複雑さは、O(N)からO(1)に低減される。これは照会時間を低減する。さらに、旧関数のアドレスと関数スタックとの間の対応関係は、ハッシュテーブルを使用することにより記憶され、それにより、新関数のアドレスを照会するための時間が低減できる。
この出願の実施形態は、関数ジャンプを実現するための方法を提供する。図13に示すように、当該方法は以下のステップを含んでもよい。
ステップS701:第1の関数についての呼び出し命令を受信し、呼び出し命令は、第1の関数のアドレスを含んでもよい。
ステップS702:第1の関数の関数ヘッダにあるftraceモジュールのコールバック関数のポインタに基づいてftraceモジュールにジャンプし、入力パラメータとして使用される第1の関数のアドレスをftraceモジュールに送信する。
ホットフィックスモジュールの登録の段階では、第1の関数の関数ヘッダのエントリにおけるいくつかのバイトは、ftraceモジュールのコールバック関数のポインタに置換されている。ポインタは、ftraceモジュールの実行ロジック、すなわち、ステップS703を指す。
ステップS703:ftraceモジュールは、第1の関数のアドレスが第1のハッシュテーブルに記憶されているか否かを決定する。
ftraceモジュールは、第1の構造体内のポインタに基づいて第1のハッシュテーブルのアドレスが記憶されている構造体を見つける。ftraceモジュールは、第1の関数のアドレスに基づいて、第1のハッシュテーブルに記憶されている複数の関数のアドレスをトラバースする。
任意選択で、ftraceモジュールが、第1の関数のアドレスに基づいて第1のハッシュテーブル内の第1の関数のアドレスを見つけた場合、すなわち、第1の関数のアドレスが第1のハッシュテーブルに記憶されている場合、ステップS704が実行される。関数1のアドレス~関数Nのアドレスのように、修正される必要がある複数の関数のアドレスは、第1のハッシュテーブルに記憶され、Nは1よりも大きい正の整数である。第1の構造体のデータ構造については、ステップS502における対応する説明を参照する。詳細はここでは再び説明しない。ftraceモジュールは、第1の関数のアドレスのハッシュ値を計算し、第1の関数のアドレスのハッシュ値が第1のハッシュテーブルに記憶されているか否かを確認するために第1のハッシュテーブルをトラバースしてもよい。
任意選択で、ftraceモジュールが第1のハッシュテーブル内に第1の関数のアドレスを見つけなかった場合、ftraceモジュールは、第1の関数のレジスタに記録された第1の関数のアドレスを呼び出し、第1の関数を実行する。
ステップS704:ftraceモジュールは、第1の構造体に記憶されたlivepatchモジュールのコールバック関数のポインタに基づいてlivepatchモジュールにジャンプし、第1の関数のアドレスをlivepatchモジュールに送信し、livepatchモジュールのコールバック関数のポインタは、livepatchモジュールの実行ロジックを指す。
ステップS705:livepatchモジュール内の管理ユニットは、第1の関数のアドレスに基づいて、第1の関数のパッチ関数のアドレスを検索する。
管理ユニットは、第1の関数のアドレスに基づいて、第1の関数のパッチ関数のアドレスを求めて第2のハッシュテーブルを検索する。管理ユニットは、第1の関数のアドレスに基づいて第1の関数の第2の構造体を求めて複数の第2の構造体を検索し、第1の関数の第2の構造体に記憶されている関数スタックの先頭から、第1の関数のパッチ関数のアドレスを取得する。複数の関数のそれぞれのアドレスと関数の第2の構造体との間の対応関係は、第3のハッシュテーブルに記憶される。例えば、関数1~関数Nのアドレスと関数1~関数Nの第2の構造体との間の対応関係は、第2のハッシュテーブルに記憶される。管理ユニットは、第1の関数のアドレスに基づいて第2のハッシュテーブルから、第1の関数の第2の構造体が関数Nの第2の構造体であることを見つける。管理ユニットは、関数Nの第2の構造体内の関数スタックNの先頭のアドレス、すなわち、第1の関数のパッチ関数のアドレスを取得する。
ステップS706(図13に図示せず):livepatchモジュールは、第1の関数のレジスタに記憶された第1の関数のアドレスを、第1の関数のパッチ関数のアドレスに置換する。
レジスタは、元々は第1の関数のアドレスを記憶するか、或いは、最後に第1の関数を修正するために使用された関数のアドレスを記憶する。livepatchモジュールは、第1の関数のレジスタに記憶されている関数のアドレスをパッチ関数のアドレスに置換する。
ステップS707:呼び出し命令に応じてパッチ関数を実行する。
この出願において提供されるこの実施形態では、ftraceモジュール及びlivepatchモジュールの関数が指定される。ftraceモジュールは、旧関数に対応するlivepatchモジュールのコールバック関数のポインタを検索するように構成される。ftraceモジュールは、複数の旧関数のアドレスが記憶されている構造体において、現在呼び出されている旧関数のアドレスを照会し、現在呼び出されている旧関数のアドレスが構造体に記憶されていると決定し、livepatchモジュールのコールバック関数のポインタを取得し、照会の複雑さはO(1)である。livepatchモジュールは、新関数のアドレスを検索し、レジスタ内の値を置換し、関数ジャンプを実現するように構成される。さらに、livepatchモジュールは、照会においてより効率的であるデータ構造(例えば、ハッシュテーブル又は赤黒木)を使用することにより、迅速な照会を実現する。ハッシュテーブルは例として使用されており、照会のための時間の複雑さはO(1)である。
ホットフィックス関数の性能に影響を与える主な要因は、旧関数のエントリから新関数への関数ジャンプ時間である。この出願のこの実施形態において提供される関数ジャンプを実現するための方法によれば、1000個のホットフィックス関数のシナリオにおいて、関数ジャンプ時間は、元の関数ジャンプ時間の0.5%まで低減され、図14A及び図14Bに示すように、関数ジャンプ時間は、ホットフィックス関数の数の増加に伴ってもはや線形に増加しない。
他の実施形態では、ステップS707の後に、当該方法は、livepatchモジュールが第1の関数についてのロールバック命令を受信したとき、livepatchモジュールが、第1の関数のアドレスに基づいて、第1の関数の第2の構造体を求めて複数の第2の構造体を検索し、関数スタックの先頭のアドレスを削除することを更に含む。livepatchモジュールが関数スタックの先頭のアドレスを削除した後に、関数スタックに関数の残りのアドレスが存在する場合、livepatchモジュールは、残りのアドレスのうち関数スタックの先頭のアドレスを、第1の関数のレジスタに記憶されたアドレスに置換する。
他の実施形態では、図15A及び図15Bに示すように、ステップS701の前に、当該方法は以下のステップを更に含んでもよい。
ステップS708:livepatchモジュールは、ホットフィックスモジュールを受信して解析する。
カーネルの関数が修正される必要があるとき、livepatchモジュールはホットフィックスモジュールに関する情報を受信して解析する。ホットフィックスモジュールは、1つ以上の旧関数のアドレスと、各旧関数に対応する新関数のアドレスとを含んでもよい。旧関数は修正される必要がある関数であり、新関数は旧関数を修正するために使用される関数である。関数のアドレスは、アドレス空間における関数の位置を示す。
ステップS709:livepatchモジュールは、旧関数の第2の構造体が登録されているか否かを決定する。
livepatchモジュールは、第2の構造体がホットフィックスモジュール内の1つ以上の旧関数のうちいずれか1つについて登録されているか否かを決定する。第2の構造体は、旧関数のアドレス及び旧関数の関数スタックを記憶するために使用され、第2の構造体のデータ構造が図11Bに示されている。関数は、複数回修正されてもよく、関数を修正するために使用される1つ以上の関数のアドレスは、関数の関数スタックに記憶される。
任意選択で、対応する第2の構造体が旧関数について登録されている場合、これは、旧関数が現在の関数の修正の前に修正されていることを示す。最後に旧関数を修正するために使用された関数は、関数スタックに記憶されている。次いで、ステップS714がその後に実行される。
任意選択で、対応する関数スタックが旧関数について登録されていない場合、ステップS710が実行される。
ステップS710:livepatchモジュールは、旧関数の第2の構造体を登録する。
livepatchモジュール内の新たに追加された管理ユニットは、旧関数について第2の構造体を登録する。第2の構造体のデータ構造が図11Aに示されており、旧関数のアドレスと、旧関数に対応する新関数のアドレスを記憶するために使用される関数スタックとを含む。livepatchモジュール内の新たに追加された管理ユニットは、第2の構造体のアドレス空間を記憶し、旧関数のアドレス及び旧関数に対応する新関数のアドレスを第2の構造体に記憶することを申請する。
任意選択で、管理ユニットは第2の構造体と、第2の構造体が属する関数のアドレスとを第2のハッシュテーブルに追加する。言い換えると、管理ユニットは、旧関数のアドレスと旧関数の第2の構造体とを第2のハッシュテーブルに追加する。
任意選択で、livepatchモジュールは、rcuインタフェースを呼び出し、カーネル内のrcuモジュールが、第2のハッシュテーブルが読み取られていると決定したとき、第2のハッシュテーブルはロックされ、それにより、第2のハッシュテーブルは、読み取られているときに変更されない。例えば、関数を追加するとき或いは第2のハッシュテーブルから削除するとき、livepatchモジュールは、カーネル内のrcuインタフェースを呼び出し、リンクリストを管理するためにrcuモジュールを使用する。rcuモジュールは、第2のハッシュテーブルに対して読み取り操作が実行されたか否かを決定する。第2のハッシュテーブルに対して読み取り操作が実行された場合、読み取り操作が完了するまで、第2のハッシュテーブルに対して変更操作は実行されない。
ステップS711:livepatchモジュールが第1の構造体をftraceモジュールに登録しているか否かを決定する。
第1の構造体は、第2のコールバック関数のポインタ及び複数の旧関数のアドレスを記憶するために使用される。第2のコールバック関数は、呼び出された関数のアドレスに基づいて、呼び出された関数を修正するために使用される新関数のアドレスを検索するように命令するために使用される。第1の構造体のデータ構造が図10に示されている。第1の構造体のデータ構造については、ステップS502における対応する説明を参照する。詳細はここでは再び説明しない。
任意選択で、第1の構造体が登録されないとき、ステップS712が実行される。
任意選択で、第1の構造体が登録されているとき、ステップS713が実行される。
ステップS712:livepatchモジュールは、第1の構造体をftraceモジュールに登録する。
livepatchモジュールは、第1の構造体にデータを記憶するためにいくつかのアドレス空間を申請し、第1の構造体のアドレスをftraceモジュールに送信し、ftraceモジュールのインタフェースを呼び出し、第1の構造体をftraceモジュールに登録し、それにより、ftraceモジュールは、第1の構造体の受信アドレスに基づいて第1の構造体に記憶されたデータを読み取ることができる。第1の構造体は、コールバック関数のポインタ及び関数のアドレスを記憶するために使用される。livepatchモジュールは、ftraceモジュールにより提供された第1の構造体のデータ構造の定義に基づいて、livepatchモジュールのコールバック関数のポインタ及び旧関数のアドレスを第1の構造体に記録する。livepatchモジュールのコールバック関数は、livepatchモジュールに対して、旧関数のアドレスに基づいて新関数のアドレスを検索するように命令するために使用される。第1の構造体がftraceモジュールに登録されたとき、livepatchモジュールは、旧関数のアドレスをftraceモジュールに送信する。ftraceモジュールは、旧関数のアドレスに基づいて旧関数の関数ヘッダを見つけ、関数ヘッダのエントリにおけるいくつかのバイトを、ftraceモジュールのコールバック関数のポインタに置換する。ftraceモジュールのコールバック関数は、呼び出された関数のアドレスを求めて第1の構造体を検索し、第2のコールバック関数のポインタを取得するように命令するために使用される。
任意選択で、第1の構造体内の第1のハッシュテーブルは、複数の旧関数のアドレスを記憶するために使用される。
ステップS713:ftraceモジュールは、旧関数のアドレスを第1のハッシュテーブルに追加する。
livepatchモジュールは、旧関数のアドレスをftraceモジュールに送信する。ftraceモジュールは、第1の構造体内のポインタが指す構造体から、第1のハッシュテーブルのアドレスを取得し、旧関数のアドレスを第1のハッシュテーブルに追加する。
ステップS714:livepatchモジュールは、新関数のアドレスを関数スタックの先頭にプッシュする。
livepatchモジュールは、関数スタックのアドレス空間の開始部分において新関数のアドレスを記憶する。
上記の実施形態におけるlivepatchモジュール及びftraceモジュールは、図8に記載のlivepatchモジュール及びftraceモジュールでもよい。
この出願の実施形態は、関数ジャンプを実現するための装置800を提供する。図16に示すように、装置は、受信ユニット801及び処理ユニット802を含む。受信ユニット801は、ステップS501又はS701を実行するように構成される。処理ユニットは、ステップS502~S504のうち1つ以上、ステップS601~S607のうち1つ以上、ステップS702~S707のうち1つ以上又はステップS708~S714のうち1つ以上を実行するように構成される。
この出願の実施形態は、コンピュータシステムを提供する。コンピュータシステムは、プロセッサ及びメモリを含む。メモリは、コンピュータプログラムを記憶するように構成され、プロセッサは、コンピュータプログラムを実行し、この出願のいずれかの実施形態において提供される関数ジャンプを実現するための方法を実現するように構成される。
この出願の実施形態は、コンピュータ読み取り可能記憶媒体を提供し、コンピュータプログラムがコンピュータ読み取り可能記憶媒体に記憶される。コンピュータプログラムがプロセッサにより呼び出されたとき、この出願のいずれかの実施形態において提供される関数ジャンプを実現するための方法が実行される。
この出願の実施形態は、コンピュータプログラム製品を提供し、コンピュータプログラム製品は、コンピュータプログラムを含む。コンピュータプログラムがプロセッサにより呼び出されたとき、この出願のいずれかの実施形態において提供される関数ジャンプを実現するための方法が実行される。
当業者は、この出願の実施形態が、方法、システム又はコンピュータプログラム製品として提供されてもよいことを理解すべきである。したがって、この出願は、ハードウェアのみの実施形態、ソフトウェアのみの実施形態又はソフトウェアとハードウェアとの組み合わせを有する実施形態の形式を使用してもよい。さらに、この出願は、コンピュータ使用可能プログラムコードを含む1つ以上のコンピュータ使用可能記憶媒体(ディスクメモリ、CD-ROM、光メモリ等を含むが、これらに限定されない)上に実現されたコンピュータプログラム製品の形式を使用してもよい。
この出願は、この出願による方法、デバイス(システム)及びコンピュータプログラム製品のフローチャート及び/又はブロック図を参照して記載されている。コンピュータプログラム命令は、フローチャート及び/又はブロック図の各プロセス及び/又は各ブロックと、フローチャート及び/又はブロック図のプロセス及び/又はブロックの組み合わせとを実現するために使用されてもよいことが理解されるべきである。これらのコンピュータプログラム命令は、機械を生成するために汎用コンピュータ、専用コンピュータ、埋め込みプロセッサ、又はいずれかの他のプログラム可能データ処理デバイスのプロセッサに提供されてもよく、それにより、コンピュータ又はいずれかの他のプログラム可能データ処理デバイスのプロセッサにより実行された命令は、フローチャート内の1つ以上のプロセス及び/又はブロック図内の1つ以上のブロックにおいて特定の機能を実現するための装置を生成する。
これらのコンピュータプログラム命令は、コンピュータ又はいずれかの他のプログラム可能データ処理デバイスに対して特定の方式で機能するように命令できるコンピュータ読取可能メモリに記憶されてもよく、それにより、コンピュータ読み取り可能メモリに記憶された命令は、命令装置を含むアーチファクトを生成する。命令装置は、フローチャート内の1つ以上のプロセス及び/又はブロック図内の1つ以上のブロックにおける特定の機能を実現する。
これらのコンピュータプログラム命令は、コンピュータ又は他のプログラム可能データ処理デバイスにロードされてもよく、それにより、一連の動作及びステップがコンピュータ又は他のプログラム可能デバイス上で実行され、それにより、コンピュータで実現される処理を生成する。したがって、コンピュータ又は他のプログラム可能デバイス上で実行される命令は、フローチャート内の1つ以上のプロセス及び/又はブロック図内の1つ以上のブロックにおいて特定の機能を実現するためのステップを提供する。
当業者は、この出願の範囲から逸脱することなく、この出願に対して様々な変更及び変形を行うことができることは明らかである。この出願は、以下の特許請求の範囲及びこれらの等価な技術により定義される保護の範囲内に入ることを条件として、この出願のこれらの変更及び変形をカバーすることを意図する。
実現方式では、当該方法は、第1の関数についてのロールバック命令に応じて、第2のハッシュテーブル及び第1の関数のアドレスに基づいて、第1の関数のパッチ関数のアドレスを求めて第1の関数の第2の構造体を検索し、第1の関数のパッチ関数のアドレスを削除するステップであり、ロールバック命令は、第1の関数のパッチ関数との第1の関数の置換を元に戻すために、すなわち、第1の関数がパッチ関数に置換される前の状態にロールバックするために使用される。例えば、関数2、3及び4は関数1を修正するために順次使用されるパッチ関数であり、関数4は関数1が最後に修正されるときに使用されるパッチ関数である。関数1のロールバック命令を受信したとき、関数1のアドレスに基づいて、第2のハッシュテーブル内で関数4のアドレスが検索され、関数4のアドレスが削除される。関数4は、関数が関数4に置換される前の状態にロールバックされ、当該状態は、関数1が関数3に置換されることを意味する。第1の関数がロールバックされたとき、第2のハッシュテーブルは、複数の関数のアドレス及び複数の関数の第2の構造体を管理するために使用され、それにより、第1の関数のパッチ関数を検索するために消費される時間が低減できる。
他の実現方式では、処理ユニットは、第1の関数についてのロールバック命令に応じて、第2のハッシュテーブル及び第1の関数のアドレスに基づいて、第1の関数のパッチ関数のアドレスを求めて第1の関数の第2の構造体を検索し、第1の関数のパッチ関数のアドレスを削除するように更に構成され、ロールバック命令は、第1の関数のパッチ関数との第1の関数の置換を元に戻すために使用される。
他の実現方式では、処理ユニットは、第2のハッシュテーブルに対して読み取り操作が実行されたときに第1の関数のロールバック命令が受信された場合、第2のハッシュテーブルに対して読み取り操作が実行された後に、以下のステップ、すなわち、第1の関数のアドレス及び第2のハッシュテーブルに基づいて、第1の関数のパッチ関数のアドレスを求めて検索するステップと、第1の関数のパッチ関数のアドレスを削除するステップとが実行され、ロールバック命令は、第1の関数のパッチ関数との第1の関数の置換を元に戻すために使用される、ように更に構成される。
ホットフィックスモジュールがコンピュータシステムにリリースされた後に、コンピュータシステムは、関数1を置換するために使用される新関数(パッチ関数)を登録する。図6における関数1の関数ヘッダに予約されているいくつかのバイトは、ジャンプ命令に置換される。コンピュータシステムは、図6に示す、関数1の関数ボディ内に関数を定義するコードを実行し続けない。この場合、関数1から関数2へのジャンプの実現プロシージャが図5及び図6に示されている。関数1は旧関数であり、関数2は新関数である。
図8に示すように、図1におけるカーネル104は、ftraceモジュール401、livepatchモジュール402及びカーネル内の関数404を含んでもよい。1つ以上のアプリケーションプログラム406は、インタフェース405を通じてカーネル内の関数404を呼び出してもよい。アプリケーションプログラム203は、インタフェース405を通じてftraceモジュール401を更に構成してもよい。
ハッシュテーブルのアドレス(*buckets)は、記憶空間においてハッシュテーブルのアドレスを記録するために使用される。ハッシュテーブルは、複数の関数のアドレスを記憶するために使用される。ここに記載される複数の関数は、対応するパッチ関数が登録された旧関数である。これらの関数が呼び出されたとき、実行のために対応するパッチ関数にジャンプされる必要がある。図10に示すように、N個の関数のip(1)からip(N)までのアドレスが記憶されており、ip(1)~ip(N)はそれぞれ関数1のアドレス~関数Nのアドレスを示す。
ステップS505:第1の関数についてのロールバック命令に応じて、第2のハッシュテーブル及び第1の関数のアドレスに基づいて、第1の関数のパッチ関数のアドレスを検索し、第1の関数のパッチ関数のアドレスを削除し、ロールバック命令は、第1の関数のパッチ関数との第1の関数の置換を元に戻すために使用される。
いくつかのアドレス空間は、第1の構造体にデータを記憶するために使用される。第2のコールバック関数のポインタ及び複数の旧関数のアドレスは、第1の構造体に記憶される。旧関数の関数ヘッダは旧関数のアドレスに基づいて見つけられ、関数ヘッダのエントリにおけるいくつかのバイトは、第1のコールバック関数のポインタに置換される。第1のコールバック関数は、呼び出された関数のアドレスを求めて第1の構造体を検索し、第2のコールバック関数のポインタを取得するために使用される。
管理ユニットは、第1の関数のアドレスに基づいて、第1の関数のパッチ関数のアドレスを求めて第2のハッシュテーブルを検索する。管理ユニットは、第1の関数のアドレスに基づいて第1の関数の第2の構造体を求めて複数の第2の構造体を検索し、第1の関数の第2の構造体に記憶されている関数スタックの先頭から、第1の関数のパッチ関数のアドレスを取得する。複数の関数のそれぞれのアドレスと関数の第2の構造体との間の対応関係は、第2のハッシュテーブルに記憶される。例えば、関数1~関数Nのアドレスと関数1~関数Nの第2の構造体との間の対応関係は、第2のハッシュテーブルに記憶される。管理ユニットは、第1の関数のアドレスに基づいて第2のハッシュテーブルから、第1の関数の第2の構造体が関数Nの第2の構造体であることを見つける。管理ユニットは、関数Nの第2の構造体内の関数スタックNの先頭のアドレス、すなわち、第1の関数のパッチ関数のアドレスを取得する。
livepatchモジュールは、第2の構造体がホットフィックスモジュール内の1つ以上の旧関数のうちいずれか1つについて登録されているか否かを決定する。第2の構造体は、旧関数のアドレス及び旧関数の関数スタックを記憶するために使用され、第2の構造体のデータ構造が図11Aに示されている。関数は、複数回修正されてもよく、関数を修正するために使用される1つ以上の関数のアドレスは、関数の関数スタックに記憶される。
第1の構造体は、第2のコールバック関数のポインタ及び複数の旧関数のアドレスを記憶するために使用される。第2のコールバック関数は、呼び出された関数のアドレスに基づいて、呼び出された関数を修正するために使用される新関数のアドレスを検索するために使用される。第1の構造体のデータ構造が図10に示されている。第1の構造体のデータ構造については、ステップS502における対応する説明を参照する。詳細はここでは再び説明しない。
livepatchモジュールは、第1の構造体にデータを記憶するためにいくつかのアドレス空間を申請し、第1の構造体のアドレスをftraceモジュールに送信し、ftraceモジュールのインタフェースを呼び出し、第1の構造体をftraceモジュールに登録し、それにより、ftraceモジュールは、第1の構造体の受信アドレスに基づいて第1の構造体に記憶されたデータを読み取ることができる。第1の構造体は、コールバック関数のポインタ及び関数のアドレスを記憶するために使用される。livepatchモジュールは、ftraceモジュールにより提供された第1の構造体のデータ構造の定義に基づいて、livepatchモジュールのコールバック関数のポインタ及び旧関数のアドレスを第1の構造体に記録する。livepatchモジュールのコールバック関数は、livepatchモジュールに対して、旧関数のアドレスに基づいて新関数のアドレスを検索するように命令するために使用される。第1の構造体がftraceモジュールに登録されたとき、livepatchモジュールは、旧関数のアドレスをftraceモジュールに送信する。ftraceモジュールは、旧関数のアドレスに基づいて旧関数の関数ヘッダを見つけ、関数ヘッダのエントリにおけるいくつかのバイトを、ftraceモジュールのコールバック関数のポインタに置換する。ftraceモジュールのコールバック関数は、呼び出された関数のアドレスを求めて第1の構造体を検索し、第2のコールバック関数のポインタを取得するために使用される。