2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Linux カーネル

Last updated at Posted at 2025-07-16

はじめに

メモリ上に常駐し、システムの基幹となる制御を行う OS の中核部分を担うプログラムを カーネル(Kernel) と言う。

software (3).png

カーネルが制御している対象は下記のとおり。

「Linux」という用語は、実は厳密には OS ではなく、このカーネルを指している。

つまり狭義の Linux が「カーネル」であり、広義の Linux が「OS」や「Linuxディストリビューション」までを含んだものということになる。

デバイスへのアクセスはカーネルのみが持つ特権

カーネルは ハードウェアとソフトウェアの橋渡し 的な役割を担っている。

ユーザプロセスは「直接」デバイスへアクセスすることが許されていないため、ハードウェアにアクセスを行う場合、カーネルから提供されるインターフェース(システムコール)を利用する。

ユーザプロセスにとってはカーネルを介してしか、ハードウェアにアクセスができないという制約は、アクセスの競合のために存在している。

複数のアクセスが競合した場合、カーネルは中央集権的に、それぞれのアクセスの交通整理や調停を行う。

カーネルがユーザプロセスに公開するインターフェースや、命令または関数を システムコール 、スーパーバイザコール(SVC:supervisor call)という。

システムコールや SVC が提供するインターフェースは、ハードウェア側の仕様の違いに依存しないように抽象化されている。つまり、カーネルを利用する側は、ハードウェアの仕様の違いを意識する必要がない。

カーネルはプロセスなのか

プロセスとは、実行中のプログラムがメモリ上に展開されたものであり、カーネルが生成、管理する実行単位である。

各プロセスは、カーネルによって プロセスID(PID)を割り当てられ、カーネルによって メモリ空間や CPU の使用時間が管理される。

つまり、プロセスとは「カーネルの管理対象」であり、「カーネルが作り出す実行単位」である

カーネル自身は一般的なユーザプロセスではなく、PID を持つ「実行単位」ではない。ただし、カーネル内部には カーネルスレッド と呼ばれる PID を持つ処理が存在し、それらはプロセスリストに表示されることがある(kthreaddkworker)。

カーネルはメモリ上に常に存在しているが、$ 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 などのように表現される。

LPIC (33).png

ユーザプロセスが展開されるメモリ上の領域は ユーザ空間 と呼ばれる。

「ユーザ空間」上で動作するプロセスは 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(initsystemd)の情報
/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 で書き込みすることができる。

procfs を読み取る
$ 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
procfs を書き込む
$ 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

モジュールの依存関係が記述されたファイル。

modeuls.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 で出力される情報と同じ情報を知ることができる。

  • モジュール名
  • サイズ
  • 参照回数
/proc/modules
$ 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
  • /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:
        ...
モジュールの作成者名を表示する(--author)
$  modinfo -a モジュール名
モジュールの説明を表示する(--descrption)
$ modinfo -d モジュール名
モジュールの実体ファイル名を表示する(--filename)
$ modinfo -n モジュールファイル名

$ insmod

insert module

モジュール(.ko ファイル)をカーネルに手動で挿入(ロード)するコマンド。

依存関係の自動解決を行わない。ロードするモジュールが依存する別モジュールは事前にロードしておく必要がある。

$ modprobe とは異なり、モジュール名だけでなく絶対パスでモジュールを指定する必要がある。

モジュールをモードする
$ insmod モジュールのファイルパス

$ rmmod

ロードされているモジュールをアンロードする。

モジュールが使用中の場合、他のモジュールがこのモジュールに依存している場合、はアンロードすることができない。

モジュールをアンロードする
$ rmmod モジュール名

$ modprobe

probe=探査する、調査する

モジュールをロード、アンロードするコマンド。

指定したモジュールが必要とする別のモジュールなど、依存関係も自動で探査(probe)して解決してくれる

モジュールのロードに使用するパラメータ(オプション)は、以下の設定ファイルに記述できる。

モジュールをロードする
$ modprobe モジュール名
モジュールをアンロードする(remove)
$ modprobe -r モジュール名
全てのモジュールをロードする
$ modprobe -a モジュール名1 モジュール名2 モジュール名3 ...
依存関係を表示する
$ modprobe --show-depends モジュール名
処理を実行せず、何をするかを表示する(no action)
$ 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 の 公式サイト からダウンロードできる。

Screenshot 2025-07-12 at 16.08.54.png

また、パッケージ としても提供されている。

カーネルのソースコードをダウンロードする
$ 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
...

$ tar

カーネルのソースコードは以下のファイル、ディレクトリで構成されている。

ディレクトリ構成
$ 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

カーネルビルド時のビルド設定ファイル。

.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 ファイルに従って実行される。

カレントディレクトリの Makefile に従いビルドを行う
$ make
Makefile を指定する
$ make --file=Makefileパス

Makefile にはコンパイルやリンク時に必要な以下の情報が記述される。

  • ターゲット
  • 依存ファイル
  • コマンド
Makefile
ターゲット: 依存ファイル
    コマンド
hello.c があるときだけ、$ gcc を使って hello という実行ファイルを作る
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/ や 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 の場合)。

初期 RAM ディスクの実体は、アーカイブの圧縮ファイル
$ 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 ディストリビューションに含まれ提供される。

初期 RAM ディスクはカーネルと共に、Linux ディストリビューションの一部として提供される
/boot/vmlinuz-バージョン         # カーネル
/boot/initrd.img-バージョン      # 初期 RAM ディスク

initrdinitramfs の 2 種類が存在する。

  • initrd
    • 実体はデバイスファイルを圧縮($ gzip)したもの
    • ファイルシステムのイメージファイル
    • ファイルシステムドライバが必要
    • ループバックでマウントされる
  • initramfs
    • 実体はアーカイブ($ cpio)の圧縮($ gzip)ファイル
    • ファイルシステムではなく、単なるアーカイブ
    • ファイルシステムドライバを必要としない
    • ファイルシステムではないので、マウントはされず、直接 RAM 上に展開される

initrd は近年の Linux では廃止傾向にある一方で、initrd という名前にもかかわらず、中身は initramfs ということもあり、名前だけは現在の Linux にも残っていることがある。

名前は initrd でも、中身は initramfs
$ file /boot/initrd.img-6.8.0-63-generic
/boot/initrd.img-6.8.0-63-generic: ASCII cpio archive (SVR4 with no CRC)

$ file

上記は、ファイル名は initrd という名前だが、$ cpio によるアーカイブ形式のため、実体は initramfs であることがわかる。

初期 RAM ディスクに入っているもの

起動直後のカーネルはストレージをマウントしていないため、ストレージ上のルートファイルシステムへはアクセスすることができない。

また基本的にカーネルは「できるだけ小さな」構成にされるため、デバイスドライバはカーネルに組み込まず、モジュールとすることが多い。カーネルにデバイスドライバが含まれていないハードウェアは、カーネル単体では認識して使うことができない。

初期 RAM ディスクには、カーネルがルートファイルシステムをマウントするために必要な「デバイスドライバ」や「設定用スクリプト」が格納されている。

例えば、ルートファイルシステムが以下のようなストレージ構成の場合、特定のドライバやツールが必要になる。

  • ルートファイルシステムが LVM 上にある
    • $ dm-mod$ lvm コマンドが必要
  • ルートファイルシステムが、USB 接続された外部ディスク上にある
    • USB ストレージ用ドライバが必要
  • ルートファイルシステムが、ネットワーク越しの外部ディスク上にある
    • ネットワーク初期化、ドライバが必要
  • ディスクが暗号化されている(LUKS)
  • RAID 構成になっている
    • $ mdadm など RAID 用ツールが必要

初期 RAM ディスクのライフサイクル

初期 RAM ディスクは、ブートローダによって、OS 起動時にカーネルと共にメモリ上にロードされる。

カーネルは初期 RAM ディスクを解凍、展開してメモリ上に展開する。

RAM ディスクの役割は「ルートファイルシステムをマウントすること」なので、OS が起動すると、役割を終えメモリから解放される。

$ mkinitrd

initial RAM disk

古い initrd で使用されていた。現在の initrd では、内部的に $ dracut が呼ばれている。

初期 RAM ディスクを作成する
$ mkinitrd 作成するイメージファイル カーネルバージョン

$ mkinitramfs

init RAM file system

初期 RAM ディスクを作成する
$ mkinitramfs -o 作成するイメージファイル カーネルバージョン

$ dracut

drastic constructor of unified tools

mkinitrd の後継。Red Hat 系(RHEL、CentOS、Fedora)で使用される。

初期 RAM ディスクを作成する
$ dcacut 作成するイメージファイル カーネルバージョン

ログは /var/log/dracut.log に保存される。

カーネルパラメータ

カーネルは ブートローダ によって起動される。

ブートローダは、カーネルに起動時コマンドラインパラメータ(カーネルパラメータ)を与えることができ、これによってカーネルの挙動を変更することができる。

LPIC (31).png

また、稼働中のカーネルがユーザに対して公開してくれる内部情報を カーネルパラメータ と呼ぶことがある。

LPIC (32).png

カーネルパラメータは文脈によって異なる意味を持つが、一般に、単に「カーネルパラメータ」といった場合、後者を指すことが多い。

起動時のコマンドライン引数

The kernel’s command-line parameters(公式サイト より)

カーネルはブートローダから起動されるとき、以下のコマンドライン引数を受け取ることができる。

これらの設定値は カーネルパラメータ と呼ばれる。

LPIC (31).png

カーネルパラメータ一覧
引数 意味
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.cfgGRUB_CMDLINE_LINUX に設定されたパラメータをカーネル起動時に使用する。

/boot/grub/grub.cfg は直接編集して利用するファイルではなく、$ update-grub の実行によって更新するファイル。

$ update-grub は、テンプレートファイル /etc/default/grub を基に grub.cfg を自動生成する。

つまり、カーネルパラメータを変更する場合、/etc/default/grubGRUB_CMDLINE_LINUX を編集することになる。

/etc/default/grub
# 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 ファイルによって確認することができる。

【カーネルパラメータを変更する一連の流れ】

  1. $ cat /proc/cmdline で現在のパラメータを確認する
  2. /etc/default/grubGRUB_CMDLINE_LINUX を手動変更する
  3. $ update-grub を実行する
  4. /boot/grub/grub.cfg が再生成される
  5. $ reboot を実行してカーネルを再起動する
  6. $ cat /proc/cmdline で反映されたことを確認する

/proc/cmdline

command line

現在動作中のカーネルが、起動時にブートローダから受け取ったパラメータをそのまま文字列として表示する仮想ファイル。

/proc/cmdline を確認する
$ cat /proc/cmdline
BOOT_IMAGE=/vmlinuz-6.8.0-62-generic root=/dev/mapper/ubuntu--vg-ubuntu--lv ro

動作中(ランタイム)のカーネルパラメータ

runtime kernel parameters

カーネルには内部の情報を /proc/sys ディレクトリ配下の仮想ファイルとして公開する仕組みがある。

仮想ファイルとしてカーネルから公開される情報を カーネルパラメータ と呼ぶ。

LPIC (32).png

カーネルパラメータを確認する
$ 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
/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/ 以降のパスをドット . で区切った カーネル変数 として扱う。

全てのカーネルパラメータを一覧表示する(all)
$ sysctl -a # すべて表示
特定のカーネルパラメータを確認する
$ sysctl カーネル変数名
カーネルパラメータを更新する(write)
$ 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

システムに関する情報(カーネル名、バージョン、アーキテクチャ など)を表示できるコマンド。

カーネル名を表示する(system)
$ uname
Linux

$ uname -s
Linux
ホスト名を表示する(node:ネットワークノード)
$ uname -n
カーネルのバージョンを表示する(release)
$ uname -r
6.8.0-62-generic
カーネルバージョンを表示する(version)
$ uname -v
#65-Ubuntu SMP PREEMPT_DYNAMIC Mon May 19 17:08:41 UTC 2025
アーキテクチャを表示する(machine)
$ uname -m
aarch64
全ての情報を表示する(all)
uname -a

$ dmesg

/var/log/dmesg に保存された、起動時のカーネルのログを確認する。

起動時のカーネルのログを確認する
$ dmesg

/var/log/dmesg の情報は $ dmesg --clear にて明示的に削除することができる(Ubuntu では /var/log/dmesg は作成されない)。

ログを削除する
$ dmesg --clear
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?