デバイスとudev

はじめに

第27章はじめに

Linuxは、ハードウェアと周辺機器を、システムのブート時とシステムに接続された後の両方で検出するために、インテリジェントなツールであるudevを使用します。デバイス ノードを動的に作成し、アプリケーションやオペレーティング システムのサブシステムで使用して、デバイスと通信したり、デバイスとの間でデータを転送したりします。システム管理者は、希望どおりの動作結果を保証するため、udevの動作を制御したり特別なudevルールを作成したりできます。


学習目標
この章の終わりまでに、次のことができるようになります。

デバイス ノードの役割と、それらがメジャー番号とマイナー番号を使用する方法を説明できます。
udev方式の必要性を理解し、その主要コンポーネントをリストできます。
udevデバイス マネージャーの機能を説明できます。
udevルール ファイルを特定し、カスタム ルールを作成する方法を学習します。


デバイスとudev

デバイス ノード
キャラクタ デバイスとブロック デバイスには、ファイルシステム エントリが関連付けられていますが、Linuxのネットワーク デバイスはそうではありません。デバイス ノードは、open()、close()、read()、write()などの通常のI/Oシステムコールを使用して、プログラムがデバイスと通信するために使われます。一方、ネットワーク デバイスはパケットの送受信によって機能します。パケットは、データのストリームを分割して構成するか、受信時にストリームに再構成する必要があります。

デバイス ドライバは、複数のデバイス ノードを管理できます。これらは通常、/devディレクトリに置かれます。

$ ls -l /dev
total 0
crw------- 1 coop audio 14, 4 Jul 9 01:54 audio
crw------- 1 root root 10, 62 Jul 9 01:54 autofs
lrwxrwxrwx 1 root root 4 Jul 9 01:54 cdrom -> scd0
lrwxrwxrwx 1 root root 4 Jul 9 01:54 cdrw -> scd0
crw------- 1 coop root 5, 1 Jul 9 06:54 console
....
lrwxrwxrwx 1 root root 4 Jul 9 01:54 dvd -> scd0
lrwxrwxrwx 1 root root 4 Jul 9 01:54 dvdwriter -> scd0
....
brw-r----- 1 root disk 8, 0 Jul 9 01:53 sda
brw-r----- 1 root disk 8, 1 Jul 9 01:53 sda1
brw-r----- 1 root disk 8, 2 Jul 9 06:54 sda2

....
brw-r----- 1 root disk 8, 16 Jul 9 01:53 sdb
brw-r----- 1 root disk 8, 17 Jul 9 01:53 sdb1
brw-r----- 1 root disk 8, 18 Jul 9 01:53 sdb2
....
crw-rw-rw- 1 root tty 5, 0 Jul 9 01:54
-rw---- 1 root root 4, 0 Jul 9 14:54 tty0
crw------- 1 root root 4, 1 Jul 9 06:54 tty1
cr--r--r-- 1 root root 1, 9 Jul 9 01:53 urandom
....
crw-rw-rw- 1 root root 1, 5 Jul 9 01:54 zero

デバイス ノードは次の方法で作成できます。

$ sudo mknod [-m mode] /dev/name
例えば、「sudo mknod -m 666 /dev/mycdrv c 254 1」のように使います。

デバイス ノード


メジャー番号とマイナー番号
メジャー番号とマイナー番号は、ドライバとそれが制御するデバイスや使用方法を識別するものです。ドライバは番号のグループを一意に予約します。ほとんどの場合（すべてではありません）、同じメジャー番号を持つ同じ種類（ブロックまたはキャラクタ）のデバイス ノードは、同じドライバを使用します。

いくつかのデバイス ノードをリストする場合、次のように入力します。

$ ls -l /dev/sda*
brw-rw---- 1 root disk 8, 0 Dec 29 06:40 /dev/sda
brw-rw---- 1 root disk 8, 1 Dec 29 06:40 /dev/sda1
brw-rw---- 1 root disk 8, 2 Dec 29 06:40 /dev/sda2
.......

メジャー番号とマイナー番号は、通常のファイル情報を見たときにファイル サイズが表示される場所に表示されます。上記の例では「8，1」などです。通常のユーザーは、おそらくメジャー番号とマイナー番号を明示的に参照する必要はなく、デバイスを名前で参照します。一方でシステム管理者は、システムがデバイスについて混乱したり、実行時にハードウェアが追加されたりした場合には、それらを解決する必要があります。

マイナー番号は、デバイス ドライバが制御する可能性のあるさまざまなデバイス、またはそれらの使用方法を区別するためにのみ使用されます。これらは、同じ種類のデバイスの異なるインスタンス（1番目と2番目のサウンド カード、ハードディスク パーティションなど）、または特定のデバイスの異なる動作モード（異なる密度のフロッピー ドライブ メディアなど）のいずれかです。

デバイス番号は、ユーザー空間でも意味を持ちます。2つのシステムコール、mknod()とstat()は、メジャー番号とマイナー番号に関する情報を返します。


udev
Linuxの進化に伴い、デバイス ノードの管理は使いにくく難しくなりました。/devとそのサブディレクトリにあるデバイス ノードの数は、カーネル バージョン2.4シリーズのほとんどのインストールにおいて、15,000〜20,000の数に達しました。ディストリビュータはシステム上にどのハードウェアが存在するかを正確に確認できません。そのため、ほとんどのインストールでは、使用されることのないあらゆる種類のデバイス ノードがデフォルトで作成されました。

もちろん、多くの開発者とシステム管理者は、特に組み込み分野で実際に必要なものにあわせて調整していましたが、これは基本的に手動で行っており、潜在的なエラーが発生しやすい作業でした。

デバイス ノードは通常のファイルではないため、ファイルシステム上に大きな領域を占有することはありません。ただ、巨大なディレクトリがあると、特に最初の使用時に、デバイス ノードへのアクセスが遅くなります。さらに、使用可能なメジャー番号とマイナー番号の枯渇に対応するために、デバイス ノードの作成と保守に関してより最新で動的なアプローチが必要でした。理想的な方法は、名前でデバイスを登録することです。ただし、POSIX標準ではメジャー番号とマイナー番号が必要であるため、これらを完全に取り除くことはできません。（POSIXは、異なるオペレーティング システム間の互換性を確保するために設計された標準規格であり、Portable Operating System Interfaceの頭字語です。）

udev方式では、必要に応じてデバイス ノードを動的に作成します。使用されないデバイス ノードを大量に保持する必要はありません。udevのuはユーザーを表し、デバイス ノードの作成、削除、変更のほとんどの作業がユーザー空間で行われることを示します。

udevはデバイス ノードを動的に作成します。以前のメカニズムであるdevfsやhotplugなどの後継として進化しました。優れた機能の1つは、恒久的なデバイス名のサポートです。名前は、デバイス接続やプラグインの順序に依存する必要はありません。このような動作は、udevルールの仕様によって制御されます。


udevコンポーネント
udevはデーモン（udevdまたはsystemd-udevd）として実行され、netlinkソケットを監視します。新しいデバイスが初期化されたり削除されると、ueventカーネル機能はソケットを介してメッセージを送信します。udevはそれを受信し、ルールに従って正しい名前とプロパティのデバイス ノードを作成したり削除したりします。

udevは、以下の3つのコンポーネントで構成されています。

デバイスに関する情報へのアクセスを許可するlibudevライブラリ。
/devディレクトリを管理するudevdまたはsystemd-udevdデーモン。
制御および診断を行うudevadmユーティリティ。

udevを使用する最も正しい方法は、余計なモジュールなどがロードされていないシステムで行うことです。/devディレクトリは、最初のカーネル起動時には空であり、必要に応じてデバイス ノードが読み込まれます。この方法で使用する場合、initramfsイメージを使用してブートする必要があります。initramfsイメージには、予備のデバイス ノードのセットと、udevインフラストラクチャが含まれています。


udevとホットプラグ
システムにデバイスが追加または削除されると、通知されるイベントに基づいてudevは、ホットプラグ サブシステムと連携してデバイス ノードを作成または削除します。デバイス ノードを作成するために必要な、名前、メジャー番号、マイナー番号、パーミッションなどの情報は、sysfs疑似ファイルシステム（/sysにマウント）と一連の設定ファイルに既に登録されている情報を調べて収集します。

主要な設定ファイルは/etc/udev/udev.confです。ここにはデバイス ノードの配置場所、デフォルトのパーミッション、所有権などの情報が含まれています。デバイスの命名規則は、デフォルトでは/etc/udev/rules.dと/usr/lib/udev/rules.dディレクトリにあります。udevのmanページを読むことで、一般的な状況におけるルール設定方法について、多くの特定情報を取得できます。


udevデバイス マネージャ
udevは、追加または削除されるデバイスに関するメッセージをカーネルから受信すると、そのデバイスに関連するルールがあるかを見るために、/etc/udev/rules.d/*.rulesと/usr/lib/udev/rules.d/*.rulesのルール設定ファイルを参照します。

その後、以下のようなアクションを実行します。

デバイス ノードの名前を決定します。
デバイス ノードとシンボリックリンクを作成します。
デバイス ノードのファイル パーミッションと所有権を設定します。
その他のアクションを実行して、デバイスを初期化し、デバイスを使用可能にします。

これらのルールは完全にカスタマイズ可能です。


udevルールのファイル
udevルールのファイルは/etc/udev/rules.d/<rulename>.rulesの下に、次のような名前で存在します。

30-usb.rules
90-mycustom.rules

デフォルトでは、udevは接尾辞が.rulesのファイルを探してルール ファイルを読み取ります。複数のファイルが見つかった場合は、辞書順に、つまりアルファベットの昇順で1つずつ読み取ります。通常、標準のルール ファイル名は、2桁の数字の後に説明的な名前（ルールに関するもの）が続き、その後に.rulesサフィックスが続きます。

1行に2つの情報が定義されています。

最初の部分は、==で示される1つ以上の一致するペアで構成されます。これらは、デバイスの属性や特性もしくはその両方が、ここに指定した値に一致するかをみます。
2番目の部分は、ファイル名、グループの割り当て、さらにはファイルのパーミッションなど名前に値を割り当てる、1つ以上の割り当てキーと値のペアで構成されます。

一致するルールが見つからない場合、デフォルトのデバイス ノード名とその他の属性が使用されます。

$ cat /etc/udev/rules.d/99-fitbit.rules
SUBSYSTEM=="usb", ATTR{idVendor}=="2687", ATTR{idProduct}=="fb01", SYMLINK+="fitbit", MODE="0666"

$ cat /etc/udev/rules.d/60-vboxdrv.rules
KERNEL=="vboxdrv", NAME="vboxdrv", OWNER="root", GROUP="vboxusers", MODE="0660"
KERNEL=="vboxdrvu", NAME="vboxdrvu", OWNER="root", GROUP="root", MODE="0666"
KERNEL=="vboxnetctl", NAME="vboxnetctl", OWNER="root", GROUP="vboxusers", MODE="0660"
SUBSYSTEM=="usb_device", ACTION=="add", RUN+="/usr/lib/virtualbox/VBoxCreateUSBNode.sh $major $minor $attr{bDeviceClass}"
SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", RUN+="/usr/lib/virtualbox/VBoxCreateUSBNode.sh $major $minor $attr{bDeviceClass}"
SUBSYSTEM=="usb_device", ACTION=="remove", RUN+="/usr/lib/virtualbox/VBoxCreateUSBNode.sh --remove $major $minor"
SUBSYSTEM=="usb", ACTION=="remove", ENV{DEVTYPE}=="usb_device", RUN+="/usr/lib/virtualbox/VBoxCreateUSBNode.sh --remove $major $minor"


udevルールの発行
udevルールの書式は簡単です。

<match><op>value [, ...] <assignment><op>value [, ... ]

1行に2つの情報が定義されています。最初の部分は、1つ以上の一致ペアで構成されます（二重等号==で示されます）。これらは、デバイスの属性や特性もしくはその両方が、ここに指定した値に一致するかをみます。2番目の部分は、ファイル名、グループの割り当て、さらにはファイルのパーミッションなど名前に値を割り当てる、1つ以上の割り当てキーと値のペアで構成されます。

例：

KERNEL=="sdb", NAME="my-spare-disk"
KERNEL=="sdb", DRIVER=="usb-disk", SYMLINK+="sparedisk"
KERNEL=="sdb", RUN+="/usr/bin/my-program"
KERNEL=="sdb", MODE="0660", GROUP="mygroup"

一致するルールが見つからない場合、デフォルトのデバイス ノード名が使用されます。


ルール ファイルの例
Fitbitデバイスのルール ファイルの例を次に示します。

$ cat /usr/lib/udev/rules.d/99-fitbit.rules
SUBSYSTEM=="usb", ATTR{idVendor}=="2687", ATTR{idProduct}=="fb01", SYMLINK+="fitbit", MODE="0666"

以下に、kdump/kexecを使用してクラッシュダンプと高速カーネル ローディングを設定する例を示します。

$ cat /usr/lib/udev/rules.d/98-kexec.rules
SUBSYSTEM=="cpu", ACTION=="online", PROGRAM="/bin/systemctl try-restart kdump.service"
SUBSYSTEM=="cpu", ACTION=="offline", PROGRAM="/bin/systemctl try-restart kdump.service"
SUBSYSTEM=="memory", ACTION=="add", PROGRAM="/bin/systemctl try-restart kdump.service"
SUBSYSTEM=="memory", ACTION=="remove", PROGRAM="/bin/systemctl try-restart kdump.service"

kvm仮想マシン ハイパーバイザの例を次に示します。

$ cat /usr/lib/udev/rules.d/80-kvm.rules
KERNEL=="kvm", GROUP="kvm", MODE="0666"

$ cat /usr/lib/udev/rules.d/99-fuse.rules
KERNEL=="fuse", MODE="0666",OWNER="root",GROUP="root"


デモ：udevの使用

このビデオは、udevの使用の簡単なデモを提供します。


演習

課題 27.1: udev

🚩
以下のPDFドキュメントに埋め込まれた外部URLにアクセスする場合は、常に右クリックして新しいタブまたはウィンドウで開いてください。直接クリックしてURLを開こうとすると、コース ウィンドウ／タブが閉じます。

【【これ以降は橋本さんの訳を参照】】

1.  Create and implement a rule on your system that will create a symlink called myusb when a USB device is plugged in.

2.  Plug in a USB device to your system. It can be a pen drive, mouse, webcam, etc.
Note: If you are running a virtual machine under a hypervisor, you will have to make sure the USB device is seen by the guest, which usually is just a mouse click which also disconnects it from the host.

3.  Get a listing of the /dev directory and see if your symlink was created.

4.  Remove the USB device. (If it is a drive you should always umount it first for safety.)

5.  See if your symbolic link still exists in/dev.

Solution 27.1

1.  Create a file named /etc/udev/rules.d/75-myusb.rules and have it include just one line of content:
$ cat /etc/udev/rules.d/75-myusb.rules
SUBSYSTEM=="usb", SYMLINK+="myusb"
Do not use the deprecated key valueBUSin place of SUBSYSTEM, as recent versions of udev have removed it.
Note the name of this file really does not matter. If there was an ACTION component to the rule the system would execute it; look at other rules for examples.
2.  Plug in a device.
3.$ ls -lF /dev | grep myusb
4.  If the device has been mounted:
$ umount /media/whatever
where /media/whatever is the mount point. Safely remove the device.
5.$ ls -lF /dev | grep myusb


知識チェック

「第27章 - デバイスとudev」を完遂しました。おめでとうございます。このクイズに答えて、これまでに学んだ概念の理解度をチェックしてください。

クイズ開始

問題 27.1
特別なファイルとして/devの下にあるハードウェア デバイスはどれですか？当てはまるものをすべて選択してください。

A. Mouse
B. Network adapter
C. Webcam
D. Hard drive
E. USB drive


