Die Struktur file

struct file, definiert in <linux/fs.h>, ist die zweitwichtigste Datenstruktur, die in Gerätetreibern verwendet wird. Beachten Sie, daß file nichts mit der Struktur FILE in Anwendungsprogrammen zu tun hat. FILE wird in der C-Bibliothek definiert und taucht nie im Kernel-Code auf. struct file dagegen ist eine Kernel-Struktur, die nie in Anwendungsprogrammen auftaucht.

Die Struktur file repräsentiert eine offene Datei. (Sie ist nichts gerätetreiberspezifisches; jede offene Datei hat so eine struct file im Kernel-Space.) Sie wird vom Kernel beim open erzeugt und wird bis zum close an jede Funktion übergeben, die auf der Datei operiert. Nachdem die Datei geschlossen worden ist, gibt der Kernel die Datenstruktur frei. Eine offene Datei unterscheidet sich von einer Plattendatei, die durch struct inode repräsentiert wird.

In den Kernel-Quellen heißen Zeiger auf struct file üblicherweise entweder file oder filp (File Pointer). Wir werden den Zeiger durchgehend filp nennen, um Verwechslungen mit der Struktur selbst zu vermeiden: filp ist ein Zeiger (und als solcher eines der Argumente der Geräte-Methoden), file die Struktur selbst.

Die wichtigsten Felder in struct file werden unten aufgeführt. Wie der letzte Abschnitt kann auch diese Liste beim ersten Lesen übersprungen werden. Im nächsten Abschnitt werden wir dann aber auf echten C-Code stoßen, und wir werden dort auf einige dieser Felder eingehen, so daß Sie dann eventuell hier nachschlagen möchten.

mode_t f_mode;

Der Dateimodus identifiziert die Datei durch die Bits FMODE_READ und FMODE_WRITE als entweder lesbar oder schreibbar (oder beides). Es kann nützlich sein, dieses Feld auf Lese/Schreib-Erlaubnis in Ihren ioctl-Funktionen zu überprüfen, aber Sie müssen die Zugriffsrechte nicht beim read und write überprüfen, weil der Kernel das schon macht, bevor Ihr Treiber aufgerufen wird. Ein Versuch, ohne Schreibrechte zu schreiben, wird zurückgewiesen, bevor der Treiber überhaupt davon erfährt.

loff_t f_pos;

Die aktuelle Lese/Schreib-Position. loff_t ist ein 64-Bit-Wert (in gcc-Terminologie ein long long). Der Treiber kann diesen Wert auslesen, wenn er die aktuelle Position in der Datei wissen muß, sollte diesen Wert aber nie verändern (read und write sollten die Position durch den Zeiger aktualisieren, den sie als letztes Argument bekommen, anstatt direkt auf filp->f_pos zuzugreifen).

unsigned int f_flags;

Dies sind die Datei-Schalter wie O_RDONLY, O_NONBLOCK und O_SYNC. Ein Treiber muß den Schalter für das Nicht-Blockieren überprüfen; die anderen Schalter werden selten verwendet. Insbesondere sollten Lese/Schreib-Rechte mit f_mode anstelle von f_flags überprüft werden. Alle Flags werden in der Header-Datei <linux/fcntl.h> definiert.

struct file_operations *f_op;

Die Operationen, die mit der Datei assoziiert sind. Der Kernel weist die Zeiger im Zuge der Implementation von open zu und liest sie immer, wenn er eine Operation weiterleiten muß. Der Wert in filp->f_op wird nie für später abgespeichert; das bedeutet, daß Sie die Datei-Operationen auf Ihrer Datei ändern können, wann immer Sie wollen. Die neuen Methoden gelten dann unmittelbar nach dem Rücksprung zum Aufrufer. Beispielsweise ersetzt der Code für open für die Major-Nummer 1 (/dev/null, /dev/zero usw.) die Operationen in filp->f_op je nachdem, welche Minor-Nummer geöffnet wird. Dieses Verfahren erlaubt die Implementation unterschiedlichen Verhaltens für die gleiche Major-Nummer, ohne daß ein zusätzlicher Systemaufruf eingeführt werden muß. Die Möglichkeit, die Datei-Operationen zu ersetzen, ist das Kernel-Äquivalent zu der Technik, die in der objektorientierten Programmierung Überschreiben von Methoden genannt wird.

void *private_data;

Der Systemaufruf open setzt diesen Zeiger auf NULL, bevor die open-Methode des Treibers aufgerufen wird. Der Treiber kann dieses Feld für seine eigenen Zwecke verwenden oder ignorieren. Er kann das Feld auch verwenden, um auf allozierte Daten zu verweisen, muß es dann aber in der release-Methode wieder freigeben, bevor die file-Struktur vom Kernel zerstört wird. private_data ist eine gute Möglichkeit, um Zustandsinformationen zwischen Systemaufrufen abzuspeichern und wird von den meisten unserer Beispielmodule verwendet.

struct dentry *f_dentry;

Die Verzeichniseintrag-Struktur (dentry, von directory entry), die zur Datei gehört. Dentries sind eine in der 2.1-Serie eingeführte Optimierung. Autoren von Gerätetreibern müssen sich — abgesehen vom Zugriff auf die inode-Struktur als filp->f_dentry->d_inode — normalerweise nicht mit Dentry-Strukturen befassen.

Die tatsächliche Struktur hat noch einige weitere Felder, die aber für Gerätetreiber nicht nützlich sind. Wir können diese Felder problemlos ignorieren, weil Treiber file-Strukturen nie füllen; sie greifen nur auf andernorts erzeugte Strukturen zu.