本セッションの登壇者
セッション動画
「カーネルコードの歩き方」というタイトルでお話しする武内覚と申します。ふだんはsatと呼ばれています。社会人1年目から15年ぐらいカーネルの開発とサポートをずっとやってきました。今も必要に応じてカーネルソースを見ています。
本LTで学べるのは「Linuxのカーネルソースの読み方についての勘所」です。直接読んでいくというより、もう少しメタな知識を身に付けるためのLTです。汎用的なあらゆるソースコードの読み方、とくに大きめのソースコードの読み方についても同様の知識が得られるかと思います。このセッションを聞くにあたっての前提知識としては、何らかのプログラミング経験があるのとGitが使えるぐらいのレベルを想定しています。
Linuxカーネルは巨大! 目的を絞り込もう
「Linuxカーネル」と聞いてなんとなく惹きつけられる人々は少なくないらしくて、ソースを読みたいという人もいるのですが、規模感を知らない人も多いので紹介しておくと、最新安定版のv6.3時点で3000万行を超えています。バージョン間の変化でいうと、2023年2月に出たv6.2からv6.3(2023年4月)までの間に、コミット数が1万5000件超、これは行数でいうと4万7000行を超えています。2カ月でこれだけ増えて、全体としては3000万行。めちゃくちゃ多くて、とてもじゃないけれど前から順番にがんばって寝ずに読んでも絶対追いつかないボリュームです。なので目的を定めずに「とりあえずカーネルソースを読んでみよう」というのはかなり厳しくて、無理です。
そういうわけで「Linuxカーネルを読むコツ」というものが存在するんですが、一番大事なコツは明確かつ小さめの目標を立てるということです。「カーネルを完全に理解したい」という目的だと、3000万行を隅から隅まで読む必要がありますが、読んでいる間にソースコードが変わっていくので無理です。それに対して、「この機能でこのオプションを使ったときのコードを知りたい」という具合に1000行ぐらいに絞ると、なんとかなる感じになってきます。この場合、Gitなどのツールを駆使して、読まなければならないコードを減らしていくといいです。これは後で説明します。
また、読むだけでなく、実際に動かしてみることも大事です。これも後で説明します。さらに用語を知らないと、ソースを読んでもコメントを見てもコミットログを見ても全然わからないので、書籍やWeb記事を読んで前提知識を適宜身に付けていくことも大事です。詳細は説明しませんが、スライド末尾の付録にいくつか参考サイトを挙げていますので、後でご覧ください。
実機で確認することの大切さ
では実例を示したいと思います。私が以前出版したLinuxカーネルに関係する書籍で /proc/sys/kernel/sched_latency_nsという名前のファイルを紹介してパラメータを操作する話を書いたんですが、読者に「そのファイルは自分の環境にはない」とつっこまれたんですね。実機検証したはずなのになぜだろうと、確認のためにソースを読むところにたどり着いたのがきっかけです。/proc/sysのコードを全部見たくないので、この問題はスコープを絞るところから始めます。読者のカーネルはv5.15だったんですけど、ここでファイルが本当にないのか、ないならいつなくなったかを確認します。
まず、やることはバージョンv5.15のソースをチェックアウトしてこの処理があるかどうかを確かめる……かというとそうじゃないんです。めちゃくちゃ面倒くさいのでやりません。まずは実機で確認します。このv5.15のカーネルを引っ張って自分で動かしてみるんですね。この後も何回か出てきますが、ソースコードを読まなくても動かせばわかること、動かしたほうが早いことは実はたくさんあります。
そこで、実機検証です。やることは、特定のカーネルバージョンでブートしたシステムにログインして、/proc/sys/kernel/sched_latency_nsファイルがあるかどうかを確認するだけです。結果は、自分の環境で見たらやっぱりありました。読者のカーネルバージョンのv5.15でブートしたところ、たしかにファイルがなかったです。なるほどということで、ソースを見ずにわかりました。
次に目的の2つ目、どこのバージョンでこのファイルが消えてしまったかを確認します。
ぱっと思い付く方法は、v5.4から始まってv5.5、v5.6とカーネルを実際にダウンロードしてきて、そのカーネルをブートして変わるかどうかを確認することです。先ほど「実機で動かす」と言いましたが、これはこれで面倒くさい作業です。ですので、私は以下のようなことをしました。
まず、v5.4のソース上で/proc/sys/kernel/sched_latency_nsという文字列をgrepで検索して、このファイルを作っている処理を見つけます。動かぬ証拠です。ここでいきなり/procがファイルのどこにあるのか、順番に3000万行全部を見るわけではありません。grepをかけて当たりをつけるところから始めます。これはとても重要です。
grepをかけたらすぐ処理が見つかりました。次にバージョン5.15のソース上でこの処理が存在していないことも確認して、この処理がいつなくなったのかをソースコードのバイナリサーチで確認しました。
ソースコードのバイナリサーチとは、v5.4とv5.15の中間のv5.9をチェックアウトして処理があることを確認したら、次はそのバージョン(v5.9)とv5.15の中間のv5.12をチェックアウトして処理があることをまた確認して…を繰り返す作業です。普通の整数のバイナリサーチのように、ソースコード上にファイルが存在するかどうかという条件の確認結果をtrueとfalseで分けて、ファイルがなくなったバージョンを絞り込んでいきます。最終的にバージョン5.13でこの処理がなくなったことを特定しました。ここまでソースをほとんど読まずにできています。
ソースコードリーディングは経験値がモノをいう
繰り返しますが、ここで大事なのは一見「ソースコードを読まないとわからない」と思われがちなことでも、実は読まずにできるし、読まないほうが早いこともよくあるということです。
そして、もうひとつ大事なことは、どこで読み始めるか、どこまで他のツールに任せてどこからソースを真面目に読み始めるのかですが、これについては最適解はありません。なので、考えられる選択肢から、なんとなく一番楽できそうだなものから順番に、適当に試してみるのが良いです。「なんとなく一番楽できそうなものを推測する」のは経験を詰むしかないと思ってます。また、最初から最善を求めると身動きできなくなって、何が最善かとか考え出して止まってしまうので、とにかく回数をこなしてだんだんうまくなっていくのがいいかと思います。
おわりに
最後に、Linuxカーネルはとにかくデカいです。3000万行以上あります。まともに挑むと道に迷うだけなので、目的を明確化した上で読むべき場所を減らしていくことです。読むための基礎知識はWebや書籍で適宜得る必要があって、いろいろなテクニックを使うためには経験がものを言うので、とにかく試していきましょう。そういうのを繰り返しながら苦労してどんどんカーネルハックをしていきましょう。ということで、「Happy Hacking!」で終わりにしたいと思います。スライドに掲載した参考資料もご覧ください。
以上です。ご清聴ありがとうございました。