1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

NetBSDAdvent Calendar 2021

Day 10

ロードされているカーネルモジュールの依存関係をグラフ化してみる

Posted at

NetBSD Advent Calendar 2021 10日目の記事です。今日はロードされているカーネルモジュールの依存関係を可視化する話をしようと思います。

背景

NetBSDに限らず、現代のOSでは「カーネルモジュール」という形でOSを稼働させたまま特定の機能を追加・削除できます。例えばNetBSDでは、modstat(8)コマンドでロードされているカーネルモジュールを確認できます。

$ modstat
NAME                       CLASS    SOURCE   FLAG  REFS    SIZE REQUIRES
aac                        driver   builtin  -        1       - pci
accf_dataready             misc     builtin  -        0       - -
accf_httpready             misc     builtin  -        0       - -
acpiacad                   driver   builtin  -        0       - sysmon_envsys,sysmon_power
acpibat                    driver   builtin  -        0       - sysmon_envsys
acpibut                    driver   builtin  -        0       - sysmon_power
...

NetBSDのデフォルトインストール状態だと、約260個ほどのカーネルモジュールがロードされているようです。中にはサウンド系のデバイスなど、私の環境では使用しない(※)モジュールもあるようです。
(※VirtualBox上でサウンドデバイスを無効化しているので…)

$ modstat | wc -l
     265

というワケで、不要なカーネルモジュールを除去したいのですが、モジュールには依存関係があるようで、ちゃんと順番を考えないとエラーになってしまいます。

$ sudo modunload compat_linux
modunload: compat_linux: Device busy

modstat コマンドの REQUIRES フィールドには、該当のカーネルモジュールを必要としている(=依存関係のある)モジュールが記載されているようです。この情報をパースすれば、カーネルモジュールの依存図が作成できそうです。

$ modstat | egrep 'NAME|compat_linux'
NAME                       CLASS    SOURCE   FLAG  REFS    SIZE REQUIRES
compat_linux               exec     builtin  -        1       - compat_ossaudio,sysv_ipc,compat_util,compat_50,compat_43,exec_elf64,exec_aout
compat_linux32             exec     builtin  -        0       - compat_linux,sysv_ipc,compat_sysv_50,compat_netbsd32_50,compat_netbsd32_43,exec_elf32,compat_netbsd32,compat_netbsd32_sysvipc

カーネルモジュールの依存関係を可視化する

modstat をパースする簡単なスクリプトを作成してみます。

#!/usr/bin/env ruby

kmod_list = {}
IO.popen('modstat', 'r').readlines.each_with_index do |record, index|
  next if index == 0
  name, _, _, _, _, _, requires = record.chomp.gsub(/ +/, ' ').split(' ')
  requires.split(',').each do |kmod|
    kmod_list[name] = kmod
  end
end

puts 'digraph "mygraph" {'
kmod_list.each_pair do |kmod, req|
  next if req == '-'
  puts "  \"#{kmod}\" -> \"#{req}\";"
end
puts '}'

modstat コマンドにおける、NAMEとREQUIRESの部分をグラフ化するだけです。

$ ./sample.rb > tmp.dot
digraph "mygraph" {
  "aac" -> "pci";
  "acpiacad" -> "sysmon_power";
  "acpibat" -> "sysmon_envsys";
...
  "vmbus" -> "hyperv";
  "vmt" -> "sysmon_taskq";
  "vnd" -> "zlib";
  "wmidell" -> "sysmon_power";
  "wmieeepc" -> "sysmon_power";
  "wmihp" -> "sysmon_envsys";
  "wmimsi" -> "acpiwmi";
  "xc3028" -> "i2cexec";
  "xc5k" -> "i2cexec";
}

Graphvizでグラフ化します。

$ dot -Tsvg tmp.dot > output.svg

こんな感じで可視化できました。こうやって見ると、いくつかのモジュール群になっているのがわかりますね。

nbsd1210_01.png

画像だと表示がつぶれてしまうので、SVG形式にしたものをGistに用意しました。

まとめ

modstat の出力から、カーネルモジュールの依存関係を可視化してみました。モジュール名から明らかに自分では使用していないものが判別できたりするので、不要なモジュールを除去することで、よりスリムな(?)カーネルにできそうです。

1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?