Aus Linux-Magazin 04/2003

Devfs: Konzepte, Strukturen und die Anwendung in der Praxis

Devfs bringt mit einem virtuellen Directory-Baum Ordnung und Übersicht ins chaotische »/dev«-Verzeichnis mit seinen vielen statischen Einträgen. Gentoo-Linux und Madrake arbeiten schon damit, die anderen kann man nachrüsten.

Am Anfang war die Datei. Für Unix-Systeme und Linux ist sie der Weg, um Informationen zu speichern und zu lesen. Auch der Zugriff auf die Hardware des Rechners wird über spezielle Dateien abgewickelt, die Named Pipes. Sie haben traditionell ihre Heimat im Verzeichnis »/dev« auf der Root-Partition. Mit der Menge der Anwendungsgebiete von Linux stiegt auch die Zahl der Geräteknoten im »/dev«-Verzeichnis rasant an, die das Skript »/sbin/MKDEV« statisch anlegt. Moderne Linux-Distributionen bringen es auf rund 2000 Einträge, die einen beachtlichen Teil des Root-Dateisystems in Anspruch nehmen.

Und das passiert nur auf Verdacht: Denn sieht man sich das »/dev«-Verzeichnis eines Linux-Rechners an, so ist leicht erkennbar, dass nur ein Bruchteil der angelegten Geräteknoten tatsächlich zum Betrieb der vorhandenen Komponenten benötigt wird. Welcher PC-Benutzer hat schon eine Atari-Maus, 20 Festplatten und zugleich ein RAID?

Dieser Wust verwaltet sich mehr schlecht als recht über ein numerisches Schema aus einer Major- und einer Minor-Nummer. Es schlüsselt den jeweiligen Hardwaretreiber (Major) und die jeweilige Instanz (Minors) auf, zum Beispiel die erste von mehreren Festplatten. Die Zukunft bringt für den plattenbasierten »/dev«-Mechanismus wohl weitere Bedrängnis: Es ist absehbar, dass Komplexität und Anzahl der unterstützten Hardware stetig zunehmen, statt einer Vereinheitlichung entgegenzustreben.

Versuche mit USB & Co.

Die letzten Jahre brachten für einige Subsysteme des Kernels bruchstückhafte Lösungen, die versuchen, die für ihren Teilbereich nachteilige Statik des bestehenden Systems zu überwinden. Es handelt sich dabei um die Subsysteme, die dynamisch wechselnde Endgerätekonfigurationen verwalten, zum Beispiel USB, SCSI und das zum Öffnen von Benutzersitzungen benötigten Pseudoterminal (Devptfs).

Einen Ausweg aus dem Dilemma weist das Devfs (Device Filesystem), das seit 2.3.46 im Linux-Kernel serienmäßg ist. Wie der Name bereits ausdrückt, ersetzt ein Dateisystem die Funktionalität des »/dev«-Verzeichnisses. Dieser Beitrag zeigt, mit welchen Mitteln Devfs als erster Ansatz den wachsenden Anforderungen gerecht zu werden versucht und welche Vorteile damit verbunden sind. Außerdem werden jene Funktionen in den Treibern vorgestellt, die das dynamische Registrieren von Geräten im Devfs unterstützen.

Eingeordnet

Linux unterstützt bekanntermaßen eine große Bandbreite an Dateisystemen, die das VFS (Virtual File System) dem Kernel gegenüber auf einen Satz von primitiven Datenstrukturen abbildet. Hierzu gehören zum Beispiel Superblocks, Inodes, Dateien und Verzeichniseinträge (siehe Kasten “Das allgemeine Dateimodell”).

Das allgemeine Dateimodell

Auf folgende allgemeine Datenstrukturen bildet das jeweilige Dateisystem seine Primitive im Linux-VFS intern ab:

  • Superblocks enthalten Informationen zur Verwaltung von eingehängten Dateisystemen, etwa den Typ und ob auf das Dateisystem seit seinem Einhängen geschrieben worden ist.
  • Inodes enthalten Informationen über einzelne Dateien. Die Inode-Nummer dient intern zur Identifizierung der Datei.
  • Datei-Objekte (Files) enthalten Informationen über die Interaktionen zwischen Prozessen und Dateien. Datei-Objekte existieren im Kernelspeicher nur, solange ein Prozess auf eine Datei zugreift.
  • Verzeichniseinträge (Dentry) verbinden Dateien und Verzeichnisse, indem sie die Teile des Zugriffspfads repräsentieren. Für sie existiert ein spezieller Puffer, der Dentry Cache.

Devfs gehört neben Procfs und Autofs zur Klasse der virtuellen Dateisysteme: Sie haben keine permanente Repräsentation auf einem Datenträger, der Kernel legt die Einträge dynamisch zur Laufzeit im Hauptspeicher an und vernichtet sie auch wieder. Daher existieren zu einem Zeitpunkt jeweils nur die relevanten Einträge – beim Devfs sind das die gerade gebrauchten Geräte.

Dies vermindert wirkungsvoll die exorbitante Menge der Einträge des »/dev«-Mechanismus. Ein Effekt des Devfs ist, dass das Suchen nach Geräten schneller geht, wenn zum Beispiel ein Brennprogramm wie KonCD alle vorhandenen CD-ROM-Laufwerke auflisten soll.

Abbildung 1: Das neue Identifizierungsschema verwendet ganze Namen statt Nummern und einstelliger Namen. Die Baumstruktur bildet die Hardware-Gegebenheiten gut ab.

Abbildung 1: Das neue Identifizierungsschema verwendet ganze Namen statt Nummern und einstelliger Namen. Die Baumstruktur bildet die Hardware-Gegebenheiten gut ab.

Namen und Pfade

Die Verzeichnisstruktur, die das Devfs zur Laufzeit dynamisch verwaltet, bringt weitere Vorteile: Die Pfade und Namen repräsentieren die vorhandene Hardware denkbar strukturiert – auch wenn sie auf den ersten Blick etwas ungewohnt wirkt: Die dritte Partition der ersten Festplatte am ersten IDE-Controller bildet das Devfs als »/dev/ide/host0/bus0/target0 /part3« ab.

Die vollen Namen verhelfen dem Betriebssystem, den Applikationen und in besonderem Maße auch den Benutzern zu mehr Information, um im Gerätepark intuitiver und strukturiert zu navigieren (siehe Abbildung 1). Nebenbei erledigt sich das etwas geheimnisvolle Major-Minor-Schema und damit die Notwendigkeit, eigene Treiber beim Maintainer der mit dem Kernel verteilten Datei »devices.txt« registrieren zu müssen. Denn bei Devfs ist, wie später beschrieben, der Treiber selbst für seine Registrierung und Deregistrierung zuständig.

Traditionsbedingt

Mit den neuen Namen kommen aber auch Probleme: Leicht einzusehen ist der Umstand, dass sowohl die im Umlauf befindlichen Treiber als auch die Software, die auf Devicefiles direkt zugreift, im Regelfall ohne Wissen um die neue Struktur geschrieben wurden. Zurzeit müssen deshalb Linux-Systeme mit Devfs Kompatibilitätslinks anlegen, die das Ansprechen der Hardware unter ihrem alten Namen sicherstellen.

Ähnlich problematisch ist auch die Benennung von Lockfiles, die bislang das exklusive Benutzen von Geräten absichern. Die Namen der im Verzeichnis »/var/lock« angelegt Files folgen traditionell dem Schema »LCK. Gerätename« beziehungsweise »LCK. Major#. Minor#«. Da bei Devfs oft die Blattknoten der Verzeichnisstruktur gleiche Namen haben – häufig ist es nur eine Ziffer wie bei »/dev /usb/tts/0« und »/dev/tts/0« -, kommt es zu Mehrdeutigkeiten und damit verbunden zu Beeinträchtigungen.

Das wirft auch gleich die Frage nach dem Management der Benutzerzugehörigkeit und der Zugriffsrechte in einem virtuellen Dateisystem auf, denn meist sind die von einem Benutzer verwendeten Geräte vor dem Zugriff anderer Benutzer zu schützen. Für die meisten Systeme empfiehlt sich dafür der Devfs-Daemon Devfsd (siehe unten).

Treiberprozesse können diesen Hintergrundprozess informieren, der daraufhin Benutzeridentität und Zugriffsrechte des aufrufenden Prozesses auf das Device überträgt. Wo sinnvoll, gibt die Rechtevergabe nur dem ursprünglichen Benutzer Lese- beziehungsweise Schreibzugriff, was vor unliebsamen Zugriffen der Konkurrenz auf das jeweilige Gerät schützt. Alternativ lassen sich die benötigten Geräteknoten statisch aus einem Startskript heraus mit »mkknod« anlegen und die Rechte mit »chmod« und »chgrp« setzen. Dieser Weg ist für weniger interaktive Umgebungen interessant, bei denen ein weiterer Daemon-Prozess zu viel des Guten wäre.

Listing 1: Auszug aus »devfs_fs_kernel.h«

extern devfs_handle_t devfs_register (devfs_handle_t dir, const char *name,
                                      unsigned int flags,
                                      unsigned int major, unsigned int minor,
                                      umode_t mode, void *ops, void *info);

extern void devfs_unregister (devfs_handle_t de);

Positiv schlägt bei Devfs zu Buche, dass es als vollwertiges Dateisystem die Geräteknoten unabhängig von den Eigenschaften des Root-Dateisystems behandelt. Somit kommen auch Dateisysteme wie NTFS, DOS-FAT, ISO 9660 oder ein ROM-Baustein als Root-Partition in Frage, die symbolische Links und Named Pipes nicht beherrschen.

Bei plattenbasierten Gerätezugriffen war das bisher nicht möglich. Wechselt zum Beispiel beim Start einer Benutzersitzung die Benutzeridentität des Pseudoterminals Ptty von »root« auf die des echten Benutzers, wird auf den Inode des Ptty-Geräteknotens geschrieben – in einem Read-only-Dateisystem ist das unmöglich. Devfs als allgemeinere Lösung übernimmt hier voll und ganz die Aufgaben des Devptsfs, das der Unix98-Standard fordert.

Dämonischer Verwalter

Da Devfs die Geräteeinträge an die jeweils gegebene Umgebung dynamisch anpasst, muss es eine Instanz in Devfs geben, die solche Anpassungen vornimmt. Die meist richtige Lösung dafür ist der Hintergrundprozess Devfsd, der beim Booten des Rechners aus dem »rc.sysinit«-Skript startet. Neben der erwähnten automatischen Anpassung der Benutzeridentität und der Rechtevergabe legt Devfsd die für die Rückwärtskompatibilität benötigten symbolischen Verweise selbsttätig an.

Der Linux-Administrator kann Devfsd in der Datei »/etc/devfsd.conf« auch explizit anweisen, Verweise benutzerdefiniert anzulegen. Praktisch: Für solche vom Benutzer definierbaren Aktionen in der »devfsd.conf« sind mit regulären Ausdrücken Ein- und Ausschlussklauseln definierbar; ihre Syntax zeigt die Manpage von »devfsd.conf«.

Normalerweise registriert sich ein Hardwaretreiber, indem er beim Laden seine eingebaute »devfs_register«-Funktion aufruft, die den Devfsd benachrichtigt. Das automatische Laden eines Moduls bei Bedarf managt die Devfs-Funktion »try_modload«, die Devfsd informiert, sobald eine Anwendung versucht auf den Inode eines Geräteeintrags zuzugreifen. Daraufhin legt Devfsd den entsprechenden Eintrag unter der Benutzeridentität und den Rechten des aufrufenden Prozesses an – es sei denn, dass er so konfiguriert wurde, dies zu unterlassen (siehe Abbildung 2).

Schließlich stellt Devfsd sicher, dass Änderungen an den Zugriffsberechtigungen den Neustart des Rechners überstehen. Hierzu kopiert er die Inodes der geänderten Einträge in das in der Datei »/etc/devfsd.conf« definierte Verzeichnis. Beim nächsten Bootvorgang restauriert Devfsd die Inodes, indem er sie einfach zurückschreibt.

Der Einhängepunkt von Devfs ist nicht zwingend »/dev«, es darf sogar mehrfach eingehängt werden. Deshalb ist beim Aufruf von Devfsd anzugeben, um welches Wurzelverzeichnis er sich kümmern soll. Instanzen von Devfsd können so mehrere Abbildungen des Gerätedateisystems parallel verwalten.

Treiber fürs Devfs anpassen

Damit ein Treiber mit Devfs funktioniert, muss er das Headerfile »devfs_fs _kernel.h« importieren. Die Datei definiert unter anderem die Funktionen »devfs_register« und »devfs_unregister« auf die in Listing 1 gezeigte Weise. Wie ihre Namen bereits ausdrücken, dienen sie der Registrierung und Deregistrierung von Devfs-Einträgen, wobei ein »devfs_handle« ein Zeiger auf eine »devfs_entry«-Struktur ist.

Die an »devfs_register« übergebenen Parameter decken sich exakt mit den frei wählbaren Anteilen eines solchen Eintrags. Er weist zur Verwaltung noch einige Listenzeiger auf, um die sich jedoch der Treiberentwickler nicht selbst kümmern muss. Der erste Parameter gibt das Verzeichnis an, in dem sich der neue Eintrag befinden soll, etwa »/dev/ide/«. Für die Registrierung von Verzeichnissen – also wenn man beabsichtigt eine neue Klasse von Geräten zu unterstützen – gibt es derzeit noch eine extra Funktion, »devfs_mkdir«, die ebenfalls ein »devfs _handle« zurückgibt:

devfs_handle_t devfs_mk_dir (devfs_handle_t
 dir, const char *name, void *info)

Der »flags«-Parameter bestimmt, ob der Eintrag die Benutzeridentität des aufrufenden Prozesses automatisch erbt oder die Identität jenes Benutzers erhält, der den Eintrag manuell angelegt hat, etwa »root«. Die möglichen Werte des »flags«-Parameters listet die Datei »devfs_fs _kernel.h«. »flags« kann sogar einen Eintrag verstecken, er wird dann beim Auflisten der Verzeichniseinträge nicht berücksichtigt. Zur Laufzeit entfernbare Geräte werden so auch behandelt.

Die Major/Minor-Nummern werden mit Devfs zwar überflüssig, trotzdem muss man sich um die friedliche Koexistenz mit noch auf dem alten Schema fußenden Anwendungen sorgen. Dazu führen die Devfs-Einträge Variablen mit, die sie nach dem Nummernsystem identifizierbar machen. Major und Minor werden zum Beispiel durch die Wrapper-Funktionen »devfs_register_chardev« und »devfs _register_blkdev« gesetzt, die dann nicht “Devfs-isierte” Versionen gleichen Namens aufrufen. So sind Einträge auch mit »mknod« zu erzeugen.

Zudem gibt es Funktionen zum Anlegen von symbolischen Verweisen, die beim Laden von Modulen das automatische Erzeugen von Kompatibilitätslinks ermöglichen. Der Typ »mode_t« ist eine Ganzzahl, die Benutzeridentität und die Zugriffsrechte festlegt, die beim Erzeugen des Eintrags gelten sollen.

Mit »ops« ist eine »file_operations«-Struktur aus »linux/include/fs/fs.h« gemeint, die Zugriffsoperationen auf den Eintrag definierbar gestaltet. »Info« ist für die meisten Module ohne Bedeutung und wird dann auf »NULL« gesetzt. Mit den hier vorgestellten Funktionen lassen sich Module für Devfs aus- und nachrüsten. Weitere Details finden sich in der Quelldatei »linux/fs/devfs/base.c«.

Abbildung 2: Demonstration der Registrationsfunktion. Das Devfs legt beim Laden eines Moduls den Verzeichniseintrag und die Blatteinträge automatisch an.

Abbildung 2: Demonstration der Registrationsfunktion. Das Devfs legt beim Laden eines Moduls den Verzeichniseintrag und die Blatteinträge automatisch an.

Devfs im Praxiseinsatz

Wer nur mal auf ungefährliche Weise ein System mit Devfs testen will, kann sich zum Beispiel von[5] das ISO-Image der Live-CD von Gentoo Linux herunterladen, die mit Devfs arbeitet. Sie macht übrigens von der beschriebenen Möglichkeit Gebrauch, die CD-ROM als universelles Root-Dateisystem zu nutzen. Somit braucht man keine freie Partition auf der Festplatte.

Um in anderen Linux-Distributionen Devfs zu aktivieren, ist mehr oder minder viel Vorarbeit angesagt. Als Testinstallation für diesen Beitrag diente eine Conectiva 8.0, deren mitgelieferter Kernel 2.4.18 zu Gunsten des Standardkernels 2.4.20 auszutauschen war, da die Conectiva-Quellen wegen der Devfs-Funktionen nicht durchkompilieren. Der auch von der Gentoo-CD verwendete Standard-2.4.20 lief nach dem Aktivieren der Devfs-Konfigurationsoptionen »CONFIG_EXPERIMENTAL«, »CONFIG _DEVFS_FS« und »CONFIG_DEVFS _MOUNT« problemlos durch.

Danach wurden noch die Quellen von der Homepage des Devfs-Entwicklers Richard Gooch[6] besorgt, übersetzt und installiert. Ein »make, make install« reicht im Wesentlichen. Wie ausführlich in der mit den Kernelquellen verteilten Datei[1] beschrieben, fallen noch einige Anpassungen bei den Konfigurationsdateien des Testsystems an.

Zunächst wurde die mit den Quellen kommende Standard-»devfsd.conf« nach »/etc« kopiert. Dann ist das Starten von Devfsd in die Datei »/etc/rc.d/sysinit.d« einzutragen: »/sbin/devfsd/dev«. Dadurch wird Devfs möglichst früh beim Booten aktiv. Bei Conectiva Linux war dies nicht nötig, denn ein solcher Eintrag existierte bereits.

Damit PAM (Pluggable Authentication Modules) mit dem Devfs funktioniert, sind in der Datei »/etc/securetty« die neuen Namen der lokalen virtuellen Konsolen anzugeben, um Root-Logins auf den Konsolen zu ermöglichen:

vc/1
vc/2
...
vc/8

Das ist nötig, da PAM keine symbolischen Verweise für die Konsole akzeptiert. Man kann auch noch den »/dev /pts«-Eintrag in der Datei »/etc/fstab« auskommentieren, weil er mit Devfs nicht mehr gebraucht wird.

Abbildung 3: Die neue Struktur und die relativ geringe Anzahl der Einträge auf der ersten Ebene. Viele davon sind nur Verweise, die der Abwärtskompatibilität dienen.

Abbildung 3: Die neue Struktur und die relativ geringe Anzahl der Einträge auf der ersten Ebene. Viele davon sind nur Verweise, die der Abwärtskompatibilität dienen.

Die Vorbereitungen sind abgeschlossen und der Rechner kann mit dem neuen Kernel booten. Im Test verlief dies bis auf einige Fehlermeldungen infolge nicht gefundener – da noch nicht angepasster – Treiber problemlos. Nach dem Einloggen zeigte sich das »/dev«-Verzeichnis wie erhofft mit neuer Struktur (siehe Abbildung 3).

Abbildung 4 zeigt den primitiven Anfang zum Einrichten einer Chroot-Umgebung mit Devfs. Das lässt sich vergleichsweise leicht bewerkstelligen, da Devfs vom Linux-VFS die Fähigkeit erbt, an mehreren Punkten zugleich eingehängt zu sein. Um den Zugriff auf einzelne Knoten zu beschränken, lassen sich auch nur einzelne Unterverzeichnisse von der »/dev«-Hierarchie mounten. Es ist per Eintrag in »devfsd.conf« möglich, Geräteknoten von der Registrierung auszunehmen.

Abbildung 4: Der eilige Beginn des Aufbaus einer Chroot-Umgebung mit Devfs.

Abbildung 4: Der eilige Beginn des Aufbaus einer Chroot-Umgebung mit Devfs.

Fazit: Stimmiges Konzept mit Zukunft

Devfs ist ein stimmiges Konzept, um dem Chaos auf der Root-Platte die Stirn zu bieten. Dank seiner Dateisystem-Eigenschaften handhabt Devfs vieles sauberer und eleganter als das alte »/dev«-Verzeichniskonzept mit seinen vielen statischen Einträgen. Dabei bleibt das grundlegende “Alles ist eine Datei”-Paradigma von Unix klar erhalten.

Teilweise fehlt es allerdings noch an der Unterstützung durch Treiber, die aber relativ einfach programmierbar sind, wie dieser Beitrag zeigte. Den Anwendungen und Tools, die mit den neuen Gerätenamen noch nicht klarkommen, gaukeln symbolische Kompatibilitätslinks wirksam das alte »/dev«-System vor.

Dass Distributionen wie Gentoo Linux und Mandrake 9.0 Devfs einsetzen beweist seine Alltagstauglichkeit. Stiegen auch Distributionshersteller wie SuSE und Red Hat auf den Devfs-Zug auf, müssten es alle Linux-Entwickler in ihren Programmen unterstützen. Dann entfiele die Notwendigkeit für den Kompatibilitätscode und die zusätzlichen Links – und Devfs entfaltet dem Anwender seine volle Schönheit. (jk)

Infos

[1] Devfs-Grundlagen: »Documentation/ filesystems/devfs/README« in den Kernel-Quellen

[2] Quelle aller Quellen: [http://lxr.linux.no/source/fs/devfs/]

[3] Guter Devfs-Artikel von Alessandro Rubini: [http://www.linux-mag.com/2000-05/gear_02.html]

[4] Manpage von Devfsd: [http://www.fifi.org/cgi-bin/man2html/usr/share/man/man8/devfsd.8.gz]

[5] ISO-Image von Gentoo Linux: [http://www.gentoo.org/main/en/where.xml]

[6] Devfs-Quellen: [http://www.atnf.csiro.au/~rgooch/linux/]

Der Autor

Stefan Klett studiert (noch) Informatik und hat seit 1995 ein großes Herz für den Pinguin.

LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben