2017-02-15 8 views
7

Tak więc pracuję z qemu kvm przez jakiś czas i teraz potrzebuję przejść przez urządzenia PCI. Zrobiłem wszystkie wymagane procedury, aby to zadziałało: włączone iommu, modprobed vfio module, binded device do vfio i sprawdziłem, że grupa vfio rzeczywiście została stworzona, etc ... Ale kiedy zaczynam qemu z jakimikolwiek urządzeniami pci otrzymuję komunikat o błędzie:Nie można użyć pread na deskryptorze pliku dla urządzenia vfio pci

vfio: Nie można odczytać przestrzeni konfiguracyjnej urządzenia

wbijam do kodu QEMU, aby zobaczyć, co może być problem i okazało się, że problem występuje na pread do urządzenia. Dzieje się tak nawet wtedy, gdy przesunięcie wynosi 0, a normalne czytanie deskryptora pliku działa bezproblemowo, ponieważ zmieniłem kod, aby go przetestować. Sprawdzanie errno z powodu niepowodzenia wstępnego daje komunikat o błędzie "Nielegalny poszukiwanie".

Napisałem kod, aby sprawdzić, czy dzieje się to poza kontekstem qemu (uważam, że może to być coś w kodzie qemu, który zakłócał działanie urządzenia) i miał ten sam problem. Próbowałem również odczytać normalny plik z pread i to działa idealnie ... Oto kod, który napisałem, aby go przetestować, trochę go zepsułem, aby móc wskazać bardziej istotne części:

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

To odczytu działa dobrze, daje mi kodu ret z nbytes

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

To pread niepowodzeniem z kodem ret -1 errno 'Nielegalne szukać'

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

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

Tutaj próbuję czytać i pread na wspólnym pliku w sysfs, aby zobaczyć czy pread nie powiedzie się, a on czytać i pread działać dobrze w tym przypadku:

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

Używam rodzajowe jądra linux v4.7.8 skompilowany z uClibc dla systemu wbudowanego .... Ktoś ma jakieś pomysły, dlaczego tak się dzieje? Nie mam pojęcia teraz! T.T

UPDATE: Zainstalowałem ubuntu 16.04 (jądro v4.4.0) na tym samym komputerze i powtórzyłem kroki, a pci passthrough działa dobrze i pread na moim teście kodu działa również idealnie. Nie jestem więc pewien, co dzieje się z niestandardowym jądrem generycznym.

Zgodnie z sugestią arash, próbowałem pread (fd, buf, nbytes, SEEK_CUR) i dało mi to samo "nielegalne szukanie" błąd. Przesunięcie, które otrzymuję z ftell, to 0xffffffff zarówno w ubuntu, jak iw jądrze ogólnym.

+0

[pread] (https://github.com/lattera/glibc/blob/master/sysdeps/posix/pread.c) zawiera (1) wyszukiwanie na początku pliku, aby uzyskać bieżące przesunięcie (i zapisanie go jako old_offset), (2) przeszukiwanie do przesunięcia żądania, (3) odczytanie, (4) na końcu powrót do pierwotnego przesunięcia (old_offset).Najwyraźniej widać, że przynajmniej jeden z tych poszukiwań jest nielegalny. Zastanawiam się, czy to działa "pread (fd, buf, nbytes, SEEK_CUR)" lub jaka jest wartość bieżącego przesunięcia z 'long int ftell (strumień FILE *)' – Arash

+0

Proszę również zamieścić swoją linię poleceń QEMU (szczególnie część, w której config vfio devices) – Codeguard

+0

To jest polecenie qemu, którego używam: qemu-system-x86_64 -enable-kvm -m 1024 -device vfio-pci, host = 01: 00.0 -drive file =/disk0/vdisk.qcow2, id = disk, format = qcow2. Działa to dobrze w ubuntu – igalvez

Odpowiedz

Powiązane problemy