From patchwork Tue Jul 4 09:49:20 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxime Coquelin X-Patchwork-Id: 26355 X-Patchwork-Delegate: yuanhan.liu@linux.intel.com Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [IPv6:::1]) by dpdk.org (Postfix) with ESMTP id BBB427CD8; Tue, 4 Jul 2017 11:50:44 +0200 (CEST) Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by dpdk.org (Postfix) with ESMTP id 13B447CD8 for ; Tue, 4 Jul 2017 11:50:43 +0200 (CEST) Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 6040F369C9; Tue, 4 Jul 2017 09:50:42 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 6040F369C9 Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=maxime.coquelin@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 6040F369C9 Received: from localhost.localdomain (ovpn-112-47.ams2.redhat.com [10.36.112.47]) by smtp.corp.redhat.com (Postfix) with ESMTP id E962B5C7C1; Tue, 4 Jul 2017 09:50:39 +0000 (UTC) From: Maxime Coquelin To: dev@dpdk.org, Yuanhan Liu Cc: mst@redhat.com, vkaplans@redhat.com, jasowang@redhat.com, jfreiman@redhat.com, Maxime Coquelin Date: Tue, 4 Jul 2017 11:49:20 +0200 Message-Id: <20170704094922.11405-18-maxime.coquelin@redhat.com> In-Reply-To: <20170704094922.11405-1-maxime.coquelin@redhat.com> References: <20170704094922.11405-1-maxime.coquelin@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.30]); Tue, 04 Jul 2017 09:50:42 +0000 (UTC) Subject: [dpdk-dev] [RFC 17/19] vhost-user: iommu: postpone device creation until ring are mapped X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Translating the start addresses of the rings is not enough, we need to be sure all the ring is made available by the guest. It depends on the size of the rings, which is not known on SET_VRING_ADDR reception. Furthermore, we need to be be safe against vring pages invalidates. This patch introduces a new access_ok flag per virtqueue, which is set when all the rings are mapped, and cleared as soon as a page used by a ring is invalidated. The invalidation part is implemented in a following patch. Signed-off-by: Maxime Coquelin --- lib/librte_vhost/vhost.c | 37 ++++++++++++++++++++++++++ lib/librte_vhost/vhost.h | 4 ++- lib/librte_vhost/vhost_user.c | 62 +++++++++++++++++++++++++++++++------------ lib/librte_vhost/virtio_net.c | 12 +++++++++ 4 files changed, 97 insertions(+), 18 deletions(-) diff --git a/lib/librte_vhost/vhost.c b/lib/librte_vhost/vhost.c index b1b6a97..3f193bf 100644 --- a/lib/librte_vhost/vhost.c +++ b/lib/librte_vhost/vhost.c @@ -237,6 +237,43 @@ void notify_iotlb_event(struct virtio_net *dev) } } +int +vring_translate(struct virtio_net *dev, struct vhost_virtqueue *vq) +{ + uint64_t size; + + if (!(dev->features & (1ULL << VIRTIO_F_IOMMU_PLATFORM))) + goto out; + + size = sizeof(struct vring_desc) * vq->size; + vq->desc = (struct vring_desc *)vhost_iova_to_vva(dev, vq, + vq->ring_addrs.desc_user_addr, + size, VHOST_ACCESS_RW); + if (!vq->desc) + return -1; + + size = sizeof(struct vring_avail); + size += sizeof(uint16_t) * vq->size; + vq->avail = (struct vring_avail *)vhost_iova_to_vva(dev, vq, + vq->ring_addrs.avail_user_addr, + size, VHOST_ACCESS_RW); + if (!vq->avail) + return -1; + + size = sizeof(struct vring_used); + size += sizeof(struct vring_used_elem) * vq->size; + vq->used = (struct vring_used *)vhost_iova_to_vva(dev, vq, + vq->ring_addrs.used_user_addr, + size, VHOST_ACCESS_RW); + if (!vq->used) + return -1; + +out: + vq->access_ok = 1; + + return 0; +} + static void init_vring_queue(struct virtio_net *dev, uint32_t vring_idx) { diff --git a/lib/librte_vhost/vhost.h b/lib/librte_vhost/vhost.h index 832a80a..4b03977 100644 --- a/lib/librte_vhost/vhost.h +++ b/lib/librte_vhost/vhost.h @@ -103,6 +103,7 @@ struct vhost_virtqueue { /* Currently unused as polling mode is enabled */ int kickfd; int enabled; + int access_ok; /* Physical address of used ring, for logging */ uint64_t log_guest_addr; @@ -355,6 +356,7 @@ void vhost_backend_cleanup(struct virtio_net *dev); void notify_iotlb_event(struct virtio_net *dev); uint64_t vhost_iova_to_vva(struct virtio_net *dev, struct vhost_virtqueue *vq, - uint64_t iova, uint64_t size, uint8_t perm); + uint64_t iova, uint64_t size, uint8_t perm); +int vring_translate(struct virtio_net *dev, struct vhost_virtqueue *vq); #endif /* _VHOST_NET_CDEV_H_ */ diff --git a/lib/librte_vhost/vhost_user.c b/lib/librte_vhost/vhost_user.c index 8230578..0ebaac7 100644 --- a/lib/librte_vhost/vhost_user.c +++ b/lib/librte_vhost/vhost_user.c @@ -356,6 +356,12 @@ vhost_user_set_vring_addr(struct virtio_net *dev, VhostUserMsg *msg) */ memcpy(&vq->ring_addrs, addr, sizeof(*addr)); + vq->desc = NULL; + vq->avail = NULL; + vq->used = NULL; + + vq->access_ok = 0; + return 0; } @@ -372,10 +378,10 @@ static struct virtio_net *translate_ring_addresses(struct virtio_net *dev, vq->desc = (struct vring_desc *)(uintptr_t)ring_addr_to_vva(dev, vq, addr->desc_user_addr, sizeof(struct vring_desc)); if (vq->desc == 0) { - RTE_LOG(ERR, VHOST_CONFIG, + RTE_LOG(DEBUG, VHOST_CONFIG, "(%d) failed to find desc ring address.\n", dev->vid); - return NULL; + return dev; } dev = numa_realloc(dev, vq_index); @@ -384,19 +390,19 @@ static struct virtio_net *translate_ring_addresses(struct virtio_net *dev, vq->avail = (struct vring_avail *)(uintptr_t)ring_addr_to_vva(dev, vq, addr->avail_user_addr, sizeof(struct vring_avail)); if (vq->avail == 0) { - RTE_LOG(ERR, VHOST_CONFIG, + RTE_LOG(DEBUG, VHOST_CONFIG, "(%d) failed to find avail ring address.\n", dev->vid); - return NULL; + return dev; } vq->used = (struct vring_used *)(uintptr_t)ring_addr_to_vva(dev, vq, addr->used_user_addr, sizeof(struct vring_used)); if (vq->used == 0) { - RTE_LOG(ERR, VHOST_CONFIG, + RTE_LOG(DEBUG, VHOST_CONFIG, "(%d) failed to find used ring address.\n", dev->vid); - return NULL; + return dev; } if (vq->last_used_idx != vq->used->idx) { @@ -642,7 +648,7 @@ vhost_user_set_mem_table(struct virtio_net *dev, struct VhostUserMsg *pmsg) static int vq_is_ready(struct vhost_virtqueue *vq) { - return vq && vq->desc && + return vq && vq->desc && vq->avail && vq->used && vq->kickfd != VIRTIO_UNINITIALIZED_EVENTFD && vq->callfd != VIRTIO_UNINITIALIZED_EVENTFD; } @@ -953,8 +959,29 @@ vhost_user_set_req_fd(struct virtio_net *dev, struct VhostUserMsg *msg) } static int -vhost_user_iotlb_msg(struct virtio_net *dev, struct VhostUserMsg *msg) +is_vring_iotlb_update(struct vhost_virtqueue *vq, struct vhost_iotlb_msg *imsg) { + struct vhost_vring_addr *ra; + uint64_t start, end; + + start = imsg->iova; + end = start + imsg->size; + + ra = &vq->ring_addrs; + if (ra->desc_user_addr >= start && ra->desc_user_addr < end) + return 1; + if (ra->avail_user_addr >= start && ra->avail_user_addr < end) + return 1; + if (ra->used_user_addr >= start && ra->used_user_addr < end) + return 1; + + return -1; +} + +static int +vhost_user_iotlb_msg(struct virtio_net **pdev, struct VhostUserMsg *msg) +{ + struct virtio_net *dev = *pdev; struct vhost_iotlb_msg *imsg = &msg->payload.iotlb; uint16_t i; uint64_t vva; @@ -970,6 +997,9 @@ vhost_user_iotlb_msg(struct virtio_net *dev, struct VhostUserMsg *msg) vhost_user_iotlb_insert(vq, imsg->iova, vva, imsg->size, imsg->perm); + + if (is_vring_iotlb_update(vq, imsg)) + *pdev = dev = translate_ring_addresses(dev, i); } notify_iotlb_event(dev); @@ -1120,8 +1150,12 @@ vhost_user_msg_handler(int vid, int fd) goto out; } - RTE_LOG(INFO, VHOST_CONFIG, "read message %s\n", - vhost_message_str[msg.request]); + if (msg.request != VHOST_USER_IOTLB_MSG) + RTE_LOG(INFO, VHOST_CONFIG, "read message %s\n", + vhost_message_str[msg.request]); + else + RTE_LOG(DEBUG, VHOST_CONFIG, "read message %s\n", + vhost_message_str[msg.request]); ret = vhost_user_check_and_alloc_queue_pair(dev, &msg); if (ret < 0) { @@ -1224,7 +1258,7 @@ vhost_user_msg_handler(int vid, int fd) break; case VHOST_USER_IOTLB_MSG: - ret = vhost_user_iotlb_msg(dev, &msg); + ret = vhost_user_iotlb_msg(&dev, &msg); break; default: @@ -1233,12 +1267,6 @@ vhost_user_msg_handler(int vid, int fd) } - /* - * The virtio_net struct might have been reallocated on a different - * NUMA node, so dev pointer might no more be valid. - */ - dev = get_device(vid); - if (msg.flags & VHOST_USER_NEED_REPLY) { msg.payload.u64 = !!ret; msg.size = sizeof(msg.payload.u64); diff --git a/lib/librte_vhost/virtio_net.c b/lib/librte_vhost/virtio_net.c index 62c231a..b0870df 100644 --- a/lib/librte_vhost/virtio_net.c +++ b/lib/librte_vhost/virtio_net.c @@ -263,6 +263,10 @@ virtio_dev_rx(struct virtio_net *dev, uint16_t queue_id, if (unlikely(vq->enabled == 0)) return 0; + if (unlikely(vq->access_ok == 0)) + if (unlikely(vring_translate(dev, vq) < 0)) + return 0; + avail_idx = *((volatile uint16_t *)&vq->avail->idx); start_idx = vq->last_used_idx; free_entries = avail_idx - start_idx; @@ -547,6 +551,10 @@ virtio_dev_merge_rx(struct virtio_net *dev, uint16_t queue_id, if (unlikely(vq->enabled == 0)) return 0; + if (unlikely(vq->access_ok == 0)) + if (unlikely(vring_translate(dev, vq) < 0)) + return 0; + count = RTE_MIN((uint32_t)MAX_PKT_BURST, count); if (count == 0) return 0; @@ -1029,6 +1037,10 @@ rte_vhost_dequeue_burst(int vid, uint16_t queue_id, if (unlikely(vq->enabled == 0)) goto out; + if (unlikely(vq->access_ok == 0)) + if (unlikely(vring_translate(dev, vq) < 0)) + return 0; + if (unlikely(dev->dequeue_zero_copy)) { struct zcopy_mbuf *zmbuf, *next; int nr_updated = 0;