From patchwork Thu May 5 08:32:13 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Hajnoczi X-Patchwork-Id: 9021721 Return-Path: X-Original-To: patchwork-qemu-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 198DA9FCE7 for ; Thu, 5 May 2016 08:33:06 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 6DC68203F3 for ; Thu, 5 May 2016 08:33:05 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id A2433203F7 for ; Thu, 5 May 2016 08:33:04 +0000 (UTC) Received: from localhost ([::1]:52618 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ayEiS-00076W-Lc for patchwork-qemu-devel@patchwork.kernel.org; Thu, 05 May 2016 04:33:00 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:45963) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ayEiC-0006pz-UU for qemu-devel@nongnu.org; Thu, 05 May 2016 04:32:51 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ayEi1-00013e-4G for qemu-devel@nongnu.org; Thu, 05 May 2016 04:32:39 -0400 Received: from mx1.redhat.com ([209.132.183.28]:32864) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ayEi0-00010E-Tp for qemu-devel@nongnu.org; Thu, 05 May 2016 04:32:33 -0400 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id CDDCD80B20; Thu, 5 May 2016 08:32:21 +0000 (UTC) Received: from localhost (ovpn-112-47.ams2.redhat.com [10.36.112.47]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u458WK3a015005; Thu, 5 May 2016 04:32:21 -0400 From: Stefan Hajnoczi To: qemu-devel@nongnu.org Date: Thu, 5 May 2016 09:32:13 +0100 Message-Id: <1462437137-19824-2-git-send-email-stefanha@redhat.com> In-Reply-To: <1462437137-19824-1-git-send-email-stefanha@redhat.com> References: <1462437137-19824-1-git-send-email-stefanha@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH 1/5] libqos: fix virtio descriptor free list X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: =?UTF-8?q?Marc=20Mar=C3=AD?= , Paolo Bonzini , Stefan Hajnoczi Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Although qvring_init() chains together all descriptors for the free list, free_head is used as a counter instead of as a free list head. The test cases appear to work because they are so trivial that the free_head counter never exceeds the vring size. If they added more descriptors free_head would cause an out-of-bounds memory access. Change free_head to maintain a descriptor free list. The free list is currently never replenished since there is no function to pop buffers from the used ring. This functionality will be added in a later patch. Signed-off-by: Stefan Hajnoczi --- tests/libqos/virtio.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c index 7910774..d3e4c02 100644 --- a/tests/libqos/virtio.c +++ b/tests/libqos/virtio.c @@ -139,6 +139,7 @@ void qvring_init(const QGuestAllocator *alloc, QVirtQueue *vq, uint64_t addr) vq->avail = vq->desc + vq->size * sizeof(struct vring_desc); vq->used = (uint64_t)((vq->avail + sizeof(uint16_t) * (3 + vq->size) + vq->align - 1) & ~(vq->align - 1)); + vq->free_head = 0; for (i = 0; i < vq->size - 1; i++) { /* vq->desc[i].addr */ @@ -209,6 +210,8 @@ uint32_t qvirtqueue_add(QVirtQueue *vq, uint64_t data, uint32_t len, bool write, bool next) { uint16_t flags = 0; + uint16_t idx = vq->free_head; + vq->num_free--; if (write) { @@ -220,17 +223,22 @@ uint32_t qvirtqueue_add(QVirtQueue *vq, uint64_t data, uint32_t len, bool write, } /* vq->desc[vq->free_head].addr */ - writeq(vq->desc + (16 * vq->free_head), data); + writeq(vq->desc + (16 * idx), data); /* vq->desc[vq->free_head].len */ - writel(vq->desc + (16 * vq->free_head) + 8, len); + writel(vq->desc + (16 * idx) + 8, len); /* vq->desc[vq->free_head].flags */ - writew(vq->desc + (16 * vq->free_head) + 12, flags); + writew(vq->desc + (16 * idx) + 12, flags); - return vq->free_head++; /* Return and increase, in this order */ + vq->free_head = readw(vq->desc + sizeof(struct vring_desc) * idx + + offsetof(struct vring_desc, next)); + + return idx; } uint32_t qvirtqueue_add_indirect(QVirtQueue *vq, QVRingIndirectDesc *indirect) { + uint16_t idx = vq->free_head; + g_assert(vq->indirect); g_assert_cmpint(vq->size, >=, indirect->elem); g_assert_cmpint(indirect->index, ==, indirect->elem); @@ -238,14 +246,17 @@ uint32_t qvirtqueue_add_indirect(QVirtQueue *vq, QVRingIndirectDesc *indirect) vq->num_free--; /* vq->desc[vq->free_head].addr */ - writeq(vq->desc + (16 * vq->free_head), indirect->desc); + writeq(vq->desc + (16 * idx), indirect->desc); /* vq->desc[vq->free_head].len */ - writel(vq->desc + (16 * vq->free_head) + 8, + writel(vq->desc + (16 * idx) + 8, sizeof(struct vring_desc) * indirect->elem); /* vq->desc[vq->free_head].flags */ - writew(vq->desc + (16 * vq->free_head) + 12, VRING_DESC_F_INDIRECT); + writew(vq->desc + (16 * idx) + 12, VRING_DESC_F_INDIRECT); - return vq->free_head++; /* Return and increase, in this order */ + vq->free_head = readw(vq->desc + sizeof(struct vring_desc) * idx + + offsetof(struct vring_desc, next)); + + return idx; } void qvirtqueue_kick(const QVirtioBus *bus, QVirtioDevice *d, QVirtQueue *vq,