guest侧virtio probe
https://www.jianshu.com/p/e4b29d16bae4
https://kernelgo.org/virtio-overview.html
https://blog.csdn.net/qq_15437629/article/details/82084470
virtio 虚拟化系列之一:从 virtio 论文开始
https://zhuanlan.zhihu.com/p/68154666
前端驱动通知后端:
内核流程mark一下,PCI设备驱动流程这个后面可以学习一下,先扫描PCI bus发现是virtio设备再扫描virtio-bus。
worker_thread --> process_one_work --> pciehp_power_thread --> pciehp_enable_slot -->
pciehp_configure_device --> pci_bus_add_devices --> pci_bus_add_device --> device_attach -->
__device_attach --> bus_for_each_drv --> __device_attach_driver --> driver_probe_device -->
pci_device_probe --> local_pci_probe --> virtio_pci_probe --> register_virtio_device -->
device_register --> device_add --> bus_probe_device --> device_initial_probe
--> __device_attach --> bus_for_each_drv --> __device_attach_driver -->
driver_probe_device --> virtio_dev_probe --> virtnet_probe (网卡设备驱动加载的入口)
static int virtnet_probe(struct virtio_device *vdev)
{
......
virtio_device_ready(vdev);
}
qemu侧 vhost_dev_init---- vsock也有
hw/block/vhost-user-blk.c:318: ret = vhost_dev_init(&s->dev, &s->vhost_user, VHOST_BACKEND_TYPE_USER, 0); hw/virtio/vhost-vsock.c:345: ret = vhost_dev_init(&vsock->vhost_dev, (void *)(uintptr_t)vhostfd, hw/virtio/vhost-vsock.c:348: error_setg_errno(errp, -ret, "vhost-vsock: vhost_dev_init failed"); hw/virtio/vhost-user-fs.c:384: ret = vhost_dev_init(&fs->vhost_dev, &fs->vhost_user, hw/virtio/vhost-user-fs.c:387: error_setg_errno(errp, -ret, "vhost_dev_init failed"); hw/virtio/vhost.c:1180:int vhost_dev_init(struct vhost_dev *hdev, void *opaque, hw/scsi/vhost-user-scsi.c:97: ret = vhost_dev_init(&vsc->dev, &s->vhost_user, hw/scsi/vhost-scsi.c:190: ret = vhost_dev_init(&vsc->dev, (void *)(uintptr_t)vhostfd, hw/net/vhost_net.c:174: r = vhost_dev_init(&net->dev, options->opaque, include/hw/virtio/vhost
kernel vhost + vhost user
vhost_dev_init-->vhost_virtqueue_init-->vhost_virtqueue_init-->vhost_set_vring_call hw/virtio/vhost-user.c:1935: .vhost_set_vring_call = vhost_user_set_vring_call, hw/virtio/vhost-backend.c:256: .vhost_set_vring_call = vhost_kernel_set_vring_call,
用
kernel vhost 还是 vhost user
273 int vhost_set_backend_type(struct vhost_dev *dev, VhostBackendType backend_type) 274 { 275 int r = 0; 276 277 switch (backend_type) { 278 #ifdef CONFIG_VHOST_KERNEL 279 case VHOST_BACKEND_TYPE_KERNEL: 280 dev->vhost_ops = &kernel_ops; 281 break; 282 #endif 283 #ifdef CONFIG_VHOST_USER 284 case VHOST_BACKEND_TYPE_USER: 285 dev->vhost_ops = &user_ops; 286 break; 287 #endif 288 default: 289 error_report("Unknown vhost backend type"); 290 r = -1; 291 } 292 293 return r; 294 }
![](https://img2020.cnblogs.com/blog/665372/202010/665372-20201024112042298-89478813.png)
vhost_user设置unix域套接字
vhost_user_backend_init() ---------........ ---------vhost_setup_slave_channel(dev) ------------------......... ------------------qemu_set_fd_handler(u->slave_fd, slave_read, NULL, dev) ------------------.......
Qemu IO事件处理框架
qemu添加fd
用户添加fd的函数为qemu_set_fd_handler,参数中fd为本次添加的fd,后面分别是对该fd的处理函数(read or write),最后opaque为处理函数的参数。
https://www.cnblogs.com/ck1020/p/8782032.html
vhost_user设置unix域套接字服务端
比如contrib/virtiofsd/fuse_virtio.c:722:int virtio_session_mount(struct fuse_session *se) 创建服务端
721 722 int virtio_session_mount(struct fuse_session *se) 723 { 724 struct sockaddr_un un; 725 726 if (strlen(se->vu_socket_path) >= sizeof(un.sun_path)) { 727 fprintf(stderr, "Socket path too long "); 728 return -1; 729 } 730 731 /* Poison the fuse FD so we spot if we accidentally use it; 732 * DO NOT check for this value, check for se->vu_socket_path 733 */ 734 se->fd = 0xdaff0d11; 735 736 /* Create the Unix socket to communicate with qemu 737 * based on QEMU's vhost-user-bridge 738 */ 739 unlink(se->vu_socket_path); 740 strcpy(un.sun_path, se->vu_socket_path); 741 size_t addr_len = sizeof(un.sun_family) + strlen(se->vu_socket_path); 742 743 int listen_sock = socket(AF_UNIX, SOCK_STREAM, 0); 744 if (listen_sock == -1) { 745 perror("vhost socket creation"); 746 return -1; 747 } 748 un.sun_family = AF_UNIX; 749 750 if (bind(listen_sock, (struct sockaddr *) &un, addr_len) == -1) { 751 perror("vhost socket bind"); 752 return -1; 753 } 754 755 if (listen(listen_sock, 1) == -1) { 756 perror("vhost socket listen"); 757 return -1; 758 } 759 760 fprintf(stderr, "%s: Waiting for vhost-user socket connection... ", __func__); 761 int data_sock = accept(listen_sock, NULL, NULL); 762 if (data_sock == -1) { 763 perror("vhost socket accept"); 764 close(listen_sock); 765 return -1; 766 } 767 close(listen_sock); 768 fprintf(stderr, "%s: Received vhost-user socket connection ", __func__); 769 se->vu_socketfd = data_sock; 770 771 /* TODO: Some cleanup/deallocation! */ 772 se->virtio_dev = calloc(sizeof(struct fv_VuDev), 1); 773 se->virtio_dev->se = se; 774 vu_init(&se->virtio_dev->dev, se->vu_socketfd, 775 fv_panic, 776 fv_set_watch, fv_remove_watch, 777 &fv_iface); 778 779 return 0; 780 }
gueset kernel 会调用_class_init
前端驱动通知后端:
内核流程mark一下,PCI设备驱动流程这个后面可以学习一下,先扫描PCI bus发现是virtio设备再扫描virtio-bus。
worker_thread --> process_one_work --> pciehp_power_thread --> pciehp_enable_slot -->
pciehp_configure_device --> pci_bus_add_devices --> pci_bus_add_device --> device_attach -->
__device_attach --> bus_for_each_drv --> __device_attach_driver --> driver_probe_device -->
pci_device_probe --> local_pci_probe --> virtio_pci_probe --> register_virtio_device -->
device_register --> device_add --> bus_probe_device --> device_initial_probe
--> __device_attach --> bus_for_each_drv --> __device_attach_driver -->
driver_probe_device --> virtio_dev_probe --> virtnet_probe (网卡设备驱动加载的入口)
static int virtnet_probe(struct virtio_device *vdev) { ...... virtio_device_ready(vdev); } /** * virtio_device_ready - enable vq use in probe function * @vdev: the device * * Driver must call this to use vqs in the probe function. * * Note: vqs are enabled automatically after probe returns. */ static inline void virtio_device_ready(struct virtio_device *dev) { unsigned status = dev->config->get_status(dev); BUG_ON(status & VIRTIO_CONFIG_S_DRIVER_OK); dev->config->set_status(dev, status | VIRTIO_CONFIG_S_DRIVER_OK); }