はじめに
この記事は、Linux Advent Calendar 2019 - Qiitaの8日目です。
この記事では、今使っているLinux Kernelがどんなkernelなのか、どんな設定で動いているのかを確認する方法を紹介します。
Linux Kernelは様々な用途に使われています。
そのため、ひとくちにLinux Kernelと言っても、動作はシステムによって全然違います。
現状を把握する手段を知ることで、効率的にKernelのコードリーディングやより良い設定を探す一助になれば幸いです。
また、コメント大歓迎ですので、なんでもお気づきのことがありましたらぜひお気軽にお願いします。
-
この記事で書くこと
- Linux Kernelの素性を確認する方法
- Linux Kernelの設定値を確認する方法
-
この記事で書かないこと
- 各プロセスや各ユーザなどに対する設定(
ulimit
やnice
やquotactl
など) - ユーザ空間の設定(
sysconf
やpathconf
など) - ドライバに対する設定(insmod時のparameterなど)
- 各設定項目の説明
- 各プロセスや各ユーザなどに対する設定(
下記6つの項目を紹介しています。
各項目は独立していますので、気になるところからご覧ください。
Kernel Version
まずはどのversionのkernelが使われているのかを見てみましょう。
versionを知ることで、特定の機能や修正が入っているかを調査の材料にできます。
Kernel Versionの確認方法 uname -r
uname -r
コマンドを実行することで、実行中のKernel Versionを取得できます。
以下は、素のLinux Kernel 5.3.10を使っているときの結果です。
$ uname -r
5.3.10
環境によってはuname -r
を実行すると、上記のような3つの数字の後ろにいろいろくっついてるかも知れません。
例えば、以下はUbuntu 19.10での実行結果です。
$ uname -r
5.3.0-19-generic
この場合、version 5.3.0
のLinux kernelをベースに、Ubuntu 19.10用に修正したkernel、ということになります。
どのような修正がされているかは、どこかで公開されているはずです。
Ubuntuの場合は、source codeのパッケージおよびdiffが配布されています。
versionの後ろの文字列(19-generic
)の意味は、distributionごとに違います。
Ubuntuの場合はこちらに説明があります。
なお、versionについては他にもたくさん確認方法があり、ここに詳しい記事がありますので、ぜひこちらも見てみてください。
またuname
コマンドの中身については、Linux Advent Calendar 2019の1日目で詳しく解説してくれているので、そちらもぜひご覧ください。
Kernel Versionに関する参考ページ
- The Linux Kernel Archives
- unameコマンドから始めるデバッグ&カーネルハック入門 - φ(・・*)ゞ ウーン カーネルとか弄ったりのメモ
- Linuxのバージョンを確認する方法 - Qiita
- Kernel/FAQ - Ubuntu Wiki
- 5.3.0-19.20 : linux package : Ubuntu
CPU Architecture
続いて、どのCPU向けにビルドされたkernelかを確認してみます。
Linux Kernelの文脈だと、「どのCPU向けか」というのをArchitectureとかarchとか表現することが多いです。
Architectureはいろいろな意味で使われますが、ここではCPUのISA(命令セットアーキテクチャ)のことですね。
例えば、x86_64
やarm
などがあります。
Kernelを意識するときにCPU Architectureがわかってないケースはあまりないかも知れません。
でも、実は意外なArchitecture向けのkernelが動作していることがあります。
念の為に確認しておきましょう。
CPU Architectureの確認方法 uname -m
or arch
CPU Architectureを確認するためのコマンドには、uname -m
とarch
があります。
2つのコマンドはどちらもcoreutils
というパッケージで提供されており、実装は共通なので好きな方を使えばいいです。
PC(Ubuntu 18.04)の場合は、だいたいx86_64
と表示されると思います。
$ uname -m
x86_64
Raspberry Pi 3 ModelB+(Raspbian)で試してみると、armv7l
と表示されます。
$ uname -m
armv7l
実はRaspberry Pi 3 ModelB+には、Cortex-A53という64bitのARM CPUが搭載されています。
だったら64bit用のkernelが動いていると思ってしまいますが、その場合はaarch64
と表示されるはずです。
つまり、Raspbianでは32bit用にビルドしたkernelが32bit互換モードで動作している、ということですね。
(推測ですが、おそらくRasPi2やRasPi zeroなど32bit CPUのモデルと共通化するためでしょう)
Kernelのarch
ディレクトリ
CPU Architectureを確認できたので、今度は自分が使っているCPU Architectureの処理が、
Kernelソースコード上でどこに置かれているかを見てみましょう。
Kernelのソースコードを見てみると、arch/
ディレクトリ以下に
CPU Architectureごとのディレクトリがあることがわかります。
$ ls -F arch/
Kconfig arm/ csky/ ia64/ mips/ openrisc/ riscv/ sparc/ x86/
alpha/ arm64/ h8300/ m68k/ nds32/ parisc/ s390/ um/ xtensa/
arc/ c6x/ hexagon/ microblaze/ nios2/ powerpc/ sh/ unicore32/
先程紹介したuname -m
コマンドの結果をちょっとだけ置換したものがディレクトリ名になります。
置換はscripts/subarch.include
というMakefileで行われます。
例えば、x86_64
向けのkernelをビルドするときは、x86/
ディレクトリが使われるわけですね。
同じように、Raspbianのarmv7l
の場合は、arm/
ディレクトリが使われます。
SUBARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ \
-e s/sun4u/sparc64/ \
-e s/arm.*/arm/ -e s/sa110/arm/ \
-e s/s390x/s390/ -e s/parisc64/parisc/ \
-e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
-e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \
-e s/riscv.*/riscv/)
CPU Architectureの参考ページ
Kernel Build Config
続いては、Kernel Build Configです。
人によってはコンパイルスイッチとか#ifdef
とか言ったほうがしっくりくるかも知れません。
単にKernel Configとか言ったときは、これのことを指す場合が多いです。
先にも述べたようにLinux Kernelは幅広い用途で使われていますが、なんでもできる万能Kernelを作ると、イメージサイズがいたずらに大きくなってしまいます。
そのため、使わない機能をコンパイル対象外にすることで、サイズを節約しています。
デバッグ機能もkernel build configでOFF/ONする場合が多いので、どのようなデバッグ機能が使えるかを知ることもできます。
Kernel Build Configの確認方法 1. /boot/config-X.Y.Z
Linux distributionによっては、/boot
以下にkernel imageと一緒に残してくれています。
例えば、Ubuntu19.10では、/boot/config-5.3.0-19-generic
というファイルに保存されています。
CentOS 8, Debian 10でも同等のファイルがあります。
$ head /boot/config-$(uname -r)
#
# Automatically generated file; DO NOT EDIT.
# Linux/x86 5.3.0-19-generic Kernel Configuration
#
#
# Compiler: gcc (Ubuntu 9.2.1-9ubuntu2) 9.2.1 20191008
#
CONFIG_CC_IS_GCC=y
CONFIG_GCC_VERSION=90201
Kernel Build Configの確認方法 2. /proc/config.gz
CONFIG_IKCONFIG_PROC
を有効にしているkernelでは、
Kernel Build Configを/proc/config.gz
で確認することができます。
残念ながらあまり使える環境はないです。
ただ動作中のkernelに教えてもらうため、より確実な確認方法です。
使える環境では積極的に使いましょう。
例えば、Androidで使用されているLinux Kernelではこの方法が使えることが多いです。
以下は、Android 10のEmulatorで確認したときの結果です。
(gzip圧縮されているのでzcat
コマンドを使っていることに注意してください)
Samsung Galaxy Note8 (Android 9)でも、/proc/config.gz
が有効になっていました。
$ zcat /proc/config.gz | head
#
# Automatically generated file; DO NOT EDIT.
# Linux/x86_64 4.14.112 Kernel Configuration
#
CONFIG_64BIT=y
CONFIG_X86_64=y
CONFIG_X86=y
CONFIG_INSTRUCTION_DECODER=y
CONFIG_OUTPUT_FORMAT="elf64-x86-64"
CONFIG_ARCH_DEFCONFIG="arch/x86/configs/x86_64_defconfig"
Kernel Build Configにはどんな項目があるの?
Kernelのソースコードに含まれる、Kconfig
というファイルで定義されています。
依存関係や各項目の説明などもそこに記載されています。
またmake xconfig
を実行すると、各設定項目の説明を見ながら一覧できるので、おすすめです。
Ctrl-f
で検索もできます。
ごくごく一部ですが、いくつかよく使う項目を紹介します。
-
CONFIG_IKCONFIG_PROC
Kernel Build Configを/proc/config.gz
経由で取得できるようにします。
Kernel Build Configを色々いじるときにはまず有効にしておくとわかりやすいです。 -
CONFIG_DEBUG_INFO
デバッグシンボルを付与したカーネルイメージを生成するようになります。
gdb
を使ったKernelデバッグをするときに必要です。 -
CONFIG_FTRACE
FtraceというKernelの動作を解析するための機能を有効にします。
LinuxにFtraceを導入する - Qiitaに詳しく解説してくれています。 -
CONFIG_KPROBE
動作中のKernelにバイナリパッチを当てるための仕組みである、Kprobeを有効にします。
Kprobeをもう少し使いやすくしたツール、SystemTapを使うためにも必要です。
Kernel Build Configの変更方法
Kernel Build Configを変更するためには、Kernelの再ビルドが必要です。
上述の方法で取得した、現状の.config
をベースにmake menuconfig
やmake xconfig
等で編集し、Kernelを再ビルドするのが一般的な変更方法です。
ただし、.config
はビルド時に生成されるファイルなので、ソースコード管理の対象外にすべきです。
make menuconfig
で目的の.config
が作れたら、make savedefconfig
で出力されるdefconfig
をコミットするようにしましょう。
make savedefconfig
は、その時点の.config
を再生成するための最小限のconfigを出力してくれます。
例えば、defconfig
をarch/x86/configs/mytest_defconfig
にコミットしておけば、次からはmake mytest_defconfig
とすることで、開発メンバみんなが編集後の.config
を生成することができます。
$ make savedefconfig
$ mv defconfig arch/x86/configs/mytest_defconfig
$ mv .config .config.back
$ make mytest_defconfig
#
# configuration written to .config
#
$ diff .config .config.back
Kernel Build Configの参考ページ
- Kconfig Language — The Linux Kernel documentation
- Kconfig make config — The Linux Kernel documentation
Command-line Parameters
続いて、Command-line Parametersを紹介します。
Command-line Parametersとは、Kernelの起動時に引数として指定するオプションのことです。
そのためbootloaderが指定するのが一般的です。
なお、ここまでに紹介した、Kernel Version・CPU architecture・Kernel Build Configは、3つともkernelコンパイル時に決定するものでした。
対してここから紹介するのは、Kernel自体を変更することなく動作を変える仕組みです。
Command-line Parametersの確認方法 1. /proc/cmdline
/proc/cmdline
でCommand-line Parametersを確認することができます。
$ cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-5.3.7+ root=UUID=71b4dc0a-e498-41f4-9cd2-a81e8c03cda8 ro quiet splash vt.handoff=1
Command-line Parametersの確認方法 2. dmesg
dmesg
にも出力されるので、ログしか残っていない状況でも確認可能です。
$ dmesg | grep "Kernel command line"
[ 0.104775] Kernel command line: BOOT_IMAGE=/boot/vmlinuz-5.3.7+ root=UUID=71b4dc0a-e498-41f4-9cd2-a81e8c03cda8 ro quiet splash vt.handoff=1
Command-line Parametersにはどんな項目があるの?
Command-line Parametersの設定項目については、ドキュメントがあります。
ごくごく一部ですが、参考にいくつか紹介します。
他にもたくさんあるので、ぜひドキュメントも読んでみてください。
-
loglevel
コンソールに出力するkernel logのレベルを変更できます。
起動直後の不具合解析時に変更することがよくあります。 -
log_buf_len
kernel logのリングバッファサイズを変更できます。
ログが流れてしまうときに、サイズを大きく取ることでログを見ることができるようになります。
デフォルト値はCONFIG_LOG_CPU_MAX_BUF_SHIFT
で変更可能ですが、一時的に増やす場合はこちらを使います。 -
mem
kernelが使うメモリサイズを指定することができます。
メモリが少ない状況をシミュレートするときや、メモリマップが怪しいときなどに使います。 -
ftrace
FtraceというKernelの動作を解析するための機能を、起動直後から有効にします。
起動直後のkernelの振る舞いを解析するときに使います。
Command-line Parametersの参考ページ
sysctl
次に紹介するsysctl
は、Kernel Parameterを実行中に変更する仕組みです。
Command-line parametersのように起動時だけではなく、いつでも変更できます。
sysctlの確認方法 1. sysctl
sysctl -a
を実行することで、すべてのparameterの現在値を確認することができます。
いくつかparameterを参照するためにはroot権限が必要です。
$ sudo sysctl -a | head
abi.vsyscall32 = 1
debug.exception-trace = 1
debug.kprobes-optimization = 1
dev.cdrom.autoclose = 1
dev.cdrom.autoeject = 0
dev.cdrom.check_media = 0
dev.cdrom.debug = 0
dev.cdrom.info = CD-ROM information, Id: cdrom.c 3.20 2003/12/17
dev.cdrom.info =
dev.cdrom.info = drive name:
sysctlの確認方法 2. /proc/sys/
sysctl
で設定できるparameterは、全て/proc/sys
以下にファイルとして公開されています。
このファイルを読み出すことでparamter値の確認が、書き込むことで変更ができます。
というか、sysctl
コマンドも内部では、/proc/sys
経由で確認・変更しています。
$ find /proc/sys -type f | head | xargs -I@ sh -c 'echo "@ = $(cat @ | head -1)"'
/proc/sys/abi/vsyscall32 = 1
/proc/sys/debug/exception-trace = 1
/proc/sys/debug/kprobes-optimization = 1
/proc/sys/dev/cdrom/autoclose = 1
/proc/sys/dev/cdrom/autoeject = 0
/proc/sys/dev/cdrom/check_media = 0
/proc/sys/dev/cdrom/debug = 0
/proc/sys/dev/cdrom/info = CD-ROM information, Id: cdrom.c 3.20 2003/12/17
/proc/sys/dev/cdrom/lock = 1
/proc/sys/dev/hpet/max-user-freq = 64
変更可能なparameterなのか、root権限は必要なのか、を事前に知りたいときは、
/proc/sys
以下のファイルのパーミッションを見ることで確認できます。
下記を見ると、fs.file-max
は書き込み可能だけど、
fs.file-nr
は書き込み不可だということがわかります。
また、fs.file-max
を変更するためにはroot権限が必要だ、ということもわかりますね。
$ ls -l /proc/sys/fs/file-*
-rw-r--r-- 1 root root 0 12月 6 14:01 /proc/sys/fs/file-max
-r--r--r-- 1 root root 0 12月 6 14:01 /proc/sys/fs/file-nr
sysctlにはどんな項目があるの?
sysctl
で設定できる項目についても、ドキュメントがあります。
こちらもごくごく一部ですが、参考にどんな項目があるか紹介します。
-
fs.file-max
システム全体で開くことのできるファイル数を、確認・変更することができます。 -
fs.file-nr
現在開いているファイル数と、システム全体で開くことのできるファイル数を確認することができます。
先述のとおり、read-onlyです。
例えば、15840 0 3231322
となっていた場合は、
現在開いているファイル数が15840
で、システム全体で開くことのできるファイル数が3231322
です。
真ん中の0
は、互換性のために残っているだけで常に0なので、気にしなくていいです。
システムとしてfd leakが発生していないか確認するときなどに使います。 -
fs.nr_open
1プロセスあたりでopenできるファイル数です。
ただし、実際にはプロセスごとに設定されるulimit
でより厳しく制限されていることが多いです。
ulimit
による制限は、/proc/${PID}/limits
で確認することができます。 -
kernel.print-fatal-signals
この値を1にすると、プロセスが異常終了したときにプロセス名とレジスタ値をkernel logに残します。 -
kernel.core_pattern
プロセスが異常終了したときのCoredumpを残す方法を設定できます。
Coredumpのファイル名を変更するだけではなく、特定のプログラムにリダイレクトすることもできたりします。
Linux Effective Coredump - Qiitaにて詳しく解説してくれています。 -
vm.drop_caches
値を書き込んだときにkernelのキャッシュを解放します。
この項目がちょっと変わっているのは、読み出した値に意味はなく、書き込んだときに処理が走る点です。
Linuxのdrop_cachesにwriteした時の動きを追う - Qiitaにて詳しく解説してくれています。
この項目のファイルパーミッションはread-writeになっていますが、本当はwrite-onlyであるべきですね。
sysctlに設定した値はいつまで有効なの?
基本的にsysctl
による設定は、kernelのグローバル変数に保存されるだけなので、システムを再起動したら忘れてしまいます。
永続的に設定するための仕組みはディストリビューションによって異なりますが、多くのディストリビューションでは、/etc/sysctl.conf
を起動時にデフォルト値として読み込みます。
これは、システム起動時にinitスクリプトからsysctl --system
を実行することで実現されています。
Androidの場合は、起動時の処理を記述するinitrcスクリプトから直接/proc/sys
に書き込みます。
on early-init
# Disable sysrq from keyboard
write /proc/sys/kernel/sysrq 0
sysctl
の参考ページ
- Documentation for /proc/sys - The Linux Kernel documentation
- Linux Effective Coredump - Qiita
- Linuxのdrop_cachesにwriteした時の動きを追う - Qiita
- rootdir/init.rc - platform/system/core.git - Git at Google
Device Tree
最後は、Device Treeを確認してみます。
Device Treeとは、ハードウェア構成情報です。
ARMのCPUを使った組込系のシステムでよく使われています。
組込みシステムではデバイスのメモリアドレスや割り込み番号などがシステムごとに異なります。
それらをデバイスドライバのソースコードに埋め込んでしまうと、読みにくくメンテナンスしにくくなってしまいます。
そのためこれらのハードウェア構成情報は、ソースコードから独立したDevice Tree Source(.dts
ファイル)に記述する方法が一般的です。
試しに5.3.10
で.dts
ファイルの数のarchごとのランキングを見てみると、armがダントツですね。
次がpowerpcになっています。
Device Treeは、もともとpowerpc向けに開発されたらしいので、そのためでしょうね。
$ find arch/ -name *.dts | cut -d '/' -f 2 | uniq -c | sort -n -r
1176 arm
265 arm64
200 powerpc
50 mips
17 arc
7 xtensa
5 c6x
3 h8300
2 openrisc
2 nios2
1 x86
1 sh
1 riscv
1 nds32
1 microblaze
ではPCの世界ではどうしているかというと、UEFI BIOSからACPI規格に従ってハードウェアの情報をもらうらしいですが、よく知りません。
ごめんなさい。
Device Treeの確認方法 /sys/firmware/fdt
Device Treeを使うシステムの場合、
/sys/firmware/fdt
にFDT形式に変換されたDevice Treeがあります。
FDTとは、Flattend Device Treeの略で、DTB(Device Tree Blob)とも言います。
dtc
(Device Tree Compiler)というコマンドで、FDTを.dts
ファイルに変換することができます。
組込みシステムの場合/sys/firmware/fdt
をPCに転送してから、PCで.dts
に変換することも可能です。
/proc/device-tree
以下に、ファイルシステムに展開された状態のDevice Treeもありますが、私は/sys/firmware/fdt
の方が取り回しやすいので便利だと思います。
以下は、Raspberry Pi 3 ModelB+ (Raspbian)でのDevice Treeの確認結果です。
$ sudo dtc /sys/firmware/fdt 2> /dev/null | head
/dts-v1/;
/memreserve/ 0x0000000000000000 0x0000000000001000;
/ {
memreserve = < 0x3b400000 0x4c00000 >;
serial-number = "00000000c97f6276";
compatible = "raspberrypi,3-model-b\0brcm,bcm2837";
model = "Raspberry Pi 3 Model B Rev 1.2";
interrupt-parent = < 0x01 >;
#address-cells = < 0x01 >;
Device Treeにはどんな項目があるの?
Device Treeの仕様書はこちらに公開されています。
ただし、実際Device Treeに書かれた設定値がどのような意味をもつかは、対象のハードウェア仕様およびデバイスドライバの仕様に大きく依存します。
意外な使われ方がされていることも結構あるので、Device Treeを見るときはできるだけその値を使う実装も確認しましょう。
Device Treeの参考ページ
- Specifications - DeviceTree
- Device Tree Reference - eLinux.org
- [Linux][kernel] Device Tree についてのまとめ - Qiita
- ほんのり詳しいUEFI BIOS(PDF版) - 電脳律速 - BOOTH
おわりに
最後まで読んでくださり、ありがとうございます。
設定は、直接的にKernelの振る舞いを変えることができるので、Kernelのコードリーディングの取っ掛かりとしてとても良いと思っています。
設定項目名でgrep
したらすぐに関連実装が見つかりますし、なにより設定値を変えて動作を見てみるのが簡単です。
この記事がどなたかの参考になれば、とてもうれしいです。