Alle Block-Treiber sollten die Header-Datei <linux/blk.h> einbinden. Diese Datei definiert einen großen Teil des gemeinsamen Codes, der in Block-Treibern verwendet wird, und stellt die Funktionen zum Bearbeiten der I/O-Anfrage-Warteschlange zur Verfügung.
Die Header-Datei blk.h unterscheidet sich von anderen dadurch, daß sie mehrere Symbole auf der Basis des Symbols MAJOR_NR definiert, das vom Treiber vor dem Einbinden des Headers deklariert werden muß. Diese Konvention stammt aus der Frühzeit von Linux, als alle Block-Geräte von vornherein zugewiesene Major-Nummern hatten und modulare Block-Treiber nicht unterstützt waren.
Wenn Sie sich blk.h ansehen, werden Sie feststellen, daß mehrere geräteabhängige Symbole abhängig vom Wert von MAJOR_NR deklariert werden, der also im voraus bekannt sein muß. Wenn die Major-Nummer aber dynamisch zugewiesen wird, kann der Treiber die zugewiesene Nummer im voraus nicht kennen und daher MAJOR_NR nicht korrekt definieren. Wenn MAJOR_NR aber undefiniert ist, kann blk.h einige der Makros, die mit der Anfrage-Warteschlange verwendet werden, nicht definieren. Glücklicherweise kann MAJOR_NR als Integer-Variable definiert werden, womit alles für zusätzliche Block-Treiber bestens funktioniert.
blk.h verwendet auch einige andere vordefinierte, treiberspezifische Symbole. Die folgende Liste beschreibt die Symbole in <linux/blk.h>, die im voraus definiert werden müssen; am Ende der Liste sehen Sie den in sbull verwendeten Code.
Dieses Symbol wird für den Zugriff auf einige Arrays, insbesondere blk_dev und blksize_size, verwendet. Ein benutzerdefinierter Treiber wie sbull, der dem Symbol keinen konstanten Wert zuweisen kann, sollte ihm mittels #define eine Variable zuweisen, die dann die Major-Nummer enthalten wird. In sbull ist das sbull_major.
Der Name des zu erzeugenden Gerätes.
Dieses Symbol wird benutzt, um die Ordinalzahl des physikalischen Gerätes aus der Gerätenummer des Typs kdev_t zu extrahieren. Das Symbol wird wiederum verwendet, um CURRENT_DEV zu deklarieren, das in der request-Funktion verwendet werden kann, um herauszufinden, welchem Hardware-Gerät die in einer Übertragungsanfrage vorkommende Minor-Nummer gehört. Der Wert dieses Makros kann entweder MINOR(device) oder ein anderer Ausdruck sein, je nach der Konvention, mit der Minor-Nummern an Geräte und Partitionen vergeben werden. Das Makro sollte für alle Partitionen auf dem gleichen physikalischen Gerät die gleiche Gerätenummer zurückgeben, DEVICE_NR repräsentiert also die Plattennummer und nicht die Partitionsnummer. Partitionierbare Geräte werden im Abschnitt “the Section called Partitionierbare Geräte” verwendet.
Dieses Symbol wird benutzt, um eine Zeiger-Variable zu deklarieren, die auf den aktuellen Handler der unteren Hälfte verweist. Die Variable wird mit den Makros SET_INTR(intr) und CLEAR_INTR zugewiesen. Die Verwendung mehrerer Handler ist praktisch, wenn das Gerät Interrupts mit verschiedenen Bedeutungen auslösen kann.
Diese Makros sollten Geräten helfen, die vor oder nach einem Satz von Übertragungen weitere Dinge erledigen müssen; beispielsweise könnte ein Floppy-Treiber den Laufwerksmotor starten, bevor die I/O geschieht, und ihn danach wieder anhalten. Moderne Treiber verwenden diese Makros nicht mehr, und DEVICE_ON wird sogar nicht einmal mehr aufgerufen. Portable Treiber sollten sie aber (als leere Symbole) definieren, sonst kommt es zu Kompilationsfehlern in 2.0- und 2.2-Kerneln.
Die Funktion end_request trägt defaultmäßig zur System-Entropie bei (also der gesammelten “Zufälligkeiten”) bei, die von /dev/random benutzt wird. Wenn das Gerät aber nicht in der Lage ist, hier hinreichend zufällige Werte zu liefern, sollte DEFINE_NO_RANDOM definiert werden. /dev/random wurde in “the Section called Einen Interrupt-Handler installieren in Kapitel 9” in Kapitel 9 vorgestellt, als das Symbol SA_SAMPLE_RANDOM erklärt wurde.
Wird dazu verwendet, den Namen der vom Treiber verwendeten request-Funktion anzugeben. Die Definition von DEVICE_REQUEST führt nur zu einer Forward-Deklaration der request-Funktion; dies ist ein Relikt früherer Zeiten; die meisten (oder alle) Treiber können es weglassen.
Der sbull-Treiber deklariert diese Symbole folgendermaßen:
#defineMAJOR_NRsbull_major/*Definitioneninblk.heinschalten*/ intsbull_major;/*mussvorderDeklarationvonblk.hdeklariertwerden*/ #defineDEVICE_NR(device)MINOR(device)/*hatkeinePartitions-Bits*/ #defineDEVICE_NAME"sbull"/*NamefürMeldungen*/ #defineDEVICE_INTRsbull_intrptr/*ZeigeraufdieuntereHaelfte*/ #defineDEVICE_NO_RANDOM/*traegtnichtzumZufallspoolbei*/ #defineDEVICE_REQUESTsbull_request #defineDEVICE_OFF(d)/*tutnichts*/ #include<linux/blk.h> #include"sbull.h"/*lokaleDefinitionen*/ |
Die Header-Datei blk.h verwendet die oben aufgeführten Makros, um einige weitere Makros zu definieren, die auch der Treiber verwenden kann. Wir werden diese Makros in den folgenden Abschnitten beschreiben.