Springe zum Hauptinhalt

Archiv

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

Beispiel
/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)

Beispiel
$ 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/

Beispiel
$ 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!

Beispiel
$ 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

Beispiel
$ 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?

Beispiel
$ 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

Beispiel
$ 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

Beispiel
$ $ 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

hal-dev-mananger.jpg

Verweise