Linux カーネルに機能を追加したいとします。
したがって、最初に頭に浮かぶアイデアは、コードを追加してカーネルを強化し、コードをコンパイルして新しいカーネルを起動するというものです。
しかし、このプロセスには次のような欠点があります。
- 追加されたコードにより、カーネルのサイズが永続的に増加します。
- 変更をコンパイルするには、カーネル全体を再度コンパイルする必要があります。
- これは、変更を有効にするにはマシンを再起動する必要があることを意味します。
上記の問題の解決策は、LKM の概念です。
LKM は、ローダブル カーネル モジュール (LKM) の略です。名前が示すように、LKM は実行時にカーネルに直接ロードできるモジュールです。
ロード可能なカーネル モジュールは、上記のすべての欠点を克服します。
- モジュールは個別にコンパイルできます
- マシンを再起動せずに、実行時にモジュールをカーネルにロードできます。
- モジュールはいつでもアンロードできるため、カーネル サイズに永続的な影響はありません。
LKM の作成方法
基本的なロード可能なカーネル モジュールを作成しましょう。
#include <linux/module.h> #include <linux/kernel.h> int init_module(void) { printk(KERN_INFO "Welcome.....\n"); return 0; } void cleanup_module(void) { printk(KERN_INFO "Bye....\n"); }
したがって、上記のコードは基本的な LKM であることがわかります。
- 「init_module」と「cleanup_module」という名前は、LKM の標準的な名前です。
- よく見ると、「printf」の代わりに「printk」を使用していることがわかります。これは、通常の C プログラミングではなく、通常のユーザー レベルのプログラミングとは少し異なるカーネル レベルのプログラミングであるためです。
- コードをコンパイルするには、ヘッダー module.h と kernel.h をインクルードする必要があります。
LKM のコンパイル方法
上記の LKM をコンパイルするために、次の Makefile を使用しました:
obj-m += lkm.o all: sudo make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: sudo make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
上記のキーワード「sudo」で始まるコマンドには、左から 1 つのタブ スペースが必要であることに注意してください。
したがって、上記のコマンドを実行すると、次の出力が観察されます:
make: Entering directory `/usr/src/linux-headers-2.6.32-21-generic' CC [M] /home/himanshu/practice/lkm.o Building modules, stage 2. MODPOST 1 modules CC /home/himanshu/practice/lkm.mod.o LD [M] /home/himanshu/practice/lkm.ko make: Leaving directory `/usr/src/linux-headers-2.6.32-21-generic'
上記のコンパイルが成功すると、コンパイルが行われたのと同じディレクトリに .ko ファイルが見つかります。
この .ko ファイルは、カーネルにロードされるモジュールです。 modinfo ユーティリティを使用して、このモジュールに関する情報を取得できます:
$ modinfo lkm.ko filename: lkm.ko srcversion: 19967CB3EAB7B31E643E006 depends: vermagic: 2.6.32.11+drm33.2 SMP mod_unload modversions
したがって、ユーティリティ「modinfo」がこのモジュールに関する情報を提供していることがわかります。
LKM の読み込み方法
モジュールのコンパイルと作成が成功したら、カーネルに挿入して、実行時にロードされるようにします。モジュールの挿入は、次の 2 つのユーティリティを使用して行うことができます:
- modprobe
- インモッド
2 つの違いは、モジュールが他のモジュールに依存している場合、そのモジュールが最初にロードされ、次にメイン モジュールがロードされるという事実を「modprobe」が処理するという事実にあります。一方、「insmod」ユーティリティは、モジュール (名前が指定されている) をカーネルに挿入するだけです。
したがって、「modprobe」の方が優れたユーティリティですが、このモジュールは他のモジュールに依存していないため、「insmod」のみを使用します。
したがって、モジュールを挿入するには、次のコマンドを使用します:
$ sudo insmod ./lkm.ko
このコマンドでエラーが発生しない場合は、LKM がカーネルに正常にロードされたことを意味します。
LKM をアンロードするには、次のコマンドを使用します:
$ sudo rmmod lkm.ko
繰り返しますが、このコマンドでエラーが発生しない場合は、LKM がカーネルで正常にアンロードされたことを意味します。
モジュールが正しくロードおよびアンロードされたことを確認するには、dmesg ユーティリティを使用して、カーネルによって記録された最後のログ セットを提供します。他のすべてのログの中に次の 2 行が表示されます:
.... .... [ 4048.333756] Welcome..... [ 4084.205143] Bye....
コードに戻って確認すると、これらがコード内の 2 つの関数からのログであることがわかります。
したがって、「insmod」が呼び出されたときに 1 つの関数が呼び出され、「rmmod」が呼び出されたときに別の関数が呼び出されたことがわかります。
これは単なるダミー LKM でした。このようにして、多くの LKM (意味のあるタスクを実行する) が Linux カーネル内で動作します。