🐧 Linux 総合学習プラットフォーム
デバイスドライバ実装 ・ 上級

メジャー番号とマイナー番号

デバイスファイルは名前ではなく、2つの番号でカーネル内のドライバと結びつきます。メジャー番号は「どのドライバが担当するか」を、マイナー番号は「そのドライバが扱う何番目の機器か」を表します。ls -l /dev でファイルサイズが出る位置に、カンマ区切りで「メジャー, マイナー」が表示されます。たとえば同じディスクドライバ配下で /dev/sda と /dev/sdb がマイナー番号で区別される、といった具合です。

デバイスファイルは /dev の中にそれぞれ名前を持って並んでいる。では、カーネルがそのファイルと担当するドライバを結びつけるとき、頼りにしているのは、その名前なのだろうか。

意外にも、答えは「いいえ」だ。本当に使われるのは、デバイス番号と呼ばれる2つの数字の組である。

💡
ポイントカーネルがファイルとドライバを結びつける鍵は名前ではなく、デバイス番号(メジャー+マイナーの2つの数字)だ。

ファイル名は、人間が読んで分かりやすいようにつけた目印にすぎず、カーネルの内部では「どのドライバが、どの機器を担当するか」をこの番号で管理している。

だから、ファイル名を付け替えても番号さえ同じなら同じ機器を指すし、逆に同じ名前を付けても番号が違えば別物として扱われる。この番号こそが、デバイスファイルとドライバをつなぐ、目には見えない本当の鍵なのだ。

デバイスファイル8, 0メジャー番号どのドライバが担当かマイナー番号その中の何番目の機器か担当ドライバの正しい機器へ部署を選ぶ(メジャー)→ 内線で個人を呼ぶ(マイナー)

🏢 前半の番号は何を指すのか — メジャー番号

デバイス番号は、メジャー番号とマイナー番号という2つの数字で構成される。

前半のメジャー番号は「どのドライバが担当するか」を表す。ディスクを扱うドライバ、シリアル通信を扱うドライバ、といった具合に、ドライバごとにメジャー番号が割り当てられ、同じメジャー番号を持つデバイスファイルはすべて同じドライバの管轄に入る。

アプリがあるデバイスファイルを開くと、カーネルはまずそのメジャー番号を見て、「この読み書きの要求は、このドライバに渡せばよい」と判断する。

🔗
たとえメジャー番号は、用件をどの部署に回すかを決める「担当部署の番号」のようなものだ。

会社にたとえるなら、用件を受け付けてどの部署に回すかを決める、担当部署の番号のようなものだと考えると分かりやすい。

🔢 では後半の番号は — マイナー番号

後半のマイナー番号は「そのドライバが扱う、何番目の機器か」を表す。

なぜそんな番号が要るのか。1つのドライバが、同じ種類の機器を複数まとめて受け持つことはよくあり、それらを互いに区別するのがマイナー番号の役目だからだ。

分かりやすい例がディスクで、同じディスクドライバの配下にある /dev/sda と /dev/sdb は、メジャー番号は同じでありながら、マイナー番号が違うことで「1台目」「2台目」と区別されている。

つまり、メジャー番号でまず担当ドライバを選び、続いてマイナー番号でその中の個々の機器を選ぶ。この2段階の指定によって、たくさんの機器を整理して扱えるわけだ。部署を選んでから内線番号で個人を呼び出す、という流れに似ている。

👀 その番号は、どこを見れば分かるのか

メジャー番号とマイナー番号は、ls -l /dev を実行すれば実際に目で見て確かめられる。

普通のファイルでは、所有者やグループの右側にファイルサイズが表示されるが、デバイスファイルでは、ちょうどそのサイズが入る位置に、カンマで区切って「メジャー, マイナー」の2つの番号が並ぶ。

ls -l /dev でファイルサイズの位置を見る。8, 0 のように並んでいれば、メジャー番号8・マイナー番号0だ。

たとえば 8, 0 のように表示されていれば、メジャー番号が8、マイナー番号が0という意味だ。

ディスクの行をいくつか見比べてみると、メジャー番号は共通のまま、マイナー番号だけが 0、1、2 と変わっていく様子が確認でき、先ほどの「同じドライバの配下を番号で区別する」という説明が、目で見て腑に落ちる。

📦 2つの番号は、どう詰め込まれているのか

もう少し内側に踏み込んでみよう。デバイス番号は1つの32ビットの値の中に、メジャー番号とマイナー番号が一緒に詰め込まれた形になっている。

前半部分がメジャー、後半部分がマイナーに割り当てられ、メジャー番号よりもマイナー番号のほうに広いビット幅が与えられている。

なぜマイナー側を広く取るのか。ひとつのドライバが受け持つ機器の数を、十分に多く確保できるようにするためだ。

そのため、ドライバのプログラムでは、2つの番号から1つのデバイス番号を組み立てたり、逆に1つのデバイス番号からメジャー・マイナーを取り出したりする、専用のマクロ(あらかじめ用意された短い命令)が使われる。

また、いまシステムの中でどのメジャー番号がどのドライバに使われているかは、/proc/devices というファイルを見れば一覧できる。自作のドライバを組み込んだあとにここをのぞけば、自分のドライバに割り当てられたメジャー番号がいくつなのかを、その場で確かめられる。

🎟 番号は、自分で決めるのか・もらうのか

メジャー番号は、昔から決まっている機器に対しては固定の値が使われるが、自作ドライバの場合はどうするのが安全だろう。

一般的なのは、いま空いている番号をその場でカーネルに割り当ててもらう「動的割り当て」だ。番号を自分で固定して決め打ちにすると、他のドライバが使っている番号とぶつかってしまう恐れがあるため、未使用の番号を動的に受け取るほうが安全だからである。

そうして手に入れた番号をもとに、対応するデバイスファイルを作る。デバイスファイルを手作業で作るには mknod というコマンドを使い、ファイル名、キャラクタ型(c)かブロック型(b)かの種別、そしてメジャー番号とマイナー番号を、この順で指定する。

たとえば、あるドライバに割り当てられたメジャー番号を /proc/devices で調べ、その番号と、何番目の機器かを示すマイナー番号を mknod に渡してファイルを作る、という流れだ。

種別に c を選べばキャラクタ型のデバイスファイルが、b を選べばブロック型のデバイスファイルが作られる。こうして番号を与えて作られたファイルが、その番号を通じて目的のドライバと正しく結びつくのだ。

🔍 自動化された今、なぜ番号を学ぶのか

現代のシステムでは、機器を挿すたびに udev が適切な番号でデバイスファイルを自動生成してくれるため、日常的に mknod を手で打つ場面はそれほど多くない。

それなら、もう番号を気にしなくていいのか。いや、メジャー番号とマイナー番号の意味をきちんと理解しておくことは欠かせない。

なぜなら、デバイスファイルが本当に期待したドライバに結びついているか、複数の機器が正しく区別されているかを調べたいとき、最後の最後で頼りになるのが、この番号だからだ。

💡
ポイント自作ドライバが動かないとき、ls -l /dev の番号を /proc/devices と突き合わせる。これが原因切り分けの確かな出発点だ。

自作したドライバが思うように動かないとき、ls -l /dev で番号を確かめ、それを /proc/devices の内容と突き合わせる。この一手が、原因を切り分けていくときの確かな出発点になる。

この項目に出てくる用語

メジャー番号/マイナー番号めじゃーばんごうまいなーばんごう
デバイスを識別する2つの番号。メジャー=担当ドライバ、マイナー=何番目の機器か。
デバイスファイルでばいすふぁいる
ハードウェアをファイルとして扱うための特殊ファイル。/dev にある。

関連コマンド

lsmknod

▶ 学習アプリでこの続きを学ぶ・演習する