X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=lib%2Flibrte_vhost%2Fvhost.c;h=b83cf639eb8bace1a6bd7afb6e4efdf4a4196b1a;hb=96d1d898dcbc4319d8416b222aa6ba081e605823;hp=14b3e253e8377c6680cee480425d0a955fba2fde;hpb=b46a99c6006ab8edf098e4ac351d366336f6ac71;p=dpdk.git diff --git a/lib/librte_vhost/vhost.c b/lib/librte_vhost/vhost.c index 14b3e253e8..b83cf639eb 100644 --- a/lib/librte_vhost/vhost.c +++ b/lib/librte_vhost/vhost.c @@ -324,6 +324,24 @@ cleanup_device(struct virtio_net *dev, int destroy) } } +static void +vhost_free_async_mem(struct vhost_virtqueue *vq) +{ + if (vq->async_pkts_pending) + rte_free(vq->async_pkts_pending); + if (vq->async_pkts_info) + rte_free(vq->async_pkts_info); + if (vq->it_pool) + rte_free(vq->it_pool); + if (vq->vec_pool) + rte_free(vq->vec_pool); + + vq->async_pkts_pending = NULL; + vq->async_pkts_info = NULL; + vq->it_pool = NULL; + vq->vec_pool = NULL; +} + void free_vq(struct virtio_net *dev, struct vhost_virtqueue *vq) { @@ -331,10 +349,7 @@ free_vq(struct virtio_net *dev, struct vhost_virtqueue *vq) rte_free(vq->shadow_used_packed); else { rte_free(vq->shadow_used_split); - if (vq->async_pkts_pending) - rte_free(vq->async_pkts_pending); - if (vq->async_pending_info) - rte_free(vq->async_pending_info); + vhost_free_async_mem(vq); } rte_free(vq->batch_copy_elems); rte_mempool_free(vq->iotlb_pool); @@ -529,17 +544,21 @@ init_vring_queue(struct virtio_net *dev, uint32_t vring_idx) } vq = dev->virtqueue[vring_idx]; + if (!vq) { + VHOST_LOG_CONFIG(ERR, "Virtqueue not allocated (%d)\n", + vring_idx); + return; + } memset(vq, 0, sizeof(struct vhost_virtqueue)); vq->kickfd = VIRTIO_UNINITIALIZED_EVENTFD; vq->callfd = VIRTIO_UNINITIALIZED_EVENTFD; + vq->notif_enable = VIRTIO_UNINITIALIZED_NOTIF; vhost_user_iotlb_init(dev, vring_idx); /* Backends are set to -1 indicating an inactive device. */ vq->backend = -1; - - TAILQ_INIT(&vq->zmbuf_list); } static void @@ -556,6 +575,12 @@ reset_vring_queue(struct virtio_net *dev, uint32_t vring_idx) } vq = dev->virtqueue[vring_idx]; + if (!vq) { + VHOST_LOG_CONFIG(ERR, "Virtqueue not allocated (%d)\n", + vring_idx); + return; + } + callfd = vq->callfd; init_vring_queue(dev, vring_idx); vq->callfd = callfd; @@ -565,22 +590,29 @@ int alloc_vring_queue(struct virtio_net *dev, uint32_t vring_idx) { struct vhost_virtqueue *vq; + uint32_t i; - vq = rte_malloc(NULL, sizeof(struct vhost_virtqueue), 0); - if (vq == NULL) { - VHOST_LOG_CONFIG(ERR, - "Failed to allocate memory for vring:%u.\n", vring_idx); - return -1; - } + /* Also allocate holes, if any, up to requested vring index. */ + for (i = 0; i <= vring_idx; i++) { + if (dev->virtqueue[i]) + continue; - dev->virtqueue[vring_idx] = vq; - init_vring_queue(dev, vring_idx); - rte_spinlock_init(&vq->access_lock); - vq->avail_wrap_counter = 1; - vq->used_wrap_counter = 1; - vq->signalled_used_valid = false; + vq = rte_malloc(NULL, sizeof(struct vhost_virtqueue), 0); + if (vq == NULL) { + VHOST_LOG_CONFIG(ERR, + "Failed to allocate memory for vring:%u.\n", i); + return -1; + } - dev->nr_vring += 1; + dev->virtqueue[i] = vq; + init_vring_queue(dev, i); + rte_spinlock_init(&vq->access_lock); + vq->avail_wrap_counter = 1; + vq->used_wrap_counter = 1; + vq->signalled_used_valid = false; + } + + dev->nr_vring = RTE_MAX(dev->nr_vring, vring_idx + 1); return 0; } @@ -703,18 +735,6 @@ vhost_set_ifname(int vid, const char *if_name, unsigned int if_len) dev->ifname[sizeof(dev->ifname) - 1] = '\0'; } -void -vhost_enable_dequeue_zero_copy(int vid) -{ - struct virtio_net *dev = get_device(vid); - - if (dev == NULL) - return; - - dev->dequeue_zero_copy = 1; - VHOST_LOG_CONFIG(INFO, "dequeue zero copy is enabled\n"); -} - void vhost_set_builtin_virtio_net(int vid, bool enable) { @@ -1251,7 +1271,12 @@ rte_vhost_avail_entries(int vid, uint16_t queue_id) if (!dev) return 0; + if (queue_id >= VHOST_MAX_VRING) + return 0; + vq = dev->virtqueue[queue_id]; + if (!vq) + return 0; rte_spinlock_lock(&vq->access_lock); @@ -1311,6 +1336,23 @@ vhost_enable_notify_packed(struct virtio_net *dev, return 0; } +int +vhost_enable_guest_notification(struct virtio_net *dev, + struct vhost_virtqueue *vq, int enable) +{ + /* + * If the virtqueue is not ready yet, it will be applied + * when it will become ready. + */ + if (!vq->ready) + return 0; + + if (vq_is_packed(dev)) + return vhost_enable_notify_packed(dev, vq, enable); + else + return vhost_enable_notify_split(dev, vq, enable); +} + int rte_vhost_enable_guest_notification(int vid, uint16_t queue_id, int enable) { @@ -1321,14 +1363,17 @@ rte_vhost_enable_guest_notification(int vid, uint16_t queue_id, int enable) if (!dev) return -1; + if (queue_id >= VHOST_MAX_VRING) + return -1; + vq = dev->virtqueue[queue_id]; + if (!vq) + return -1; rte_spinlock_lock(&vq->access_lock); - if (vq_is_packed(dev)) - ret = vhost_enable_notify_packed(dev, vq, enable); - else - ret = vhost_enable_notify_split(dev, vq, enable); + vq->notif_enable = enable; + ret = vhost_enable_guest_notification(dev, vq, enable); rte_spinlock_unlock(&vq->access_lock); @@ -1433,6 +1478,9 @@ int rte_vhost_get_vring_base(int vid, uint16_t queue_id, if (dev == NULL || last_avail_idx == NULL || last_used_idx == NULL) return -1; + if (queue_id >= VHOST_MAX_VRING) + return -1; + vq = dev->virtqueue[queue_id]; if (!vq) return -1; @@ -1459,6 +1507,9 @@ int rte_vhost_set_vring_base(int vid, uint16_t queue_id, if (!dev) return -1; + if (queue_id >= VHOST_MAX_VRING) + return -1; + vq = dev->virtqueue[queue_id]; if (!vq) return -1; @@ -1483,15 +1534,23 @@ rte_vhost_get_vring_base_from_inflight(int vid, uint16_t *last_used_idx) { struct rte_vhost_inflight_info_packed *inflight_info; + struct vhost_virtqueue *vq; struct virtio_net *dev = get_device(vid); if (dev == NULL || last_avail_idx == NULL || last_used_idx == NULL) return -1; + if (queue_id >= VHOST_MAX_VRING) + return -1; + + vq = dev->virtqueue[queue_id]; + if (!vq) + return -1; + if (!vq_is_packed(dev)) return -1; - inflight_info = dev->virtqueue[queue_id]->inflight_packed; + inflight_info = vq->inflight_packed; if (!inflight_info) return -1; @@ -1522,12 +1581,16 @@ int rte_vhost_async_channel_register(int vid, uint16_t queue_id, struct vhost_virtqueue *vq; struct virtio_net *dev = get_device(vid); struct rte_vhost_async_features f; + int node; if (dev == NULL || ops == NULL) return -1; f.intval = features; + if (queue_id >= VHOST_MAX_VRING) + return -1; + vq = dev->virtqueue[queue_id]; if (unlikely(vq == NULL || !dev->async_copy)) @@ -1554,19 +1617,32 @@ int rte_vhost_async_channel_register(int vid, uint16_t queue_id, goto reg_out; } - vq->async_pkts_pending = rte_malloc(NULL, - vq->size * sizeof(uintptr_t), - RTE_CACHE_LINE_SIZE); - vq->async_pending_info = rte_malloc(NULL, - vq->size * sizeof(uint64_t), - RTE_CACHE_LINE_SIZE); - if (!vq->async_pkts_pending || !vq->async_pending_info) { - if (vq->async_pkts_pending) - rte_free(vq->async_pkts_pending); - - if (vq->async_pending_info) - rte_free(vq->async_pending_info); +#ifdef RTE_LIBRTE_VHOST_NUMA + if (get_mempolicy(&node, NULL, 0, vq, MPOL_F_NODE | MPOL_F_ADDR)) { + VHOST_LOG_CONFIG(ERR, + "unable to get numa information in async register. " + "allocating async buffer memory on the caller thread node\n"); + node = SOCKET_ID_ANY; + } +#else + node = SOCKET_ID_ANY; +#endif + vq->async_pkts_pending = rte_malloc_socket(NULL, + vq->size * sizeof(uintptr_t), + RTE_CACHE_LINE_SIZE, node); + vq->async_pkts_info = rte_malloc_socket(NULL, + vq->size * sizeof(struct async_inflight_info), + RTE_CACHE_LINE_SIZE, node); + vq->it_pool = rte_malloc_socket(NULL, + VHOST_MAX_ASYNC_IT * sizeof(struct rte_vhost_iov_iter), + RTE_CACHE_LINE_SIZE, node); + vq->vec_pool = rte_malloc_socket(NULL, + VHOST_MAX_ASYNC_VEC * sizeof(struct iovec), + RTE_CACHE_LINE_SIZE, node); + if (!vq->async_pkts_pending || !vq->async_pkts_info || + !vq->it_pool || !vq->vec_pool) { + vhost_free_async_mem(vq); VHOST_LOG_CONFIG(ERR, "async register failed: cannot allocate memory for vq data " "(vid %d, qid: %d)\n", vid, queue_id); @@ -1596,16 +1672,24 @@ int rte_vhost_async_channel_unregister(int vid, uint16_t queue_id) if (dev == NULL) return ret; + if (queue_id >= VHOST_MAX_VRING) + return ret; + vq = dev->virtqueue[queue_id]; if (vq == NULL) return ret; ret = 0; - rte_spinlock_lock(&vq->access_lock); if (!vq->async_registered) - goto out; + return ret; + + if (!rte_spinlock_trylock(&vq->access_lock)) { + VHOST_LOG_CONFIG(ERR, "Failed to unregister async channel. " + "virt queue busy.\n"); + return -1; + } if (vq->async_pkts_inflight_n) { VHOST_LOG_CONFIG(ERR, "Failed to unregister async channel. " @@ -1614,15 +1698,7 @@ int rte_vhost_async_channel_unregister(int vid, uint16_t queue_id) goto out; } - if (vq->async_pkts_pending) { - rte_free(vq->async_pkts_pending); - vq->async_pkts_pending = NULL; - } - - if (vq->async_pending_info) { - rte_free(vq->async_pending_info); - vq->async_pending_info = NULL; - } + vhost_free_async_mem(vq); vq->async_ops.transfer_data = NULL; vq->async_ops.check_completed_copies = NULL;