2016-07-30 4 views
4

Mon problème est de traiter les lectures de fichiers éparses et de comprendre où les extensions du fichier doivent effectuer une certaine logique autour de lui. Comme il n'y a pas d'appel API direct pour comprendre ces choses, j'ai décidé d'utiliser ioctl api pour cela. J'ai eu l'idée de la façon dont la commande cp traite des problèmes de copie de fichiers clairsemés en passant par leur code et a fini par voir cela.Comment utiliser ioctl avec FS_IOC_FIEMAP

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

Alors, j'ai essayé de faire la même chose dans mon exemple de programme en cours d'exécution dans l'espace utilisateur et les erreurs dues à « Invalid argument ». Je ne suis pas sûr de ce qui me manque ou si c'est même possible de l'espace utilisateur. Je cours sur Ubuntu 14.04 sur un système de fichiers ext4. Cela pourrait-il être un problème avec le pilote de périphérique supportant ces modes de requête en dessous?

#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; 
    } 

Répondre

3

Comme vous n'êtes pas correctement mise les fiemap_buf.f paramètres avant d'invoquer ioctl(), il est probable que le EINVAL provient du fiemap contenu non valable que du support d'identification de la demande FS_IOC_FIEMAP lui-même.

Par exemple, le ioctl_fiemap() (du noyau) évaluera la fiemap.fm_extent_count afin de déterminer si elle est supérieure à FIEMAP_MAX_EXTENTS et retour -EINVAL dans ce cas. Comme aucune réinitialisation de la mémoire ou aucun paramétrage n'est effectué sur fiemap, il s'agit probablement de la cause du problème.

Notez que du code coreutils vous avez fait référence, il effectue le paramétrage correct de fiemap avant d'appeler ioctl():

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

initialisation du fiemap travaillé! Merci beaucoup! – Aila

1

Remarque fiemap n'est pas recommandé que vous devez être sûr de passer FIEMAP_FLAG_SYNC qui a des effets secondaires. L'interface lseek(), SEEK_DATA et SEEK_HOLE est recommandée, mais notez que cela dépendra du système de fichiers et représentera les extensions non écrites (zéros alloués) comme des trous.

+0

Merci pour la suggestion. Nous avons essayé SEEK_DATA et SEEK_HOLE avec lseek, mais il semblerait qu'il soit supporté uniquement à partir d'une version plus haute du noyau Linux pour le système de fichiers xfs que celui sur lequel nous sommes. Donc, nous avons dû recourir à la façon ioctl. Je suis un peu nouveau à cette programmation de bas niveau, pourriez-vous conseiller sur ce qui pourrait être les effets secondaires avec le drapeau FIEMAP_FLAG_SYNC? – Aila

+0

La synchronisation peut avoir de grandes implications sur les performances et doit être évitée autant que possible – pixelbeat