Device Handling im Linux
Vorgeschichte
- Unix: Alles ist ein File
- Device-Files (
/dev/tty0
) ermöglichen Zugang zu Geräten (Major-/Minor-Number)
- Devices-Files entstehen durch
mknod
- Devices-Files existieren unabhängig vom Gerät
- Ansatz ist unflexibel/fehleranfällig
- mehrere Ansätze zur dynamischen Erkennung von Geräten (Dev-FS, udev)
- Ziele:
- Device-Files erzeugen/entfernen nach Bedarf
- Regeln entscheiden über die Namen der Device-Files (nicht die Reihenfolge, in der die Geräte erkannt werden)
- Geräte in grafische Desktops einbinden (z.B. Applikationen starten)
- Zugriffsberechtigungen setzen
- Filesysteme montieren/demontieren
- Stand
- große Unterschiede zwischen
- Kernel-Versionen
- Distributionen
- Schwerpunkt: aktuelle, moderne Verfahren
- Erläuterungen am Beispiel von Scientific Linux 5.0 / Fedora Core 6
Controller / Kernel / Gerätetreiber
- Controller des jeweiligen Busses (ISA, USB, PCI)
- erzeugt Interrupt bei Anschluss oder Entfernen eines Gerätes
- Interrupt-Behandlung:
- Informationen über das Gerät ermitteln
- Controller "befragen"
- Konfig-Bereich von PCI-Karten auslesen (Vendor/Product-ID)
- Verwaltungsinformationen ablegen (Kobject)
- sysfs-Eintrag erzeugen
- Ereignis an Anwendungen weiterleiten (uevent)
Sysfs
- virtuelles Filesystem
- exportiert Informationen zu Geräten aus dem Kernel in Userspace
- beginnt in
/sys
- für jedes Gerät und jeden Treiber existiert ein Verzeichnis in
/sys
- Eltern-Kind-Beziehungen werden durch Unterzeichnisse reflektiert
- ein Gerät an einem Bus
- eine Partition auf einer Festplatte
- verschiedene Pfade ermöglichen den Zugang zu Informationen aus verschiedenen Perspektiven
- intensiver Gebrauch von symb. Links
/sys/devices/ | Device Tree, physische Sicht |
/sys/bus/ | Zuordnung der Geräte zu den einzelnen Bussen |
/sys/class/ | Zuordnung der Geräte zu Geräteklassen |
- Beispiel: interne SATA-Festplatte
sda
 |
/sys/devices/pci0000:00/0000:00:0e.0/host0/target0:0:0/0:0:0:0/
/sys/bus/scsi/devices/0:0:0:0
/sys/class/scsi_disk/0:0:0:0
/sys/class/scsi_device/0:0:0:0
/sys/class/scsi_generic/sg0
/sys/block/sda
|
-
/sys/block/sda
ist sog. top-level device path
- Verzeichnis, welches den Eintrag
dev
enthält (Major-/Minornumber)
 |
$ find /sys -name dev |grep sda
/sys/block/sda/sda2/dev
/sys/block/sda/sda1/dev
/sys/block/sda/dev
$ cat /sys/block/sda/dev
8:0
|
udev
- Hotplug-Verfahren des Linux-Gerätemanagements
- Erzeugen der Einträge in
/dev/
im Userspace
- Ziele/Möglichkeiten:
- default names umbennen
- alternative/persistene Namen für Geräte in Form eines symb. Links zum default name erzeugen
- Name durch externes Programm ermitteln lassen
- Eigentümer/Gruppe und Zugriffsberechtigungen setzen
- Script beim Hinzufügen und/oder Entfernen eines Gerätes starten
- befolgt konfigurierbare Namenskonventionen
- bearbeitet uevents
- Geräteklasse als Argument: z.B.
usb
, scsi
, net
, ieee1394
, ...
- weitere Informationen in Umgebungsvariablen
-
ACTION
: add
| remove
[ | mount
| umount
]
-
SEQNUM
: Folgenummer, definiert Reihenfolge der uevents
-
DEVPATH
: Pfad in /sys
des Gerätes, beginnend mit "/devices/"
- ggf. weitere, z.B.
DEVICE
bei USB-Geräten, enthält entsprechenden Eintrag im USB-FS (/proc/bus/usb/...
)
-
/sbin/udevd
- serialisiert uevents anhand der
SEQNUM
- verzögert uevents für child devices (z.B. USB-Stick) bis handling des parent device (z.B. USB-Controller) beendet ist
- behandelt uevents in Kind-Prozessen
- konfiguriert über
/etc/udev/udev.conf
- definiert allgemeingültige Einstellungen
-
udev_root
: device directory (/dev
)
-
udev_rules
: udev rules file or directory (/etc/udev/rules.d
)
-
udev_log
: logging priority (err
)
- führt Aktionen entsprechend zutreffender Regeln aus
- führt Hilfsprogramme aus (
/lib/udev/
)
Persistente Namen
- "built-in"-Schema für Storage Devices in
/dev/disk/
 |
$ ls -lR /dev/disk
/dev/disk:
insgesamt 0
drwxr-xr-x 2 root root 160 16. Mär 13:33 by-id
drwxr-xr-x 2 root root 180 16. Mär 13:33 by-path
drwxr-xr-x 2 root root 100 16. Mär 13:33 by-uuid
/dev/disk/by-id:
insgesamt 0
lrwxrwxrwx 1 root root 9 16. Mär 13:33 scsi-SATA_WDC_WD2500YS-01_WD-WCANY1551209 -> ../../sda
lrwxrwxrwx 1 root root 10 16. Mär 13:33 scsi-SATA_WDC_WD2500YS-01_WD-WCANY1551209-part1 -> ../../sda1
lrwxrwxrwx 1 root root 10 16. Mär 13:33 scsi-SATA_WDC_WD2500YS-01_WD-WCANY1551209-part2 -> ../../sda2
lrwxrwxrwx 1 root root 9 16. Mär 13:33 scsi-SATA_WDC_WD2500YS-01_WD-WCANY1570429 -> ../../sdb
lrwxrwxrwx 1 root root 10 16. Mär 13:33 scsi-SATA_WDC_WD2500YS-01_WD-WCANY1570429-part1 -> ../../sdb1
lrwxrwxrwx 1 root root 10 16. Mär 13:33 scsi-SATA_WDC_WD2500YS-01_WD-WCANY1570429-part2 -> ../../sdb2
/dev/disk/by-path:
insgesamt 0
lrwxrwxrwx 1 root root 9 16. Mär 13:33 pci-0000:00:0d.0-ide-0:0 -> ../../hda
lrwxrwxrwx 1 root root 9 16. Mär 13:33 pci-0000:00:0e.0-scsi-0:0:0:0 -> ../../sda
lrwxrwxrwx 1 root root 10 16. Mär 13:33 pci-0000:00:0e.0-scsi-0:0:0:0-part1 -> ../../sda1
lrwxrwxrwx 1 root root 10 16. Mär 13:33 pci-0000:00:0e.0-scsi-0:0:0:0-part2 -> ../../sda2
lrwxrwxrwx 1 root root 9 16. Mär 13:33 pci-0000:00:0e.0-scsi-1:0:0:0 -> ../../sdb
lrwxrwxrwx 1 root root 10 16. Mär 13:33 pci-0000:00:0e.0-scsi-1:0:0:0-part1 -> ../../sdb1
lrwxrwxrwx 1 root root 10 16. Mär 13:33 pci-0000:00:0e.0-scsi-1:0:0:0-part2 -> ../../sdb2
/dev/disk/by-uuid:
insgesamt 0
lrwxrwxrwx 1 root root 10 16. Mär 13:33 23cb3db6-36c3-bcd6-3f69-3d1c8639bfb8 -> ../../sda2
lrwxrwxrwx 1 root root 9 16. Mär 13:33 27f0c8b9-a496-4234-8716-187918fd46be -> ../../md0
lrwxrwxrwx 1 root root 10 16. Mär 13:33 e5b48c8a-833a-40a5-65d0-716cf26601c0 -> ../../sda1
|
udev-Regeln
-
/etc/udev/rules.d/*.rules
- Files mit Regeldefinitionen zur Namensbildung
- einzelne Files dienen der Gruppierung von Regeln
- Sortierreihenfolge der Filenamen!
 |
$ ls /etc/udev/rules.d
05-udev-early.rules 55-usbdisk.rules 60-wacom.rules bluetooth.rules
20-scanner.rules 60-libsane.rules 90-alsa.rules xen-backend.rules
50-udev.rules 60-net.rules 90-hal.rules
51-hotplug.rules 60-pcmcia.rules 95-pam-console.rules
|
- Beachte:
/etc/udev/rules.d/50-udev.rules
enthält sog. default-Regeln, daran nichts ändern!
- eine Zeile definiert das Mapping von Geräteeigenschaften (device attributes) und Gerätename (device name)
- pro Zeile wenigstens ein key value pair, es können mehrere keys definiert werden (getrennt durch Komma)
- zwei Arten von keys
- match keys
- assignment keys
- entspricht das aktuelle Gerät allen match keys wird die Regel angewendet und der definierte Name wird verwendet
- es werden alle zutreffenden Regeln angewendet (aus allen Regel-Files)
- mehrere (unabhängige) Namen für ein Gerät möglich
- kommt kein Treffer zustande wird der kernel device name (default name) vergeben
Beispiele
 |
$ cat /etc/udev/rules.d/55-usbdisk.rules
# usb disk
KERNEL=="sd[a-z]*", BUS=="usb", SYMLINK="usbdisk%n"
|
- wenn der default Name auf das Muster
sd[a-z]*
passt und
- wenn das Gerät am Bus
usb
angeschlossen ist (genauer: im devpath zum Gerät muss das Subsystem usb
liegen)
- dann wird der symbolische Link
/dev/usbdisk%n
eingerichtet
-
%n
ist die kernel number des Geräts (die 3
aus /dev/sda3
)
- Beachte: das ist fehleranfällig: Was passiert wenn mehrere USB-Disks, -Sticks angeschlossen werden?
 |
$ cat !$
cat 90-hal.rules
# pass all events to the HAL daemon
RUN+="socket:/org/freedesktop/hal/udev_event"
|
- nur assignment key
- weiterleiten des uevents an HAL
 |
$ cat 40-multipath.rules
# multipath wants the devmaps presented as meaninglful device names
# so name them after their devmap name
SUBSYSTEM!="block", GOTO="end_mpath"
KERNEL!="dm-[0-9]*", ACTION=="add", PROGRAM=="/bin/bash -c '/sbin/lsmod | /bin/grep ^dm_multipath'", RUN+="/sbin/multipath -v0 %M:%m"
KERNEL!="dm-[0-9]*", GOTO="end_mpath"
ACTION=="add", RUN+="/sbin/dmsetup ls --target multipath --exec '/sbin/kpartx -a' -j %M -m %m"
PROGRAM=="/sbin/dmsetup ls --target multipath --exec /bin/basename -j %M -m %m", RESULT=="?*", NAME="%k", SYMLINK="mpath/%c"
PROGRAM!="/bin/bash -c '/sbin/dmsetup info -c --noheadings -j %M -m %m | /bin/grep -q .*:.*:.*:.*:.*:.*:.*:part[0-9]*-mpath-'", GOTO="end_mpath"
PROGRAM=="/sbin/dmsetup ls --target linear --exec /bin/basename -j %M -m %m", NAME="%k", RESULT=="?*", SYMLINK="mpath/%c"
LABEL="end_mpath"
$ grep "dm-" 50-udev.rules
KERNEL=="dm-[0-9]*", OPTIONS+="ignore_device"
|
- Behandlung von multipath devices
- andere device mapper nodes sollen von udev ignoriert werden
Zusammenfassung
- zahlreiche Möglichkeiten
- oftmals mehrere match keys erforderlich, um ein Gerät genau zu identifizieren
- siehe Manual zu
udev(7)
und Writing udev rules
- udev erzeugt immer nur einen device node, weitere Namen als symb. Links
- als device node wird i.d.R. der default name benutzt
- Experimentieren mit:
-
udevmonitor
-
udevinfo
-
udevtest
HAL / D-BUS
- HAL: Hardware Abstraction Layer
- einheitliche Darstellung der vorhandenen Hardware
- Hardware-Komponenten werden als device object dargestellt
- unique identifier
- z.B.:
/org/freedesktop/Hal/devices/storage_serial_SATA_WDC_WD2500YS_01_WD_WCANY1551209
- device properties (key-value pairs)
- abgeleitet aus der Komponente und ihrer Konfiguration selbst
- aus sog. device information files (
*.fdi
)
- z.B.:
block.device = '/dev/sda'
- benutzt/unterstützt D-BUS
- IPC-Framework
- Protokoll zum
- asynchronen Nachrichtenaustausch über einen daemon oder
- direkten Nachrichtenaustausch zwischen peers
- zwei daemon-Prozesse
-
dbus-daemon --system
-
/etc/rc.d/init.d/messagebus
- systemweite Nachrichten (hinzukommen/entfernen von Geräten)
-
dbus-daemon --session
- gestartet bei Login über grafischem Desktop
- IPC-Mechanismus von Applikationen des Desktops (GNOME, KDE)
- Anwendungen registrieren ihr Interesse an bestimmten Ereignissen
- plug-and-play-Mechanismus für Desktops
Architektur
Zusammenwirken von D-Bus, HAL, udev:
HAL-Architekturschema:
- HAL daemon
- verwaltet Datenbasis aller HW-Komponenten (device object list)
- stellt Informationen zusammen (
*.fdi
, ...)
- erkennt und beobachtet Busse (PCI, USB) und Geräte (network, storage)
- aktiviert externe Programme (callouts) um Änderungen an system _level components durchzuführen (z.B. Modifikation von
/etc/fstab
)
- sendet Nachrichten über D-Bus an session level components
- Applikationen
- benutzen HAL zur Informationsgewinnung über Geräte (z.B. Device Node)
- Grafische Desktops (GNOME, KDE) benutzen einen session level daemon um policies umzusetzen
- montieren des Filesystems auf einem USB-Stick, ...
- Start einer Foto-Management-Anwendung bei Anschluss einer Kamera
- ...
Komponenten
- vollständige Liste:
rpm -ql hal
/usr/sbin/hald | HAL daemon |
/etc/rc.d/init.d/haldaemon | Start-Script |
/usr/bin/lshal | Anzeige der HAL device objects |
/usr/bin/hal-device-manager | GUI zur Anzeige der HAL device objects |
/usr/bin/hal-{get,set}-property | Einzelne Eigenschaften abfragen/setzen |
/usr/libexec/hald* | Hilfsprogramme |
/usr/share/hal/fdi/ | Repository der device information files |
/usr/lib/libhal.so | HAL API |
/usr/lib/libhal_storage.so | HAL API für storage devices |
Applikationen
- die folgenden Anwendungen benutzen die HAL API, die Liste ist nicht vollständig ...
eggcups
evolution
gfloppy
gnome-cd
gnome-default-printer
gnome-eject
gnome-mount
gnome-power-manager
gnome-power-preferences
gnome-sound-properties
gnome-umount
gnome-volume-manager
gnome-volume-properties
gswitchit-plugins-capplet
hal-device
hal-find-by-capability
hal-find-by-property
hal-get-property
hal-set-property
lshal
nautilus-cd-burner
nm-applet
nm-tool
rhythmbox
sound-juicer
totem
Datenbasis
 |
$ $ lshal -l -u storage_serial_SATA_WDC_WD2500YS_01_WD_WCANY1551209
udi = '/org/freedesktop/Hal/devices/storage_serial_SATA_WDC_WD2500YS_01_WD_WCANY1551209'
volume.ignore = true (bool)
block.storage_device = '/org/freedesktop/Hal/devices/storage_serial_SATA_WDC_WD2500YS_01_WD_WCANY1551209' (string)
info.udi = '/org/freedesktop/Hal/devices/storage_serial_SATA_WDC_WD2500YS_01_WD_WCANY1551209' (string)
storage.partitioning_scheme = 'mbr' (string)
storage.removable.media_size = 250999111168 (0x3a70b67e00) (uint64)
storage.requires_eject = false (bool)
storage.hotpluggable = false (bool)
info.capabilities = {'storage', 'block'} (string list)
info.category = 'storage' (string)
info.product = 'WDC WD2500YS-01S' (string)
info.vendor = 'ATA' (string)
storage.size = 250999111168 (0x3a70b67e00) (uint64)
storage.removable = false (bool)
storage.removable.media_available = true (bool)
storage.physical_device = '/org/freedesktop/Hal/devices/pci_10de_266_scsi_host_0_scsi_device_lun0' (string)
storage.lun = 0 (0x0) (int)
storage.firmware_version = '20.0' (string)
storage.serial = 'SATA_WDC_WD2500YS-01_WD-WCANY1551209' (string)
storage.vendor = 'ATA' (string)
storage.model = 'WDC WD2500YS-01S' (string)
storage.drive_type = 'disk' (string)
storage.automount_enabled_hint = true (bool)
storage.media_check_enabled = false (bool)
storage.no_partitions_hint = false (bool)
storage.bus = 'scsi' (string)
block.is_volume = false (bool)
block.minor = 0 (0x0) (int)
block.major = 8 (0x8) (int)
block.device = '/dev/sda' (string)
linux.hotplug_type = 3 (0x3) (int)
info.parent = '/org/freedesktop/Hal/devices/pci_10de_266_scsi_host_0_scsi_device_lun0' (string)
linux.sysfs_path_device = '/sys/block/sda' (string)
linux.sysfs_path = '/sys/block/sda' (string)
$ hal-get-property --udi /org/freedesktop/Hal/devices/storage_serial_SATA_WDC_WD2500YS_01_WD_WCANY1551209 --key block.device
/dev/sda
$ hal-device-manager
|
Verweise