Schnellreferenz

Die wichtigsten Funktionen und Makros, die beim Schreiben von Block-Treibern benutzt werden, sind hier zusammengefaßt. Um Platz zu sparen, führen wir allerdings die Felder von struct request, struct buffer_head und struct genhd nicht auf und lassen auch die vordefinierten ioctl-Befehle weg.

int register_blkdev(unsigned int major, const char *name, struct block_device_operations *bdops);, int unregister_blkdev(unsigned int major, const char *name);

Diese Funktionen übernehmen die Registrierung des Geräts in der Initialisierungsfunktion und die Deregistrierung in der Aufräumfunktion.

#include <linux/blkdev.h>, blk_init_queue(request_queue_t *queue, request_fn_proc *request);, blk_cleanup_queue(request_queue_t *queue);

Die erste Funktion initialisiert eine Warteschlange und etabliert die request-Funktion, die zweite wird zum Aufräumen verwendet.

BLK_DEFAULT_QUEUE(major)

Dieses Makro gibt die Default-I/O-Anfrage-Warteschlange für eine gegebene Major-Nummer zurück.

struct blk_dev_struct blk_dev[MAX_BLKDEV];

Dieses Array wird vom Kernel dazu benutzt, die passende Warteschlange für eine bestimmte Anfrage zu finden.

int read_ahead[];, int max_readahead[][];

read_ahead enthält Vorauslesewerte auf Block-Ebene für jede Major-Nummer. Ein Wert von 8 ist für Geräte wie Festplatten sinnvoll; bei langsameren Medien sollte ein größerer Wert gewählt werden. max_readahead enthält Vorauslesewerte für alle Major- und Minornummern auf Dateisystem-Ebene und wird normalerweise gegenüber dem System-Default nicht verändert.

int max_sectors[][];

Dieses Array, das per Major- und Minor-Nummer indiziert wird, enthält die maximale Anzahl von Sektoren, die in einer einzigen I/O-Anfrage zusammengefaßt werden sollten.

int blksize_size[][];, int blk_size[][];, int hardsect_size[][];

Diese zweidimensionalen Arrays werden mit der Major- und Minor-Nummer indiziert. Der Treiber ist dafür zuständig, die zur jeweiligen Major-Nummer gehörende Reihe im Array zu allozieren bzw. zu deallozieren. In den Arrays steht die Größe der Blocks auf dem Gerät (normalerweise 1 KByte), die Größe jedes Minor-Gerätes in KByte (nicht in Blocks) und die Hardware-Sektorengröße in Bytes.

MAJOR_NR, DEVICE_NAME, DEVICE_NR(kdev_t device), DEVICE_INTR, #include <linux/blk.h>

Diese Makros müssen vom Treiber definiert werden, bevor die Header-Datei <linux/blk.h> eingebunden wird, weil sie in dieser Datei verwendet werden. MAJOR_NR ist die Major-Nummer des Geräts, DEVICE_NAME der Name des Geräts, wie er in Fehlermeldungen verwendet wird, DEVICE_NR gibt die Minor-Nummer des physikalischen Geräts zurück, auf das die Geräte-Nummer verweist, und DEVICE_INTR ist ein selten verwendetes Symbol, das auf die untere Hälfte des Interrupt-Handlers des Geräts verweist.

spinlock_t io_request_lock;

Das Spinlock muß gehalten werden, wann immer eine I/O-Anfrage-Warteschlange manipuliert wird.

struct request *CURRENT

Dieses Makro zeigt auf die aktuelle Anfrage, wenn die Default-Warteschlange verwendet wird. Die Anfrage-Struktur beschreibt einen Datenblock, der übertragen werden soll, und wird von der request-Funktion im Treiber benutzt.

INIT_REQUEST;, end_request(int status);

INIT_REQUEST überprüft die nächste Anfrage in der Warteschlange und springt zurück, wenn keine weiteren Anfragen mehr auszuführen sind. end_request wird bei der Beendigung einer Block-Anfrage aufgerufen.

spinlock_t io_request_lock;

Die I/O-Anfrage-Sperre muß zu jedem Zeitpunkt gehalten werden, an dem die Anfrage-Warteschlange manipuliert wird.

struct request *blkdev_entry_next_request(struct list_head *head);, struct request *blkdev_next_request(struct request *req);, struct request *blkdev_prev_request(struct request *req);, blkdev_dequeue_request(struct request *req);, blkdev_release_request(struct request *req);

Diverse Funktionen zur Arbeit mit der I/O-Anfrage-Warteschlange.

blk_queue_headactive(request_queue_t *queue, int active);

Gibt an, ob die erste Anfrage in der Warteschlange aktiv vom Treiber bearbeitet wird oder nicht.

void blk_queue_make_request(request_queue_t *queue, make_request_fn *func);

Stellt eine Funktion bereit, die Block-I/O-Anfragen direkt aus dem Kernel heraus bearbeitet.

end_that_request_first(struct request *req, int status, char *name);, end_that_request_last(struct request *req);

Erledigen die erforderlichen Schritte, um eine Block-I/O-Anfrage abzuschließen. end_that_request_last wird nur dann aufgerufen, wenn alle Puffer in der Anfrage verarbeitet worden sind, also wenn end_that_request_first 0 zurückgegeben hat.

bh->b_end_io(struct buffer_head *bh, int status);

Meldet die Beendigung der I/O auf dem angegebenen Puffer.

int blk_ioctl(kdev_t dev, unsigned int cmd, unsigned long arg);

Eine Hilfsfunktion, die die meisten der Standard-ioctl-Befehle von Block-Geräten implementiert.

int check_disk_change(kdev_t dev);

Diese Funktion überprüft, ob ein Medienwechsel auf dem angegebenen Gerät erfolgt ist, und ruft, sollte das der Fall sein, die Methode revalidate des Treibers auf.

#include<linux/gendisk.h>, struct gendisk;, struct gendisk *gendisk_head

Mit der generischen Festplatte kann Linux leicht partitionierbare Geräte unterstützen. Die gendisk-Struktur beschreibt eine generische Festplatte; gendisk_head ist der Anfang einer verketteten Liste von Strukturen, die alle Festplatten im System beschreibt.

void register_disk(struct gendisk *gd, int drive, unsigned minors, struct block_device_operations *ops, long size);

> Diese Funktion liest die Partitionstabelle der Festplatte neu ein und ändert genhd->part, um die neue Partitionierung wiederzugeben.