Linux Kernel Architecture Overview
Linux Kernel Architecture Overview — 包括的技術解説
目次
- はじめに
- Linuxカーネルの歴史と設計哲学
- モノリシックカーネル設計
- カーネル空間とユーザー空間
- システムコールインターフェース
- カーネルサブシステムの全体像
- ブートプロセス
- カーネルによるハードウェアとソフトウェアの仲介
- カーネルの設定とビルド
- カーネルのデバッグと監視
- 最新のカーネル動向
- まとめ
1. はじめに
Linuxカーネルは、現代のコンピューティングインフラストラクチャにおいて最も重要なソフトウェアコンポーネントの一つである。スマートフォン(Android)からスーパーコンピュータ、クラウドインフラ、組み込みシステム、IoTデバイスに至るまで、Linuxカーネルはあらゆる場所で動作している。本記事では、Linuxカーネルのアーキテクチャを包括的に解説し、その内部構造、設計思想、および実際の設定例を通じて、カーネルの全容を明らかにする。
1.1 カーネルとは何か
カーネル(kernel)とは、オペレーティングシステム(OS)の中核部分であり、ハードウェアとソフトウェアの間を仲介する役割を果たす。具体的には以下の責務を担う。
- プロセス管理: プロセスの生成、スケジューリング、終了
- メモリ管理: 物理メモリと仮想メモリの管理、ページング
- ファイルシステム: ディスク上のデータへのアクセス抽象化
- デバイス管理: ハードウェアデバイスとの通信
- ネットワーク: TCP/IPスタックの実装とネットワーク通信
- セキュリティ: アクセス制御、権限管理
1.2 Linuxカーネルの規模
2024年時点で、Linuxカーネルのソースコードは約3,500万行に達している。これは世界最大級のオープンソースプロジェクトの一つであり、数千人の開発者が継続的に貢献している。
# カーネルソースコードの行数を確認する例
$ cloc linux-6.8/
Language files blank comment code
-------------------------------------------------------------------------------
C 28916 3214567 2876543 21345678
C/C++ Header 21345 654321 876543 6789012
Assembly 1234 54321 23456 345678
...
2. Linuxカーネルの歴史と設計哲学
2.1 誕生の経緯
Linuxカーネルは1991年、フィンランドのヘルシンキ大学の学生であったLinus Torvaldsによって開発が開始された。当初はIntel 80386プロセッサ向けの小規模なカーネルであったが、オープンソースとして公開されたことで急速に成長した。
主要なマイルストーン:
| バージョン | 年 | 主な特徴 |
|---|---|---|
| 0.01 | 1991 | 最初のリリース、タスクスイッチングとコンソール |
| 1.0 | 1994 | ネットワーキングサポート |
| 2.0 | 1996 | SMP(対称型マルチプロセッシング)サポート |
| 2.4 | 2001 | USB、ISA Plug-and-Play |
| 2.6 | 2003 | preemptionサポート、NPTL |
| 3.0 | 2011 | バージョニング方式の変更 |
| 4.0 | 2015 | ライブパッチング |
| 5.0 | 2019 | Adiantumファイルシステム暗号化 |
| 6.0 | 2022 | Rust言語サポートの初期導入 |
2.2 設計哲学
Linuxカーネルの設計は以下の原則に基づいている。
UNIX哲学の継承
LinuxはUNIXの設計哲学を強く受け継いでいる。
- 「すべてはファイルである」: デバイス、プロセス情報、カーネルパラメータもファイルとして抽象化される
- 小さなツールの組み合わせ: カーネル自体もモジュール化され、機能ごとに分離されている
- テキストベースのインターフェース:
/procや/sysファイルシステムによるテキストベースの設定
# すべてがファイルとして見える例
# デバイスファイル
$ ls -la /dev/sda
brw-rw---- 1 root disk 8, 0 Jan 15 10:00 /dev/sda
# プロセス情報
$ cat /proc/1/status
Name: systemd
State: S (sleeping)
Tgid: 1
Pid: 1
PPid: 0
...
# カーネルパラメータ
$ cat /proc/sys/vm/swappiness
60
# sysfsによるハードウェア情報
$ cat /sys/class/net/eth0/speed
1000
実用主義
Linuxカーネルの開発は、理論的な純粋さよりも実用性を重視する。Linus Torvaldsは「理論より実践」のアプローチを一貫して支持しており、パフォーマンスと使いやすさのバランスを重要視している。
後方互換性
カーネルのユーザー空間ABI(Application Binary Interface)は極めて強固に保護されている。「ユーザー空間を壊すな」(Don't break userspace)というルールは、Linuxカーネル開発における最も重要な原則の一つである。
2.3 開発モデル
Linuxカーネルは、時間ベースのリリースモデルを採用している。
マージウィンドウ(2週間)
↓
rc1 → rc2 → rc3 → ... → rc7 → リリース
(各rcは約1週間)
全体のリリースサイクル: 約9〜10週間
各リリースの流れ:
- マージウィンドウ: 新機能のプルリクエストが受け入れられる2週間
- RC(Release Candidate)期間: バグ修正のみが受け入れられる
- 安定版リリース: テストが十分と判断された時点でリリース
# 現在のカーネルバージョンを確認
$ uname -r
6.8.0-40-generic
# カーネルのリリース情報
$ cat /proc/version
Linux version 6.8.0-40-generic (buildd@lcy02-amd64-080)
(x86_64-linux-gnu-gcc-13 (Ubuntu 13.2.0-23ubuntu4) 13.2.0,
GNU ld (GNU Binutils for Ubuntu) 2.42)
#40-Ubuntu SMP PREEMPT_DYNAMIC Thu Jan 16 14:25:29 UTC 2025
3. モノリシックカーネル設計
3.1 カーネルアーキテクチャの分類
OSカーネルのアーキテクチャは大きく以下の種類に分類される。
マイクロカーネル
マイクロカーネルは、カーネル内に最小限の機能(プロセス間通信、基本的なスケジューリング、低レベルのアドレス空間管理)のみを実装し、ファイルシステムやデバイスドライバなどの機能はユーザー空間のサーバープロセスとして実装する設計である。
代表例: Mach, L4, MINIX 3, QNX
┌──────────────────────────────────────────────────┐
│ ユーザー空間 │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌────────┐ │
│ │ ファイル │ │デバイス │ │ネットワ │ │アプリ │ │
│ │ サーバー │ │ドライバ │ │ークスタ │ │ケーシ │ │
│ │ │ │ │ │ック │ │ョン │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ └───┬────┘ │
│ │ │ │ │ │
│ ─────┴──────────┴──────────┴──────────┴───── │
│ IPC │
├─────────────────────────────────────────────────┤
│ マイクロカーネル │
│ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │
│ │IPC │ │基本スケジ │ │アドレス空間管理 │ │
│ │ │ │ューリング │ │ │ │
│ └──────────┘ └──────────┘ └──────────────────┘ │
├─────────────────────────────────────────────────┤
│ ハードウェア │
└─────────────────────────────────────────────────┘
利点: 安定性(一つのサービスがクラッシュしてもカーネル全体に影響しない)、モジュール性 欠点: IPCのオーバーヘッド、パフォーマンスの低下
モノリシックカーネル
モノリシックカーネルは、OSの主要な機能すべてをカーネル空間で実行する設計である。プロセス管理、メモリ管理、ファイルシステム、デバイスドライバ、ネットワークスタックなどが単一のアドレス空間で動作する。
代表例: Linux, FreeBSD, Solaris(一部)
┌────────────────────────────────────────────────┐
│ ユーザー空間 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ アプリ1 │ │ アプリ2 │ │ アプリ3 │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ ─────┴────────────┴────────────┴─────────── │
│ システムコール │
├────────────────────────────────────────────────┤
│ モノリシックカーネル │
│ ┌──────────┐ ┌────────┐ ┌──────────────────┐ │
│ │プロセス │ │メモリ │ │ファイルシステム │ │
│ │管理 │ │管理 │ │ │ │
│ ├──────────┤ ├────────┤ ├──────────────────┤ │
│ │デバイス │ │ネット │ │セキュリティ │ │
│ │ドライバ │ │ワーク │ │ │ │
│ └──────────┘ └────────┘ └──────────────────┘ │
├────────────────────────────────────────────────┤
│ ハードウェア │
└────────────────────────────────────────────────┘
利点: 高パフォーマンス(コンテキストスイッチなしでカーネル機能にアクセス可能) 欠点: 一つのバグがカーネル全体をクラッシュさせる可能性
ハイブリッドカーネル
マイクロカーネルとモノリシックカーネルの特徴を組み合わせた設計。
代表例: Windows NT, macOS (XNU)
3.2 Linuxのモノリシック設計
Linuxはモノリシックカーネルに分類されるが、純粋なモノリシック設計ではない。ローダブルカーネルモジュール(Loadable Kernel Modules: LKM) の仕組みにより、モノリシックカーネルの利点を維持しつつ、モジュール的な拡張性を実現している。
┌──────────────────────────────────────────────────────────┐
│ Linuxカーネル │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ コアカーネル │ │
│ │ プロセス管理 | メモリ管理 | VFS | ネットワーク │ │
│ │ スケジューラ | IPC | セキュリティ │ │
│ └──────────────────────────────────────────────────┘ │
│ ↕ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │モジュール│ │モジュール│ │モジュール│ │モジュール│ │
│ │ ext4 │ │ nvidia │ │ iptable │ │ btrfs │ │
│ │ │ │ │ │ _filter │ │ │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
│ (実行時にロード・アンロード可能) │
└──────────────────────────────────────────────────────────┘
3.3 カーネルモジュールの管理
カーネルモジュールは、実行時に動的にロードおよびアンロードできる。これにより、必要な機能のみをメモリに読み込むことが可能となる。
# 現在ロードされているモジュールの一覧
$ lsmod
Module Size Used by
nvidia_drm 77824 12
nvidia_modeset 1228800 13 nvidia_drm
nvidia 56467456 832 nvidia_modeset
ext4 999424 2
mbcache 16384 1 ext4
jbd2 147456 1 ext4
...
# モジュールの詳細情報
$ modinfo ext4
filename: /lib/modules/6.8.0-40-generic/kernel/fs/ext4/ext4.ko
softdep: pre: crc32c
license: GPL
description: Fourth Extended Filesystem
author: Remy Card, Stephen Tweedie, Andrew Morton, ...
alias: fs-ext4
alias: ext3
depends: mbcache,jbd2
retpoline: Y
intree: Y
name: ext4
vermagic: 6.8.0-40-generic SMP preempt mod_unload modversions
# モジュールのロード
$ sudo modprobe vfat
# 依存関係も自動的に解決される
# モジュールのアンロード
$ sudo modprobe -r vfat
# モジュールのパラメータを指定してロード
$ sudo modprobe snd_hda_intel power_save=1 power_save_controller=Y
3.4 モジュールの自動ロード設定
# /etc/modules-load.d/ に設定ファイルを配置
$ cat /etc/modules-load.d/custom.conf
# カーネルモジュールの自動ロード設定
vfat
nfs
brd
# モジュールのブラックリスト設定
$ cat /etc/modprobe.d/blacklist-custom.conf
# 特定のモジュールを無効化
blacklist nouveau
blacklist pcspkr
# モジュールパラメータの永続化
$ cat /etc/modprobe.d/custom-params.conf
options snd_hda_intel power_save=1
options iwlwifi 11n_disable=1
3.5 モノリシック設計の利点とLinuxにおける緩和策
| 課題 | Linuxにおける緩和策 |
|---|---|
| カーネルバグの影響範囲が大きい | Kernel Address Space Layout Randomization (KASLR) |
| ドライバの品質がシステム安定性に直結 | ドライバのステージング領域、コードレビュー |
| カーネルサイズの肥大化 | ローダブルモジュールによる動的ロード |
| セキュリティリスク | Seccomp, LSM (SELinux, AppArmor) |
| メンテナンスの複雑さ | サブシステムごとのメンテナー体制 |
4. カーネル空間とユーザー空間
4.1 仮想アドレス空間の分割
Linuxは仮想メモリ機構を使用して、プロセスごとに独立した仮想アドレス空間を提供する。この仮想アドレス空間は、カーネル空間とユーザー空間に分割される。
x86_64(64ビット)アーキテクチャの場合
仮想アドレス空間 (x86_64, 4レベルページテーブル)
┌───────────────────────────────────┐ 0xFFFFFFFFFFFFFFFF
│ │
│ カーネル空間 │ 128 TB
│ (すべてのプロセスで共有) │
│ │
│ ┌─────────────────────────────┐ │ 0xFFFF800000000000
│ │ ダイレクトマッピング領域 │ │ (物理メモリ全体をマッピング)
│ ├─────────────────────────────┤ │
│ │ vmalloc領域 │ │ (不連続な仮想メモリ)
│ ├─────────────────────────────┤ │
│ │ カーネルテキスト・データ │ │ (カーネルコード自体)
│ ├─────────────────────────────┤ │
│ │ モジュール領域 │ │
│ └─────────────────────────────┘ │
├───────────────────────────────────┤
│ 非正規アドレス領域 │ (ガード領域)
│ (使用不可) │
├───────────────────────────────────┤
│ │ 0x00007FFFFFFFFFFF
│ ユーザー空間 │ 128 TB
│ (プロセスごとに独立) │
│ │
│ ┌─────────────────────────────┐ │
│ │ スタック ↓ │ │ (高アドレスから成長)
│ ├─────────────────────────────┤ │
│ │ │ │
│ │ (未マッピング領域) │ │
│ │ │ │
│ ├─────────────────────────────┤ │
│ │ mmap領域 │ │ (共有ライブラリ、ファイルマッピング)
│ ├─────────────────────────────┤ │
│ │ ヒープ ↑ │ │ (brk()で拡張)
│ ├─────────────────────────────┤ │
│ │ BSS セグメント │ │ (未初期化グローバル変数)
│ ├─────────────────────────────┤ │
│ │ データセグメント │ │ (初期化済みグローバル変数)
│ ├─────────────────────────────┤ │
│ │ テキストセグメント │ │ (プログラムコード)
│ └─────────────────────────────┘ │
│ │ 0x0000000000000000
└───────────────────────────────────┘
# プロセスのメモリマッピングを確認
$ cat /proc/self/maps
555555554000-555555556000 r--p 00000000 103:02 1234567 /usr/bin/cat
555555556000-55555555b000 r-xp 00002000 103:02 1234567 /usr/bin/cat
55555555b000-55555555e000 r--p 00007000 103:02 1234567 /usr/bin/cat
55555555e000-55555555f000 r--p 00009000 103:02 1234567 /usr/bin/cat
55555555f000-555555560000 rw-p 0000a000 103:02 1234567 /usr/bin/cat
555555560000-555555581000 rw-p 00000000 00:00 0 [heap]
7ffff7c00000-7ffff7c28000 r--p 00000000 103:02 2345678 /usr/lib/x86_64-linux-gnu/libc.so.6
...
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack]
# カーネルのメモリレイアウトを確認(root権限が必要)
$ sudo cat /proc/iomem
00000000-00000fff : Reserved
00001000-0009fbff : System RAM
000a0000-000fffff : Reserved
00100000-3fffffff : System RAM
01000000-01c08a6d : Kernel code
01c08a6e-0228c6bf : Kernel data
02557000-02afffff : Kernel bss
...
4.2 保護リングとCPU特権レベル
x86アーキテクチャは4つの保護リング(Ring 0〜Ring 3)を提供するが、Linuxは2つのみを使用する。
Ring 0 (カーネルモード)
┌─────────────────┐
│ カーネル │ - すべてのCPU命令を実行可能
│ Ring 0 │ - すべてのメモリにアクセス可能
│ │ - I/Oポートにアクセス可能
│ ┌─────────┐ │ - 割り込みの制御
│ │ │ │
│ │ Ring 3 │ │ Ring 3 (ユーザーモード)
│ │ ユーザー │ │ - 制限された命令セット
│ │ プロセス │ │ - 自分のアドレス空間のみアクセス
│ │ │ │ - 特権命令は実行不可
│ └─────────┘ │
└─────────────────┘
Ring 1, 2 は Linuxでは未使用
(仮想化環境ではRing -1としてVMX root modeが使用される)
4.3 カーネル空間とユーザー空間の遷移
ユーザー空間からカーネル空間への遷移は、以下の3つのメカニズムで発生する。
1. システムコール(ソフトウェア割り込み)
ユーザープロセスがカーネルの機能を呼び出す際に使用する。
// ユーザー空間からのシステムコール呼び出し
// (実際にはglibcなどのラッパーを通じて呼び出される)
#include <unistd.h>
#include <sys/syscall.h>
// write()システムコールの呼び出し
ssize_t ret = write(1, "Hello\n", 6);
// 同等の低レベル呼び出し
ssize_t ret = syscall(SYS_write, 1, "Hello\n", 6);
// x86_64のアセンブリレベル
// mov rax, 1 ; syscall番号 (write)
// mov rdi, 1 ; fd (stdout)
// lea rsi, [msg] ; バッファポインタ
// mov rdx, 6 ; 長さ
// syscall ; カーネルに遷移
2. ハードウェア割り込み
外部デバイスがCPUに割り込み信号を送る。
# 割り込みの統計を確認
$ cat /proc/interrupts
CPU0 CPU1 CPU2 CPU3
0: 24 0 0 0 IR-IO-APIC 2-edge timer
1: 0 0 0 89 IR-IO-APIC 1-edge i8042
8: 0 0 0 0 IR-IO-APIC 8-edge rtc0
9: 0 0 0 4567 IR-IO-APIC 9-fasteoi acpi
16: 0 0 123456 0 IR-IO-APIC 16-fasteoi ehci_hcd
...
NMI: 234 234 234 234 Non-maskable interrupts
LOC: 8765432 7654321 6543210 5432109 Local timer interrupts
3. 例外(Exception)
CPU例外(ページフォルト、ゼロ除算など)が発生した場合。
# ページフォルトの統計
$ cat /proc/vmstat | grep pgfault
pgfault 12345678
pgmajfault 5678
4.4 VDSO(Virtual Dynamic Shared Object)
頻繁に使用される一部のシステムコール(gettimeofday(), clock_gettime()など)は、カーネル空間への遷移なしに高速に実行できるよう、VDSOメカニズムが提供されている。
# VDSOのマッピングを確認
$ cat /proc/self/maps | grep vdso
7fff12345000-7fff12347000 r-xp 00000000 00:00 0 [vdso]
# VDSOが提供する関数
$ objdump -T /proc/self/exe 2>/dev/null | head
# または
$ LD_SHOW_AUXV=1 /bin/true | grep SYSINFO
AT_SYSINFO_EHDR: 0x7fff12345000
通常のシステムコール:
ユーザー空間 → syscall命令 → カーネル空間 → 処理 → sysret命令 → ユーザー空間
↑ コストが高い ↑
VDSO経由:
ユーザー空間 → VDSO関数呼び出し(ユーザー空間のまま) → 結果取得
↑ カーネル遷移なし = 高速 ↑
4.5 カーネル空間とユーザー空間間のデータ転送
カーネルとユーザー空間の間でデータを安全にコピーするために、専用の関数が使用される。
// カーネル内のコード例
#include <linux/uaccess.h>
// ユーザー空間からカーネル空間へのコピー
unsigned long copy_from_user(void *to, const void __user *from, unsigned long n);
// カーネル空間からユーザー空間へのコピー
unsigned long copy_to_user(void __user *to, const void *from, unsigned long n);
// 使用例(簡略化されたデバイスドライバのread関数)
static ssize_t mydev_read(struct file *filp, char __user *buf,
size_t count, loff_t *f_pos)
{
char kernel_buf[256];
int len;
// カーネル空間でデータを準備
len = snprintf(kernel_buf, sizeof(kernel_buf), "Hello from kernel!\n");
if (*f_pos >= len)
return 0;
if (count > len - *f_pos)
count = len - *f_pos;
// カーネル空間からユーザー空間へ安全にコピー
if (copy_to_user(buf, kernel_buf + *f_pos, count))
return -EFAULT; // コピー失敗(不正なアドレス)
*f_pos += count;
return count;
}
4.6 KPTI(Kernel Page Table Isolation)
2018年に発覚したMeltdown脆弱性への対策として、KPTI(旧称KAISER)が導入された。KPTIにより、ユーザー空間で実行中は最小限のカーネルページしかマッピングされなくなった。
# KPTIの有効状態を確認
$ cat /sys/devices/system/cpu/vulnerabilities/meltdown
Mitigation: PTI
# dmesgでKPTIの状態を確認
$ dmesg | grep "page tables isolation"
[ 0.000000] Kernel/User page tables isolation: enabled
# KPTIの無効化(非推奨、テスト目的のみ)
# カーネルブートパラメータ: nopti
5. システムコールインターフェース
5.1 システムコールの概要
システムコール(syscall)は、ユーザー空間のプロセスがカーネルの機能を利用するための唯一の正式なインターフェースである。Linuxカーネルは、x86_64アーキテクチャで約450以上のシステムコールを提供している。
# システムコールの一覧を確認
$ ausyscall --dump
Using x86_64 syscall table:
0 read
1 write
2 open
3 close
4 stat
5 fstat
6 lstat
7 poll
8 lseek
9 mmap
10 mprotect
11 munmap
...
# ヘッダファイルから確認
$ grep -r "define __NR_" /usr/include/asm/unistd_64.h | head -20
#define __NR_read 0
#define __NR_write 1
#define __NR_open 2
#define __NR_close 3
#define __NR_stat 4
...
5.2 システムコールのカテゴリ
| カテゴリ | 主なシステムコール | 説明 |
|---|---|---|
| プロセス管理 | fork, exec, wait, exit, clone | プロセスの生成・制御 |
| ファイルI/O | open, read, write, close, lseek | ファイル操作 |
| ファイルシステム | mkdir, rmdir, link, unlink, stat | ディレクトリ・メタデータ操作 |
| メモリ管理 | mmap, munmap, brk, mprotect | メモリ割り当て・保護 |
| ネットワーク | socket, bind, listen, accept, connect | ネットワーク通信 |
| IPC | pipe, shmget, semget, msgget | プロセス間通信 |
| シグナル | kill, sigaction, sigprocmask | シグナル処理 |
| 時間 | gettimeofday, clock_gettime, nanosleep | 時間関連操作 |
| I/O多重化 | select, poll, epoll_create, io_uring | 非同期I/O |
5.3 システムコールの実行フロー
ユーザー空間 カーネル空間
┌──────────┐ ┌──────────────────────────┐
│ アプリ │ │ │
│ ↓ │ │ │
│ glibc │ ①syscall番号を │ │
│ wrapper │ raxレジスタに設定 │ │
│ ↓ │ │ │
│ SYSCALL │──②CPUがRing3→Ring0──→│ ③entry_SYSCALL_64 │
│ 命令 │ │ ↓ │
│ │ │ ④sys_call_table[rax] │
│ │ │ ↓ │
│ │ │ ⑤実際のシステムコール関数 │
│ │ │ (例: sys_write) │
│ │ │ ↓ │
│ 戻り値 │←⑥SYSRET命令で復帰───│ ⑦戻り値をraxに設定 │
│ 取得 │ │ │
└──────────┘ └──────────────────────────┘
5.4 システムコールのトレーシング
# straceでシステムコールをトレース
$ strace -c ls /tmp
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
25.00 0.000125 6 19 mmap
15.00 0.000075 5 13 mprotect
12.00 0.000060 8 7 openat
8.00 0.000040 5 8 close
8.00 0.000040 5 7 fstat
7.00 0.000035 4 8 read
5.00 0.000025 25 1 getdents64
5.00 0.000025 12 2 write
4.00 0.000020 10 2 ioctl
3.00 0.000015 7 2 statfs
...
------ ----------- ----------- --------- --------- ----------------
100.00 0.000500 85 3 total
# 特定のシステムコールのみをトレース
$ strace -e trace=open,read,write cat /etc/hostname
openat(AT_FDCWD, "/etc/hostname", O_RDONLY) = 3
read(3, "myhost\n", 131072) = 7
write(1, "myhost\n", 7) = 7
read(3, "", 131072) = 0
# タイムスタンプ付きでトレース
$ strace -tt -e trace=network curl -s https://example.com > /dev/null
14:23:45.123456 socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
14:23:45.123789 connect(3, {sa_family=AF_INET, sin_port=htons(443),
sin_addr=inet_addr("93.184.216.34")}, 16) = -1 EINPROGRESS
...
5.5 システムコールテーブル
カーネル内部では、システムコールは関数ポインタのテーブル(sys_call_table)で管理される。
// arch/x86/entry/syscall_64.c (カーネルソース)
// システムコールテーブルの定義
asmlinkage const sys_call_ptr_t sys_call_table[] = {
[0] = __x64_sys_read,
[1] = __x64_sys_write,
[2] = __x64_sys_open,
[3] = __x64_sys_close,
// ...
};
// システムコールの定義マクロ
// include/linux/syscalls.h
SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
size_t, count)
{
return ksys_write(fd, buf, count);
}
// SYSCALL_DEFINE3 は引数が3つであることを示す
// SYSCALL_DEFINE0〜SYSCALL_DEFINE6 まで存在
5.6 新しいシステムコールの追加
Linuxカーネルでは、新しい機能のために定期的にシステムコールが追加される。近年追加された重要なシステムコールの例:
| システムコール | カーネルバージョン | 説明 |
|---|---|---|
io_uring_setup | 5.1 | 高性能非同期I/O |
pidfd_open | 5.3 | PIDのファイルディスクリプタ化 |
openat2 | 5.6 | 拡張されたopen操作 |
close_range | 5.9 | 範囲指定でのfdクローズ |
landlock_create_ruleset | 5.13 | Landlockセキュリティ |
futex_waitv | 5.16 | 複数futexの待機 |
cachestat | 6.5 | ページキャッシュ統計 |
// io_uring の使用例(簡略化)
#include <linux/io_uring.h>
#include <sys/syscall.h>
// io_uring のセットアップ
int io_uring_setup(unsigned entries, struct io_uring_params *p) {
return syscall(__NR_io_uring_setup, entries, p);
}
// 使用例
struct io_uring_params params;
memset(¶ms, 0, sizeof(params));
int ring_fd = io_uring_setup(32, ¶ms);
5.7 Seccompによるシステムコールフィルタリング
セキュリティのために、プロセスが利用可能なシステムコールを制限するSeccomp(Secure Computing Mode)が提供されている。
// Seccomp BPFフィルタの例
#include <linux/seccomp.h>
#include <linux/filter.h>
#include <sys/prctl.h>
// 基本的なSeccompフィルタ: read, write, exit, sigreturnのみ許可
struct sock_filter filter[] = {
// アーキテクチャの確認
BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
offsetof(struct seccomp_data, arch)),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_X86_64, 1, 0),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL),
// システムコール番号の取得
BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
offsetof(struct seccomp_data, nr)),
// 許可するシステムコール
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_read, 3, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_write, 2, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_exit, 1, 0),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_rt_sigreturn, 0, 1),
// 許可
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
// 拒否(プロセスをkill)
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL),
};
struct sock_fprog prog = {
.len = (unsigned short)(sizeof(filter) / sizeof(filter[0])),
.filter = filter,
};
// フィルタの適用
prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
# Dockerコンテナのデフォルトseccompプロファイルを確認
$ docker run --rm alpine cat /proc/1/status | grep Seccomp
Seccomp: 2
Seccomp_filters: 1
# seccomp_bpf_filter が有効な場合の値:
# 0 - SECCOMP_MODE_DISABLED
# 1 - SECCOMP_MODE_STRICT
# 2 - SECCOMP_MODE_FILTER
6. カーネルサブシステムの全体像
Linuxカーネルは、複数のサブシステムが協調して動作する複雑なシステムである。各サブシステムの概要と相互関係を解説する。
6.1 サブシステムの構成
┌──────────────────────────────────────────────────────────────────────┐
│ システムコールインターフェース │
└─┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬──────────┘
│ │ │ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
┌─────┐┌─────┐┌─────┐┌─────┐┌─────┐┌─────┐┌─────┐┌──────────┐
│プロセ││メモリ││ VFS ││ネット││デバイ││セキュ││ IPC ││タイマー/ │
│ス管理││管理 ││ ││ワーク││スド ││リテ ││ ││クロック │
│ ││ ││ ││ ││ライバ││ィ ││ ││ │
└──┬──┘└──┬──┘└──┬──┘└──┬──┘└──┬──┘└──┬──┘└──┬──┘└────┬─────┘
│ │ │ │ │ │ │ │
▼ ▼ ▼ ▼ ▼ ▼ ▼ ▼
┌──────────────────────────────────────────────────────────────────────┐
│ アーキテクチャ依存コード (arch/) │
│ (x86, ARM, RISC-V, MIPS, PowerPC, ...) │
└──────────────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────────┐
│ ハードウェア │
│ CPU | メモリ | ストレージ | NIC | GPU | USB | PCIe | ... │
└──────────────────────────────────────────────────────────────────────┘
6.2 プロセス管理サブシステム
プロセス管理は、プロセスの生成、スケジューリング、終了を制御する。
// プロセスを表現するtask_struct構造体(主要フィールドのみ)
// include/linux/sched.h
struct task_struct {
// プロセスの状態
volatile long state; // TASK_RUNNING, TASK_INTERRUPTIBLE, ...
// スケジューリング情報
int prio; // 動的優先度
int static_prio; // 静的優先度
int normal_prio; // 正常優先度
unsigned int rt_priority; // リアルタイム優先度
const struct sched_class *sched_class; // スケジューリングクラス
// プロセスID
pid_t pid; // プロセスID
pid_t tgid; // スレッドグループID
// プロセスツリー
struct task_struct *parent; // 親プロセス
struct list_head children; // 子プロセスリスト
struct list_head sibling; // 兄弟プロセスリスト
// メモリ管理
struct mm_struct *mm; // メモリディスクリプタ
// ファイルシステム
struct fs_struct *fs; // ファイルシステム情報
struct files_struct *files; // オープンファイルテーブル
// シグナル
struct signal_struct *signal; // シグナル情報
// 名前空間
struct nsproxy *nsproxy; // 名前空間
// cgroup
struct css_set *cgroups; // cgroup情報
// ...他にも多数のフィールドが存在
};
# プロセスの状態を確認
$ ps aux --sort=-%cpu | head -10
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 169256 13120 ? Ss Jan15 0:12 /sbin/init
...
# プロセスツリーを表示
$ pstree -p
systemd(1)─┬─ModemManager(789)─┬─{ModemManager}(823)
│ └─{ModemManager}(829)
├─NetworkManager(791)─┬─{NetworkManager}(845)
│ └─{NetworkManager}(847)
├─sshd(1234)───sshd(5678)───bash(5679)───pstree(9012)
...
# スケジューラの統計
$ cat /proc/schedstat
version 15
timestamp 1234567890
cpu0 12345 6789 111213 141516 171819 202122 0 0 0
...
CFS(Completely Fair Scheduler)
Linux 2.6.23以降のデフォルトスケジューラ。赤黒木(Red-Black Tree)を使用して、各プロセスに「公平な」CPU時間を割り当てる。
# スケジューリングポリシーの確認
$ chrt -p 1
pid 1's current scheduling policy: SCHED_OTHER
pid 1's current scheduling priority: 0
# リアルタイムスケジューリングの設定
$ sudo chrt -f -p 50 <PID> # SCHED_FIFO, 優先度50
# nice値の設定
$ nice -n -10 ./my_program # 高優先度で実行
$ renice -n 5 -p <PID> # 実行中プロセスの優先度変更
# CPUアフィニティの設定
$ taskset -c 0,1 ./my_program # CPU 0,1のみで実行
$ taskset -pc 0-3 <PID> # 実行中プロセスのCPU割り当て変更
6.3 メモリ管理サブシステム
物理メモリ管理の階層構造:
┌─────────────────────────────────────────────────────────────────┐
│ 仮想メモリ管理 (VMM) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────────────┐ │
│ │ ページ │ │ VMA │ │ mmap │ │ ページ │ │
│ │ テーブル │ │ (Virtual │ │ 管理 │ │ フォルト │ │
│ │ 管理 │ │ Memory │ │ │ │ ハンドラ │ │
│ │ │ │ Areas) │ │ │ │ │ │
│ └──────────┘ └──────────┘ └──────────┘ └────────────────┘ │
├─────────────────────────────────────────────────────────────────┤
│ 物理メモリ管理 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────────────┐ │
│ │ バディ │ │ スラブ │ │ ページ │ │ メモリ │ │
│ │ システム │ │ アロケータ│ │ 回収 │ │ コンパクション │ │
│ │ (buddy) │ │ (SLUB) │ │ (reclaim)│ │ (compaction) │ │
│ └──────────┘ └──────────┘ └──────────┘ └────────────────┘ │
├─────────────────────────────────────────────────────────────────┤
│ スワップ管理 │
│ ┌──────────┐ ┌──────────┐ ┌──────────────────────────────┐ │
│ │ スワップ │ │ zswap │ │ OOM Killer │ │
│ │ デバイス │ │ (圧縮 │ │ (メモリ不足時のプロセス強制終了) │ │
│ │ │ │ スワップ)│ │ │ │
│ └──────────┘ └──────────┘ └──────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
# メモリの使用状況
$ cat /proc/meminfo
MemTotal: 16384000 kB
MemFree: 4096000 kB
MemAvailable: 8192000 kB
Buffers: 512000 kB
Cached: 4096000 kB
SwapCached: 32000 kB
Active: 6144000 kB
Inactive: 4096000 kB
SwapTotal: 8192000 kB
SwapFree: 7168000 kB
Slab: 512000 kB
SReclaimable: 384000 kB
SUnreclaim: 128000 kB
...
# スラブアロケータの統計
$ sudo slabtop -o | head -20
Active / Total Objects (% used) : 1234567 / 2345678 (52.6%)
Active / Total Slabs (% used) : 45678 / 45678 (100.0%)
Active / Total Caches (% used) : 123 / 180 (68.3%)
Active / Total Size (% used) : 456.78M / 789.12M (57.9%)
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
234567 123456 52% 0.19K 11170 21 44680K dentry
123456 98765 80% 1.06K 4115 30 131680K ext4_inode_cache
...
# vmstatでメモリの挙動を監視
$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 32000 4096000 512000 4096000 0 0 25 50 1234 5678 15 5 79 1 0
0 0 32000 4094000 512000 4098000 0 0 0 16 987 4321 12 3 85 0 0
6.4 仮想ファイルシステム(VFS)
VFSは、異なるファイルシステム実装を統一的なインターフェースで抽象化する層である。
ユーザー空間のアプリケーション
│
│ open(), read(), write(), ...
▼
┌──────────────────────────────────────────────────┐
│ VFS 層 │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ スーパー │ │ inode │ │ dentry │ │
│ │ ブロック │ │ │ │ (ディレ │ │
│ │ │ │ │ │ クトリ │ │
│ │ │ │ │ │ エントリ) │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ ┌──────────┐ ┌──────────┐ │
│ │ file │ │ ページ │ │
│ │ (ファイル│ │ キャッシュ│ │
│ │ オブジェ │ │ │ │
│ │ クト) │ │ │ │
│ └──────────┘ └──────────┘ │
├──────────────────────────────────────────────────┤
│ ファイルシステム実装 │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ ext4 │ │ XFS │ │Btrfs │ │ NFS │ │tmpfs │ │
│ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘ │
├──────────────────────────────────────────────────┤
│ ブロックI/O層 │
├──────────────────────────────────────────────────┤
│ ストレージデバイス │
└──────────────────────────────────────────────────┘
# マウントされたファイルシステムの確認
$ mount | column -t
/dev/sda2 on / type ext4 (rw,relatime,errors=remount-ro)
tmpfs on /run type tmpfs (rw,nosuid,nodev,noexec,relatime,size=1638400k)
/dev/sda1 on /boot type ext4 (rw,relatime)
/dev/sdb1 on /data type xfs (rw,relatime)
tmpfs on /tmp type tmpfs (rw,nosuid,nodev,relatime)
# ファイルシステムの統計情報
$ df -Th
Filesystem Type Size Used Avail Use% Mounted on
/dev/sda2 ext4 234G 89G 133G 41% /
/dev/sdb1 xfs 1.0T 456G 568G 45% /data
tmpfs tmpfs 7.8G 1.2M 7.8G 1% /tmp
# カーネルがサポートするファイルシステムの一覧
$ cat /proc/filesystems
nodev sysfs
nodev tmpfs
nodev bdev
nodev proc
nodev cgroup2
nodev devtmpfs
nodev debugfs
ext3
ext4
xfs
btrfs
vfat
...
6.5 ネットワークサブシステム
┌─────────────────────────────────────────────────────────────┐
│ アプリケーション │
│ socket(), bind(), listen(), ... │
├─────────────────────────────────────────────────────────────┤
│ ソケット層 │
│ (struct socket, struct sock) │
├─────────────────────────────────────────────────────────────┤
│ トランスポート層 │
│ ┌──────────┐ ┌──────────┐ │
│ │ TCP │ │ UDP │ │
│ └──────────┘ └──────────┘ │
├─────────────────────────────────────────────────────────────┤
│ ネットワーク層 │
│ ┌──────┐ ┌──────────┐ ┌──────────┐ ┌────────────┐ │
│ │ IPv4 │ │ IPv6 │ │ルーティング│ │ Netfilter │ │
│ └──────┘ └──────────┘ └──────────┘ └────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ データリンク/デバイス層 │
│ ┌──────────────────┐ ┌──────────────────────────────┐ │
│ │ ネットワーク │ │ Traffic Control │ │
│ │ デバイスドライバ │ │ (qdisc, tc) │ │
│ └──────────────────┘ └──────────────────────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ NIC (物理ネットワーク) │
└─────────────────────────────────────────────────────────────┘
# ネットワークスタックの統計情報
$ cat /proc/net/snmp
Ip: Forwarding DefaultTTL InReceives InHdrErrors ...
Ip: 1 64 12345678 0 ...
Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ...
Tcp: 1 200 120000 -1 ...
# ネットワーク接続の状態
$ ss -tuanp
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
tcp LISTEN 0 4096 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=1234,fd=6))
tcp ESTAB 0 0 10.0.0.1:52346 10.0.0.2:443 users:(("curl",pid=5678,fd=3))
# Netfilter/iptablesのルール確認
$ sudo iptables -L -n -v
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
12345 1234K ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0
9876 987K ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22
5678 567K ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
6.6 デバイスドライバサブシステム
# デバイスの種類と一覧
$ ls -la /dev/ | head -20
total 0
drwxr-xr-x 21 root root 4800 Jan 15 10:00 .
drwxr-xr-x 25 root root 4096 Jan 10 08:00 ..
crw-rw-rw- 1 root root 1, 3 Jan 15 10:00 null # キャラクタデバイス
crw-rw-rw- 1 root root 1, 5 Jan 15 10:00 zero
crw-rw-rw- 1 root root 1, 8 Jan 15 10:00 random
crw-rw-rw- 1 root root 1, 9 Jan 15 10:00 urandom
brw-rw---- 1 root disk 8, 0 Jan 15 10:00 sda # ブロックデバイス
brw-rw---- 1 root disk 8, 1 Jan 15 10:00 sda1
# PCIデバイスの一覧
$ lspci
00:00.0 Host bridge: Intel Corporation 8th Gen Core Processor Host Bridge
00:02.0 VGA compatible controller: Intel Corporation UHD Graphics 630
00:14.0 USB controller: Intel Corporation Cannon Lake USB 3.1 xHCI Host Controller
00:1f.0 ISA bridge: Intel Corporation Cannon Lake LPC Controller
...
# USBデバイスの一覧
$ lsusb
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 002: ID 8087:0aaa Intel Corp. Bluetooth 9460/9560 Jefferson Peak
...
# sysfs経由でのデバイス情報
$ cat /sys/class/net/eth0/address
00:11:22:33:44:55
$ cat /sys/class/block/sda/size
976773168 # 512バイトセクタ数
6.7 セキュリティサブシステム
┌──────────────────────────────────────────────────────────┐
│ セキュリティフレームワーク │
│ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ LSM (Linux Security Modules) │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ SELinux │ │ AppArmor │ │ Smack │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ TOMOYO │ │ Landlock │ │ Yama │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ │ │
│ └────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │Capability│ │ Seccomp │ │ Audit │ │ 暗号API │ │
│ │ │ │ │ │ │ │ │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└──────────────────────────────────────────────────────────┘
# SELinuxの状態確認
$ getenforce
Enforcing
$ sestatus
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: targeted
Current mode: enforcing
Mode from config file: enforcing
Policy MLS status: enabled
Policy deny_unknown status: allowed
Memory protection checking: actual (secure)
# Capabilityの確認
$ getpcaps 1
1: cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,...
# Linuxの監査ログ
$ sudo ausearch -m AVC -ts recent
type=AVC msg=audit(1234567890.123:456): avc: denied { read } for
pid=1234 comm="nginx" name="index.html" dev="sda2" ino=567890
scontext=system_u:system_r:httpd_t:s0
tcontext=unconfined_u:object_r:user_home_t:s0 tclass=file
7. ブートプロセス
7.1 全体の流れ
Linuxシステムのブートプロセスは、電源投入からユーザーがログインできる状態になるまでの一連のステップで構成される。
電源投入
│
▼
┌──────────┐
│ ファーム │ POST (Power-On Self-Test)
│ ウェア │ ハードウェアの初期化
│ (UEFI/ │ ブートデバイスの検出
│ BIOS) │
└────┬─────┘
│
▼
┌──────────┐
│ ブート │ GRUBがカーネルイメージとinitramfsをロード
│ ローダー │ カーネルのコマンドラインパラメータを設定
│ (GRUB2) │ カーネルに制御を移行
└────┬─────┘
│
▼
┌──────────┐
│ カーネル │ ハードウェアの初期化
│ 初期化 │ メモリ管理の初期化
│ │ スケジューラの初期化
│ │ initramfsのマウント
└────┬─────┘
│
▼
┌──────────┐
│initramfs │ 必要なドライバのロード
│ (初期 │ ルートファイルシステムの検出・マウント
│ RAM │ 暗号化ボリュームのアンロック
│ ディスク)│ 実際のルートFSへのpivot_root
└────┬─────┘
│
▼
┌──────────┐
│ init │ systemd (PID 1) の起動
│ プロセス │ サービスの起動
│ (systemd)│ ターゲット(ランレベル)への遷移
│ │ ログイン画面の表示
└──────────┘
7.2 UEFI/BIOSファームウェア
UEFI(Unified Extensible Firmware Interface)
# UEFIブート変数の確認
$ efibootmgr -v
BootCurrent: 0001
Timeout: 3 seconds
BootOrder: 0001,0002,0003
Boot0001* Ubuntu HD(1,GPT,12345678-abcd-1234-5678-1234567890ab,0x800,0x100000)/\EFI\ubuntu\shimx64.efi
Boot0002* Windows Boot Manager HD(1,GPT,...)/\EFI\Microsoft\Boot\bootmgfw.efi
Boot0003* UEFI: Network Boot PciRoot(0x0)/Pci(0x1f,0x6)
# UEFIシステムパーティション(ESP)の内容
$ ls /boot/efi/EFI/
BOOT ubuntu
$ ls /boot/efi/EFI/ubuntu/
shimx64.efi grubx64.efi mmx64.efi grub.cfg
7.3 GRUBブートローダー
GRUB(GRand Unified Bootloader)は、最も広く使用されているLinuxブートローダーである。
# GRUB設定ファイル
$ cat /etc/default/grub
GRUB_DEFAULT=0
GRUB_TIMEOUT_STYLE=menu
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
GRUB_CMDLINE_LINUX=""
# カーネルブートパラメータの例
GRUB_CMDLINE_LINUX="
root=UUID=12345678-abcd-1234-5678-1234567890ab
ro
quiet
splash
intel_iommu=on
iommu=pt
hugepagesz=1G
hugepages=4
isolcpus=4-7
nohz_full=4-7
rcu_nocbs=4-7
transparent_hugepage=madvise
mitigations=auto
"
# GRUB設定の更新
$ sudo update-grub
Sourcing file `/etc/default/grub'
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-6.8.0-40-generic
Found initrd image: /boot/initrd.img-6.8.0-40-generic
...
done
# ブート可能なカーネルの一覧
$ ls /boot/vmlinuz-*
/boot/vmlinuz-6.8.0-38-generic
/boot/vmlinuz-6.8.0-40-generic
7.4 カーネルの初期化
カーネルが制御を受け取った後の初期化プロセス:
start_kernel() [init/main.c]
│
├── setup_arch() // アーキテクチャ固有の初期化
│ ├── setup_memory_map() // メモリマップの設定
│ ├── parse_early_param() // 早期ブートパラメータの解析
│ └── init_mem_mapping() // メモリマッピングの初期化
│
├── mm_core_init() // メモリ管理コアの初期化
│ ├── page_alloc_init() // ページアロケータの初期化
│ └── kmem_cache_init() // スラブアロケータの初期化
│
├── sched_init() // スケジューラの初期化
│
├── init_IRQ() // 割り込みの初期化
│
├── time_init() // タイマーの初期化
│
├── console_init() // コンソールの初期化
│
├── vfs_caches_init() // VFSキャッシュの初期化
│
├── rest_init() // 残りの初期化
│ ├── kernel_thread(kernel_init, ...) // initプロセス(PID 1)
│ └── kernel_thread(kthreadd, ...) // カーネルスレッドデーモン(PID 2)
│
└── cpu_idle() // アイドルループに入る
# カーネルの起動メッセージを確認
$ dmesg | head -50
[ 0.000000] Linux version 6.8.0-40-generic (buildd@lcy02-amd64-080) ...
[ 0.000000] Command line: BOOT_IMAGE=/boot/vmlinuz-6.8.0-40-generic
root=UUID=12345678 ro quiet splash
[ 0.000000] BIOS-provided physical RAM map:
[ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
[ 0.000000] BIOS-e820: [mem 0x0000000000100000-0x00000000bfffffff] usable
[ 0.000000] NX (Execute Disable) protection: active
[ 0.000000] SMBIOS 3.2.0 present.
[ 0.000000] DMI: Dell Inc. PowerEdge R740/0T3YFT, BIOS 2.12.2 01/15/2024
[ 0.000000] e820: update [mem 0x00000000-0x00000fff] usable ==> reserved
[ 0.000000] tsc: Detected 2100.000 MHz processor
[ 0.004000] Calibrating delay loop (skipped), value calculated using timer
[ 0.004000] pid_max: default: 32768 minimum: 301
[ 0.004000] LSM: initializing lsm=lockdown,capability,apparmor
[ 0.006000] Mount-cache hash table entries: 65536
[ 0.006000] Mountpoint-cache hash table entries: 65536
[ 0.012000] smpboot: CPU0: Intel(R) Xeon(R) Gold 6130 CPU @ 2.10GHz
[ 0.016000] smp: Bringing up secondary CPUs ...
[ 0.024000] smp: Brought up 2 nodes, 32 CPUs
...
# ブート時間の分析
$ systemd-analyze
Startup finished in 2.345s (kernel) + 5.678s (userspace) = 8.023s
graphical.target reached after 5.432s in userspace
# 各サービスの起動時間
$ systemd-analyze blame | head -10
2.345s NetworkManager-wait-online.service
1.234s snapd.service
0.987s dev-sda2.device
0.876s systemd-journal-flush.service
0.765s systemd-udevd.service
...
# ブート時間のチャートを生成
$ systemd-analyze plot > boot-chart.svg
7.5 initramfs
initramfsは、カーネルが実際のルートファイルシステムをマウントするために必要な初期ルートファイルシステムである。
# initramfsの内容を確認
$ lsinitramfs /boot/initrd.img-6.8.0-40-generic | head -30
.
kernel
kernel/x86
kernel/x86/microcode
kernel/x86/microcode/GenuineIntel.bin
bin
bin/busybox
conf
conf/initramfs.conf
etc
etc/modprobe.d
lib
lib/modules
lib/modules/6.8.0-40-generic
lib/modules/6.8.0-40-generic/kernel
lib/modules/6.8.0-40-generic/kernel/drivers
...
scripts
scripts/init-top
scripts/init-premount
scripts/local-top
scripts/local-premount
scripts/local-bottom
# initramfsの再生成
$ sudo update-initramfs -u -k $(uname -r)
update-initramfs: Generating /boot/initrd.img-6.8.0-40-generic
# カスタムinitramfsの作成
$ sudo mkinitramfs -o /boot/initrd.img-custom 6.8.0-40-generic
# initramfsの設定
$ cat /etc/initramfs-tools/initramfs.conf
MODULES=most
BUSYBOX=auto
COMPRESS=zstd
DEVICE=
NFSROOT=auto
RUNSIZE=10%
7.6 systemdの初期化
# systemdのターゲット一覧
$ systemctl list-units --type=target
UNIT LOAD ACTIVE SUB DESCRIPTION
basic.target loaded active active Basic System
cryptsetup.target loaded active active Local Encrypted Volumes
graphical.target loaded active active Graphical Interface
local-fs.target loaded active active Local File Systems
multi-user.target loaded active active Multi-User System
network.target loaded active active Network
sysinit.target loaded active active System Initialization
timers.target loaded active active Timer Units
# デフォルトターゲットの確認・変更
$ systemctl get-default
graphical.target
$ sudo systemctl set-default multi-user.target # CUIモードに変更
# ブートプロセスの依存関係を可視化
$ systemd-analyze dot | dot -Tsvg > dependencies.svg
# カーネルコマンドラインの確認
$ cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-6.8.0-40-generic root=UUID=12345678 ro quiet splash
8. カーネルによるハードウェアとソフトウェアの仲介
8.1 HAL(Hardware Abstraction Layer)
Linuxカーネルは、ハードウェアの複雑さをソフトウェアから隠蔽するためのハードウェア抽象化層を提供する。
アプリケーション
│
│ POSIX API (open, read, write, ioctl, ...)
▼
┌──────────────────────────────────────────────────────────┐
│ カーネル抽象化層 │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ ブロック │ │ キャラ │ │ ネット │ │ サウンド │ │
│ │ デバイス │ │ クタ │ │ ワーク │ │ (ALSA) │ │
│ │ │ │ デバイス │ │ デバイス │ │ │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │ │
│ ┌────┴────┐ ┌───┴────┐ ┌──┴─────┐ ┌──┴─────┐ │
│ │ SCSI │ │ TTY │ │ ethtool│ │ PCM │ │
│ │ サブ │ │ サブ │ │ サブ │ │ サブ │ │
│ │ システム│ │ システム│ │ システム│ │ システム│ │
│ └────┬────┘ └───┬────┘ └──┬─────┘ └──┬─────┘ │
├───────┴───────────┴──────────┴────────────┴──────────┤
│ デバイスドライバ │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ ahci │ │serial│ │e1000e│ │snd- │ │ nvme │ │
│ │ │ │ │ │ │ │hda │ │ │ │
│ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘ │
├─────────────────────────────────────────────────────────┤
│ バスドライバ │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ PCI │ │ USB │ │ I2C │ │ SPI │ │
│ └──────┘ └──────┘ └──────┘ └──────┘ │
├─────────────────────────────────────────────────────────┤
│ ハードウェア │
└─────────────────────────────────────────────────────────┘
8.2 デバイスモデルとsysfs
Linuxカーネルのデバイスモデルは、kobjectを基盤として、デバイス、ドライバ、バスの関係を統一的に管理する。
# sysfsの構造
$ ls /sys/
block bus class dev devices firmware fs kernel module power
# デバイスの階層構造
$ tree /sys/devices/pci0000:00/0000:00:1f.2/ -L 2
/sys/devices/pci0000:00/0000:00:1f.2/
├── ata1/
│ ├── host0/
│ └── link1/
├── ata2/
│ ├── host1/
│ └── link1/
├── class -> ../../class/ata
├── device -> ../../../devices/pci0000:00/0000:00:1f.2
├── driver -> ../../../bus/pci/drivers/ahci
├── irq -> 30
├── vendor -> 0x8086
├── device -> 0xa282
└── subsystem -> ../../../bus/pci
# udevルールの例
$ cat /etc/udev/rules.d/99-custom.rules
# SSDに対するI/Oスケジューラの設定
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="0", \
ATTR{queue/scheduler}="none"
# 特定のUSBデバイスに固定デバイス名を割り当て
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", \
SYMLINK+="serial_device"
# udevルールの再読み込み
$ sudo udevadm control --reload-rules
$ sudo udevadm trigger
8.3 割り込み処理
ハードウェア割り込みの処理は、トップハーフとボトムハーフに分割される。
ハードウェア割り込みの処理フロー:
1. デバイスが割り込み信号を発生
│
▼
2. CPUが現在の処理を中断
│
▼
3. 割り込みベクタテーブルから
ハンドラのアドレスを取得
│
▼
┌──────────────────────────────────────┐
│ トップハーフ(ハードウェア割り込み) │
│ - 割り込みの原因を特定 │
│ - 最小限の緊急処理を実行 │
│ - 割り込みのACK │
│ - ボトムハーフをスケジュール │
│ ※ 他の割り込みを禁止した状態で実行 │
└──────────┬───────────────────────────┘
│ ボトムハーフをスケジュール
▼
┌──────────────────────────────────────┐
│ ボトムハーフ(遅延処理) │
│ 以下のいずれかのメカニズムで実行: │
│ │
│ ┌─────────┐ ┌─────────┐ ┌────────┐ │
│ │ソフト │ │tasklet │ │ワーク │ │
│ │IRQ │ │ │ │キュー │ │
│ │(softirq)│ │ │ │(work- │ │
│ │ │ │ │ │queue) │ │
│ └─────────┘ └─────────┘ └────────┘ │
│ │
│ ※ 割り込みが有効な状態で実行 │
│ ※ より長時間の処理が可能 │
└──────────────────────────────────────┘
# softirqの統計
$ cat /proc/softirqs
CPU0 CPU1 CPU2 CPU3
HI: 5 0 0 0
TIMER: 1234567 1123456 1098765 987654
NET_TX: 1234 567 890 432
NET_RX: 567890 456789 345678 234567
BLOCK: 12345 11234 10987 9876
IRQ_POLL: 0 0 0 0
TASKLET: 5678 4567 3456 2345
SCHED: 456789 423456 398765 376543
HRTIMER: 234 123 345 234
RCU: 234567 223456 212345 201234
# IRQアフィニティの設定
$ cat /proc/irq/30/smp_affinity
f # すべてのCPUで処理
# 特定のCPUにIRQを固定
$ echo 2 | sudo tee /proc/irq/30/smp_affinity # CPU1のみ
# irqbalanceの設定
$ sudo systemctl status irqbalance
● irqbalance.service - irqbalance daemon
Active: active (running) since ...
8.4 DMA(Direct Memory Access)
DMAは、CPUを介さずにデバイスとメモリ間でデータを直接転送する仕組みである。
// DMA APIの使用例(カーネルドライバ内)
#include <linux/dma-mapping.h>
// 一貫性のあるDMAバッファの確保
void *cpu_addr;
dma_addr_t dma_handle;
cpu_addr = dma_alloc_coherent(dev, size, &dma_handle, GFP_KERNEL);
// DMAマッピング(ストリーミング)
dma_addr_t dma_addr = dma_map_single(dev, cpu_buf, size, DMA_TO_DEVICE);
if (dma_mapping_error(dev, dma_addr)) {
// エラー処理
}
// デバイスにDMA転送を開始させる
// ...
// DMAの同期(CPUがバッファを読む前に)
dma_sync_single_for_cpu(dev, dma_addr, size, DMA_FROM_DEVICE);
// DMAマッピングの解除
dma_unmap_single(dev, dma_addr, size, DMA_TO_DEVICE);
# IOMMU(DMAリマッピング)の確認
$ dmesg | grep -i iommu
[ 0.000000] DMAR: IOMMU enabled
[ 0.012345] DMAR: Intel(R) Virtualization Technology for Directed I/O
[ 0.023456] DMAR-IR: IOAPIC id 2 under DRHD base 0xfed91000
8.5 電源管理
# 電源管理の状態
$ cat /sys/power/state
freeze mem disk
# サスペンドの実行
$ echo mem | sudo tee /sys/power/state
# CPUの省電力状態の確認
$ cat /sys/devices/system/cpu/cpu0/cpuidle/state*/name
POLL
C1
C1E
C3
C6
# CPU周波数ガバナーの設定
$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
powersave
# ガバナーの変更
$ echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
# 利用可能なガバナー
$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors
conservative ondemand userspace powersave performance schedutil
# CPUの現在の周波数
$ cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq
2100000 # 2.1 GHz (kHz単位)
8.6 procfsとsysfs
カーネルとユーザー空間の仲介において、/procと/sysファイルシステムは重要な役割を果たす。
# /proc - プロセスとカーネルの情報
$ ls /proc/
1 2 3 ... # プロセスごとのディレクトリ
buddyinfo # メモリのバディシステム情報
cmdline # カーネルコマンドライン
cpuinfo # CPU情報
devices # 登録されたデバイス
diskstats # ディスクI/O統計
interrupts # 割り込み統計
iomem # I/Oメモリマップ
ioports # I/Oポートマップ
loadavg # 負荷平均
meminfo # メモリ情報
modules # ロード済みモジュール
mounts # マウントポイント
net/ # ネットワーク統計
schedstat # スケジューラ統計
slabinfo # スラブアロケータ情報
stat # システム全体の統計
sys/ # カーネルパラメータ(sysctl)
uptime # 稼働時間
version # カーネルバージョン
vmstat # 仮想メモリ統計
zoneinfo # メモリゾーン情報
# sysctlによるカーネルパラメータの調整
$ sysctl -a | wc -l
1500+ # 1500以上のパラメータが存在
# ネットワーク関連のチューニング例
$ sysctl -w net.core.somaxconn=65535
$ sysctl -w net.ipv4.tcp_max_syn_backlog=65535
$ sysctl -w net.core.netdev_max_backlog=5000
$ sysctl -w net.ipv4.tcp_fin_timeout=15
$ sysctl -w net.ipv4.tcp_keepalive_time=300
# メモリ関連のチューニング
$ sysctl -w vm.swappiness=10
$ sysctl -w vm.dirty_ratio=20
$ sysctl -w vm.dirty_background_ratio=5
$ sysctl -w vm.overcommit_memory=0
# 永続化設定
$ cat /etc/sysctl.d/99-custom.conf
# ネットワークチューニング
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.core.netdev_max_backlog = 5000
# メモリチューニング
vm.swappiness = 10
vm.dirty_ratio = 20
vm.dirty_background_ratio = 5
# セキュリティ
kernel.randomize_va_space = 2
net.ipv4.conf.all.rp_filter = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
9. カーネルの設定とビルド
9.1 カーネル設定(Kconfig)
Linuxカーネルは、Kconfigシステムを使用して数千のコンパイルオプションを管理する。
# カーネルソースのダウンロード
$ wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.8.tar.xz
$ tar xf linux-6.8.tar.xz
$ cd linux-6.8
# 設定方法
$ make menuconfig # NCursesベースのメニュー
$ make nconfig # 改良版NCursesメニュー
$ make xconfig # Qtベースの GUI
$ make gconfig # GTKベースのGUI
# 既存の設定をベースに作成
$ cp /boot/config-$(uname -r) .config
$ make oldconfig # 新しいオプションのみ質問
$ make olddefconfig # 新しいオプションにデフォルト値を使用
# 最小構成の作成
$ make localmodconfig # 現在ロードされているモジュールのみ有効化
$ make tinyconfig # 最小構成
# 設定の検索
$ make menuconfig
# → "/" キーで検索可能
# 例: "EXT4" と入力して ext4 関連の設定を検索
9.2 主要なカーネル設定オプション
# .configファイルの例(主要オプション)
# 一般設定
CONFIG_LOCALVERSION="-custom"
CONFIG_DEFAULT_HOSTNAME="(none)"
CONFIG_PREEMPT_VOLUNTARY=y # プリエンプションモデル
# CONFIG_PREEMPT_NONE is not set
# CONFIG_PREEMPT is not set
# プロセッサ
CONFIG_SMP=y # SMPサポート
CONFIG_NR_CPUS=256 # 最大CPU数
CONFIG_SCHED_MC=y # マルチコアスケジューリング
CONFIG_X86_MCE=y # Machine Check Exception
# メモリ
CONFIG_PAGE_SIZE_4KB=y # ページサイズ
CONFIG_TRANSPARENT_HUGEPAGE=y # 透過的ヒュージページ
CONFIG_ZSWAP=y # 圧縮スワップ
CONFIG_ZRAM=m # 圧縮RAMブロック
CONFIG_KSM=y # カーネル同一ページマージ
# ファイルシステム
CONFIG_EXT4_FS=y # ext4サポート
CONFIG_XFS_FS=m # XFSサポート
CONFIG_BTRFS_FS=m # Btrfsサポート
CONFIG_FUSE_FS=m # FUSEサポート
CONFIG_OVERLAY_FS=m # OverlayFSサポート
# ネットワーク
CONFIG_NETFILTER=y # Netfilter
CONFIG_NF_CONNTRACK=m # 接続追跡
CONFIG_IP_NF_IPTABLES=m # iptables
CONFIG_NFT_CORE=m # nftables
CONFIG_BRIDGE=m # ブリッジ
CONFIG_VETH=m # 仮想イーサネット
# セキュリティ
CONFIG_SECURITY=y # LSMフレームワーク
CONFIG_SECURITY_SELINUX=y # SELinux
CONFIG_SECURITY_APPARMOR=y # AppArmor
CONFIG_SECURITY_LANDLOCK=y # Landlock
CONFIG_SECCOMP=y # Seccomp
# 仮想化
CONFIG_VIRTUALIZATION=y # 仮想化サポート
CONFIG_KVM=m # KVM
CONFIG_VHOST_NET=m # vhost-net
# コンテナ
CONFIG_NAMESPACES=y # 名前空間
CONFIG_CGROUPS=y # cgroups
CONFIG_CGROUP_V2=y # cgroups v2
# デバッグ
CONFIG_DEBUG_KERNEL=y # カーネルデバッグ
CONFIG_FTRACE=y # ftrace
CONFIG_BPF_SYSCALL=y # BPF
CONFIG_KPROBES=y # Kprobes
9.3 カーネルのビルドとインストール
# カーネルのビルド
$ make -j$(nproc) # カーネルイメージのビルド
$ make -j$(nproc) modules # モジュールのビルド
# インストール
$ sudo make modules_install # モジュールのインストール
$ sudo make install # カーネルのインストール
# initramfsの生成
$ sudo update-initramfs -c -k 6.8.0-custom
# GRUBの更新
$ sudo update-grub
# ビルドの確認
$ ls /boot/vmlinuz-6.8.0-custom
$ ls /boot/initrd.img-6.8.0-custom
$ ls /lib/modules/6.8.0-custom/
# リブート
$ sudo reboot
# 新しいカーネルで起動したことを確認
$ uname -r
6.8.0-custom
9.4 DKMS(Dynamic Kernel Module Support)
# DKMSによるモジュール管理
$ dkms status
nvidia/535.183.01, 6.8.0-40-generic, x86_64: installed
virtualbox/7.0.14, 6.8.0-40-generic, x86_64: installed
# DKMSモジュールの追加
$ sudo dkms add -m mymodule -v 1.0
$ sudo dkms build -m mymodule -v 1.0
$ sudo dkms install -m mymodule -v 1.0
10. カーネルのデバッグと監視
10.1 ftrace
ftraceは、カーネルに組み込まれた関数トレーサーである。
# ftraceの利用
$ cd /sys/kernel/debug/tracing
# 利用可能なトレーサーの確認
$ cat available_tracers
hwlat blk mmiotrace function_graph wakeup_dl wakeup_rt wakeup function nop
# 関数トレースの有効化
$ echo function > current_tracer
$ echo 1 > tracing_on
# トレース結果の確認
$ cat trace | head -20
# tracer: function
#
# entries-in-buffer/entries-written: 12345/67890 #P:4
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
<idle>-0 [000] d... 12345.678901: tick_nohz_idle_exit <-do_idle
<idle>-0 [000] d... 12345.678902: arch_cpu_idle_exit <-do_idle
# 特定の関数のみトレース
$ echo 'schedule' > set_ftrace_filter
$ echo 'do_sys_open' >> set_ftrace_filter
# 関数グラフトレーサー
$ echo function_graph > current_tracer
$ cat trace | head -30
# tracer: function_graph
#
2) | do_sys_openat2() {
2) | getname() {
2) 0.156 us | kmem_cache_alloc();
2) | strncpy_from_user() {
2) 0.312 us | _copy_from_user();
2) 0.625 us | }
2) 1.250 us | }
2) | do_filp_open() {
2) | path_openat() {
...
# トレースの停止
$ echo 0 > tracing_on
$ echo nop > current_tracer
10.2 perf
# CPUプロファイリング
$ sudo perf top
# リアルタイムでホットスポットを表示
# システム全体のプロファイリング
$ sudo perf record -a -g sleep 10
$ sudo perf report
# 特定プロセスのプロファイリング
$ sudo perf record -p <PID> -g sleep 30
$ sudo perf report --stdio
# スケジューラの統計
$ sudo perf sched record sleep 5
$ sudo perf sched latency
Task | Runtime ms | Switches | Avg delay ms |
----------------------|---------------|----------|--------------|
migration/0:14 | 0.012 ms | 3 | 0.001 ms |
nginx:1234 | 45.678 ms | 234 | 0.123 ms |
...
# ハードウェアイベントのカウント
$ sudo perf stat -a sleep 5
Performance counter stats for 'system wide':
120,456.78 msec cpu-clock # 4.000 CPUs utilized
12,345 context-switches # 0.102 K/sec
234 cpu-migrations # 0.002 K/sec
5,678 page-faults # 0.047 K/sec
1,234,567,890 cycles # 10.249 GHz
2,345,678,901 instructions # 1.90 insn per cycle
345,678,901 branches # 2.869 M/sec
3,456,789 branch-misses # 1.00% of all branches
10.3 BPF/eBPF
# bpftraceの使用例
# システムコールの頻度を計測
$ sudo bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count(); }'
Attaching 1 probe...
^C
@[nginx]: 12345
@[bash]: 6789
@[sshd]: 4567
# プロセスのファイルオープンを監視
$ sudo bpftrace -e 'tracepoint:syscalls:sys_enter_openat { printf("%s %s\n", comm, str(args->filename)); }'
nginx /etc/nginx/nginx.conf
bash /etc/passwd
...
# BCCツールの使用
$ sudo biolatency # ブロックI/Oレイテンシ
$ sudo tcplife # TCP接続のライフタイム
$ sudo execsnoop # 新規プロセスの起動を監視
$ sudo opensnoop # ファイルオープンを監視
$ sudo cachestat # ページキャッシュのヒット率
$ sudo filetop # ファイルI/Oのトップ
10.4 カーネルクラッシュダンプ
# kdumpの設定
$ sudo apt install linux-crashdump kexec-tools makedumpfile
# kdumpの設定ファイル
$ cat /etc/default/kdump-tools
USE_KDUMP=1
KDUMP_SYSCTL="kernel.panic_on_oops=1"
KDUMP_COREDIR="/var/crash"
MAKEDUMP_ARGS="-c -d 31"
# クラッシュダンプの解析
$ sudo crash /usr/lib/debug/boot/vmlinux-$(uname -r) /var/crash/vmcore
crash> bt # バックトレース
crash> log # カーネルログ
crash> ps # プロセスリスト
crash> vm # 仮想メモリ情報
crash> files # オープンファイル
crash> sys # システム情報
11. 最新のカーネル動向
11.1 Rust言語のサポート
Linux 6.1以降、カーネル内でRust言語が使用可能になった。メモリ安全性の向上が期待されている。
// カーネル内のRustコードの例
// samples/rust/rust_minimal.rs
use kernel::prelude::*;
module! {
type: RustMinimal,
name: "rust_minimal",
author: "Rust for Linux Contributors",
description: "Rust minimal sample",
license: "GPL",
}
struct RustMinimal;
impl kernel::Module for RustMinimal {
fn init(_module: &'static ThisModule) -> Result<Self> {
pr_info!("Rust minimal sample (init)\n");
Ok(RustMinimal)
}
}
impl Drop for RustMinimal {
fn drop(&mut self) {
pr_info!("Rust minimal sample (exit)\n");
}
}
11.2 io_uring
io_uringは、Linux 5.1で導入された高性能非同期I/Oインターフェースである。
io_uringのアーキテクチャ:
┌──────────────────┐ ┌──────────────────┐
│ ユーザー空間 │ │ カーネル空間 │
│ │ │ │
│ ┌────────────┐ │ │ ┌────────────┐ │
│ │ Submission │──┼───────┼─→│ SQ処理 │ │
│ │ Queue (SQ) │ │ 共有 │ │ スレッド │ │
│ │ │ │ メモリ │ │ │ │
│ └────────────┘ │ │ └─────┬──────┘ │
│ │ │ │ │
│ ┌────────────┐ │ │ ┌─────▼──────┐ │
│ │ Completion │←─┼───────┼──│ CQ処理 │ │
│ │ Queue (CQ) │ │ 共有 │ │ │ │
│ │ │ │ メモリ │ │ │ │
│ └────────────┘ │ │ └────────────┘ │
└──────────────────┘ └──────────────────┘
※ システムコールなしで I/O を submit/complete できる
11.3 EEVDF スケジューラ
Linux 6.6で、CFSに代わりEEVDF(Earliest Eligible Virtual Deadline First)スケジューラが導入された。
11.4 その他の注目すべき動向
| 機能 | バージョン | 概要 |
|---|---|---|
| MGLRU | 6.1 | マルチジェネレーションLRU(ページ回収の改善) |
| Maple Tree | 6.1 | VMAを管理する新しいデータ構造 |
| User-space IO | 6.0+ | ユーザー空間からのNVMeアクセス |
| BPF Token | 6.9 | BPFプログラムの権限管理 |
| Composefs | 6.10 | コンテナイメージ用の読み取り専用FS |
| Bcachefs | 6.7 | 新しいCopy-on-Writeファイルシステム |
12. まとめ
Linuxカーネルは、モノリシック設計を基盤としながらも、ローダブルモジュールによる拡張性を備えた高度に洗練されたオペレーティングシステムカーネルである。
主要な設計特徴:
- モノリシック + モジュール: 高パフォーマンスと拡張性の両立
- カーネル空間とユーザー空間の明確な分離: セキュリティと安定性の確保
- 統一されたシステムコールインターフェース: POSIX準拠の安定したAPI
- 階層化されたサブシステム: VFS、ネットワークスタック、デバイスモデルなどの抽象化層
- 「すべてはファイル」の哲学: /proc、/sys、/devによる統一的なインターフェース
- 継続的な進化: Rust言語サポート、io_uring、新スケジューラなど
Linuxカーネルは、世界中のインフラストラクチャを支える基盤ソフトウェアとして、今後も進化を続けていくであろう。カーネルの内部構造を理解することは、システムの性能チューニング、トラブルシューティング、セキュリティ強化において不可欠な知識である。
参考資料:
- Linux Kernel Documentation
- Robert Love, "Linux Kernel Development", 3rd Edition
- Daniel P. Bovet & Marco Cesati, "Understanding the Linux Kernel", 3rd Edition
- LWN.net - Linux Weekly News
- The Linux Kernel Archives