1999年発行(日本語翻訳版)のLinuxカーネル解説本を見返してみる

この記事はLinux Advent Calendar 2020の24日目の記事です。

自分がLinuxを使いだした頃、OSはどうやってブートしてんるんだろう🤔とか色々知りたくて買ったのが↓の本です。

f:id:masami256:20201225194100j:plain
Linuxカーネルインターナル

買った当時は知識がなくて読むのが大変だったけど今はそれなりに読めるようになり、さすがに成長したなとも思ってみたり😃 初版が1999年6月25日と書いてあるので2000年台の始めの頃に買ったんでしょう。それにしても翻訳版の初版が発行された時点からでも21年前の本ということか。

この本が対象としているのはLinux 2.0です。目次は次のようになってます。メモリ管理、ファイルシステム、モジュール、ネットワーク等々ありますね。基本的な機能は変わってないので現在のカーネルでこの目次の内容に沿ってコードを読んでみるというのは面白いかもしれません。この記事を書いている時点での最新のLinuxのバージョンは5.10.2です。本で説明されてるこの構造体は今でもあるのかな?と思ったときは5.10.2で調べてます。本書は付属としてLinux 2.0のソースコード入りCDが付いてます。

序文

本書の序文はLinusさんが書いています。「OSの開発は今も昔もエキサイティングなプロジェクトだ。でも、カーネルの内部を詳しく知ろうとするとドキュメントが足りないのが難点で、ハックしようと思ったらコードを読むしかなかった。それは良いことなんだけど、本書のようにLinuxの使用とカーネルにつて説明する本書のようなドキュメントが出たのは良いね」といった感じのことが書かれてます。

はじめに

本書は著者さんによる同名の著書の第2版で、Linux2.0をカバーしていると書いてあるので第1版は1.xの解説をしてたということなんでしょう。本書の方針として上げている「Linux はオープンなOS。隠された秘密は何もない。問題に遭遇したらソースコードに当たれば良い」ってのが個人的に好きです。

第1章 Linuxオペレーティングシステム

Linuxがどんなものかの説明です。機能や、Linuxディストリビューションとは?といったことの説明が書かれています。

第2章 カーネルコンパイル

カーネルハックをする上でカーネルコンパイルは必須ですからね。最近のカーネルに関しては@progrunner17さんによるLinuxカーネルビルド大全が詳しいです。本書ではカーネルのコードの場所は/usr/src/linuxを使用しています。最近は任意なところにgitでコードをクローンしてビルドできますが当時は/usr/src/linuxが標準だったんですね。この章ではこのディレクトリにはこの機能のコードがあるよなんてのも軽く解説しています。本章ではカーネルコンパイル方法、i386以外のarchを使いたい場合のMakefileの変更方法なんかも説明されてます。

第3章 カーネルの概要

章の流れとしてはカーネルとはなにか?といったところの説明、プロセスとタスク、システムコール、割り込みルーチン、プロセスとスレッドなどの用語の説明カーネルのデータ構造、シグナル、割り込み、カーネルの最初のc関数、スケジューラ、システムコールの実装(仕組み、fork()などいくつかのシステムコールの説明)など盛りだくさんです。この章で説明されている構造体のtask_struct、mm_struct、fs_struct、inode、fileなどは今でも重要な立ち位置ですね。それとは逆にプロセスを登録するプロセステーブルは今ではもうありませんね。メモリの確保・解放だと__get_free_pages()、kmalloc()、kfree()なんかも今でも使われてますね。

第4章 メモリ管理

Linux 2.0の時点で複数のアーキテクチャに対応しているのでまずはアーキテクチャ非依存のモデルについて説明しています(仮想アドレス空間など)。次はi386のページテーブルの説明がきて、LinuxのPGD・PMD・PTEの説明になります。そしてvm_area_struct構造体(これも今もありますね)、brkシステムコールmmapシステムコールの説明ときて、カーネルが使うセグメント(x86のセグメント)の説明があります。つぎにkmallo()・kfree()やvmalloc()・vfree()の説明です。この次にバッファキャッシュの説明があります。ここで説明されているbuffer_head構造体もいまでもあります。bdflushの説明もあります。バッファキャッシュの管理・利用方法の説明もここで行っています。あとはswap処理、空きページの管理(今でもページの管理に使うpage構造体はこの当時からあります)。最後にページフォルトの処理を説明して本章は終わりです。

第5章 プロセス間通信

まずはカーネル内の処理で同期を取る方法の説明があります。キューを使って寝て待って、処理が終わったら起こしてもらったり、セマフォを使うなどの説明です。fcntl(2)によるファイルのロックの処理についても説明されてます。あとはpipeの実装、ptrace(2)の仕様、System V IPC、共有メモリ、Unixドメインソケットを使ったプロセス間通信などです。この辺りの機能は今でも使われますね。

第6章 Linuxファイルシステム

VFSの説明、カーネルでのファイルシステムの表現、マウント処理、スーパーブロックの処理(super_operations構造体に含まれる各種関数の説明)、inodeの処理(inode_operations構造体に含まれる各種関数の説明)、file構造体の説明、ファイル操作(file_operations構造体に含まれる各種関数の説明)、ファイルを開くときの処理、procファイルシステムext2ファイルシステムのデータ構造、ブロックへの配置アルゴリズムなどの説明があります。ジャーナリングファイルシステムについての説明はさすがにないですが今だと当たり前にある機能とも言えるので現在カーネルの解説本を書くなら必須項目になるんでしょうね。

第7章 Linuxデバイスドライバ

ブロックデバイス・キャラクターデバイス、メジャー・マイナー番号の説明があり、割り込み・ポーリングの説明、ハードウェアの検出などの説明があります。ドライバの実装の説明としてはPC内蔵スピーカーを例にしたりしてます。デバドラの実装の説明では初期化、open・read/write・ioctlの実装方法など説明してます。また、DMAの操作も説明してます。

第8章 ネットワークの実装

ネットワークの実装ではsk_buff構造体の説明、proto構造体の説明など構造体の説明の他に、ネットワークデバイスの実装の説明があります。プロトコルの説明としてはarp、ipの説明があります。ルーティングやパケットフィルタについても説明されています。そして、tcpの説明ももちろんあります。

第9章 モジュールとデバッグ

カーネルモジュールの説明です。モジュールがどのようにロードされるか、モジュールのタイプ別にどのような関数を実装するべき(ファイルシステムならregister_filesystem()と言った感じで)かといった説明などあります。 モジュールの例としてはPCMCIAのモジュールを使って説明してます。デバッグでは今でも使われるprintkデバッグgdbを使ったデバッグ方法について触れられています。printkデバッグでは最良のデバッガ:printk()と書かれています。この当時だとカーネルデバッグというとprintk()というのが主だったんでしょうね。カーネルのビルド・再起動に時間はかかるけど手軽さは確かにありますが今ならftrace、perf、eBPFなどがお薦めの手段でしょうか。

第10章 マルチプロセッシング

この章ではSMPの実装におけるカーネルの初期化、cpu間の通信、割り込み処理についての説明があります。smp対応のカーネルコンパイルする場合はMakefileSMP = 1の部分のコメントを削除してねって説明がありますが、時代を感じるところですね。

Appendix A システムコール

この章は色々なシステムコールについての説明です。例えばfork()ならカーネルのどのファイルにこのシステムコールの実装が合って、プロトタイプはこうでシステムコールの仕様はこんなんだよといった感じの説明があります。カーネルよりなmanページと言った感じでしょうか。システムコールはプロセス管理系、ファイルシステム系、プロセス間通信系、メモリ管理系というような感じでカテゴライズされています。

Appendix B カーネル関連のコマンド

manのセクション8というかpsだったりfreeだったりといったコマンドの説明があります。また、pid1のinitプロセスについても説明があります。/etc/inittabの説明もあります。ほかにはstrace、shutdown、ifconfig、traceroute、mountコマンドのなどの説明があります。

Appendix C Procファイルシステム

/procにあるファイルの説明です。14ページほどあるので結構なボリュームですよね。

Appendix D ブートプロセス

BIOSから始まるブートプロセスの説明です。ブートローダーのLILOについての説明もあります。当時はブートローダーといえばLILOでしたね。カーネルの再構築後にLILOのコマンド忘れて起動できないとかよくやったもんです😭 LILOの説明もファイルの書式、オプション、エラーメッセージの意味、起動時の表示メッセージの意味などの説明がありかなり親切です。LIで止まっている場合の原因はXXXだよみたいな説明があってホント親切だと思います。

Appendix E 重要なカーネル関数

カーネルのコードを書く時に使う関数の説明ですmanのセクション9に近いでしょうか。


というわけで1999年発行のLinuxカーネル解説本を見返してみたわけですが、基本的な機能は変わってないのでというかメモリ管理とかファイルシステムは今でも重要な機能ですが実装についてはだいぶ変わっているのでその辺の差分を見ていくとカーネルの進化の歴史を辿れますね。

この目次の内容でLinux 5.10版も見てみたいですね👍