/* Open vhost I/O on given TAP file descriptor and specified memory range. The caller is responsible for passing a valid tap file descriptor and memory structure but not for initializing the vio struct. Return 0 on success. See this link for a discussion of the Linux/KVM vhost_net feature: http://blog.vmsplice.net/2011/09/qemu-internals-vhost-architecture.html */ int vhost_open(struct vio *vio, int tapfd, struct vio_memory *memory) { vio->tapfd = tapfd; if ((vio->vhostfd = open("/dev/vhost-net", O_RDWR)) < 0 || (ioctl(vio->vhostfd, VHOST_SET_OWNER, NULL)) < 0 || (ioctl(vio->vhostfd, VHOST_GET_FEATURES, &vio->features)) < 0 || vhost_set_memory(vio, memory) || setup_vring(vio, 0) < 0 || setup_vring(vio, 1) < 0) { /* Error */ if (vio->vhostfd >= 0) { close(vio->vhostfd); vio->vhostfd = -1; } return -1; } return 0; }
static void vhost_region_add(MemoryListener *listener, MemoryRegionSection *section) { struct vhost_dev *dev = container_of(listener, struct vhost_dev, memory_listener); if (!vhost_section(section)) { return; } ++dev->n_mem_sections; dev->mem_sections = g_renew(MemoryRegionSection, dev->mem_sections, dev->n_mem_sections); dev->mem_sections[dev->n_mem_sections - 1] = *section; vhost_set_memory(listener, section, true); }
static void vhost_region_del(MemoryListener *listener, MemoryRegionSection *section) { struct vhost_dev *dev = container_of(listener, struct vhost_dev, memory_listener); int i; if (!vhost_section(section)) { return; } vhost_set_memory(listener, section, false); for (i = 0; i < dev->n_mem_sections; ++i) { if (dev->mem_sections[i].offset_within_address_space == section->offset_within_address_space) { --dev->n_mem_sections; memmove(&dev->mem_sections[i], &dev->mem_sections[i+1], (dev->n_mem_sections - i) * sizeof(*dev->mem_sections)); break; } } }
/* Caller must have device mutex */ long vhost_dev_ioctl(struct vhost_dev *d, unsigned int ioctl, unsigned long arg) { void __user *argp = (void __user *)arg; struct file *eventfp, *filep = NULL; struct eventfd_ctx *ctx = NULL; u64 p; long r; int i, fd; /* If you are not the owner, you can become one */ if (ioctl == VHOST_SET_OWNER) { r = vhost_dev_set_owner(d); goto done; } /* You must be the owner to do anything else */ r = vhost_dev_check_owner(d); if (r) goto done; switch (ioctl) { case VHOST_SET_MEM_TABLE: r = vhost_set_memory(d, argp); break; case VHOST_SET_LOG_BASE: r = copy_from_user(&p, argp, sizeof p); if (r < 0) break; if ((u64)(unsigned long)p != p) { r = -EFAULT; break; } for (i = 0; i < d->nvqs; ++i) { struct vhost_virtqueue *vq; void __user *base = (void __user *)(unsigned long)p; vq = d->vqs + i; mutex_lock(&vq->mutex); /* If ring is inactive, will check when it's enabled. */ if (vq->private_data && !vq_log_access_ok(vq, base)) r = -EFAULT; else vq->log_base = base; mutex_unlock(&vq->mutex); } break; case VHOST_SET_LOG_FD: r = get_user(fd, (int __user *)argp); if (r < 0) break; eventfp = fd == -1 ? NULL : eventfd_fget(fd); if (IS_ERR(eventfp)) { r = PTR_ERR(eventfp); break; } if (eventfp != d->log_file) { filep = d->log_file; ctx = d->log_ctx; d->log_ctx = eventfp ? eventfd_ctx_fileget(eventfp) : NULL; } else filep = eventfp; for (i = 0; i < d->nvqs; ++i) { mutex_lock(&d->vqs[i].mutex); d->vqs[i].log_ctx = d->log_ctx; mutex_unlock(&d->vqs[i].mutex); } if (ctx) eventfd_ctx_put(ctx); if (filep) fput(filep); break; default: r = vhost_set_vring(d, ioctl, argp); break; } done: return r; }