Kernel Module Management

Linuxカーネルモジュール管理 完全ガイド

目次

  1. はじめに
  2. カーネルモジュールアーキテクチャ
  3. モジュール情報の確認
  4. モジュールのロードとアンロード
  5. モジュールパラメータ
  6. /etc/modprobe.d/ による設定
  7. モジュールのブラックリスト
  8. /etc/modules-load.d/ による自動ロード
  9. モジュール署名とSecure Boot
  10. DKMS (Dynamic Kernel Module Support)
  11. カスタムカーネルモジュールの構築
  12. カーネルモジュールの依存関係
  13. モジュールのデバッグ
  14. 実践シナリオ
  15. モジュール管理コマンド比較表
  16. トラブルシューティング
  17. ベストプラクティス
  18. 参考資料

1. はじめに

Linuxカーネルモジュールは、カーネルの機能を動的に拡張するための仕組みである。デバイスドライバ、ファイルシステム、ネットワークプロトコルなど、多くのカーネル機能がモジュールとして実装されている。モジュールシステムにより、必要な機能だけをカーネルにロードでき、メモリ効率の向上とシステムの柔軟性が実現されている。

本ドキュメントでは、カーネルモジュールのアーキテクチャ、管理コマンド、設定方法、カスタムモジュールの開発、そしてトラブルシューティングまで、包括的に解説する。

対象読者

  • Linuxシステム管理者
  • カーネルモジュール開発者
  • SREエンジニア
  • DevOpsエンジニア

前提環境

OS: RHEL 8/9, Ubuntu 22.04/24.04, Rocky Linux 8/9
Kernel: 5.x 以降

2. カーネルモジュールアーキテクチャ

2.1 カーネルモジュールとは

カーネルモジュール(Loadable Kernel Module, LKM)は、実行中のカーネルに動的にロード・アンロードできるオブジェクトコードである。カーネルを再コンパイルしたり再起動したりすることなく、機能を追加・削除できる。

┌─────────────────────────────────────────────────────────┐
│                    ユーザ空間                             │
│  ┌─────────┐  ┌──────────┐  ┌──────────┐               │
│  │ アプリ   │  │ modprobe │  │  insmod  │               │
│  └────┬────┘  └────┬─────┘  └────┬─────┘               │
│───────┼─────────────┼────────────┼──────────────────────│
│       │         システムコール                            │
│───────┼─────────────┼────────────┼──────────────────────│
│                    カーネル空間                           │
│  ┌────────────────────────────────────────────┐         │
│  │              カーネルコア                     │         │
│  │  ┌──────┐  ┌──────┐  ┌──────┐  ┌──────┐   │         │
│  │  │ VFS  │  │ Net  │  │ MM   │  │ Sched│   │         │
│  │  └──────┘  └──────┘  └──────┘  └──────┘   │         │
│  └────────────────────────────────────────────┘         │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐              │
│  │ Module A │  │ Module B │  │ Module C │              │
│  │ (ext4)   │  │ (e1000e) │  │ (nvidia) │              │
│  └──────────┘  └──────────┘  └──────────┘              │
│                    ハードウェア                           │
│  ┌──────┐  ┌──────────┐  ┌──────────────┐              │
│  │ Disk │  │   NIC    │  │     GPU      │              │
│  └──────┘  └──────────┘  └──────────────┘              │
└─────────────────────────────────────────────────────────┘

2.2 モジュールの種類

種類説明
デバイスドライバハードウェアデバイスとの通信を処理e1000e, nvme, snd_hda_intel
ファイルシステムファイルシステムの実装ext4, xfs, btrfs, nfs
ネットワークプロトコルネットワークプロトコルの実装tcp_bbr, nf_conntrack
暗号化暗号化アルゴリズムの実装aes_x86_64, sha256_ssse3
その他仮想化、セキュリティなどkvm, vhost_net, nf_tables

2.3 モジュールの格納場所

カーネルモジュールは以下のディレクトリに格納される。

# モジュールディレクトリの構造
$ ls /lib/modules/$(uname -r)/
build   kernel    modules.alias      modules.builtin      modules.dep
extra   misc      modules.alias.bin  modules.builtin.bin  modules.dep.bin
source  updates   modules.devname    modules.order        modules.softdep
                  modules.symbols    modules.symbols.bin

# カーネルモジュールのサブディレクトリ
$ ls /lib/modules/$(uname -r)/kernel/
arch  block  crypto  drivers  fs  lib  net  security  sound  virt

# ドライバモジュールの例
$ ls /lib/modules/$(uname -r)/kernel/drivers/net/ethernet/intel/
e1000/  e1000e/  i40e/  ice/  igb/  igc/  ixgbe/  ixgbevf/

2.4 モジュールファイルの形式

# .ko (kernel object) ファイル - 圧縮されている場合もある
$ file /lib/modules/$(uname -r)/kernel/drivers/net/ethernet/intel/e1000e/e1000e.ko.xz
e1000e.ko.xz: XZ compressed data, checksum CRC64

# 解凍して確認
$ xz -dk /tmp/e1000e.ko.xz
$ file /tmp/e1000e.ko
e1000e.ko: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), BuildID[sha1]=...

3. モジュール情報の確認

3.1 lsmod - ロード済みモジュール一覧

lsmod コマンドは、現在カーネルにロードされているモジュールの一覧を表示する。内部的には /proc/modules を読みやすい形式で表示している。

# ロード済みモジュール一覧
$ lsmod
Module                  Size  Used by
nf_conntrack_netlink    49152  0
xfrm_user              40960  1
xt_addrtype            16384  2
br_netfilter           28672  0
overlay                151552  6
nf_nat                 49152  3 xt_MASQUERADE,nft_chain_nat
nf_conntrack          167936  7 xt_conntrack,nf_nat,nf_conntrack_netlink,...
nf_defrag_ipv6         24576  1 nf_conntrack
nf_defrag_ipv4         16384  1 nf_conntrack
e1000e                282624  0
ext4                  802816  1
mbcache                16384  1 ext4
jbd2                  131072  1 ext4

# モジュール数のカウント
$ lsmod | wc -l
87

# 特定のモジュールを検索
$ lsmod | grep -i nvme
nvme                   45056  3
nvme_core             110592  5 nvme
nvme_common            16384  1 nvme_core

# /proc/modules を直接確認(より詳細な情報)
$ cat /proc/modules | head -5
nf_conntrack_netlink 49152 0 - Live 0xffffffffc0a40000
xfrm_user 40960 1 - Live 0xffffffffc0a30000
xt_addrtype 16384 2 - Live 0xffffffffc0a20000
br_netfilter 28672 0 - Live 0xffffffffc0a10000
overlay 151552 6 - Live 0xffffffffc09e0000

lsmod の出力フィールド:

フィールド説明
Moduleモジュール名
Sizeモジュールのメモリサイズ(バイト)
Used byこのモジュールを使用している他のモジュールの数と名前

3.2 modinfo - モジュール詳細情報

modinfo コマンドは、カーネルモジュールの詳細情報を表示する。

# モジュールの詳細情報
$ modinfo e1000e
filename:       /lib/modules/5.15.0-91-generic/kernel/drivers/net/ethernet/intel/e1000e/e1000e.ko
license:        GPL v2
description:    Intel(R) PRO/1000 Network Driver
author:         Intel Corporation, <linux.nics@intel.com>
srcversion:     50E3A252B8D9D0B2A2FD421
alias:          pci:v00008086d00001F41sv*sd*bc*sc*i*
alias:          pci:v00008086d00001F40sv*sd*bc*sc*i*
...
depends:
retpoline:      Y
intree:         Y
name:           e1000e
vermagic:       5.15.0-91-generic SMP mod_unload modversions
sig_id:         PKCS#7
signer:         Build time autogenerated kernel key
sig_key:        76:B0:C4:...
sig_hashalgo:   sha512
signature:      30:82:...
parm:           TxIntDelay:Transmit Interrupt Delay (array of int)
parm:           TxAbsIntDelay:Transmit Absolute Interrupt Delay (array of int)
parm:           RxIntDelay:Receive Interrupt Delay (array of int)
parm:           RxAbsIntDelay:Receive Absolute Interrupt Delay (array of int)
parm:           InterruptThrottleRate:Interrupt Throttling Rate (array of int)
parm:           IntMode:Interrupt Mode (array of int)
parm:           SmartPowerDownEnable:Enable PHY smart power down (array of int)
parm:           KumeranLockLoss:Enable Kumeran lock loss workaround (array of int)
parm:           WriteProtectNVM:Write-protect NVM [WARNING] (array of int)
parm:           CrcStripping:Enable CRC Stripping, disable if your BMC needs CRC (array of int)

# 特定のフィールドだけ表示
$ modinfo -F filename e1000e
/lib/modules/5.15.0-91-generic/kernel/drivers/net/ethernet/intel/e1000e/e1000e.ko

$ modinfo -F parm e1000e
TxIntDelay:Transmit Interrupt Delay (array of int)
TxAbsIntDelay:Transmit Absolute Interrupt Delay (array of int)
RxIntDelay:Receive Interrupt Delay (array of int)
...

# ライセンス情報
$ modinfo -F license e1000e
GPL v2

# 依存モジュール
$ modinfo -F depends kvm_intel
kvm

# カーネルバージョンの確認
$ modinfo -F vermagic e1000e
5.15.0-91-generic SMP mod_unload modversions

4. モジュールのロードとアンロード

4.1 modprobe - 推奨されるモジュール管理コマンド

modprobe は依存関係を自動的に解決してモジュールをロード・アンロードする、最も推奨されるコマンドである。

# モジュールのロード
$ sudo modprobe vfat
$ lsmod | grep vfat
vfat                   20480  0
fat                    81920  1 vfat    # 依存モジュールも自動ロード

# モジュールのアンロード
$ sudo modprobe -r vfat
$ lsmod | grep vfat
(出力なし)

# パラメータ付きでロード
$ sudo modprobe e1000e InterruptThrottleRate=3000

# ドライランモード(実際にはロードしない)
$ sudo modprobe -n -v bonding
insmod /lib/modules/5.15.0-91-generic/kernel/drivers/net/bonding/bonding.ko

# 依存関係の表示
$ modprobe --show-depends ext4
insmod /lib/modules/5.15.0-91-generic/kernel/lib/crc16.ko
insmod /lib/modules/5.15.0-91-generic/kernel/fs/mbcache.ko
insmod /lib/modules/5.15.0-91-generic/kernel/fs/jbd2/jbd2.ko
insmod /lib/modules/5.15.0-91-generic/kernel/fs/ext4/ext4.ko

# 全依存モジュールを含めてアンロード
$ sudo modprobe -r --remove-dependencies bonding

# 設定ファイルを指定してロード
$ sudo modprobe -C /etc/modprobe.d/custom.conf mymodule

modprobe の主要オプション:

オプション説明
-r, --removeモジュールをアンロード
-v, --verbose詳細出力
-n, --dry-run実行せずに表示のみ
-f, --forceバージョンチェックを無視して強制ロード
-q, --quietエラーメッセージを抑制
--show-depends依存関係を表示
-C, --config設定ファイルを指定
--first-timeモジュールが既にロード済みの場合にエラー

4.2 insmod / rmmod - 低レベルモジュール管理

insmodrmmod は低レベルのモジュール管理コマンドで、依存関係を自動解決しない。

# insmod - フルパスを指定してモジュールをロード
$ sudo insmod /lib/modules/$(uname -r)/kernel/fs/fat/vfat.ko
insmod: ERROR: could not insert module: Unknown symbol in module
# 依存モジュール(fat)がロードされていないためエラー

# 依存モジュールを先にロード
$ sudo insmod /lib/modules/$(uname -r)/kernel/fs/fat/fat.ko
$ sudo insmod /lib/modules/$(uname -r)/kernel/fs/fat/vfat.ko
$ lsmod | grep fat
vfat                   20480  0
fat                    81920  1 vfat

# rmmod - モジュールをアンロード
$ sudo rmmod vfat
$ sudo rmmod fat

# 使用中のモジュールをアンロード(-f で強制)
$ sudo rmmod e1000e
rmmod: ERROR: Module e1000e is in use
$ sudo rmmod -f e1000e    # 非推奨:システム不安定の原因になりうる

# rmmod の詳細出力
$ sudo rmmod -v vfat
rmmod vfat

insmod vs modprobe 比較:

特性insmodmodprobe
パス指定フルパス必須モジュール名のみ
依存関係解決なし自動
設定ファイル参照なし/etc/modprobe.d/ を参照
ブラックリスト対応なし対応
推奨度低(デバッグ用)高(通常使用)

4.3 depmod - モジュール依存関係の更新

depmod はモジュールの依存関係データベースを生成・更新する。

# 全モジュールの依存関係を再生成
$ sudo depmod -a

# 特定のカーネルバージョンの依存関係を再生成
$ sudo depmod -a 5.15.0-91-generic

# 詳細出力で依存関係を再生成
$ sudo depmod -av 2>&1 | head -20

# ドライランモード
$ sudo depmod -n | head -20

# 依存関係ファイルの確認
$ head -20 /lib/modules/$(uname -r)/modules.dep
kernel/arch/x86/events/intel/intel-cstate.ko: 
kernel/arch/x86/events/intel/intel-uncore.ko: 
kernel/arch/x86/events/rapl.ko: 
kernel/arch/x86/crypto/crc32c-intel.ko: 
kernel/arch/x86/crypto/aesni-intel.ko: kernel/crypto/aes_generic.ko
kernel/fs/ext4/ext4.ko: kernel/fs/jbd2/jbd2.ko kernel/fs/mbcache.ko kernel/lib/crc16.ko

# modules.alias - デバイスIDとモジュールのマッピング
$ grep "pci:v00008086d0000156F" /lib/modules/$(uname -r)/modules.alias
alias pci:v00008086d0000156Fsv*sd*bc*sc*i* e1000e

# modules.symbols - エクスポートされたシンボル
$ grep "ext4" /lib/modules/$(uname -r)/modules.symbols | head -5
alias symbol:ext4_bread ext4
alias symbol:ext4_get_group_desc ext4

5. モジュールパラメータ

カーネルモジュールは、ロード時にパラメータを受け取ることができる。

# モジュールパラメータの確認
$ modinfo -p e1000e
TxIntDelay:Transmit Interrupt Delay (array of int)
TxAbsIntDelay:Transmit Absolute Interrupt Delay (array of int)
RxIntDelay:Receive Interrupt Delay (array of int)
RxAbsIntDelay:Receive Absolute Interrupt Delay (array of int)
InterruptThrottleRate:Interrupt Throttling Rate (array of int)

# パラメータ付きでモジュールをロード
$ sudo modprobe e1000e InterruptThrottleRate=3000

# 現在のパラメータ値を確認
$ cat /sys/module/e1000e/parameters/InterruptThrottleRate
3000

# sysfs からパラメータ一覧を確認
$ ls /sys/module/e1000e/parameters/
CrcStripping  IntMode  InterruptThrottleRate  KumeranLockLoss
RxAbsIntDelay  RxIntDelay  SmartPowerDownEnable  TxAbsIntDelay
TxIntDelay  WriteProtectNVM

# 書き込み可能なパラメータの変更(一部のパラメータのみ対応)
$ echo 4000 | sudo tee /sys/module/e1000e/parameters/InterruptThrottleRate
4000

# ブートパラメータでカーネルモジュールのパラメータを設定
# /etc/default/grub に追加
GRUB_CMDLINE_LINUX="e1000e.InterruptThrottleRate=3000"

# GRUB設定を反映
$ sudo grub2-mkconfig -o /boot/grub2/grub.cfg    # RHEL/CentOS
$ sudo update-grub                                 # Ubuntu/Debian

パラメータの型

説明
int整数値modprobe mymod param=42
uint符号なし整数modprobe mymod param=100
long長整数modprobe mymod param=100000
charp文字列(char pointer)modprobe mymod param="hello"
boolブール値modprobe mymod param=1 または param=Y
invbool逆ブール値modprobe mymod param=0
array of int整数配列modprobe mymod param=1,2,3

6. /etc/modprobe.d/ による設定

/etc/modprobe.d/ ディレクトリには、モジュールロード時の設定ファイルを配置する。

# 設定ファイルの一覧
$ ls /etc/modprobe.d/
blacklist.conf      dkms.conf       nvidia.conf
disable-usb.conf    iwlwifi.conf    tuned.conf

# 設定ファイルの形式
$ cat /etc/modprobe.d/example.conf

6.1 options ディレクティブ

# /etc/modprobe.d/e1000e.conf
# モジュールパラメータのデフォルト値を設定
options e1000e InterruptThrottleRate=3000 RxIntDelay=0

# /etc/modprobe.d/bonding.conf
options bonding mode=4 miimon=100 lacp_rate=1

# /etc/modprobe.d/kvm.conf
options kvm_intel nested=1 enable_apicv=1
options kvm ignore_msrs=1

6.2 alias ディレクティブ

# /etc/modprobe.d/aliases.conf
# デバイスのエイリアスを定義
alias eth0 e1000e
alias wlan0 iwlwifi

# ワイルドカードを使用したエイリアス
alias char-major-10-200 tun
alias net-pf-17 af_packet

6.3 install / remove ディレクティブ

# /etc/modprobe.d/custom-install.conf
# モジュールロード時にカスタムコマンドを実行
install pcspkr /bin/true                           # モジュールを実質無効化
install usb-storage modprobe --ignore-install usb-storage && logger "USB storage loaded"

# モジュールアンロード時にカスタムコマンドを実行
remove bonding rmmod bonding && logger "Bonding removed"

6.4 softdep ディレクティブ

# /etc/modprobe.d/softdep.conf
# ソフト依存関係を定義(ロード順序の制御)
softdep mlx4_core post: mlx4_en mlx4_ib
softdep snd-hda-intel pre: snd-hda-codec-hdmi

# pre: このモジュールの前にロードされるモジュール
# post: このモジュールの後にロードされるモジュール

7. モジュールのブラックリスト

特定のモジュールが自動的にロードされるのを防ぐ場合に使用する。

# /etc/modprobe.d/blacklist.conf
# 方法1: blacklist ディレクティブ(推奨)
blacklist nouveau          # NVIDIAオープンソースドライバを無効化
blacklist pcspkr           # PCスピーカーを無効化
blacklist floppy           # フロッピードライバを無効化
blacklist usb-storage      # USBストレージを無効化(セキュリティ目的)

# 方法2: install ディレクティブで /bin/true にリダイレクト
install nouveau /bin/true
install pcspkr /bin/false

# blacklist vs install の違い
# blacklist: 自動ロードを防ぐが、手動ロード(modprobe)は可能
# install /bin/true: 手動ロードも含めて完全にブロック

ブラックリストの実践例

# NVIDIAプロプライエタリドライバを使用する場合
$ cat /etc/modprobe.d/blacklist-nouveau.conf
blacklist nouveau
options nouveau modeset=0

# initramfs を更新して反映
$ sudo dracut --force                    # RHEL/CentOS
$ sudo update-initramfs -u              # Ubuntu/Debian

# ブラックリストの確認
$ modprobe --showconfig | grep blacklist | head -10
blacklist nouveau
blacklist pcspkr
blacklist floppy

# ブートパラメータでもブラックリスト可能
# /etc/default/grub
GRUB_CMDLINE_LINUX="modprobe.blacklist=nouveau,pcspkr"

8. /etc/modules-load.d/ による自動ロード

ブート時に自動的にロードするモジュールを指定する。

# /etc/modules-load.d/ のファイル形式
$ cat /etc/modules-load.d/modules.conf
# 1行に1つのモジュール名
# コメント行は # で開始
br_netfilter
overlay
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
nf_conntrack

# Kubernetes/Docker用の設定例
$ cat /etc/modules-load.d/k8s.conf
# Kubernetes required modules
br_netfilter
overlay
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
nf_conntrack_ipv4

# IPVS用の設定
$ cat /etc/modules-load.d/ipvs.conf
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh

# 設定の反映確認
$ sudo systemctl restart systemd-modules-load.service
$ systemctl status systemd-modules-load.service
● systemd-modules-load.service - Load Kernel Modules
     Loaded: loaded (/usr/lib/systemd/system/systemd-modules-load.service; static)
     Active: active (exited) since Mon 2024-01-15 10:00:00 JST

modules-load.d と modprobe.d の違い

項目/etc/modules-load.d//etc/modprobe.d/
目的ブート時にロードするモジュールの指定モジュールの設定(パラメータ、ブラックリストなど)
形式モジュール名のリスト設定ディレクティブ
管理者systemd-modules-load.servicemodprobe/kmod
パラメータ設定不可可能

9. モジュール署名とSecure Boot

9.1 Secure Boot とモジュール署名

Secure Boot が有効な環境では、カーネルモジュールにデジタル署名が必要となる。

# Secure Boot の状態確認
$ mokutil --sb-state
SecureBoot enabled

# モジュール署名の確認
$ modinfo -F sig_id e1000e
PKCS#7

$ modinfo -F signer e1000e
Build time autogenerated kernel key

# カーネルの署名キー情報
$ cat /proc/keys | grep -i kernel

9.2 モジュール署名の設定

# カーネル署名設定の確認
$ cat /boot/config-$(uname -r) | grep MODULE_SIG
CONFIG_MODULE_SIG=y
CONFIG_MODULE_SIG_FORCE=n
CONFIG_MODULE_SIG_ALL=y
CONFIG_MODULE_SIG_SHA512=y
CONFIG_MODULE_SIG_HASH="sha512"
CONFIG_MODULE_SIG_KEY="certs/signing_key.pem"

# モジュール署名の検証
$ cat /proc/sys/kernel/module.sig_enforce
0    # 0 = 署名チェックは警告のみ、1 = 必須

9.3 カスタムモジュールの署名

# 1. 署名用の鍵ペアを生成
$ openssl req -new -x509 -newkey rsa:2048 \
    -keyout /root/module-signing/MOK.priv \
    -outform DER -out /root/module-signing/MOK.der \
    -nodes -days 36500 \
    -subj "/CN=Custom Module Signing Key/"

# 2. MOK (Machine Owner Key) を登録
$ sudo mokutil --import /root/module-signing/MOK.der
# パスワードを設定(再起動時に必要)

# 3. 再起動してMOK登録を完了(UEFIメニューで承認)
$ sudo reboot

# 4. モジュールに署名
$ sudo /usr/src/kernels/$(uname -r)/scripts/sign-file \
    sha256 \
    /root/module-signing/MOK.priv \
    /root/module-signing/MOK.der \
    /path/to/mymodule.ko

# 5. 署名の確認
$ modinfo /path/to/mymodule.ko | grep sig
sig_id:         PKCS#7
signer:         Custom Module Signing Key
sig_key:        XX:XX:XX:...
sig_hashalgo:   sha256

# 6. 登録済みMOKの一覧
$ mokutil --list-enrolled

10. DKMS (Dynamic Kernel Module Support)

DKMSは、カーネルのアップデート時にサードパーティのカーネルモジュールを自動的にリビルドする仕組みである。

10.1 DKMSのインストール

# RHEL/CentOS/Rocky
$ sudo dnf install dkms kernel-devel kernel-headers

# Ubuntu/Debian
$ sudo apt install dkms linux-headers-$(uname -r)

10.2 DKMSの基本操作

# DKMSに登録されたモジュールの一覧
$ dkms status
nvidia/535.129.03, 5.15.0-91-generic, x86_64: installed
virtualbox/7.0.12, 5.15.0-91-generic, x86_64: installed

# モジュールの追加
$ sudo dkms add -m mymodule -v 1.0
# または dkms.conf があるディレクトリを指定
$ sudo dkms add /usr/src/mymodule-1.0/

# モジュールのビルド
$ sudo dkms build -m mymodule -v 1.0

# モジュールのインストール
$ sudo dkms install -m mymodule -v 1.0

# モジュールのアンインストール
$ sudo dkms uninstall -m mymodule -v 1.0

# モジュールの削除(DKMSから完全に除去)
$ sudo dkms remove -m mymodule -v 1.0 --all

10.3 DKMS設定ファイル(dkms.conf)

# /usr/src/mymodule-1.0/dkms.conf
PACKAGE_NAME="mymodule"
PACKAGE_VERSION="1.0"
BUILT_MODULE_NAME[0]="mymodule"
DEST_MODULE_LOCATION[0]="/updates"
AUTOINSTALL="yes"
REMAKE_INITRD="no"
CLEAN="make clean"
MAKE[0]="make -C /lib/modules/${kernelver}/build M=${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION}/build"

# 複数モジュールの場合
BUILT_MODULE_NAME[0]="mymodule_core"
BUILT_MODULE_LOCATION[0]="core/"
DEST_MODULE_LOCATION[0]="/updates"
BUILT_MODULE_NAME[1]="mymodule_io"
BUILT_MODULE_LOCATION[1]="io/"
DEST_MODULE_LOCATION[1]="/updates"

10.4 DKMSの実践例 - NVIDIAドライバ

# NVIDIAドライバのDKMS状態確認
$ dkms status | grep nvidia
nvidia/535.129.03, 5.15.0-91-generic, x86_64: installed
nvidia/535.129.03, 5.15.0-92-generic, x86_64: installed

# カーネルアップデート後の自動リビルド確認
$ sudo dkms autoinstall -k $(uname -r)

# 手動でのリビルド(トラブル時)
$ sudo dkms remove nvidia/535.129.03 -k $(uname -r)
$ sudo dkms build nvidia/535.129.03 -k $(uname -r)
$ sudo dkms install nvidia/535.129.03 -k $(uname -r)

11. カスタムカーネルモジュールの構築

11.1 Hello Worldモジュール

// /usr/src/hello-1.0/hello.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Hello World kernel module");
MODULE_VERSION("1.0");

static int __init hello_init(void)
{
    printk(KERN_INFO "Hello: Module loaded successfully\n");
    printk(KERN_INFO "Hello: Kernel version %s\n", UTS_RELEASE);
    return 0;    // 0 = 成功、負の値 = エラー
}

static void __exit hello_exit(void)
{
    printk(KERN_INFO "Hello: Module unloaded successfully\n");
}

module_init(hello_init);
module_exit(hello_exit);

11.2 Makefileの作成

# /usr/src/hello-1.0/Makefile
obj-m += hello.o

# 複数ソースファイルの場合
# obj-m += mymodule.o
# mymodule-objs := file1.o file2.o file3.o

KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

all:
	$(MAKE) -C $(KDIR) M=$(PWD) modules

clean:
	$(MAKE) -C $(KDIR) M=$(PWD) clean

install:
	$(MAKE) -C $(KDIR) M=$(PWD) modules_install

.PHONY: all clean install

ビルドと実行

# ビルドに必要なパッケージのインストール
$ sudo dnf install kernel-devel kernel-headers gcc make    # RHEL/CentOS
$ sudo apt install linux-headers-$(uname -r) build-essential  # Ubuntu

# ビルド
$ cd /usr/src/hello-1.0/
$ make
make -C /lib/modules/5.15.0-91-generic/build M=/usr/src/hello-1.0 modules
make[1]: Entering directory '/usr/src/linux-headers-5.15.0-91-generic'
  CC [M]  /usr/src/hello-1.0/hello.o
  MODPOST /usr/src/hello-1.0/Module.symvers
  CC [M]  /usr/src/hello-1.0/hello.mod.o
  LD [M]  /usr/src/hello-1.0/hello.ko
  BTF [M] /usr/src/hello-1.0/hello.ko
make[1]: Leaving directory '/usr/src/linux-headers-5.15.0-91-generic'

# 生成されたファイルの確認
$ ls -la hello.*
-rw-r--r-- 1 root root   458 Jan 15 10:00 hello.c
-rw-r--r-- 1 root root 12680 Jan 15 10:01 hello.ko
-rw-r--r-- 1 root root   458 Jan 15 10:01 hello.mod
-rw-r--r-- 1 root root  1096 Jan 15 10:01 hello.mod.c
-rw-r--r-- 1 root root  4480 Jan 15 10:01 hello.mod.o
-rw-r--r-- 1 root root  9336 Jan 15 10:01 hello.o

# モジュール情報の確認
$ modinfo hello.ko
filename:       /usr/src/hello-1.0/hello.ko
version:        1.0
description:    A simple Hello World kernel module
author:         Your Name
license:        GPL
srcversion:     A1B2C3D4E5F6G7H8I9J0K1
depends:
retpoline:      Y
name:           hello
vermagic:       5.15.0-91-generic SMP mod_unload modversions

# モジュールのロード
$ sudo insmod hello.ko
$ dmesg | tail -2
[12345.678901] Hello: Module loaded successfully
[12345.678902] Hello: Kernel version 5.15.0-91-generic

# モジュールの確認
$ lsmod | grep hello
hello                  16384  0

# モジュールのアンロード
$ sudo rmmod hello
$ dmesg | tail -1
[12350.123456] Hello: Module unloaded successfully

11.3 パラメータ付きモジュール

// /usr/src/param_module-1.0/param_module.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/moduleparam.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A kernel module with parameters");
MODULE_VERSION("1.0");

// 整数パラメータ
static int count = 1;
module_param(count, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(count, "Number of times to print the message");

// 文字列パラメータ
static char *message = "Hello";
module_param(message, charp, S_IRUGO);
MODULE_PARM_DESC(message, "The message to print");

// ブールパラメータ
static bool verbose = false;
module_param(verbose, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(verbose, "Enable verbose output");

// 配列パラメータ
static int arr_values[5] = {0};
static int arr_count = 0;
module_param_array(arr_values, int, &arr_count, S_IRUGO);
MODULE_PARM_DESC(arr_values, "An array of integer values");

static int __init param_init(void)
{
    int i;

    if (verbose)
        printk(KERN_INFO "param_module: Verbose mode enabled\n");

    for (i = 0; i < count; i++) {
        printk(KERN_INFO "param_module: [%d] %s\n", i, message);
    }

    if (arr_count > 0) {
        printk(KERN_INFO "param_module: Array values (%d elements):\n", arr_count);
        for (i = 0; i < arr_count; i++) {
            printk(KERN_INFO "  arr_values[%d] = %d\n", i, arr_values[i]);
        }
    }

    return 0;
}

static void __exit param_exit(void)
{
    printk(KERN_INFO "param_module: Module unloaded\n");
}

module_init(param_init);
module_exit(param_exit);
# ビルドとロード
$ make
$ sudo insmod param_module.ko count=3 message="World" verbose=1 arr_values=10,20,30

$ dmesg | tail -8
[12400.000001] param_module: Verbose mode enabled
[12400.000002] param_module: [0] World
[12400.000003] param_module: [1] World
[12400.000004] param_module: [2] World
[12400.000005] param_module: Array values (3 elements):
[12400.000006]   arr_values[0] = 10
[12400.000007]   arr_values[1] = 20
[12400.000008]   arr_values[2] = 30

# sysfs からパラメータを確認
$ cat /sys/module/param_module/parameters/count
3
$ cat /sys/module/param_module/parameters/message
World
$ cat /sys/module/param_module/parameters/verbose
Y

# 書き込み可能なパラメータを変更(S_IWUSR を指定したもの)
$ echo 5 | sudo tee /sys/module/param_module/parameters/count
5

パラメータ権限フラグ

フラグ説明
S_IRUGO0444全ユーザが読み取り可能
S_IWUSR0200root が書き込み可能
S_IRUGO | S_IWUSR0644全ユーザ読み取り、root 書き込み
00000sysfs に表示されない

12. カーネルモジュールの依存関係

12.1 依存関係の仕組み

# モジュールの依存関係を確認
$ modprobe --show-depends xfs
insmod /lib/modules/5.15.0-91-generic/kernel/lib/libcrc32c.ko
insmod /lib/modules/5.15.0-91-generic/kernel/fs/xfs/xfs.ko

# modules.dep ファイルの内容
$ grep "^kernel/fs/ext4" /lib/modules/$(uname -r)/modules.dep
kernel/fs/ext4/ext4.ko: kernel/fs/jbd2/jbd2.ko kernel/fs/mbcache.ko kernel/lib/crc16.ko

# 依存関係ツリーの可視化
$ modprobe --show-depends kvm_intel
insmod /lib/modules/5.15.0-91-generic/kernel/arch/x86/kvm/kvm.ko
insmod /lib/modules/5.15.0-91-generic/kernel/arch/x86/kvm/kvm-intel.ko

12.2 ソフト依存関係

# modules.softdep の確認
$ cat /lib/modules/$(uname -r)/modules.softdep
softdep mlx4_core post: mlx4_en mlx4_ib
softdep snd-hda-intel pre: snd-hda-codec-hdmi

# カスタムソフト依存関係の設定
$ cat /etc/modprobe.d/softdep-custom.conf
softdep mydriver pre: dependency_module
softdep mydriver post: optional_module

12.3 シンボル依存関係

# モジュールがエクスポートするシンボル
$ cat /lib/modules/$(uname -r)/modules.symbols | grep nf_conntrack | head -5
alias symbol:nf_conntrack_destroy nf_conntrack
alias symbol:nf_conntrack_find_get nf_conntrack
alias symbol:nf_conntrack_alloc nf_conntrack

# カスタムモジュールでのシンボルエクスポート
# EXPORT_SYMBOL(my_function);         // GPL以外のモジュールからも利用可能
# EXPORT_SYMBOL_GPL(my_function);     // GPLモジュールからのみ利用可能

13. モジュールのデバッグ

13.1 dmesg によるカーネルログ確認

# カーネルメッセージの表示
$ dmesg | tail -20

# リアルタイムでカーネルメッセージを監視
$ dmesg -w

# 特定のモジュールに関するメッセージを検索
$ dmesg | grep -i "e1000e"
[    2.345678] e1000e 0000:00:19.0: 2.000 Gb/s available PCIe bandwidth...
[    2.345789] e1000e 0000:00:19.0 eth0: (PCI Express:2.5GT/s:Width x1)...
[    2.345890] e1000e 0000:00:19.0 eth0: Intel(R) PRO/1000 Network Connection
[    2.345901] e1000e 0000:00:19.0 eth0: MAC: 11, PHY: 12, PBA No: FFFFFF-0FF

# ログレベルでフィルタ
$ dmesg --level=err,warn
[    1.234567] ACPI Error: [DSDT] Namespace lookup failure...
[    2.345678] Warning: CPU: 0 PID: 1 at ...

# タイムスタンプ付きで表示
$ dmesg -T | tail -10
[Mon Jan 15 10:00:01 2024] Hello: Module loaded successfully

# カーネルメッセージをクリア(root権限)
$ sudo dmesg -c

# ログレベルの設定
$ cat /proc/sys/kernel/printk
4    4    1    7
# console_loglevel  default_message_loglevel  minimum_console_loglevel  default_console_loglevel

# ログレベルを変更(デバッグ用に全メッセージを表示)
$ echo 8 | sudo tee /proc/sys/kernel/printk

13.2 printk によるデバッグ出力

// printk のログレベル
#include <linux/kernel.h>

// ログレベル定数
printk(KERN_EMERG   "Emergency: System is unusable\n");      // 0
printk(KERN_ALERT   "Alert: Action must be taken immediately\n"); // 1
printk(KERN_CRIT    "Critical: Critical conditions\n");       // 2
printk(KERN_ERR     "Error: Error conditions\n");             // 3
printk(KERN_WARNING "Warning: Warning conditions\n");         // 4
printk(KERN_NOTICE  "Notice: Normal but significant\n");      // 5
printk(KERN_INFO    "Info: Informational\n");                 // 6
printk(KERN_DEBUG   "Debug: Debug-level messages\n");         // 7

// 推奨: pr_* マクロの使用
pr_emerg("Emergency message\n");
pr_alert("Alert message\n");
pr_crit("Critical message\n");
pr_err("Error message\n");
pr_warn("Warning message\n");
pr_notice("Notice message\n");
pr_info("Info message\n");
pr_debug("Debug message\n");    // CONFIG_DYNAMIC_DEBUG が有効な場合のみ

// デバイスドライバ向け: dev_* マクロ
dev_err(&pdev->dev, "Device error: %d\n", err);
dev_warn(&pdev->dev, "Device warning\n");
dev_info(&pdev->dev, "Device info\n");
dev_dbg(&pdev->dev, "Device debug\n");

13.3 動的デバッグ (Dynamic Debug)

# Dynamic Debug の有効化(カーネルコンフィグで CONFIG_DYNAMIC_DEBUG=y が必要)
$ cat /sys/kernel/debug/dynamic_debug/control | head -10

# 特定モジュールのデバッグを有効化
$ echo "module e1000e +p" | sudo tee /sys/kernel/debug/dynamic_debug/control

# 特定ファイルのデバッグを有効化
$ echo "file drivers/net/ethernet/intel/e1000e/netdev.c +p" | \
    sudo tee /sys/kernel/debug/dynamic_debug/control

# 特定関数のデバッグを有効化
$ echo "func e1000_open +p" | sudo tee /sys/kernel/debug/dynamic_debug/control

# デバッグ出力にスタックトレースを追加
$ echo "module mymodule +pt" | sudo tee /sys/kernel/debug/dynamic_debug/control

# デバッグを無効化
$ echo "module e1000e -p" | sudo tee /sys/kernel/debug/dynamic_debug/control

14. 実践シナリオ

14.1 ストレージドライバの管理

# NVMe ドライバの確認
$ lsmod | grep nvme
nvme                   45056  3
nvme_core             110592  5 nvme
nvme_common            16384  1 nvme_core

# NVMe デバイスの確認
$ lsblk | grep nvme
nvme0n1      259:0    0  477G  0 disk
├─nvme0n1p1  259:1    0    1G  0 part /boot/efi
├─nvme0n1p2  259:2    0    1G  0 part /boot
└─nvme0n1p3  259:3    0  475G  0 part

# SCSI/SAS ドライバの管理
$ lsmod | grep -E "sd_mod|scsi"
sd_mod                 57344  3
scsi_mod              253952  5 sd_mod,sg,sr_mod,libata,scsi_transport_sas

# iSCSIイニシエータの設定
$ sudo modprobe iscsi_tcp
$ lsmod | grep iscsi
iscsi_tcp              28672  0
libiscsi_tcp           32768  1 iscsi_tcp
libiscsi               61440  2 libiscsi_tcp,iscsi_tcp
scsi_transport_iscsi   122880  2 iscsi_tcp,libiscsi

# multipath ドライバ
$ sudo modprobe dm_multipath
$ sudo modprobe dm_round_robin
$ lsmod | grep dm_
dm_multipath           32768  0
dm_round_robin         16384  0
dm_mod                155648  3 dm_multipath,dm_log,dm_mirror

14.2 GPUドライバの管理

# 現在のGPUドライバを確認
$ lspci | grep -i vga
00:02.0 VGA compatible controller: Intel Corporation...
01:00.0 VGA compatible controller: NVIDIA Corporation...

# 使用中のドライバ確認
$ lspci -k -s 01:00.0
01:00.0 VGA compatible controller: NVIDIA Corporation GA106M [GeForce RTX 3060]
        Subsystem: Dell GA106M [GeForce RTX 3060 Mobile]
        Kernel driver in use: nvidia
        Kernel modules: nvidia_drm, nvidia

# NVIDIAプロプライエタリドライバのロード
$ lsmod | grep nvidia
nvidia_drm             73728  4
nvidia_modeset       1232896  6 nvidia_drm
nvidia              56270848  162 nvidia_modeset
drm_kms_helper        217088  1 nvidia_drm
drm                   548864  8 drm_kms_helper,nvidia,nvidia_drm

# nouveauからNVIDIAプロプライエタリへの切り替え手順
# 1. nouveauをブラックリスト
$ cat /etc/modprobe.d/blacklist-nouveau.conf
blacklist nouveau
options nouveau modeset=0

# 2. initramfs を更新
$ sudo dracut --force                  # RHEL
$ sudo update-initramfs -u            # Ubuntu

# 3. 再起動後にNVIDIAドライバをインストール
$ sudo dnf install nvidia-driver       # RHEL(RPM Fusion利用)
$ sudo apt install nvidia-driver-535   # Ubuntu

# 4. ドライバの動作確認
$ nvidia-smi
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 535.129.03   Driver Version: 535.129.03   CUDA Version: 12.2     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce RTX 3060    Off  | 00000000:01:00.0  On |                  N/A |
|  0%   40C    P8     8W / 170W |    256MiB /  12288MiB|      0%      Default |
+-------------------------------+----------------------+----------------------+

14.3 ネットワークドライバの管理

# ネットワークインターフェースとドライバの対応
$ ethtool -i eth0
driver: e1000e
version: 3.8.7-k
firmware-version: 0.6-4
bus-info: 0000:00:19.0
supports-statistics: yes
supports-test: yes
supports-eeprom-access: yes
supports-register-dump: yes
supports-priv-flags: yes

# ドライバのバインド/アンバインド
$ echo "0000:00:19.0" | sudo tee /sys/bus/pci/drivers/e1000e/unbind
$ echo "0000:00:19.0" | sudo tee /sys/bus/pci/drivers/e1000e/bind

# ボンディング(チーミング)の設定
$ sudo modprobe bonding mode=4 miimon=100
$ lsmod | grep bonding
bonding               196608  0

# VLAN モジュール
$ sudo modprobe 8021q
$ lsmod | grep 8021q
8021q                  36864  0
garp                   16384  1 8021q
mrp                    20480  1 8021q

# Virtio ネットワークドライバ(仮想環境)
$ sudo modprobe virtio_net
$ lsmod | grep virtio
virtio_net             57344  0
virtio_ring            36864  2 virtio_net,virtio_pci
virtio                 16384  2 virtio_net,virtio_pci

# SR-IOV の確認
$ lspci | grep -i virtual
03:10.0 Ethernet controller: Intel Corporation 82599 Ethernet Controller Virtual Function
$ echo 4 | sudo tee /sys/class/net/eth0/device/sriov_numvfs

15. モジュール管理コマンド比較表

コマンド用途依存関係解決設定ファイル参照推奨度
lsmodロード済みモジュール一覧--
modinfoモジュール情報表示--
modprobeモジュールのロード/アンロードありあり
modprobe -rモジュールのアンロードありあり
insmodモジュールのロードなしなし
rmmodモジュールのアンロードなしなし
depmod依存関係DB更新--
dkms動的カーネルモジュールサポート-あり

16. トラブルシューティング

16.1 よくある問題と解決策

モジュールがロードできない

# エラー: Unknown symbol
$ sudo modprobe mymodule
modprobe: ERROR: could not insert 'mymodule': Unknown symbol in module (-1)
# 対処: 依存モジュールを先にロードする
$ modprobe --show-depends mymodule
$ sudo depmod -a

# エラー: Invalid module format
$ sudo modprobe mymodule
modprobe: ERROR: could not insert 'mymodule': Invalid module format
# 対処: カーネルバージョンの不一致 - モジュールを再ビルド
$ uname -r
$ modinfo mymodule | grep vermagic

# エラー: Operation not permitted (Secure Boot)
$ sudo modprobe mymodule
modprobe: ERROR: could not insert 'mymodule': Operation not permitted
# 対処: モジュールに署名するか、Secure Bootを無効化
$ mokutil --sb-state
$ sudo mokutil --disable-validation

# エラー: Module is in use
$ sudo rmmod e1000e
rmmod: ERROR: Module e1000e is in use
# 対処: 使用中のプロセスを確認
$ lsmod | grep e1000e
e1000e                282624  1

モジュールの依存関係エラー

# 依存関係の再構築
$ sudo depmod -a

# 依存関係ファイルの確認
$ cat /lib/modules/$(uname -r)/modules.dep | grep mymodule

# キャッシュの再構築
$ sudo dracut --force    # RHEL/CentOS
$ sudo update-initramfs -u  # Ubuntu/Debian

DKMS関連のトラブル

# DKMS ビルドエラーの確認
$ sudo dkms build -m mymodule -v 1.0 2>&1 | tail -20

# DKMSログの確認
$ cat /var/lib/dkms/mymodule/1.0/build/make.log

# カーネルヘッダの確認
$ ls /usr/src/kernels/$(uname -r)/     # RHEL
$ ls /usr/src/linux-headers-$(uname -r)/  # Ubuntu

# カーネルヘッダのインストール
$ sudo dnf install kernel-devel-$(uname -r)     # RHEL
$ sudo apt install linux-headers-$(uname -r)    # Ubuntu

16.2 デバッグ手法

# strace でモジュールロードプロセスを追跡
$ sudo strace -e trace=open,read,write modprobe mymodule 2>&1 | head -30

# カーネルログのリアルタイム監視
$ sudo journalctl -kf

# モジュールの詳細ロードログ
$ sudo modprobe -v mymodule

# sysfs からモジュール状態を確認
$ ls /sys/module/mymodule/
coresize  holders  initsize  initstate  notes  parameters  refcnt  sections  taint  uevent

$ cat /sys/module/mymodule/initstate
live    # live, coming, going のいずれか

$ cat /sys/module/mymodule/refcnt
0       # 参照カウント(0なら安全にアンロード可能)

17. ベストプラクティス

17.1 運用上のベストプラクティス

  1. modprobe を使用する: insmod/rmmod ではなく modprobe を使用する。依存関係の自動解決とブラックリスト対応が行われる。

  2. 設定は /etc/modprobe.d/ に配置する: モジュールパラメータの変更は設定ファイルに記載し、一貫性と再現性を確保する。

  3. 不要なモジュールはブラックリストに追加する: セキュリティ強化のため、使用しないモジュール(USBストレージ、ファイルシステムなど)をブラックリストに追加する。

  4. カーネルアップデート後のテスト: カーネルアップデート後はモジュールの動作を確認する。DKMSを使用している場合は自動リビルドが行われるが、確認は必要。

  5. DKMS を活用する: サードパーティモジュールはDKMSで管理し、カーネルアップデート時の自動リビルドを確実にする。

17.2 セキュリティのベストプラクティス

# 1. 不要なモジュールの無効化
$ cat /etc/modprobe.d/security-hardening.conf
# USB ストレージの無効化
install usb-storage /bin/true

# ファイルシステムの無効化
install cramfs /bin/true
install freevxfs /bin/true
install jffs2 /bin/true
install hfs /bin/true
install hfsplus /bin/true
install squashfs /bin/true
install udf /bin/true

# ネットワークプロトコルの無効化
install dccp /bin/true
install sctp /bin/true
install rds /bin/true
install tipc /bin/true

# 2. モジュール署名の強制
# カーネルコンフィグ
CONFIG_MODULE_SIG=y
CONFIG_MODULE_SIG_FORCE=y

# 3. カーネルロックダウン
$ cat /sys/kernel/security/lockdown
none [integrity] confidentiality

17.3 パフォーマンスのベストプラクティス

# 1. 不要なモジュールをロードしない
$ lsmod | wc -l    # ロード済みモジュール数を確認

# 2. モジュールパラメータの最適化
$ cat /etc/modprobe.d/performance.conf
# ネットワーク割り込みの最適化
options e1000e InterruptThrottleRate=8000

# NVMeのキュー深度設定
options nvme_core default_ps_max_latency_us=0

# 3. initramfsの最適化(不要なモジュールを除外)
# /etc/dracut.conf.d/optimization.conf (RHEL)
omit_drivers+=" floppy pcspkr nouveau "

18. 参考資料

公式ドキュメント

主要ファイルパス

パス説明
/lib/modules/$(uname -r)/カーネルモジュールのルートディレクトリ
/lib/modules/$(uname -r)/kernel/カーネルに含まれるモジュール
/lib/modules/$(uname -r)/extra/サードパーティモジュール
/lib/modules/$(uname -r)/updates/更新されたモジュール
/lib/modules/$(uname -r)/modules.depモジュール依存関係DB
/lib/modules/$(uname -r)/modules.aliasデバイスエイリアスDB
/etc/modprobe.d/モジュール設定ディレクトリ
/etc/modules-load.d/自動ロードモジュール設定
/proc/modulesロード済みモジュール情報
/sys/module/モジュールのsysfsインターフェース

関連 man ページ

man modprobe
man modinfo
man lsmod
man insmod
man rmmod
man depmod
man modprobe.d
man modules-load.d
man dkms

ドキュメント情報:

  • 作成日: 2024年1月
  • 対象: Linux カーネルモジュール管理
  • バージョン: 1.0
  • 著者: AI Generated Technical Documentation