Die Header-Datei blk.h

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.

MAJOR_NR

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.

DEVICE_NAME

Der Name des zu erzeugenden Gerätes.

DEVICE_NR(kdev_t device)

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.

DEVICE_INTR

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.

DEVICE_ON(kdev_t device), DEVICE_OFF(kdev_t device)

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.

DEVICE_NO_RANDOM

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.

DEVICE_REQUEST

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:


 
#define MAJOR_NR sbull_major /* Definitionen in blk.h einschalten */
int sbull_major; /* muss vor der Deklaration von blk.h deklariert werden */

#define DEVICE_NR(device) MINOR(device) /* hat keine Partitions-Bits */
#define DEVICE_NAME "sbull"             /* Name für Meldungen */
#define DEVICE_INTR sbull_intrptr       /* Zeiger auf die untere Haelfte */
#define DEVICE_NO_RANDOM                /* traegt nicht zum Zufallspool bei */
#define DEVICE_REQUEST sbull_request
#define DEVICE_OFF(d) /* tut nichts */

#include <linux/blk.h>

#include "sbull.h"        /* lokale Definitionen */

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.