2016-07-30 35 views
4

Mein Problem ist es, mit Lesevorgänge sparse Datei umzugehen und zu verstehen, wo die Extents der Datei einige Logik um es ausführen sollen.So verwenden Sie ioctl mit FS_IOC_FIEemap

Da es keinen direkten API-Aufruf gibt, um diese Dinge herauszufinden, entschied ich mich dafür, ioctl api zu verwenden. Ich kam auf die Idee, wie der cp-Befehl mit Problemen beim Kopieren über Sparse-Dateien umgeht, indem er ihren Code durchgeht und dies schließlich sah.

https://github.com/coreutils/coreutils/blob/df88fce71651afb2c3456967a142db0ae4bf9906/src/extent-scan.c#L112

Also habe ich versucht, die gleiche Sache in meinem Beispielprogramm zu tun, im User-Space laufen und es Fehler heraus mit „Invalid argument“. Ich bin mir nicht sicher, was ich vermisse oder ob das überhaupt aus dem Userspace möglich ist. Ich laufe auf Ubuntu 14.04 auf einem ext4 Dateisystem. Könnte dies ein Problem mit dem Gerätetreiber sein, der diese Anforderungsmodi darunter unterstützt?

#include <stdio.h> 
    #include <string.h> 
    #include <stdlib.h> 
    #include <sys/fcntl.h> 
    #include <errno.h> 
    #include <sys/types.h> 
    #include <sys/stat.h> 
    #include <unistd.h> 
    #include <sys/ioctl.h> 
    #include <linux/fs.h> 
    #include "fiemap.h" //This is from https://github.com/coreutils/coreutils/blob/df88fce71651afb2c3456967a142db0ae4bf9906/src/fiemap.h 

    int main(int argc, char* argv[]) { 

     int input_fd; 

     if(argc != 2){ 
      printf ("Usage: ioctl file1"); 
      return 1; 
     } 

     /* Create input file descriptor */ 
     input_fd = open (argv [1], O_RDWR); 
     if (input_fd < 0) { 
       perror ("open"); 
       return 2; 
     } 

     union { struct fiemap f; char c[4096]; } fiemap_buf; 
     struct fiemap *fiemap = &fiemap_buf.f; 
     int s = ioctl(input_fd, FS_IOC_FIEMAP, fiemap); 

     if (s == 0) { 
      printf("ioctl success\n"); 
     } else { 
      printf("ioctl failure\n"); 
      char * errmsg = strerror(errno); 
      printf("error: %d %s\n", errno, errmsg); 
     } 

     /* Close file descriptors */ 
     close (input_fd); 

     return s; 
    } 

Antwort

3

Wie Sie die fiemap_buf.f Parameter nicht korrekt sind, bevor Einstellung ioctl() Aufruf, ist es wahrscheinlich, dass die EINVAL aus den fiemap ungültigen Inhalten als von der selbst Unterstützung FS_IOC_FIEMAP Anforderungskennung kommen.

Zum Beispiel kann die ioctl_fiemap() (von kernel) die fiemap.fm_extent_count auswerten, um zu bestimmen, ob sie größer als FIEMAP_MAX_EXTENTS sind und das Rück -EINVAL in diesem Fall. Da unter fiemap kein Urlöschen oder Parametrieren durchgeführt wird, ist dies wahrscheinlich die Ursache des Problems.

Beachten Sie, dass aus dem coreutils Code, den Sie Bezug genommen wird, führt er die korrekte Parametrierung von fiemap vor ioctl() Aufruf:

fiemap->fm_start = scan->scan_start; 
    fiemap->fm_flags = scan->fm_flags; 
    fiemap->fm_extent_count = count; 
    fiemap->fm_length = FIEMAP_MAX_OFFSET - scan->scan_start; 
+1

Initialisierung der Fiemap funktioniert! Vielen Dank! – Aila

1

Hinweis fiemap wird nicht empfohlen, da Sie sicher sein müssen FIEMAP_FLAG_SYNC passieren, welche Nebenwirkungen hat. Die Schnittstelle lseek(), SEEK_DATA und SEEK_HOLE ist die empfohlene Schnittstelle, beachten Sie jedoch, dass je nach Dateisystem ungeschriebene Extents (zugeordnete Nullen) als Lücken dargestellt werden.

+0

Danke für den Vorschlag. Wir haben SEEK_DATA und SEEK_HOLE mit lseek versucht, aber es sieht so aus, als ob es nur von einer höheren Linux-Kernel-Version für das xfs-Dateisystem unterstützt wird als die, auf der wir uns befinden. Also mussten wir auf den ioctl-Weg zurückgreifen. Ich bin irgendwie neu in dieser Low-Level-Programmierung, könnten Sie Ratschläge zu den möglichen Nebenwirkungen des FIEMAP_FLAG_SYNC-Flags geben? – Aila

+0

Synchronisierung kann große Auswirkungen auf die Leistung haben und sollte möglichst vermieden werden – pixelbeat