2017-02-15 2 views
7

Donc je travaille avec qemu kvm depuis un moment et maintenant je dois passer les périphériques PCI. J'ai fait toutes les procédures requises pour faire ce travail: activé iommu, modfobed module vfio, périphérique lié à vfio et vérifié que le groupe vfio a bien été créé, etc ... Mais quand je démarre qemu avec des périphériques pci, je reçois le message d'erreur:Je ne peux pas utiliser pread sur un descripteur de fichier pour un périphérique vfio pci

vfio: Impossible de lire l'espace périphérique de configuration

Je creuser dans le code de qemu pour voir ce que la question pourrait être et a découvert que le problème se produit sur un pread à l'appareil. Cela se produit même lorsque le décalage est 0, et faire une lecture normale sur le descripteur de fichier fonctionne sans problème, car j'ai changé le code pour le tester. Vérification d'errno pour la raison de l'échec pread me donne un message d'erreur 'Illégal chercher'.

J'ai écrit du code pour voir si cela se passait en dehors du contexte qemu (je pensais que c'était quelque chose dans le code de qemu qui interférait avec le périphérique), et j'avais le même problème. J'ai aussi essayé de lire un fichier normal avec pread et qui fonctionne parfaitement ... Voici le code que j'ai écrit pour le tester, je l'ai cassé vers le bas pour être en mesure de signaler les parties les plus pertinentes:

#define BUF_SIZE 4096 

int main(){  
    char buf[BUF_SIZE], buf1[BUF_SIZE], buf2[BUF_SIZE];   
    int ret,group_fd, fd, fd2; 
    size_t nbytes = 4096; 
    ssize_t bytes_read;  
    int iommu1, iommu2; 

    int container, group, device, i; 
    struct vfio_group_status group_status = { .argsz = sizeof(group_status) }; 
    struct vfio_iommu_type1_info iommu_info = { .argsz = sizeof(iommu_info) }; 
    struct vfio_iommu_type1_dma_map dma_map = { .argsz = sizeof(dma_map) }; 
    struct vfio_device_info device_info = { .argsz = sizeof(device_info) };  
    container = open("/dev/vfio/vfio",O_RDWR);   

    if(ioctl(container,VFIO_GET_API_VERSION)!=VFIO_API_VERSION){ 
     printf("Unknown api version: %m\n");  
    } 
    group_fd = open("/dev/vfio/22",O_RDWR);  printf("Group fd = %d\n", group_fd); 
    ioctl(group_fd, VFIO_GROUP_GET_STATUS, &group_status); 
    if (!(group_status.flags & VFIO_GROUP_FLAGS_VIABLE)){ 
     printf("Group not viable\n"); 
     return 1; 
    } 
    ret = ioctl(group_fd, VFIO_GROUP_SET_CONTAINER,&container);  
    ret = ioctl(container,VFIO_SET_IOMMU,VFIO_TYPE1_IOMMU);   
    ioctl(container, VFIO_IOMMU_GET_INFO, &iommu_info);   

    /* Allocate some space and setup a DMA mapping */    
    dma_map.vaddr = (unsigned long int) mmap(0, 1024 * 1024, PROT_READ | PROT_WRITE,MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); 
    dma_map.size = 1024 * 1024; 
    dma_map.iova = 0; /* 1MB starting at 0x0 from device view */ 
    dma_map.flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE; 

    ioctl(container, VFIO_IOMMU_MAP_DMA, &dma_map);   
    printf("\n\nGETTING DEVICE FD\n");  
    fd = ioctl(group_fd,VFIO_GROUP_GET_DEVICE_FD,"0000:08:00.0"); 


    printf("Fd = %d\n",fd);  
    printf("VFIO_GROUP_GET_DEV_ID = %lu\n",VFIO_GROUP_GET_DEVICE_FD); 

Cette lecture fonctionne très bien, me donne un code ret de nbytes

ret = read(fd,buf,nbytes); 
    if(ret<1){  
     printf("ERROR: %m \n"); 
    } 

Ce pread échoue avec le code ret -1 et errno 'illégaux cherchent'

ret = pread(fd,buf,nbytes,0); 

    if(ret<0){  
     printf("ERROR: %m \n"); 
    } 

Ici j'essaie de lire et pread sur un fichier commun dans sysfs pour voir si pread échoue, et à la fois lire et travailler pread très bien dans ce cas:

printf("TESTING PREAD ON A COMMON FILE\n");  

    fd2 = open("/sys/bus/pci/devices/0000:08:00.0/device",O_RDONLY);  
    ret = read(fd2,buf1,nbytes);  
    if(ret<0){ 
     printf("ERROR: %m\n"); 
    } 
    printf("Result from read: ret = %d, content = %s\n",ret,buf1); 
    ret = pread(fd2,buf2,nbytes,2);  
    if(ret<0){ 
     printf("ERROR: %m\n"); # 
    } 
    printf("Result from pread: ret = %d, content = %s\n",ret,buf2);   
    close(fd2); 
    getchar(); 
    close(fd); 
    close(container); 
    close(group_fd);  
    return 0; 
} 

J'utilise un noyau Linux générique v4.7.8 compilé avec uClibc pour un système embarqué ... Quelqu'un a-t-il une idée de la raison pour laquelle cela pourrait se produire? Je suis désemparé en ce moment !! J'ai installé Ubuntu 16.04 (noyau v4.4.0) sur la même machine et répété les étapes et le Pci passthrough fonctionne très bien et le pread sur mon code de test fonctionne également parfaitement. Donc, je ne suis pas sûr de ce qui ne va pas avec le noyau générique personnalisé.

Selon la suggestion d'arash, j'ai essayé pread (fd, buf, nbytes, SEEK_CUR) et il m'a donné la même erreur de «recherche illégale». Le décalage que j'obtiens de ftell est 0xffffffff à la fois dans ubuntu et dans le noyau générique.

+0

[pread] (https://github.com/lattera/glibc/blob/master/sysdeps/posix/pread.c) comprend (1) cherchent au début du fichier pour obtenir le décalage actuel (et l'enregistrer comme old_offset), (2) une recherche sur le décalage de la requête, (3) read, (4) enfin revenir au décalage d'origine (old_offset).Apparemment, ce que vous voyez est qu'au moins une de ces demandes est illégale. Je me demande si cela fonctionne 'pread (fd, buf, nbytes, SEEK_CUR)' ou quelle est la valeur de décalage actuel de 'long int ftell (FILE * flux)' – Arash

+0

S'il vous plaît poster votre commandline QEMU ainsi (en particulier la partie où vous config vfio devices) – Codeguard

+0

Il s'agit de la commande qemu que j'utilise: qemu-system-x86_64 -enable-kvm -m 1024 -device vfio-pci, host = 01: 00.0 -drive fichier =/disk0/vdisk.qcow2, id = disque, format = qcow2. Cela fonctionne très bien dans Ubuntu – igalvez

Répondre

1

J'ai trouvé quel était le problème et j'ai eu l'intention de le poster ici pendant un moment pour tous ceux qui pourraient frapper ce mur. Il s'avère que les fonctions pread et pwrite de la version 0.9.33 d'uClibc sont cassées, ce qui fait que ces fonctions ne fonctionnent pas avec des décalages supérieurs à 4G. Les patchs à partir du lien ci-dessous fixe le problème pour moi: http://uclibc.10924.n7.nabble.com/backport-pread-pwrite-fix-for-0-9-33-branch-td11921.html