Итак, я работаю с qemu kvm некоторое время, и теперь мне нужно переходить через PCI-устройства. Я сделал все необходимые процедуры для выполнения этой работы: включил iommu, modprobed vfio module, связал устройство с vfio и проверил, что группа vfio действительно создана и т. Д. Но когда я запускаю qemu с любыми устройствами pci, я получаю сообщение об ошибке:Невозможно использовать pread в файловом дескрипторе для устройства vfio pci
vfio: Не удалось прочитать устройство конфигурации пространства
копаюсь в код из QEMU, чтобы увидеть, что может быть проблемой, и выяснил, что проблема возникает на pread к устройству. Это происходит даже тогда, когда смещение равно 0, и нормальное чтение в файловом дескрипторе работает без проблем, поскольку я изменил код для его проверки. Проверка errno по причине отказа pread дает мне сообщение об ошибке «Illegal seek».
Я написал код, чтобы узнать, произошло ли это за пределами контекста qemu (подумал, что это может быть что-то в коде qemu, который мешал устройству) и имел ту же проблему. Я также попытался прочитать обычный файл с pread и прекрасно работает ... Вот код, который я написал, чтобы проверить это, я сломал его немного вниз, чтобы быть в состоянии указать на более соответствующие части:
#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);
Это чтение прекрасно работает, дает мне в отставке код-байт
ret = read(fd,buf,nbytes);
if(ret<1){
printf("ERROR: %m \n");
}
Это pread терпит неудачу с кодом -1 в отставке и ERRNO 'Illegal искать'
ret = pread(fd,buf,nbytes,0);
if(ret<0){
printf("ERROR: %m \n");
}
Здесь я стараюсь читать и pread на общий файл в sysfs, чтобы увидеть, если pread выходит из строя, и на чтение и pread прекрасно работает в этом случае:
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;
}
Я использую стандартное ядро Линукса v4.7.8, скомпилированный с uClibc для встроенной системы ... У кого-нибудь есть идеи, почему это может произойти? Я сейчас не знаю! T.T
UPDATE: Я установил ubuntu 16.04 (ядро v4.4.0) на том же компьютере и повторил шаги, и pci passthrough отлично работает, и pread на моем тестовом коде также отлично работает. Поэтому я не уверен, что происходит с обычным ядром.
Согласно предложению arash, я попробовал pread (fd, buf, nbytes, SEEK_CUR), и он дал мне ту же ошибку «незаконного поиска». Смещение, которое я получаю от ftell, составляет 0xffffffff как в ubuntu, так и в общем ядре.
[pread] (https://github.com/lattera/glibc/blob/master/sysdeps/posix/pread.c) включает в себя (1) поиск к началу файла, чтобы получить текущее смещение (и сохранить его как old_offset), (2) искать смещение запроса, (3) прочитать, (4), наконец, вернуться к исходному смещению (old_offset).Видимо, вы видите, что хотя бы один из этих иска незаконен. Интересно, работает ли это 'pread (fd, buf, nbytes, SEEK_CUR)' или какое значение текущего смещения от 'long int ftell (поток FILE *)' – Arash
Пожалуйста, отправьте также свою командную строку QEMU (особенно ту часть, где вы config vfio) – Codeguard
Это команда qemu, которую я использую: qemu-system-x86_64 -enable-kvm -m 1024 -device vfio-pci, host = 01: 00.0 -drive file =/disk0/vdisk.qcow2, id = диск, формат = qcow2. Это отлично работает в ubuntu – igalvez