はじめに
メモリ上に常駐し、システムの基幹となる制御を行う OS の中核部分を担うプログラムを カーネル(Kernel) と言う。
カーネルが制御している対象は下記のとおり。
「Linux」という用語は、実は厳密には OS ではなく、このカーネルを指している。
つまり狭義の Linux が「カーネル」であり、広義の Linux が「OS」や「Linuxディストリビューション」までを含んだものということになる。
デバイスへのアクセスはカーネルのみが持つ特権
カーネルは ハードウェアとソフトウェアの橋渡し 的な役割を担っている。
ユーザプロセスは「直接」デバイスへアクセスすることが許されていないため、ハードウェアにアクセスを行う場合、カーネルから提供されるインターフェース(システムコール)を利用する。
ユーザプロセスにとってはカーネルを介してしか、ハードウェアにアクセスができないという制約は、アクセスの競合のために存在している。
複数のアクセスが競合した場合、カーネルは中央集権的に、それぞれのアクセスの交通整理や調停を行う。
カーネルがユーザプロセスに公開するインターフェースや、命令または関数を システムコール 、スーパーバイザコール(SVC:supervisor call)という。
システムコールや SVC が提供するインターフェースは、ハードウェア側の仕様の違いに依存しないように抽象化されている。つまり、カーネルを利用する側は、ハードウェアの仕様の違いを意識する必要がない。
カーネルはプロセスなのか
プロセスとは、実行中のプログラムがメモリ上に展開されたものであり、カーネルが生成、管理する実行単位である。
各プロセスは、カーネルによって プロセスID(PID)を割り当てられ、カーネルによって メモリ空間や CPU の使用時間が管理される。
つまり、プロセスとは「カーネルの管理対象」であり、「カーネルが作り出す実行単位」である。
カーネル自身は一般的なユーザプロセスではなく、PID を持つ「実行単位」ではない。ただし、カーネル内部には カーネルスレッド と呼ばれる PID を持つ処理が存在し、それらはプロセスリストに表示されることがある(kthreadd
、kworker
)。
カーネルはメモリ上に常に存在しているが、$ ps
や $ top
で表示される実行中のプロセスとして扱われない。
カーネルは、プロセス同様に実体はプログラム(/boot/vmlinuz-バージョン
)である。
ただし、/boot/vmlinuz-バージョン
はブートローダによって 初期 RAM ディスク と共にメモリ上に展開されるものであり、ユーザが直接実行することはできない。
カーネルとプロセスは CPU を共有する関係にある
カーネルはプロセスではないが、CPU の視点では、両者は共に CPU を利用し合う関係にある。
$ top
で出力される us
はユーザ空間、sys
はカーネル空間を表す。このことからも、両者が CPU を共有する関係にあることがわかる。
$ top
top - 21:03:57 up 24 min, 1 user, load average: 0.00, 0.00, 0.00
Tasks: 119 total, 1 running, 118 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us 👈(user:ユーザ), 0.0 sy 👈(system:カーネル), 0.0 ni, 100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
プロセスがシステムコールの read()
を呼ぶと、カーネル空間で実際の I / O が行われる。カーネルは割り込みにより、プロセスとカーネルの CPU 制御権を切り替える。
この間、CPU はカーネル空間の処理に使われるため、$ top
では %sy
に CPU 使用時間が加算される。$ top
の %sy
の数値が高いと「カーネル空間の処理が重たい」ことを示す
ただしプロセスと異なり、カーネルはシステムコールを使用できるので、「CPU を誰に使わせるか」を決める立場にある。
カーネルモード / ユーザモード
CPU の動作モードには、カーネルモード と ユーザモード がある。
カーネルもプログラムなので、ユーザプロセスと同様に演算装置(CPU)を使用して動作する。
カーネルモードは、その名の通りカーネルが CPU を使用する際の動作モードである。カーネルはデバイスドライバなどを使用してデバイスへのアクセスを行う。
ユーザモードで動作中の CPU は、システムコールの呼び出しによってカーネルモードに切り替わり、システムコール終了によって再びユーザモードへと戻る。
前述の通り、ハードウェアにアクセスできるのはカーネルだけなので、カーネルモードは 特権モード とも呼ばれる。
たとえば x86
アーキテクチャでは、ユーザモードは Ring3
、カーネルモードは Ring0
という特権レベルで実装されている。
カーネルモードの CPU は、メモリ、I / O デバイスなどのハードウェアリソースに制限なくアクセスを行うことができる。
そのため、カーネルモードで不正な操作が行われたりバグが発生すると、メモリが破壊されたり、デバイスの動作が停止するといった、システム全体に影響が出る事態が発生する。
一方、ユーザモードは、通常のアプリケーションプログラムが動作するモードであり、直接ハードウェアにアクセスを行うことができない。
ユーザモードで動作するプロセスは、カーネルの提供するシステムコールを介してハードウェアにアクセスを行う。
カーネル空間 / ユーザ空間
メモリには カーネル空間 と ユーザ空間 という概念が存在する。
空間とは、メモリ空間(アドレス空間)と CPU の実行モードを併せて抽象化した用語である。
コンピュータのメモリ(RAM)には、番地(アドレス)があり、CPU から見ると巨大な表のようなものになっている。
コンピュータのメモリは、基本的に byte(8 bit)単位で構成され、番地は 0x00000000
~ 0xFFFFFFFF
などのように表現される。
ユーザプロセスが展開されるメモリ上の領域は ユーザ空間 と呼ばれる。
「ユーザ空間」上で動作するプロセスは CPU をユーザモードでしか利用できず、そのためにハードウェアには直接アクセスできない。
一方、ブートローダによって展開されるカーネルが常駐するメモリ上の空間は カーネル空間 と呼ばれる。
「カーネル空間」上で動作するプログラム、すなわちカーネルは CPU をカーネルモード(特権モード)で使用できる。
通常、プロセスがアクセスできるのは自身のユーザ空間だけで、カーネル空間にはアクセスできない。
このカーネルの安定性とセキュリティを担保するためのメモリ空間の分離を メモリ保護 と呼ぶ。
ユーザ空間とカーネル空間が分かれているのは、アプリケーション(ユーザプログラム)が異常を起こしても、カーネルを巻き込まないようにするためである。
もし両者が独立していない場合、一つのアプリの異常によって OS 全体がクラッシュしてしまう。
システムコール
カーネルから提供される、プロセスがカーネルの特権的な機能を呼び出すためのインターフェース。
スーパーバイザコール(SVC:supervisor call)と呼ばれることもある。
- ファイル操作:
open
,read
,write
- プロセス管理:
fork
,exec
,kill
- ネットワーク通信:
socket
,connect
システムコールは、「ユーザモード」で動作中の CPU を「カーネルモード」へ遷移させる手段でもある。
システムコールの実行が終了すると、CPU はカーネルモードから再びユーザモードに戻ってプロセスの実行を継続する。
システムコールを呼び出すことができるプログラミング言語は複数ある。
- C言語
- アセンブリ言語
- Rust
- Go
- Python
- C++
- Perl
- Ruby
- AssemblyScript / WebAssembly
C 言語やアセンブリ言語は、OS やカーネル開発において主要言語として採用されることが多い。一方、Python や Perl などはシステムコールを直接呼び出す用途ではなく、ラッパーやモジュール経由で利用することが多い。
C 言語には、glibc
と呼ばれる 標準Cライブラリ が存在し、この中にはシステムコールを内部的に呼び出すラッパー関数が含まれている。
アセンブリ言語は直接システムコールを呼び出すことができるものの、アーキテクチャ ごとに存在するシステムコールを環境に応じて呼び分ける必要がある。
C言語では glibc
のようなラッパー関数がアーキテクチャごとの違いを吸収するため、呼び出し側はその違いを意識する必要がない。
Linux ディストリビューションに含まれる様々なプログラムは、この glibc
の存在を前提として作られている。
例外
プロセスがシステムコールを発行すると、CPU において 例外 が発生する。
この例外をトリガーにして、CPU は ユーザモード から カーネルモード へ遷移し、システムコールの処理を行う。
システムコールの処理が終了すると、CPU は再びユーザモードに戻り、プロセスを継続する。
標準Cライブラリ
C言語に標準で付属しているライブラリ。
システムコール のラッパー関数が含まれ、glibc
(GNU C Library)とも言う。
- 入出力操作(
printf
,scanf
) - メモリ管理(
malloc
,free
) - ファイル操作(
fopen
,fread
,fwrite
) - システムコールのラップ(
open
,read
,write
)
システムコール | 標準Cライブラリのラッパー関数 | 説明 |
---|---|---|
open |
open |
ファイルを開く |
read |
read |
ファイルやデバイスからデータを読み取る |
write |
write |
ファイルやデバイスにデータを書き込む |
close |
close |
ファイルを閉じる |
仮想ファイルシステム
virtual file system, VFS
メモリ上にカーネルが動的に生成するファイルシステム。
UNIX 哲学には、Everything is a file という設計思想があり、仮想ファイルはカーネルがデータを
「ファイル」として外部に公開しているインターフェースにすぎず、ストレージ上にファイルの実体が存在しない。
syfs
カーネルが検出したデバイス(PCI、USB、ブロックデバイスなど)の情報を確認できる仮想ファイルシステム。
/sys
ディレクトリでマウントされる。
udevd
デーモンはユーザ空間で動作するプロセスのため、デバイスに直接アクセスすることができないが、/sys
ディレクトリ配下の仮想ファイルを通じてデバイス情報を取得している。
procfs
process file system
カーネル、プロセス、ハードウェアなどの状態を確認できる仮想ファイルシステム。
一部のファイルは変更が可能で、これによってカーネルの挙動を変更することができる。
/proc
ディレクトリでマウントされ、ファイルの中身はリアルタイムで更新される。
/proc 配下のファイル一覧
パス | 説明 |
---|---|
/proc/cpuinfo |
CPU に関する情報(コア数、モデル名、キャッシュサイズなど) |
/proc/meminfo |
メモリの使用状況(全体、空き、キャッシュなど) |
/proc/version |
カーネルのバージョン情報 |
/proc/cmdline |
カーネル起動時のコマンドライン引数 |
/proc/modules |
現在ロードされているカーネルモジュール一覧 |
/proc/uptime |
起動してからの経過時間(秒)とアイドル時間 |
/proc/loadavg |
平均負荷(1分、5分、15分)など |
/proc/filesystems |
カーネルがサポートしているファイルシステム一覧 |
/proc/mounts |
現在マウントされているファイルシステムの情報 |
/proc/swaps |
スワップ領域の使用状況 |
/proc/interrupts |
割り込みの発生回数(デバイスごと) |
/proc/dma |
DMA(direct memory access) チャネルの割り当て状況 DMA:CPU を介さずにデバイスがメモリと直接データ転送を行う仕組み |
/proc/ioports |
使用されている I / O アドレス領域。 ハードウェアごとに使用する I/ O ポートは決まっていて、カーネルは競合しないよう管理している。 |
/proc/プロセスID/ |
各プロセス情報 |
/proc/1/ |
PID 1(init や systemd )の情報 |
/proc/プロセスID/cmdline |
プロセス起動時のコマンド |
/proc/プロセスID/cwd |
プロセスの現在の作業ディレクトリ(相対パスの起点)へのシンボリックリンク |
/proc/プロセスID/exe |
実行している実行可能ファイルへのシンボリックリンク |
/proc/self/ |
現在このコマンドを実行しているプロセス自身へのシンボリックリンク |
/proc/プロセスID/fd/ |
オープンしている ファイルディスクリプタ |
/proc/プロセスID/status |
プロセスの状態(UID、メモリ使用量、状態コードなど) |
/proc/プロセスID/environ |
環境変数 |
/proc/プロセスID/stack |
カーネルスタックのトレース |
/proc/bus/pci |
PCI バス(peripheral component interconnect bus)に接続されているデバイス情報 |
/proc//bus/usb |
USB(universal serial bus)に接続されたデバイス情報 |
ファイルとして $ cat
で読み取り、$ echo
で書き込みすることができる。
$ cat /proc/version
Linux version 6.8.0-63-generic (buildd@bos03-arm64-119) (aarch64-linux-gnu-gcc-13 (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0, GNU ld (GNU Binutils for Ubuntu) 2.42) #66-Ubuntu SMP PREEMPT_DYNAMIC Fri Jun 13 20:09:49 UTC 2025
$ echo 1 > /proc/sys/net/ipv4/ip_forward # 0:無効化、1:有効化
$ sysctl
を使用すると、読み書きどちらも行える(ただし、扱えるものは カーネル変数 に限定される)。
$ sysctl kernel.osrelease
kernel.osrelease = 6.8.0-63-generic
$ sysctl -w net.ipv4.ip_forward=1 # 0:無効化、1:有効化
また、以下のコマンドは内部的には /proc
配下のファイルから情報を取得している。
カーネルモジュール
kernel object
.ko
ファイル。
デバイスドライバはカーネルとは別のモジュールとして分離されているため、必要に応じてロードして追加することができる。
この仕組みによりカーネル本体のサイズを小さくすることができる。カーネルが小さくなることにより、起動時間が短縮され、またデバイスドライバを必要に応じて切り替えることにより、様々なハードウェアに対応できるようになる。
ただし、必ずしも全てのデバイスドライバがモジュール化されている必要はなく、頻繁に利用デバイスドライバはカーネル本体に組み込んでしまうこともできる。
カーネルに組み込まれたモジュールは .ko
ファイルとしては存在しないが、/lib/modules
ディレクトリ配下のファイルに情報として格納されており、これを介して確認することができる。
$ ls /lib/modules
6.8.0-53-generic 6.8.0-55-generic 6.8.0-60-generic 6.8.0-63-generic 👈
6.8.0-54-generic 6.8.0-59-generic 6.8.0-62-generic
$ ls /lib/modules/6.8.0-63-generic/
build modules.alias.bin modules.builtin.modinfo modules.order vdso
initrd modules.builtin 👈 modules.dep modules.softdep
kernel modules.builtin.alias.bin modules.dep.bin modules.symbols
modules.alias modules.builtin.bin modules.devname modules.symbols.bin
$ cat /lib/modules/6.8.0-63-generic/modules.builtin | less
kernel/arch/arm64/kvm/kvm.ko 👈
kernel/arch/arm64/crypto/sha512-ce.ko
...
/lib/modules/modules.dep
モジュールの依存関係が記述されたファイル。
モジュールのパス:依存するモジュールのパス
$ cat /lib/modules/6.8.0-63-generic/modules.dep | less
kernel/arch/arm64/crypto/sha1-ce.ko.zst: # 依存モジュールなし
kernel/arch/arm64/crypto/sha2-ce.ko.zst: kernel/arch/arm64/crypto/sha256-arm64.ko.zst
kernel/arch/arm64/crypto/sha3-ce.ko.zst: # 依存モジュールなし
kernel/arch/arm64/crypto/sm3-neon.ko.zst: kernel/crypto/sm3.ko.zst
kernel/arch/arm64/crypto/sm3-ce.ko.zst: kernel/crypto/sm3.ko.zst
...
/proc/modules
現在カーネルにロードされているカーネルモジュールを知ることができる仮想ファイル。
$ lsmod
で出力される情報と同じ情報を知ることができる。
- モジュール名
- サイズ
- 参照回数
$ ls /proc/
ls /proc
1 18 27 2947 3094 4 50 628 690 80 devices kcore modules 👈 sys
10 19 2706 2953 32 40 51 629 7 84 diskstats key-users mounts sysrq-trigger
110 195 2778 2962 33 420 52 63 70 850 driver keys net sysvipc
12 2 28 2967 331 421 53 637 707 acpi dynamic_debug kmsg pagetypeinfo thread-self
13 20 2851 2970 332 43 54 64 71 asound execdomains kpagecgroup partitions timer_list
139 21 2855 2972 34 44 55 642 752 bootconfig fb kpagecount pressure tty
14 22 2874 2973 342 45 56 649 753 buddyinfo filesystems kpageflags schedstat uptime
140 23 2883 2974 346 46 564 65 754 bus fs latency_stats scsi version
1453 238 29 3 35 469 57 650 755 cgroups interrupts loadavg self version_signature
15 239 2904 30 353 47 58 66 78 cmdline iomem locks slabinfo vmallocinfo
16 24 2918 307 36 48 6 67 788 consoles ioports mdstat softirqs vmstat
165 2433 2925 3081 38 49 60 689 794 cpuinfo irq meminfo stat zoneinfo
17 26 2946 3082 39 5 61 69 797 crypto kallsyms misc swaps
$ cat /proc/modules
tls 159744 0 - Live 0x0000000000000000
qrtr 49152 2 - Live 0x0000000000000000
uas 32768 0 - Live 0x0000000000000000
...
/etc/modprobe.conf
/ /etc/modprode.d/
-
/etc/modprobe.conf
- 古い Linux
-
$ modprobe
の設定ファイル
-
/etc/modprobe.d/
- 現代の Linux で一般的
-
$ modprobe
の設定ファイルが配置されるディレクトリ
項目 | 意味 |
---|---|
alias |
別名をつけることができる |
options |
モジュールに渡すパラメータ |
install |
インストール時の処理$ modprobe
|
remove |
削除時の処理 |
blacklist |
自動読み込みされるモジュールを禁止するリスト |
$ ls /etc/modprobe.d
blacklist-ath_pci.conf blacklist-framebuffer.conf blacklist.conf mdadm.conf
blacklist-firewire.conf blacklist-rare-network.conf iwlwifi.conf
$ cat /etc/modprobe.d/blacklist-ath_pci.conf
# For some Atheros 5K RF MACs, the madwifi driver loads buts fails to
# correctly initialize the hardware, leaving it in a state from
# which ath5k cannot recover. To prevent this condition, stop
# madwifi from loading by default. Use Jockey to select one driver
# or the other. (Ubuntu: #315056, #323830)
blacklist ath_pci 👈
$ lsmod
現在カーネルにロードされているカーネルモジュールを一覧表示することができる。
$ lsmod
$ lsmod
Module Size Used by
tls 159744 0
qrtr 49152 2
uas 32768 0
usb_storage 90112 1 uas
input_leds 12288 0
joydev 36864 0
...
Used by
は参照回数、そのモジュールを利用している別モジュールを示す。
$ modinfo
モジュール情報を表示する。
$ modinfo モジュール名
$ modinofo tls
filename: /lib/modules/6.8.0-62-generic/kernel/net/tls/tls.ko.zst
alias: tcp-ulp-tls
alias: tls
license: Dual BSD/GPL
description: Transport Layer Security Support
author: Mellanox Technologies
srcversion: 7D318BDDFB06F1AC4EA96BF
depends:
intree: Y
name: tls
vermagic: 6.8.0-62-generic SMP preempt mod_unload modversions aarch64
sig_id: PKCS#7
signer: Build time autogenerated kernel key
sig_key: 14:98:64:4F:19:A8:A4:B7:A0:BB:39:A3:D6:93:7B:43:1F:A2:ED:DA
sig_hashalgo: sha512
signature: 26:1C:5B:E7:93:C3:F2:73:B7:83:45:56:B4:91:CA:7B:3B:D9:BD:20:
8F:FB:97:62:CD:63:4D:BF:87:0D:9A:F5:06:C6:AB:13:C9:AC:DF:2A:
96:F8:04:81:5B:DA:7F:33:04:4B:97:AB:5A:4D:AD:53:3C:92:17:BF:
...
$ modinfo -a モジュール名
$ modinfo -d モジュール名
$ modinfo -n モジュールファイル名
$ insmod
insert module
モジュール(.ko
ファイル)をカーネルに手動で挿入(ロード)するコマンド。
依存関係の自動解決を行わない。ロードするモジュールが依存する別モジュールは事前にロードしておく必要がある。
$ modprobe
とは異なり、モジュール名だけでなく絶対パスでモジュールを指定する必要がある。
$ insmod モジュールのファイルパス
$ rmmod
ロードされているモジュールをアンロードする。
モジュールが使用中の場合、他のモジュールがこのモジュールに依存している場合、はアンロードすることができない。
$ rmmod モジュール名
$ modprobe
probe=探査する、調査する
モジュールをロード、アンロードするコマンド。
指定したモジュールが必要とする別のモジュールなど、依存関係も自動で探査(probe)して解決してくれる。
モジュールのロードに使用するパラメータ(オプション)は、以下の設定ファイルに記述できる。
-
/etc/modprobe.conf
- 古い形式。現在はあまり使われない
-
/etc/modprobe.d/ファイル名.conf
- 現在の主流
$ modprobe モジュール名
$ modprobe -r モジュール名
$ modprobe -a モジュール名1 モジュール名2 モジュール名3 ...
$ modprobe --show-depends モジュール名
$ modprobe -n モジュール名
$ depmod
依存関係が記述される modules.dep
ファイルを作成する。
modules.dep
ファイルは /lib/modules
ディレクトリに配置される。
$ insmod
vs modprobe
違い | $ insmod |
$ modprobe |
---|---|---|
ロードするモジュールの指定方法 |
.ko ファイルパス |
モジュール名 |
依存関係 | 解決しない | 自動解決 |
カーネルの実体
カーネルは イメージファイル の /boot/vmlinuz-バージョン
として存在している。
カーネルイメージはカーネルをコンパイルすることで生成される。
(vm)virtual memory (linu)linux (.z)compressed
= 圧縮された Linux カーネルイメージファイル(仮想メモリ機能あり)
かつてのカーネルは仮想メモリ機能に対応するものと非対応のものがあった。
カーネルのソースコード
カーネルのソースコードは Linux の 公式サイト からダウンロードできる。
また、パッケージ としても提供されている。
$ apt search linux-source
Sorting... Done
Full Text Search... Done
linux-source/noble-updates,noble-security 6.8.0-63.66 all
Linux kernel source with Ubuntu patches
linux-source-6.8.0/noble-updates,noble-security 6.8.0-63.66 all
Linux kernel source for version 6.8.0 with Ubuntu patches
$ apt install linux-source
$ apt
でインストールを実行した場合、/usr/src
ディレクトリにソースコードをダウンロードされる。
$ ls -l /usr/src/
drwxr-xr-x 2 root root 4096 Jul 12 07:44 linux-source-6.8.0
lrwxrwxrwx 1 root root 45 Jun 13 14:50 linux-source-6.8.0.tar.bz2 -> linux-source-6.8.0/linux-source-6.8.0.tar.bz2
$ ls -l /usr/src/linux-source-6.8.0
total 349632
-rw-r--r-- 1 root root 358017471 Jun 13 14:50 linux-source-6.8.0.tar.bz2
$ tar -tvjf /usr/src/linux-source-6.8.0/linux-source-6.8.0.tar.bz2
... # 膨大な表示数だったため Ctrl + C で中止
$ tar -tvjf /usr/src/linux-source-6.8.0/linux-source-6.8.0.tar.bz2 | wc -l
89000 # ファイルが 89000 個もあった
$ tar -xvjf /usr/src/linux-source-6.8.0/linux-source-6.8.0.tar.bz2
...
カーネルのソースコードは以下のファイル、ディレクトリで構成されている。
$ ls linux-source-6.8.0/
COPYING Kconfig README certs fs init lib samples tools
CREDITS LICENSES Ubuntu.md crypto generic.depmod.log io_uring mm scripts ubuntu
Documentation MAINTAINERS arch drivers generic.inclusion-list.log ipc net security usr
Kbuild Makefile block dropped.txt include kernel rust sound virt
ファイル | 説明 |
---|---|
Makefile |
$ make で使用される |
.config |
カーネルビルド時の設定ファイル |
ディレクトリ | 説明 |
---|---|
arch |
アーキテクチャの固有コード |
Documentation |
ドキュメント |
drivers |
デバイスドライバ関連 |
fs |
ファイルシステム関連 |
include |
C 言語のヘッダファイル(.h ) |
init |
カーネル起動時の処理 |
ipc |
プロセス間通信関連 |
kernel |
プロセススケジューラ、シグナル、システムコール |
lib |
共通ライブラリ |
mm |
ページ管理、仮想メモリ、スワップ等のメモリ管理関連 |
net |
ネットワークプロトコル関連 |
scripts |
ビルド用のスクリプトなど |
sound |
サウンドドライバ |
.config
カーネルビルド時のビルド設定ファイル。
設定=y # 対象機能をカーネルに組み込んでビルドする
設定=n # 組み込まない
設定=m # モジュールとしてロード可能にする
カーネルのビルドには膨大な設定項目(数千項目)がある。
これを手動でイチから作成するのは非常に大変なため、現在動作しているカーネルの設定(.config
)を再利用する手法が一般的。
具体的には、現在の設定(/boot/config-カーネルバージョン
)をカーネルのソースコードのルート位置にコピーして、$ make oldconfig
コマンドの実行によって、新旧の設定差分だけを反映させる。
差分がない場合は $ make oldconfig
の実行は不要。
$ ls /boot/ | grep config
config-6.8.0-62-generic
config-6.8.0-63-generic
$ cp /boot/config-6.8.0-62-generic linux-source-6.8.0/.config
$ cd linux-source-6.8.0
$ make oldconfig # flex パッケージが足りないと言うエラーが出たので、これ以上は時間のある時に触ることとした...
$ make
ソースコードから実行可能ファイルをビルドするコマンド。
ビルドを自動化するツールであり、用途は特定のプログラミング言語に限定されない。
ただし、言語専用のビルドツールがすでに言語体系自体に含まれている場合は、それを利用した方が良い場合もある。
$ make
によるビルドは指示書である Makefile
ファイルに従って実行される。
$ make
$ make --file=Makefileパス
Makefile
にはコンパイルやリンク時に必要な以下の情報が記述される。
- ターゲット
- 依存ファイル
- コマンド
ターゲット: 依存ファイル
コマンド
hello: hello.c
gcc -o hello hello.c
$ make
はターゲットを指定して実行することができる(省略した場合、デフォルトのターゲットが実行されている)。
$ make ターゲット
オリジナルのカーネルをビルド、インストールする
カーネルを開発者自らビルドをすることができる。
.config
によって必要なドライバだけをカーネルに組み込み、ビルドをすることによって、軽量かつ、特定のハードウェアに最適化されたオリジナルのカーネルを作成することができる。
Makefile
のあるディレクトリで $ make
を実行することで、カーネルとモジュールの両方がコンパイルされる。
$ make
ビルドしたオリジナルのカーネルをインストールするには、以下のコマンドを実行する。
$ make install
インストールしたカーネルの実体(vmlinuz-バージョン
) は /boot
ディレクトリに配置される。
オリジナルのカーネルを、Linux 起動時のデフォルトに設定したい場合、ブートローダ の設定を行う必要がある。
カーネル同様に、ビルドしたオリジナルのモジュールをインストールには、以下のコマンドを実行する。
$ make modules_install
$ patch
カーネルの開発では、修正や機能追加は パッチファイル(.diff
や .patch
)によって行われる。
たとえばバグを修正したり、新しい機能を追加したりする際にパッチファイルを記述し、配布、適用する。配布時は圧縮されていることが多い。
パッチファイルは $ diff -urN
などで作成され、$ patch
で適用(apply)される。
$ patch パッチ適用対象ファイル パッチファイル
$ patch < パッチファイル
$ patch -i パッチファイル
パッチファイルには $ diff
の出力により、以下のように a/
や b/
などのプレフィックスが自動付与された形式でファイル差分が記述される。
--- a/src/foo.c
+++ b/src/foo.c
-p
オプションを付与すると、「差分ファイルに書かれたファイルパスの先頭から何階層分を取り除くか」を指定することができる。
自動的に付与された /a
や /b
を除去するために -p1
オプションが多用される。
$ patch -p0 < パッチファイル # パスを完全一致させて適用
$ patch -p1 < パッチファイル # 先頭 1 階層(a/ や b/)を無視して適用
$ patch -p2 < パッチファイル # 先頭 2 階層を無視
$ patch -R < パッチファイル
初期 RAM ディスク
initial RAM disk(initrd
)
init RAM file system(initramfs
)
ブート時に一時的な作業領域として使用される、メモリ上の仮想的なファイルシステム。
一般に、メモリ上に一時的に作られる仮想的なファイルシステム(ディスク)を RAM ディスク と呼び、システム起動時にカーネルがメモリ上に展開する RAM ディスクを特に 初期 RAM ディスク と呼ぶ。
初期 RAM ディスクの実体はアーカイブの圧縮ファイルである(initramfs
の場合)。
$ ls -l /boot/
total 186744
-rw------- 1 root root 6646252 May 19 10:55 System.map-6.8.0-62-generic
-rw------- 1 root root 6646252 Jun 13 14:50 System.map-6.8.0-63-generic
-rw-r--r-- 1 root root 337083 May 19 10:55 config-6.8.0-62-generic
-rw-r--r-- 1 root root 337083 Jun 13 14:50 config-6.8.0-63-generic
drwxr-xr-x 3 root root 4096 Jan 1 1970 efi
drwxr-xr-x 5 root root 4096 Jul 8 07:39 grub
lrwxrwxrwx 1 root root 27 Jul 8 07:23 initrd.img -> initrd.img-6.8.0-63-generic
-rw-r--r-- 1 root root 70311428 Jun 30 21:14 initrd.img-6.8.0-62-generic
-rw-r--r-- 1 root root 70305485 Jul 8 07:39 initrd.img-6.8.0-63-generic 👈 初期 RAM ディスク
lrwxrwxrwx 1 root root 27 Jul 8 07:23 initrd.img.old -> initrd.img-6.8.0-62-generic
drwx------ 2 root root 16384 Feb 16 08:20 lost+found
lrwxrwxrwx 1 root root 24 Jul 8 07:23 vmlinuz -> vmlinuz-6.8.0-63-generic
-rw------- 1 root root 18301454 May 19 15:52 vmlinuz-6.8.0-62-generic
-rw------- 1 root root 18298233 Jun 13 15:21 vmlinuz-6.8.0-63-generic 👈 カーネル
lrwxrwxrwx 1 root root 24 Jul 8 07:23 vmlinuz.old -> vmlinuz-6.8.0-62-generic
Linux ディストリビューションに含まれ提供される。
/boot/vmlinuz-バージョン # カーネル
/boot/initrd.img-バージョン # 初期 RAM ディスク
initrd
と initramfs
の 2 種類が存在する。
-
initrd
- 実体はデバイスファイルを圧縮(
$ gzip
)したもの - ファイルシステムのイメージファイル
- ファイルシステムドライバが必要
- ループバックでマウントされる
- 実体はデバイスファイルを圧縮(
-
initramfs
- 実体はアーカイブ(
$ cpio
)の圧縮($ gzip
)ファイル - ファイルシステムではなく、単なるアーカイブ
- ファイルシステムドライバを必要としない
- ファイルシステムではないので、マウントはされず、直接 RAM 上に展開される
- 実体はアーカイブ(
initrd
は近年の Linux では廃止傾向にある一方で、initrd
という名前にもかかわらず、中身は initramfs
ということもあり、名前だけは現在の Linux にも残っていることがある。
$ file /boot/initrd.img-6.8.0-63-generic
/boot/initrd.img-6.8.0-63-generic: ASCII cpio archive (SVR4 with no CRC)
上記は、ファイル名は initrd
という名前だが、$ cpio
によるアーカイブ形式のため、実体は initramfs
であることがわかる。
初期 RAM ディスクに入っているもの
起動直後のカーネルはストレージをマウントしていないため、ストレージ上のルートファイルシステムへはアクセスすることができない。
また基本的にカーネルは「できるだけ小さな」構成にされるため、デバイスドライバはカーネルに組み込まず、モジュールとすることが多い。カーネルにデバイスドライバが含まれていないハードウェアは、カーネル単体では認識して使うことができない。
初期 RAM ディスクには、カーネルがルートファイルシステムをマウントするために必要な「デバイスドライバ」や「設定用スクリプト」が格納されている。
例えば、ルートファイルシステムが以下のようなストレージ構成の場合、特定のドライバやツールが必要になる。
- ルートファイルシステムが LVM 上にある
-
$ dm-mod
や$ lvm
コマンドが必要
-
- ルートファイルシステムが、USB 接続された外部ディスク上にある
- USB ストレージ用ドライバが必要
- ルートファイルシステムが、ネットワーク越しの外部ディスク上にある
- ネットワーク初期化、ドライバが必要
- ディスクが暗号化されている(LUKS)
-
$ cryptsetup
で復号が必要
-
- RAID 構成になっている
-
$ mdadm
など RAID 用ツールが必要
-
初期 RAM ディスクのライフサイクル
初期 RAM ディスクは、ブートローダによって、OS 起動時にカーネルと共にメモリ上にロードされる。
カーネルは初期 RAM ディスクを解凍、展開してメモリ上に展開する。
RAM ディスクの役割は「ルートファイルシステムをマウントすること」なので、OS が起動すると、役割を終えメモリから解放される。
$ mkinitrd
initial RAM disk
古い initrd
で使用されていた。現在の initrd
では、内部的に $ dracut
が呼ばれている。
$ mkinitrd 作成するイメージファイル カーネルバージョン
$ mkinitramfs
init RAM file system
$ mkinitramfs -o 作成するイメージファイル カーネルバージョン
$ dracut
drastic constructor of unified tools
mkinitrd
の後継。Red Hat 系(RHEL、CentOS、Fedora)で使用される。
$ dcacut 作成するイメージファイル カーネルバージョン
ログは /var/log/dracut.log
に保存される。
カーネルパラメータ
カーネルは ブートローダ によって起動される。
ブートローダは、カーネルに起動時コマンドラインパラメータ(カーネルパラメータ)を与えることができ、これによってカーネルの挙動を変更することができる。
また、稼働中のカーネルがユーザに対して公開してくれる内部情報を カーネルパラメータ と呼ぶことがある。
カーネルパラメータは文脈によって異なる意味を持つが、一般に、単に「カーネルパラメータ」といった場合、後者を指すことが多い。
起動時のコマンドライン引数
The kernel’s command-line parameters(公式サイト より)
カーネルはブートローダから起動されるとき、以下のコマンドライン引数を受け取ることができる。
これらの設定値は カーネルパラメータ と呼ばれる。
カーネルパラメータ一覧
引数 | 意味 |
---|---|
ro |
read only ルートファイルシステム を読み取り専用でマウントする。 その後、 init プロセスの中などで、$ fsck が実行され、戻り値が正常だった場合に $ mount -o remout,rw / される。 |
rw |
read write ルートファイルシステムを読み書き可能状態でマウントする。 |
quiet |
起動時のカーネルメッセージを最小限に抑える。 |
splash |
GUI 起動時にスプラッシュ画像を表示する。 |
debug |
カーネルをデバッグモードで起動。 詳細なログが出力される。 |
root= |
ルートファイルシステムをマウントするパーティション。 UUID、LABEL でも指定可能。 ディスク,パーティション という形式で、ディスクの指定も可能。例: root=/dev/sda1
|
init= |
最初に実行するプロセス。 通常は init または systemd 。トラブル発生時は /bin/bash にして復旧作業をすることも可能。 例: init=/usr/lib/systemd/systemd
|
rootfstype= |
ルートファイルシステムの種類。 例: rootfstype=ext4
|
ランレベル |
カーネル起動時のランレベル。 例: 3
|
loglevel= |
ログ出力のレベル。 例: loglebel=3
|
console= |
カーネルの 標準出力 に接続されるコンソール。 例: console=tty0
|
nosmp |
SMP (Symmetric Multi-Processing)を無効化する。マルチコア CPU やマルチプロセッサ環境で使用すると、1つの CPU コアだけを使用するシングルコアモードで起動する。 |
maxcpus= |
起動時に有効化する CPU コアの最大数。nosmp より柔軟な、指定した数だけコアを使うといったことが可能になる。例: maxcpus=4
|
変更する
ブートローダは、設定ファイル /boot/grub/grub.cfg
の GRUB_CMDLINE_LINUX
に設定されたパラメータをカーネル起動時に使用する。
/boot/grub/grub.cfg
は直接編集して利用するファイルではなく、$ update-grub
の実行によって更新するファイル。
$ update-grub
は、テンプレートファイル /etc/default/grub
を基に grub.cfg
を自動生成する。
つまり、カーネルパラメータを変更する場合、/etc/default/grub
の GRUB_CMDLINE_LINUX
を編集することになる。
# If you change this file, run 'update-grub' afterwards to update
# /boot/grub/grub.cfg.
# For full documentation of the options in this file, see:
# info -f grub -n 'Simple configuration'
GRUB_DEFAULT=0
GRUB_TIMEOUT_STYLE=hidden
GRUB_TIMEOUT=0
GRUB_DISTRIBUTOR=`( . /etc/os-release; echo ${NAME:-Ubuntu} ) 2>/dev/null || echo Ubuntu`
GRUB_CMDLINE_LINUX_DEFAULT=""
GRUB_CMDLINE_LINUX="" 👈 カーネルパラメータ設定用
...
GRUB_CMDLINE_LINUX
で設定される値は、ブートローダがカーネルを起動するときに使用するコマンドライン引数となる。
※ GRUB_CMDLINE_LINUX_DEFAULT
は通常起動(GUI あり)のみ使用され、リカバリーモードやカスタムブートでは無視される。一方 GRUB_CMDLINE_LINUX
はすべてのカーネル起動に共通で適用される。
カーネルは内部情報を /proc/
配下の仮想ファイルとして公開しており、稼働中のカーネルが起動時に受け取ったパラメータは、/proc/cmdline
ファイルによって確認することができる。
【カーネルパラメータを変更する一連の流れ】
-
$ cat /proc/cmdline
で現在のパラメータを確認する -
/etc/default/grub
のGRUB_CMDLINE_LINUX
を手動変更する -
$ update-grub
を実行する -
/boot/grub/grub.cfg
が再生成される -
$ reboot
を実行してカーネルを再起動する -
$ cat /proc/cmdline
で反映されたことを確認する
/proc/cmdline
command line
現在動作中のカーネルが、起動時にブートローダから受け取ったパラメータをそのまま文字列として表示する仮想ファイル。
$ cat /proc/cmdline
BOOT_IMAGE=/vmlinuz-6.8.0-62-generic root=/dev/mapper/ubuntu--vg-ubuntu--lv ro
動作中(ランタイム)のカーネルパラメータ
runtime kernel parameters
カーネルには内部の情報を /proc/sys
ディレクトリ配下の仮想ファイルとして公開する仕組みがある。
仮想ファイルとしてカーネルから公開される情報を カーネルパラメータ と呼ぶ。
$ cat /proc/sys/ファイル名
$ cat /proc/sys/kernel/ostype
kernel.ostype = Linux
カーネルパラメータ一覧
カーネルパラメータ | 説明 |
---|---|
/proc/sys/fs/file-max |
同時に開ける最大ファイル数 |
/proc/sys/vm/swappiness |
スワップの使用頻度(0 ~ 100 。低いほど物理メモリ優先) |
/proc/sys/kernel/hostname |
ホスト名 |
/proc/sys/kernel/osrelease |
カーネルのバージョン |
/proc/sys/kernel/ostype |
OS のバージョン |
/proc/sys/kernel/threads-max |
作成可能なスレッドの最大数 |
/proc/sys/kernel/pid_max |
プロセス ID の最大値 |
/proc/sys/kernel/sem |
セマフォ数 |
/proc/sys/net/core/somaxconn |
listen() の待ち受けキューの最大長 |
/proc/sys/net/core/rmem_default |
受信ソケットバッファのデフォルトサイズ |
/proc/sys/net/core/rmem_max |
受信ソケットバッファの最大サイズ |
/proc/sys/net/core/wmem_default |
送信ソケットバッファのデフォルトサイズ |
/proc/sys/net/core/wmem_max |
送信ソケットバッファの最大サイズ |
/proc/sys/net/ipv4/ip_forward |
パケットのフォワーディング有無(ルータ機能の有効化) |
/proc/sys/net/ipv4/icmp_echo_ignore_all |
$ ping への反応有無 |
/proc/sys/net/ipv4/conf/all/rp_filter |
逆方向パケットフィルタの設定(IP スプーフィング対策) |
カーネルパラメータには、動作中に変更されない 静的 な情報もあれば、動作中に値を変更して挙動を変えることができる 動的 な設定値もある。
- 静的
- カーネルのバージョン
- OS の種類
- ...
- 動的
- ホスト名
- パケットのフォワーディング有効化設定
- ...
/etc/sysctl.conf
には、静的か動的かにかかわらず、全ての設定値(初期値)が記述されていて、カーネルは起動時にこのファイルを初期値として参照する。
変更する①
動的な設定値を変更した場合、変更は即時反映される。
$ echo 値 > /proc/sys/ファイル名
ただし、/proc/
配下の 仮想ファイル に対する変更は一時的に過ぎない。
カーネルが再起動された際は、再び /etc/sysctl.conf
が読み込まれるためである。
つまり、カーネルパラメータの変更を永続的に行いたい場合には /etc/sysctl.conf
を直接編集する必要がある。
変更する②
カーネルパラメータは $ sysctl
を使用して確認、変更することもできる。
$ sysctl
によってカーネルパラメータを扱う際は カーネル変数 を利用する。
カーネル変数とは /proc/sys/
以降のパスをドット .
で区切ったものである。
例えば、カーネルパラメータ /proc/sys/net/ipv4/ip_forward
ファイルは、カーネル変数 net.ipv4.ip_forward
として表現される。
$ sysctl カーネル変数名
$ sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 0
$ sysctl -w カーネル変数=値
$ sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 0
$ sysctl -w net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1
$ sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1
/etc/sysctl.conf
カーネルパラメータ設定ファイル。
カーネルの起動時に初期値として参照される。
$ sysctl
による変更はあくまでも一時的な変更であり、永続的に変更したい場合 には、この /etc/sysctl.conf
を編集する必要がある。
パラメータ=値
/etc/sysctl.conf
#
# /etc/sysctl.conf - Configuration file for setting system variables
# See /etc/sysctl.d/ for additional system variables.
# See sysctl.conf (5) for information.
#
#kernel.domainname = example.com
# Uncomment the following to stop low-level messages on console
#kernel.printk = 3 4 1 3
###################################################################
# Functions previously found in netbase
#
# Uncomment the next two lines to enable Spoof protection (reverse-path filter)
# Turn on Source Address Verification in all interfaces to
# prevent some spoofing attacks
#net.ipv4.conf.default.rp_filter=1
#net.ipv4.conf.all.rp_filter=1
# Uncomment the next line to enable TCP/IP SYN cookies
# See http://lwn.net/Articles/277146/
# Note: This may impact IPv6 TCP sessions too
#net.ipv4.tcp_syncookies=1
# Uncomment the next line to enable packet forwarding for IPv4
#net.ipv4.ip_forward=1
# Uncomment the next line to enable packet forwarding for IPv6
# Enabling this option disables Stateless Address Autoconfiguration
# based on Router Advertisements for this host
#net.ipv6.conf.all.forwarding=1
###################################################################
# Additional settings - these settings can improve the network
# security of the host and prevent against some network attacks
# including spoofing attacks and man in the middle attacks through
# redirection. Some network environments, however, require that these
# settings are disabled so review and enable them as needed.
#
# Do not accept ICMP redirects (prevent MITM attacks)
#net.ipv4.conf.all.accept_redirects = 0
#net.ipv4.conf.default.accept_redirects = 0
# _or_
# Accept ICMP redirects only for gateways listed in our default
# gateway list (enabled by default)
# net.ipv4.conf.all.secure_redirects = 1
#
# Do not send ICMP redirects (we are not a router)
#net.ipv4.conf.all.send_redirects = 0
#
# Log Martian Packets
#net.ipv4.conf.all.log_martians = 1
#
###################################################################
# Magic system request Key
# 0=disable, 1=enable all, >1 bitmask of sysrq functions
# See https://www.kernel.org/doc/html/latest/admin-guide/sysrq.html
# for what other values do
#kernel.sysrq=438
$ sysctl
カーネルパラメータを確認、変更するためのコマンド。
操作対象のカーネルパラメータは、 /proc/sys/
以降のパスをドット .
で区切った カーネル変数 として扱う。
$ sysctl -a # すべて表示
$ sysctl カーネル変数名
$ sysctl -w カーネル変数名=値
カーネル変数
カーネルパラメータ の仮想ファイル /proc/sys/
ディレクトリ以下のパスを .
区切りで表現したもの。
/proc/sys
ディレクトリ配下のカーネルパラメータを表現する仮想ファイルと 1 対 1 で対応していて、$ sysctl
の引数として利用することができる。
カーネル変数一覧
カーネルパラメータ | カーネル変数 |
---|---|
/proc/sys/fs/file-max |
fs.file-max |
/proc/sys/vm/swappiness |
vm.swappiness |
/proc/sys/kernel/osrelease |
kernel.osrelease |
/proc/sys/net/ipv4/ip_forward |
net.ipv4.ip_forward |
/proc/sys/net/ipv4/icmp_echo_ignore_all |
net.ipv4.icmp_echo_ignore_all |
/proc/sys/net/ipv4/conf/all/rp_filter |
net.ipv4.conf.all.rp_filter |
$ uname
UNIX name
システムに関する情報(カーネル名、バージョン、アーキテクチャ など)を表示できるコマンド。
$ uname
Linux
$ uname -s
Linux
$ uname -n
$ uname -r
6.8.0-62-generic
$ uname -v
#65-Ubuntu SMP PREEMPT_DYNAMIC Mon May 19 17:08:41 UTC 2025
$ uname -m
aarch64
uname -a
$ dmesg
/var/log/dmesg
に保存された、起動時のカーネルのログを確認する。
$ dmesg
/var/log/dmesg
の情報は $ dmesg --clear
にて明示的に削除することができる(Ubuntu では /var/log/dmesg
は作成されない)。
$ dmesg --clear