
Hallo habrozhiteli! Wir haben bereits über Michael Kerrisks Buch
„Linux API. Umfassender Leitfaden .
“ Jetzt haben wir beschlossen, einen Auszug aus dem Buch "Verwalten der im Kernel verwalteten Datei-E / A-Pufferung" zu veröffentlichen.
Das Zurücksetzen des Kernel-Pufferspeichers für Ausgabedateien kann erzwungen werden. Manchmal ist dies erforderlich, wenn die Anwendung vor der Fortsetzung der Arbeit (z. B. Änderungen einer Prozessprotokollierungsdatenbank) sicherstellen muss, dass die tatsächliche Ausgabe auf die Festplatte (oder zumindest in den Hardware-Festplatten-Cache) geschrieben wird.
Bevor auf die Systemaufrufe eingegangen wird, die zur Steuerung der Kernel-Pufferung verwendet werden, sollten einige verwandte Definitionen aus SUSv3 betrachtet werden.
Synchronisierte E / A mit Daten- und DateiintegritätIn SUSv3 bedeutet das Konzept der synchronisierten E / A-Vervollständigung "eine E / A-Operation, die entweder zu einer erfolgreichen Datenübertragung [auf die Festplatte] führte oder als nicht erfolgreich diagnostiziert wurde".
SUSv3 definiert zwei verschiedene Arten von synchronisierten E / A-Abschlüssen. Der Unterschied zwischen den Typen bezieht sich auf Metadaten („Daten über Daten“), die die Datei beschreiben. Der Kernel speichert sie zusammen mit den Daten der Datei selbst. Details zu Dateimetadaten werden in Abschnitt 14.4 bei der Untersuchung von Dateiinodes erläutert. In der Zwischenzeit reicht es aus zu beachten, dass Dateimetadaten Informationen wie Informationen über den Eigentümer der Datei und ihre Gruppe, Zugriffsrechte auf die Datei, Dateigröße, Anzahl der festen Links zur Datei, Zeitstempel, die den Zeitpunkt des letzten Zugriffs auf die Datei und den Zeitpunkt der letzten Änderung enthalten, enthalten und die Zeit der letzten Metadatenänderung sowie Zeiger auf Datenblöcke.
Die erste Art der synchronisierten E / A-Vervollständigung in SUSv3 ist die Vervollständigung der Datenintegrität. Bei der Aktualisierung der Dateidaten sollte die Übertragung von Informationen sichergestellt sein, die ausreichen, um die weitere Extraktion dieser Daten zu ermöglichen, damit sie weiterarbeiten können.
- Für einen Lesevorgang bedeutet dies, dass die angeforderten Dateidaten (von der Festplatte) an den Prozess übertragen wurden. Wenn anstehende Schreibvorgänge vorliegen, die sich auf die angeforderten Daten auswirken können, werden die Daten vor dem Lesen auf die Festplatte übertragen.
- Für einen Schreibvorgang bedeutet dies, dass die in der Schreibanforderung angegebenen Daten (auf die Festplatte) übertragen wurden, wie alle zum Extrahieren dieser Daten erforderlichen Dateimetadaten. Der wichtigste Punkt, den Sie beachten sollten: Um sicherzustellen, dass Daten aus der geänderten Datei extrahiert werden, müssen nicht alle Medatendateien übertragen werden. Ein Beispiel für das Metadatenattribut einer geänderten Datei, die migriert werden muss, ist ihre Größe (wenn der Schreibvorgang die Dateigröße erhöht). Im Gegensatz dazu müssen die Zeitstempel der zu ändernden Datei nicht auf die Festplatte übertragen werden, bevor der anschließende Datenabruf erfolgt.
Der zweite in SUSv3 definierte Typ der synchronisierten E / A-Vervollständigung ist die Vervollständigung der Dateiintegrität. Dies ist eine erweiterte Option zum Abschließen synchronisierter E / A mit Datenintegrität. Der Unterschied zwischen diesem Modus besteht darin, dass während der Aktualisierung der Datei alle Metadaten auf die Festplatte übertragen werden, auch wenn dies für die nachfolgende Extraktion der Dateidaten nicht erforderlich ist.
Systemaufrufe zur Steuerung der Kernel-Pufferung während der Datei-E / A.Der Systemaufruf fsync () setzt alle gepufferten Daten und alle Metadaten zurück, die einer geöffneten Datei mit einem fd-Deskriptor zugeordnet sind. Durch Aufrufen von fsync () wird die Datei nach Abschluss der synchronen E / A in einen Integritätszustand (Datei) versetzt.
Der Aufruf von fsync () gibt die Steuerung erst zurück, nachdem die Datenübertragung zum Festplattengerät (oder zumindest zu seinem Cache) abgeschlossen ist.
#include <unistd.h> int fsync(int fd);
Gibt bei Erfolg 0 oder -1 bei Fehler zurück
Der Systemaufruf fdatasync () funktioniert genau wie fsync (), versetzt die Datei jedoch nach Abschluss der synchronen E / A in einen Integritätszustand (Daten).
#include <unistd.h> int fdatasync(int fd);
Gibt bei Erfolg 0 oder -1 bei Fehler zurück
Durch die Verwendung von fdatasync () wird möglicherweise die Anzahl der für den Systemaufruf fsync () erforderlichen Festplattenvorgänge von zwei auf eins reduziert. Wenn sich beispielsweise die Dateidaten geändert haben, die Größe jedoch gleich bleibt, werden beim Aufrufen von fdatasync () nur die Daten aktualisiert. (Es wurde bereits oben erwähnt, dass zum Abschließen eines synchronen E / A-Vorgangs mit Datenintegrität keine Änderungen an Attributen wie dem Zeitpunkt der letzten Änderung der Datei übertragen werden müssen.) Im Gegensatz dazu erzwingt der Aufruf von fsync () auch die Übertragung von Metadaten auf die Festplatte.
Eine solche Reduzierung der Anzahl der Festplatten-E / A-Vorgänge ist für einzelne Anwendungen nützlich, für die die Leistung und die genaue Aktualisierung bestimmter Metadaten (z. B. Zeitstempel) eine entscheidende Rolle spielen. Dies kann zu erheblichen Leistungsverbesserungen für Anwendungen führen, die mehrere Dateiaktualisierungen gleichzeitig erstellen. Da sich Dateidaten und Metadaten normalerweise in verschiedenen Teilen der Festplatte befinden, erfordert das Aktualisieren beider Daten eine wiederholte Vorwärts- und Rückwärtssuche auf der Festplatte.
Unter Linux 2.2 und früheren Versionen wird fdatasync () als Aufruf von fsync () implementiert, sodass keine Leistungssteigerung erzielt wird.
Ab der Kernel-Version 2.6.17 bietet Linux einen nicht standardmäßigen Systemaufruf sync_file_range (). Damit können Sie den Vorgang des Löschens von Dateidaten auf die Festplatte genauer steuern als mit fdatasync (). Beim Aufrufen können Sie den Bereich angeben, der in der Datei gelöscht werden soll, und Flags setzen, die die Bedingungen für das Blockieren dieses Anrufs festlegen. Weitere Informationen finden Sie auf der Handbuchseite von sync_file_range (2).
Der Systemaufruf sync () bewirkt, dass alle Kernelpuffer, die aktualisierte Dateiinformationen enthalten (d. H. Datenblöcke, Zeigerblöcke, Metadaten usw.), auf die Festplatte geleert werden.
#include <unistd.h> void sync(void);
In der Linux-Implementierung gibt die Funktion sync () die Steuerung erst zurück, nachdem alle Daten auf das Festplattengerät (oder zumindest in dessen Cache) übertragen wurden. In SUSv3 ist es jedoch zulässig, dass sync () einfach die Datenübertragung für die E / A-Operation in den Plan einführt und die Steuerung zurückgibt, bis die Übertragung abgeschlossen ist.
Ein kontinuierlich ausgeführter Kernel-Thread löscht geänderte Kernel-Puffer auf die Festplatte, wenn sie 30 Sekunden lang nicht explizit synchronisiert wurden. Dies geschieht, um zu verhindern, dass die Datenpuffer für längere Zeit nicht mit der entsprechenden Festplattendatei synchron sind (und um sie nicht dem Risiko eines Verlusts bei einem Systemausfall auszusetzen). Unter Linux 2.6 wird diese Aufgabe vom pdflush-Kernel-Thread ausgeführt. (Unter Linux 2.4 wurde es vom kupdated Kernel-Thread ausgeführt.)
Der Zeitraum (in Hundertstelsekunden), nach dem der geänderte Puffer durch den pdflush-Stream-Code auf die Festplatte geleert werden soll, ist in der Datei / proc / sys / vm / dirty_expire_centisecs definiert. Zusätzliche Dateien im selben Verzeichnis steuern andere Funktionen des vom pdflush-Stream ausgeführten Vorgangs.
Aktivieren Sie den Synchronisierungsmodus für alle Datensätze: O_SYNCWenn Sie beim Aufrufen von open () das O_SYNC-Flag angeben, werden alle nachfolgenden Ausgabeoperationen im synchronen Modus ausgeführt:
fd = open(pathname, O_WRONLY | O_SYNC);
Nach diesem Aufruf von open () werden bei jeder write () -Operation, die für eine Datei ausgeführt wird, automatisch Daten und Dateimetadaten auf die Festplatte gelöscht (dh Schreibvorgänge werden als synchronisierte Schreibvorgänge mit Dateiintegrität ausgeführt).
In älteren Versionen des BSD-Systems wurde das O_FSYNC-Flag verwendet, um die im O_SYNC-Flag enthaltenen Funktionen bereitzustellen. In glibc ist das O_FSYNC-Flag als Synonym für O_SYNC definiert.
Auswirkungen des O_SYNC-Flags auf die LeistungDie Verwendung des O_SYNC-Flags (oder häufige Aufrufe von fsync (), fdatasync () oder sync ()) kann die Leistung erheblich beeinträchtigen. In der Tabelle. Abbildung 13.3 zeigt die Zeit, die erforderlich ist, um 1 Million Byte in eine Datei zu schreiben, die gerade (im ext2-Dateisystem) für verschiedene Puffergrößen erstellt wurde, wobei das O_SYNC-Flag gesetzt und deaktiviert ist. Die Ergebnisse wurden (unter Verwendung des im Quellcode des Buches enthaltenen Programms filebuff / write_bytes.c) unter Verwendung des Vanille-Kernels Version 2.6.30 und des ext2-Dateisystems mit einer Blockgröße von 4096 Byte erhalten. Jede Zeile enthält den Durchschnittswert, der nach 20 Starts für eine bestimmte Puffergröße erhalten wurde.
Tabelle 13.3. Die Auswirkung des O_SYNC-Flags auf eine Schreibgeschwindigkeit von 1 Million Bytes
Wie Sie sehen können, führt die Angabe des O_SYNC-Flags zu einer ungeheuren Zunahme der Zeit, die aufgewendet wird, wenn ein Puffer von 1 Byte mehr als 1000 Mal verwendet wird. Beachten Sie auch den großen Unterschied, der beim Ausführen von Datensätzen mit dem O_SYNC-Flag zwischen der verstrichenen Zeit und der CPU-Auslastungszeit auftritt. Dies ist eine Folge des Blockierens der Programmausführung, wenn der tatsächliche Inhalt jedes Puffers auf die Festplatte geleert wird.
In den in der Tabelle gezeigten Ergebnissen. 13.3, ein weiterer Faktor, der die Leistung bei Verwendung von O_SYNC beeinflusst, wird nicht berücksichtigt. Moderne Festplatten haben einen großen internen Cache, und standardmäßig überträgt das Setzen des O_SYNC-Flags einfach Daten in diesen Cache. Wenn Sie das Festplatten-Caching deaktivieren (mit dem Befehl hdparm –W0), werden die Auswirkungen auf die Leistung von O_SYNC noch bedeutender. Bei einer Puffergröße von 1 Byte erhöht sich die verstrichene Zeit von 1030 Sekunden auf ungefähr 16.000 Sekunden. Bei einer Puffergröße von 4096 Bytes erhöht sich die verstrichene Zeit von 0,34 Sekunden auf 4 Sekunden. Wenn Sie erzwingen müssen, dass die Kernel-Puffer auf die Festplatte geleert werden, sollten Sie daher überlegen, ob Sie Ihre Anwendung mit größeren Puffern für write () oder mit periodischen Aufrufen von fsync () oder fdatasync () anstelle des O_SYNC-Flags entwerfen können.
Flags O_DSYNC und O_RSYNCSUSv3 definiert zwei zusätzliche Statusflags für offene Dateien, die sich auf synchronisierte E / A beziehen: O_DSYNC und O_RSYNC.
Das O_DSYNC-Flag führt zu nachfolgenden synchronisierten Schreibvorgängen mit Datenintegrität der abgeschlossenen E / A (ähnlich wie bei Verwendung von fdatasync ()). Der Effekt seiner Operation unterscheidet sich von der Wirkung, die durch das O_SYNC-Flag verursacht wird, dessen Verwendung zu nachfolgenden synchronisierten Schreiboperationen mit Dateiintegrität führt (wie fsync ()).
Das O_RSYNC-Flag wird zusammen mit O_SYNC oder O_DSYNC angegeben und führt zu einer Erweiterung des Verhaltens, das diesen Flags während Lesevorgängen zugeordnet ist. Das Angeben der Flags O_RSYNC und O_DSYNC beim Öffnen der Datei führt zu nachfolgenden synchronisierten Lesevorgängen mit Datenintegrität (dh bevor der Lesevorgang abgeschlossen ist, werden alle ausstehenden Dateieinträge aufgrund des Vorhandenseins von O_DSYNC abgeschlossen). Die Angabe der O_RSYNC- und O_SYNC-Flags beim Öffnen der Datei führt zu nachfolgenden synchronisierten Lesevorgängen mit Dateiintegrität (dh bevor der Lesevorgang abgeschlossen ist, werden alle ausstehenden Dateieinträge aufgrund des Vorhandenseins von O_SYNC abgeschlossen).
Vor der Veröffentlichung der Kernel-Version 2.6.33 waren die Flags O_DSYNC und O_RSYNC unter Linux nicht implementiert, und diese Konstanten wurden in den Glibc-Header-Dateien als Setzen des O_SYNC-Flags definiert. (Im Fall von O_RSYNC war dies nicht der Fall, da O_SYNC keine Funktionsmerkmale von Leseoperationen beeinflusst.)
Ab der Kernel-Version 2.6.33 implementiert Linux das O_DSYNC-Flag, und die Implementierung des O_RSYNC-Flags wird wahrscheinlich in zukünftigen Kernel-Versionen hinzugefügt.
Vor der Veröffentlichung des 2.6.33-Kernels unter Linux gab es keine vollständige Implementierung der O_SYNC-Semantik. Stattdessen wurde das O_SYNC-Flag als O_DSYNC implementiert. In Anwendungen, die mit älteren Versionen der GNU C-Bibliothek für ältere Kernel verknüpft sind, verhält sich das O_SYNC-Flag unter Linux-Versionen 2.6.33 und höher weiterhin wie O_DSYNC. Dies geschieht, um das vertraute Verhalten solcher Programme beizubehalten. (Um die Abwärts-Binärkompatibilität in Kernel 2.6.33 zu gewährleisten, wurde dem O_DSYNC-Flag das alte O_SYNC-Flag zugewiesen, und das neue O_SYNC-Flag enthält das O_DSYNC-Flag (04010000 bzw. 010000 auf einem der Computer). Dies ermöglicht Anwendungen, die mit neuen Header-Dateien kompiliert wurden.) , mindestens O_DSYNC-Semantik in Kerneln erhalten, die vor Version 2.6.33 veröffentlicht wurden.)
13.4. Übersicht über die E / A-Pufferung
In Abb. Abbildung 13.1 zeigt das Pufferschema (für Ausgabedateien), das von der stdio-Bibliothek und dem Kernel verwendet wird, sowie die Mechanismen zur Steuerung der einzelnen Puffertypen. Wenn Sie das Diagramm in die Mitte verschieben, sehen Sie die Übertragung von Benutzerdaten durch die Funktionen der stdio-Bibliothek in den stdio-Puffer, der im Benutzerspeicher arbeitet. Wenn dieser Puffer voll ist, greift die stdio-Bibliothek auf den Systemaufruf write () zurück, der Daten an den Kernel-Puffer-Cache (im Kernel-Speicher) überträgt. Infolgedessen initiiert der Kernel eine Plattenoperation, um Daten auf die Platte zu übertragen.
Im linken Teil der Schaltung in Abb. 13.1 zeigt Aufrufe, die jederzeit verwendet werden können, um das Löschen eines der Puffer explizit zu erzwingen. Der rechte Teil zeigt die Aufrufe, mit denen automatisch ein Reset durchgeführt werden kann, indem entweder die Pufferung in der stdio-Bibliothek deaktiviert oder die Dateiausgabe eines synchronen Ausführungsmodus für Systemaufrufe aktiviert wird, sodass jeder write () -Aufruf sofort auf die Festplatte übertragen wird.
13.5. Kernel-E / A-Benachrichtigung
Mit dem Systemaufruf posix_fadvise () kann der Prozess den Kernel über seine bevorzugte Methode für den Zugriff auf Dateidaten informieren.
Der Kernel kann (muss aber nicht) die vom Systemaufruf posix_fadvise () bereitgestellten Informationen verwenden, um die Verwendung des Puffercaches zu optimieren und dadurch die E / A-Leistung für den Prozess und das gesamte System zu erhöhen. Das Aufrufen von posix_fadvise () hat keinen Einfluss auf die Semantik des Programms.
#define _XOPEN_SOURCE 600 #include <fcntl.h> int posix_fadvise(int fd, off_t offset, off_t len, int advice);
Gibt bei Erfolg 0 oder eine positive Fehlernummer zurück, wenn sie auftritt
Das Argument fd ist ein Dateideskriptor, der die Datei angibt, für die der Kernel kontaktiert werden muss. Die Argumente offset und len geben den Bereich der Datei an, auf den sich die Benachrichtigung bezieht: offset gibt den anfänglichen Offset des Bereichs an und len gibt die Größe in Byte an. Wenn Sie len auf 0 setzen, sind alle Bytes gemeint, beginnend mit dem Offset und endend mit dem Ende der Datei. (In Kernelversionen vor 2.6.6 wurde der Wert 0 für len wörtlich als 0 Byte interpretiert.)
Das Hinweisargument zeigt die beabsichtigte Art des Zugriffs des Prozesses auf die Datei. Es wird mit einem der folgenden Werte definiert.
POSIX_FADV_NORMAL - Der Prozess hat keine spezielle Benachrichtigung bezüglich der Behandlungsmuster. Dies ist das Standardverhalten, wenn für die Datei keine Benachrichtigungen angegeben werden. Unter Linux wird durch diesen Vorgang das Fenster so eingestellt, dass proaktiv Daten aus einer Datei auf ihre ursprüngliche Größe (128 KB) gelesen werden.
POSIX_FADV_SEQUENTIAL - Der Prozess umfasst das sequentielle Lesen von Daten von kleineren zu größeren Offsets. Unter Linux wird durch diese Operation das Fenster so eingestellt, dass proaktiv Daten aus einer Datei gelesen werden, um den ursprünglichen Wert zu verdoppeln.
POSIX_FADV_RANDOM - Der Prozess beinhaltet den Zugriff auf Daten in zufälliger Reihenfolge. Unter Linux deaktiviert diese Option das proaktive Lesen von Daten aus einer Datei.
POSIX_FADV_WILLNEED - Der Prozess beinhaltet den Zugriff auf den angegebenen Bereich der Datei in naher Zukunft. Der Kernel liest präventiv Daten, um den Puffercache mit Dateidaten in dem durch die Argumente offset und len angegebenen Bereich zu füllen. Nachfolgende read () - Aufrufe der Datei blockieren nicht die Festplatten-E / A, sondern rufen einfach Daten aus dem Puffercache ab. Der Kernel übernimmt keine Garantie dafür, wie lange sich die aus der Datei abgerufenen Daten im Puffercache befinden. Wenn während des Betriebs eines anderen Prozesses oder Kernels ein besonderer Speicherbedarf besteht, wird die Seite möglicherweise wiederverwendet. Mit anderen Worten, wenn Speicherbedarf besteht, müssen wir eine kleine Zeitlücke zwischen dem Aufruf von posix_fadvise () und dem nachfolgenden Aufruf (oder den Aufrufen) von read () gewährleisten. (Die Funktionalität, die der Operation POSIX_FADV_WILLNEED entspricht, wird durch den Linux-spezifischen Systemaufruf readahead () bereitgestellt.)
POSIX_FADV_DONTNEED - Der Prozess beinhaltet in naher Zukunft keine Aufrufe des angegebenen Dateibereichs. Auf diese Weise wird der Kernel benachrichtigt, dass er die entsprechenden Cache-Seiten (falls vorhanden) freigeben kann. Unter Linux wird dieser Vorgang in zwei Schritten ausgeführt. Wenn die Schreibwarteschlange auf dem Hostgerät nicht mit einer Reihe von Anforderungen gefüllt ist, verwirft der Kernel zunächst alle geänderten Cache-Seiten im angegebenen Bereich. Der Kernel versucht dann, alle Cache-Seiten aus dem angegebenen Bereich freizugeben. Bei geänderten Seiten in diesem Bereich wird die zweite Stufe nur dann erfolgreich abgeschlossen, wenn sie während der ersten Stufe auf dem Basisgerät aufgezeichnet wurden, dh die Aufzeichnungswarteschlange auf dem Gerät ist nicht voll. Da die Anwendung den Status der Warteschlange auf dem Gerät nicht überprüfen kann, können Sie sicherstellen, dass die Cache-Seiten freigegeben werden, indem Sie fsync () oder fdatasync () auf dem fd-Handle aufrufen, bevor Sie POSIX_FADV_DONTNEED anwenden.
POSIX_FADV_NOREUSE - Der Prozess beinhaltet einen einmaligen Zugriff auf Daten im angegebenen Bereich der Datei, ohne diese wiederzuverwenden. Somit wird der Kernel benachrichtigt, dass er Seiten nach einem einzigen Zugriff auf sie freigeben kann. Unter Linux wird dieser Vorgang derzeit ignoriert.
Die Spezifikation posix_fadvise () wurde nur in SUSv3 angezeigt, und diese Schnittstelle wird nicht von allen UNIX-Implementierungen unterstützt. Unter Linux wurde der Aufruf posix_fadvise () seit Kernel Version 2.6 bereitgestellt.
13.6. Puffer-Cache-Bypass: Direkte E / A.
Ab Kernel Version 2.4 ermöglicht Linux einer Anwendung, den Puffercache bei der Ausführung von Festplatten-E / A zu umgehen, indem Daten direkt aus dem Benutzerspeicher in eine Datei oder auf ein Festplattengerät verschoben werden. Manchmal wird dieser Modus als direkte oder unverarbeitete E / A bezeichnet.
Die hier bereitgestellten Informationen gelten nur für Linux und sind in SUSv3 nicht standardisiert. Einige direkte E / A-Zugriffsoptionen für Geräte oder Dateien werden jedoch von den meisten UNIX-Implementierungen bereitgestellt.
Manchmal wird direkte E / A missverstanden, um eine hohe E / A-Leistung zu erzielen. Bei den meisten Anwendungen kann die Verwendung von direkten E / A die Leistung erheblich verringern. Tatsache ist, dass der Kernel mehrere Optimierungen durchführt, um die E / A-Leistung durch die Verwendung eines Puffercaches zu verbessern, einschließlich des sequentiellen proaktiven Lesens von Daten, der Durchführung von E / A in Clustern von Plattenblöcken und der Ermöglichung des Zugriffs von Prozessen auf dasselbe Volume Teilen Sie in derselben Datei Puffer im Cache. Alle diese Arten der Optimierung bei Verwendung von direkten E / A gehen verloren. Es ist nur für Anwendungen mit speziellen E / A-Anforderungen vorgesehen, z. B. Datenbankverwaltungssysteme, die ihr eigenes Caching und ihre eigene E / A-Optimierung durchführen und für die der Kernel keine CPU-Zeit und keinen Arbeitsspeicher verschwenden muss, um dieselben Aufgaben auszuführen.
Die direkte Eingabe / Ausgabe kann entweder in Bezug auf eine einzelne Datei oder in Bezug auf ein Blockgerät (z. B. eine Festplatte) erfolgen. Zu diesem Zweck wird beim Öffnen einer Datei oder eines Geräts mit dem Aufruf open () das Flag O_DIRECT angegeben.
Das O_DIRECT-Flag funktioniert seit Kernel-Version 2.4.10. Die Verwendung dieses Flags wird nicht von allen Dateisystemen und Versionen des Linux-Kernels unterstützt. Die meisten grundlegenden Dateisysteme unterstützen das O_DIRECT-Flag, viele Nicht-UNIX-Dateisysteme (wie VFAT) jedoch nicht. Sie können die Unterstützung für diese Funktion testen, indem Sie das ausgewählte Dateisystem testen (wenn das Dateisystem O_DIRECT nicht unterstützt, schlägt der Aufruf von open () mit einem EINVAL-Fehler fehl) oder indem Sie den Kernel-Quellcode darauf untersuchen.
Wenn ein Prozess die Datei mit dem O_DIRECT-Flag geöffnet hat und der andere auf die übliche Weise (dh unter Verwendung des Puffercaches), besteht keine Konsistenz zwischen dem Inhalt des Puffercaches und den Daten, die über direkte E / A gelesen oder geschrieben wurden. Eine solche Entwicklung sollte vermieden werden.
Informationen zur veralteten (jetzt nicht empfohlenen) Methode, um unformatierten Zugriff auf ein Festplattengerät zu erhalten, finden Sie auf der rohen (8) Handbuchseite.
Ausrichtungsbeschränkungen für direkte E / A.Da direkte E / A (sowohl auf Festplattengeräten als auch in Bezug auf Dateien) direkten Zugriff auf die Festplatte beinhalten, müssen bei der Ausführung von E / A einige Einschränkungen beachtet werden.
- Der tragbare Datenpuffer sollte an der Speichergrenze ausgerichtet sein, ein Vielfaches der Blockgröße.
- Der Offset in der Datei oder im Gerät, von dem aus die übertragenen Daten beginnen, muss ein Vielfaches der Blockgröße betragen.
- Die Länge der übertragenen Daten muss ein Vielfaches der Blockgröße betragen.
Die Nichteinhaltung einer dieser Einschränkungen führt zu einem EINVAL-Fehler. In der obigen Liste bezieht sich die Blockgröße auf die Größe des physischen Blocks des Geräts (normalerweise 512 Byte).
Bei der Ausführung direkter E / A unter Linux 2.4 gelten mehr Einschränkungen als unter Linux 2.6: Ausrichtung, Länge und Versatz müssen ein Vielfaches der Größe des logischen Blocks des verwendeten Dateisystems betragen. (Normalerweise beträgt die Größe der logischen Blöcke in einem Dateisystem 1024, 2048 oder 4096 Byte.)
Programmbeispiel13.1 O_DIRECT . , ( ) , , , , , , , read(). 4096 .
, :
$ ./direct_read /test/x 512 512 0 Read 512 bytes $ ./direct_read /test/x 256 ERROR [EINVAL Invalid argument] read 512 $ ./direct_read /test/x 512 1 ERROR [EINVAL Invalid argument] read 512 $ ./direct_read /test/x 4096 8192 512 Read 4096 bytes $ ./direct_read /test/x 4096 512 256 ERROR [EINVAL Invalid argument] read 512
13.1 , , , memalign(). memalign() 7.1.4.
#define _GNU_SOURCE /* O_DIRECT <fcntl.h> */ #include <fcntl.h> #include <malloc.h> #include "tlpi_hdr.h" int main(int argc, char *argv[]) { int fd; ssize_t numRead; size_t length, alignment; off_t offset; void *buf; if (argc < 3 || strcmp(argv[1], "–help") == 0) usageErr("%s file length [offset [alignment]]\n", argv[0]); length = getLong(argv[2], GN_ANY_BASE, "length"); offset = (argc > 3) ? getLong(argv[3], GN_ANY_BASE, "offset") : 0; alignment = (argc > 4) ? getLong(argv[4], GN_ANY_BASE, "alignment") : 4096; fd = open(argv[1], O_RDONLY | O_DIRECT); if (fd == -1) errExit("open"); /* memalign() , , . 'buf' , 'alignment', . , , , , 256 , , 512- . '(char *)' ( 'void *', memalign(). */ buf = (char *) memalign(alignment * 2, length + alignment) + alignment; if (buf == NULL) errExit("memalign"); if (lseek(fd, offset, SEEK_SET) == -1) errExit("lseek"); numRead = read(fd, buf, length); if (numRead == -1) errExit("read"); printf("Read %ld bytes\n", (long) numRead); exit(EXIT_SUCCESS); } _______________________________________________________________filebuff/direct_read.c
»Weitere Informationen zum Buch finden Sie auf der Website des Herausgebers»
Inhalt»
Auszug20% Rabatt auf Gutschein für Linux - Linux