New upstream version 17.11.4
[deb_dpdk.git] / lib / librte_vhost / vhost_user.c
index 50e654d..0eb5e0d 100644 (file)
@@ -476,7 +476,7 @@ vhost_user_set_vring_addr(struct virtio_net **pdev, VhostUserMsg *msg)
 
        if (vq->enabled && (dev->features &
                                (1ULL << VHOST_USER_F_PROTOCOL_FEATURES))) {
-               dev = translate_ring_addresses(dev, msg->payload.state.index);
+               dev = translate_ring_addresses(dev, msg->payload.addr.index);
                if (!dev)
                        return -1;
 
@@ -501,7 +501,7 @@ vhost_user_set_vring_base(struct virtio_net *dev,
        return 0;
 }
 
-static void
+static int
 add_one_guest_page(struct virtio_net *dev, uint64_t guest_phys_addr,
                   uint64_t host_phys_addr, uint64_t size)
 {
@@ -511,6 +511,10 @@ add_one_guest_page(struct virtio_net *dev, uint64_t guest_phys_addr,
                dev->max_guest_pages *= 2;
                dev->guest_pages = realloc(dev->guest_pages,
                                        dev->max_guest_pages * sizeof(*page));
+               if (!dev->guest_pages) {
+                       RTE_LOG(ERR, VHOST_CONFIG, "cannot realloc guest_pages\n");
+                       return -1;
+               }
        }
 
        if (dev->nr_guest_pages > 0) {
@@ -519,7 +523,7 @@ add_one_guest_page(struct virtio_net *dev, uint64_t guest_phys_addr,
                if (host_phys_addr == last_page->host_phys_addr +
                                      last_page->size) {
                        last_page->size += size;
-                       return;
+                       return 0;
                }
        }
 
@@ -527,9 +531,11 @@ add_one_guest_page(struct virtio_net *dev, uint64_t guest_phys_addr,
        page->guest_phys_addr = guest_phys_addr;
        page->host_phys_addr  = host_phys_addr;
        page->size = size;
+
+       return 0;
 }
 
-static void
+static int
 add_guest_pages(struct virtio_net *dev, struct rte_vhost_mem_region *reg,
                uint64_t page_size)
 {
@@ -543,7 +549,9 @@ add_guest_pages(struct virtio_net *dev, struct rte_vhost_mem_region *reg,
        size = page_size - (guest_phys_addr & (page_size - 1));
        size = RTE_MIN(size, reg_size);
 
-       add_one_guest_page(dev, guest_phys_addr, host_phys_addr, size);
+       if (add_one_guest_page(dev, guest_phys_addr, host_phys_addr, size) < 0)
+               return -1;
+
        host_user_addr  += size;
        guest_phys_addr += size;
        reg_size -= size;
@@ -552,12 +560,16 @@ add_guest_pages(struct virtio_net *dev, struct rte_vhost_mem_region *reg,
                size = RTE_MIN(reg_size, page_size);
                host_phys_addr = rte_mem_virt2iova((void *)(uintptr_t)
                                                  host_user_addr);
-               add_one_guest_page(dev, guest_phys_addr, host_phys_addr, size);
+               if (add_one_guest_page(dev, guest_phys_addr, host_phys_addr,
+                               size) < 0)
+                       return -1;
 
                host_user_addr  += size;
                guest_phys_addr += size;
                reg_size -= size;
        }
+
+       return 0;
 }
 
 #ifdef RTE_LIBRTE_VHOST_DEBUG
@@ -611,8 +623,9 @@ vhost_memory_changed(struct VhostUserMemory *new,
 }
 
 static int
-vhost_user_set_mem_table(struct virtio_net *dev, struct VhostUserMsg *pmsg)
+vhost_user_set_mem_table(struct virtio_net **pdev, struct VhostUserMsg *pmsg)
 {
+       struct virtio_net *dev = *pdev;
        struct VhostUserMemory memory = pmsg->payload.memory;
        struct rte_vhost_mem_region *reg;
        void *mmap_addr;
@@ -638,6 +651,11 @@ vhost_user_set_mem_table(struct virtio_net *dev, struct VhostUserMsg *pmsg)
                dev->mem = NULL;
        }
 
+       /* Flush IOTLB cache as previous HVAs are now invalid */
+       if (dev->features & (1ULL << VIRTIO_F_IOMMU_PLATFORM))
+               for (i = 0; i < dev->nr_vring; i++)
+                       vhost_user_iotlb_flush_all(dev->virtqueue[i]);
+
        dev->nr_guest_pages = 0;
        if (!dev->guest_pages) {
                dev->max_guest_pages = 8;
@@ -705,7 +723,12 @@ vhost_user_set_mem_table(struct virtio_net *dev, struct VhostUserMsg *pmsg)
                                      mmap_offset;
 
                if (dev->dequeue_zero_copy)
-                       add_guest_pages(dev, reg, alignment);
+                       if (add_guest_pages(dev, reg, alignment) < 0) {
+                               RTE_LOG(ERR, VHOST_CONFIG,
+                                       "adding guest pages to region %u failed.\n",
+                                       i);
+                               goto err_mmap;
+                       }
 
                RTE_LOG(INFO, VHOST_CONFIG,
                        "guest memory region %u, size: 0x%" PRIx64 "\n"
@@ -726,6 +749,25 @@ vhost_user_set_mem_table(struct virtio_net *dev, struct VhostUserMsg *pmsg)
                        mmap_offset);
        }
 
+       for (i = 0; i < dev->nr_vring; i++) {
+               struct vhost_virtqueue *vq = dev->virtqueue[i];
+
+               if (vq->desc || vq->avail || vq->used) {
+                       /*
+                        * If the memory table got updated, the ring addresses
+                        * need to be translated again as virtual addresses have
+                        * changed.
+                        */
+                       vring_invalidate(dev, vq);
+
+                       dev = translate_ring_addresses(dev, i);
+                       if (!dev)
+                               return -1;
+
+                       *pdev = dev;
+               }
+       }
+
        dump_guest_pages(dev);
 
        return 0;
@@ -857,8 +899,8 @@ vhost_user_get_vring_base(struct virtio_net *dev,
 
        dev->flags &= ~VIRTIO_DEV_READY;
 
-       /* Here we are safe to get the last used index */
-       msg->payload.state.num = vq->last_used_idx;
+       /* Here we are safe to get the last avail index */
+       msg->payload.state.num = vq->last_avail_idx;
 
        RTE_LOG(INFO, VHOST_CONFIG,
                "vring base idx:%d file:%d\n", msg->payload.state.index,
@@ -873,6 +915,11 @@ vhost_user_get_vring_base(struct virtio_net *dev,
 
        vq->kickfd = VIRTIO_UNINITIALIZED_EVENTFD;
 
+       if (vq->callfd >= 0)
+               close(vq->callfd);
+
+       vq->callfd = VIRTIO_UNINITIALIZED_EVENTFD;
+
        if (dev->dequeue_zero_copy)
                free_zmbufs(vq);
        rte_free(vq->shadow_used_ring);
@@ -967,7 +1014,7 @@ vhost_user_set_log_base(struct virtio_net *dev, struct VhostUserMsg *msg)
         * mmap from 0 to workaround a hugepage mmap bug: mmap will
         * fail when offset is not page size aligned.
         */
-       addr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+       addr = mmap(0, size + off, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
        close(fd);
        if (addr == MAP_FAILED) {
                RTE_LOG(ERR, VHOST_CONFIG, "mmap log base failed!\n");
@@ -1382,7 +1429,7 @@ vhost_user_msg_handler(int vid, int fd)
                break;
 
        case VHOST_USER_SET_MEM_TABLE:
-               ret = vhost_user_set_mem_table(dev, &msg);
+               ret = vhost_user_set_mem_table(&dev, &msg);
                break;
 
        case VHOST_USER_SET_LOG_BASE: