`splice()` ist ein Linux -spezifischer Systemaufruf , der Daten zwischen einem Dateideskriptor und einer Pipe verschiebt, ohne dass ein Roundtrip in den Benutzermodus erforderlich ist. Der verwandte Systemaufruf ` vmsplice()` verschiebt oder kopiert Daten zwischen einer Pipe und dem Benutzermodus. Idealerweise arbeiten `splice` und `vmsplice` durch Seitenremapping und kopieren keine Daten, was die E/A- Leistung verbessern kann. Da lineare Adressen nicht unbedingt zusammenhängenden physischen Adressen entsprechen, ist dies möglicherweise nicht in allen Fällen und auf allen Hardwarekombinationen möglich.
Funktionsweise
Mit `splice()` lassen sich Daten von einem Dateideskriptor in einen anderen verschieben, ohne dass Kopien vom Benutzermodus in den Kernelmodus erforderlich sind. Dies ist üblicherweise notwendig, um die Systemsicherheit zu gewährleisten und eine einfache Schnittstelle für Prozesse zum Lesen und Schreiben von Dateien bereitzustellen. `splice()` verwendet dazu den Pipe-Puffer . Ein Pipe-Puffer ist ein im Kernel gespeicherter Speicherpuffer, der für den Benutzermodusprozess undurchsichtig ist. Ein Benutzerprozess kann den Inhalt einer Quelldatei in diesen Pipe-Puffer einfügen und diesen anschließend in die Zieldatei einfügen, ohne dabei Daten durch den Benutzermodus zu übertragen.
Ursprünge
Linus Torvalds beschrieb splice() in einer E-Mail aus dem Jahr 2006, die in einem KernelTrap- Artikel abgedruckt wurde. [ 1 ]
Die Linux- Splice-Implementierung entlehnt einige Ideen einem ursprünglichen Vorschlag von Larry McVoy aus dem Jahr 1998. [ 2 ] Die Splice-Systemaufrufe erschienen erstmals in der Linux- Kernel-Version 2.6.17 [ 1 ] und wurden von Jens Axboe geschrieben .
Prototyp
ssize_t splice ( int fd_in , loff_t * off_in , int fd_out , loff_t * off_out , size_t len , unsigned int flags );Einige interessante Konstanten sind:
// Splice-Flags (noch nicht endgültig festgelegt). #ifndef SPLICE_F_MOVE #define SPLICE_F_MOVE 0x01 #endif#ifndef SPLICE_F_NONBLOCK #define SPLICE_F_NONBLOCK 0x02 #endif#ifndef SPLICE_F_MORE #define SPLICE_F_MORE 0x04 #endif#ifndef SPLICE_F_GIFT #define SPLICE_F_GIFT 0x08 #endifBeispiel
Dies ist ein Beispiel für einen Splice in Aktion:
// Übertragung von der Festplatte in ein Log. int log_blocks ( struct log_handle * handle , int fd , loff_t offset , size_t size ) { int file_descriptions [ 2 ]; size_t to_write = size ; int ret = pipe ( file_descriptions ); if ( ret < 0 ) { goto out ; } // Datei in die Pipe einfügen (Daten im Kernelspeicher). while ( to_write > 0 ) { ret = splice ( fd , & offset , file_descriptions [ 1 ], NULL , to_write , SPLICE_F_MORE | SPLICE_F_MOVE ); if ( ret < 0 ) { goto pipe ; } else { to_write -= ret ; } } to_write = size ; // Daten in der Pipe (im Kernelspeicher) in die Datei einfügen. while ( to_write > 0 ) { ret = splice ( file_descriptions [ 0 ], NULL , handle- > fd , & ( handle- > fd_offset ), to_write , SPLICE_F_MORE | SPLICE_F_MOVE ); if ( ret < 0 ) { goto pipe ; } else { to_write -= ret ; } }pipe : close ( file_descriptions [ 0 ]); close ( file_descriptions [ 1 ]); out : return ret < 0 ? - errno : 0 ; }Komplementäre Systemaufrufe
`splice()` ist einer von drei Systemaufrufen, die die `splice() `-Architektur vervollständigen. `vmsplice()` kann einen Anwendungsdatenbereich in eine Pipe abbilden (oder umgekehrt) und ermöglicht so Datentransfers zwischen Pipes und Benutzerspeicher, während `sys_splice()` Datentransfers zwischen einem Dateideskriptor und einer Pipe ermöglicht. `tee()` ist der letzte Teil dieser Trilogie. Er dupliziert eine Pipe in eine andere und ermöglicht so die Verzweigung der Verbindungswege zwischen Anwendungen über Pipes.
Anforderungen
Bei der Verwendung von `splice()` mit Sockets muss der Netzwerkcontroller (NIC) DMA unterstützen, da `splice()` sonst keine wesentliche Leistungssteigerung erzielt. Der Grund dafür ist, dass jede Seite der Pipe nur bis zur Framegröße belegt wird (1460 Bytes der verfügbaren 4096 Bytes pro Seite).
Nicht alle Dateisystemtypen unterstützen splice() .
Siehe auch
Referenzen
- ^ a b „Linux: Explaining splice() and tee()“ . kerneltrap.org. 21.04.2006. Archiviert vom Original am 21.05.2013 . Abgerufen am 27.04.2014 .
- ^ „Archivierte Kopie“ . Archiviert vom Original am 04.03.2016 . Abgerufen am 28.02.2016 .
{{cite web}}: CS1 Wartung: Archivierte Kopie als Titel ( Link )
Externe Links
- Linux-Kernel 2.6.17 (kernelnewbies.org)
- Zwei neue Systemaufrufe: splice() und sync_file_range() ( LWN.net )
- Einige neue Systemaufrufe (LWN.net)