From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 017E7EB8FB6 for ; Wed, 6 Sep 2023 12:04:22 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1qdrFs-0002f0-HY; Wed, 06 Sep 2023 08:03:32 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1qdrFq-0002ef-79 for qemu-devel@nongnu.org; Wed, 06 Sep 2023 08:03:30 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1qdrFl-0006Le-HD for qemu-devel@nongnu.org; Wed, 06 Sep 2023 08:03:29 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1694001804; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=fwY7zQL7xXCh0VKf+8KcF0HAxgYujbnMPfazPhnrIls=; b=VTYZ1Wa4DuoeQnc8xvXQNNOPNs9EybAPWPhjBk2xdqmjaYQl82qInhCJlLTevFUw1ixlL3 1ba8fOzdMaLJvAS1SJXvzYudPbdzhSG5Nj+ovtRt4tX2/EEBGR9P/910afxruB8tC7dWq5 fhXsbZ1elWLe75U+VtcgN5b03WlymfY= Received: from mail-pg1-f197.google.com (mail-pg1-f197.google.com [209.85.215.197]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-453-3-htpDQlNuGYrngBRmAUDQ-1; Wed, 06 Sep 2023 08:03:22 -0400 X-MC-Unique: 3-htpDQlNuGYrngBRmAUDQ-1 Received: by mail-pg1-f197.google.com with SMTP id 41be03b00d2f7-56fb25fdf06so2782594a12.1 for ; Wed, 06 Sep 2023 05:03:21 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1694001800; x=1694606600; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=fwY7zQL7xXCh0VKf+8KcF0HAxgYujbnMPfazPhnrIls=; b=MXWhq15LEzQgcgit6QND4rr9uA5lVWM70onU/bIWY4WUDBFZdpVkrXhFvobdMX/as8 TJw8vxYSA+VKIi2QZu3QQIU0NZZE5QyZm3nw8KBN3sCn8BhgYAAq4kkOIYncT+MSlVIh UEBpQxpK7QSGB7s26LiIRaOLJbOHKkORFxy3LSZqBzYxi3Mm55sc5AnSxELUMMw/ENNL LIf+qvj00g4Ho3i2mUHQepWK3T6ur9NuOMaxb2coDRNHjh5UzJesUN0wAwb01smDCD6j XU3tIajn+tNFPNn3mSS9Tp//gOJRk5GVPlgrmu2l1TGMKGFqWIwfDtk6Ecr5FN1gz0PZ lvFg== X-Gm-Message-State: AOJu0Yw2MGYttEwuvYFyanwaie0ExAnV+Tl933sMk/ylldj6lfnzXhAg lzqpOHaen2QHzzHu+Q19nq8pIavQpZpXbm+kbwwRfpLtBvCj6qZ+Agv7beqdO4wDOIXRKgzFP0x XfqJO0SgOqoeTgnKViWKgN9K+pI0q5OI0S/+YnbI= X-Received: by 2002:a05:6a20:3d91:b0:152:efa4:228 with SMTP id s17-20020a056a203d9100b00152efa40228mr5378954pzi.20.1694001799878; Wed, 06 Sep 2023 05:03:19 -0700 (PDT) X-Google-Smtp-Source: AGHT+IG4UD9c/qCN4xVgiANzCExB4p53GvKhLSmsQ1jubuWnbgdsCPEWCh6wPYlbFt0f+r8rHbOI/Znm9SUhClo4fzM= X-Received: by 2002:a05:6a20:3d91:b0:152:efa4:228 with SMTP id s17-20020a056a203d9100b00152efa40228mr5378917pzi.20.1694001799382; Wed, 06 Sep 2023 05:03:19 -0700 (PDT) MIME-Version: 1.0 References: <20230906111549.357178-1-aesteve@redhat.com> <20230906111549.357178-3-aesteve@redhat.com> In-Reply-To: <20230906111549.357178-3-aesteve@redhat.com> From: Albert Esteve Date: Wed, 6 Sep 2023 14:03:08 +0200 Message-ID: Subject: Re: [PATCH v6 2/3] virtio-dmabuf: introduce virtio-dmabuf To: qemu-devel@nongnu.org Cc: philmd@linaro.org, Fam Zheng , "Michael S. Tsirkin" , cohuck@redhat.com, kraxel@redhat.com, marcandre.lureau@gmail.com Content-Type: multipart/alternative; boundary="0000000000008065950604af8763" Received-SPF: pass client-ip=170.10.129.124; envelope-from=aesteve@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.001, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org --0000000000008065950604af8763 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Wed, Sep 6, 2023 at 1:15=E2=80=AFPM Albert Esteve w= rote: > This API manages objects (in this iteration, > dmabuf fds) that can be shared along different > virtio devices, associated to a UUID. > > The API allows the different devices to add, > remove and/or retrieve the objects by simply > invoking the public functions that reside in the > virtio-dmabuf file. > > For vhost backends, the API stores the pointer > to the backend holding the object. > > Suggested-by: Gerd Hoffmann > Signed-off-by: Albert Esteve > --- > MAINTAINERS | 7 ++ > hw/display/meson.build | 1 + > hw/display/virtio-dmabuf.c | 134 +++++++++++++++++++++++++++++ > include/hw/virtio/virtio-dmabuf.h | 103 ++++++++++++++++++++++ > tests/unit/meson.build | 1 + > tests/unit/test-virtio-dmabuf.c | 137 ++++++++++++++++++++++++++++++ > 6 files changed, 383 insertions(+) > create mode 100644 hw/display/virtio-dmabuf.c > create mode 100644 include/hw/virtio/virtio-dmabuf.h > create mode 100644 tests/unit/test-virtio-dmabuf.c > > diff --git a/MAINTAINERS b/MAINTAINERS > index 3b29568ed4..fb0f7b823f 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -2150,6 +2150,13 @@ T: git https://gitlab.com/cohuck/qemu.git s390-nex= t > T: git https://github.com/borntraeger/qemu.git s390-next > L: qemu-s390x@nongnu.org > > +virtio-dmabuf > +M: Albert Esteve > +S: Supported > +F: hw/display/virtio-dmabuf.c > +F: include/hw/virtio/virtio-dmabuf.h > +F: tests/unit/test-virtio-dmabuf.c > + > virtiofs > M: Stefan Hajnoczi > S: Supported > diff --git a/hw/display/meson.build b/hw/display/meson.build > index 413ba4ab24..05619c6968 100644 > --- a/hw/display/meson.build > +++ b/hw/display/meson.build > @@ -37,6 +37,7 @@ system_ss.add(when: 'CONFIG_MACFB', if_true: > files('macfb.c')) > system_ss.add(when: 'CONFIG_NEXTCUBE', if_true: files('next-fb.c')) > > system_ss.add(when: 'CONFIG_VGA', if_true: files('vga.c')) > +system_ss.add(when: 'CONFIG_VIRTIO', if_true: files('virtio-dmabuf.c')) > > if (config_all_devices.has_key('CONFIG_VGA_CIRRUS') or > config_all_devices.has_key('CONFIG_VGA_PCI') or > diff --git a/hw/display/virtio-dmabuf.c b/hw/display/virtio-dmabuf.c > new file mode 100644 > index 0000000000..268ffe81ec > --- /dev/null > +++ b/hw/display/virtio-dmabuf.c > @@ -0,0 +1,134 @@ > +/* > + * Virtio Shared dma-buf > + * > + * Copyright Red Hat, Inc. 2023 > + * > + * Authors: > + * Albert Esteve > + * > + * This work is licensed under the terms of the GNU GPL, version 2 or > later. > + * See the COPYING file in the top-level directory. > + */ > + > +#include "hw/virtio/virtio-dmabuf.h" > + > + > +static GMutex lock; > +static GHashTable *resource_uuids; > + > +/* > + * uuid_equal_func: wrapper for UUID is_equal function to > + * satisfy g_hash_table_new expected parameters signatures. > + */ > +static int uuid_equal_func(const void *lhv, const void *rhv) > +{ > + return qemu_uuid_is_equal(lhv, rhv); > +} > + > +static bool virtio_add_resource(QemuUUID *uuid, VirtioSharedObject *valu= e) > +{ > + bool result; > + g_mutex_lock(&lock); > + if (resource_uuids =3D=3D NULL) { > + resource_uuids =3D g_hash_table_new_full( > + qemu_uuid_hash, uuid_equal_func, NULL, g_free); > + } > + if (g_hash_table_lookup(resource_uuids, uuid) !=3D NULL) { > + g_mutex_unlock(&lock); > + return false; > + } > + result =3D g_hash_table_insert(resource_uuids, uuid, value); > + g_mutex_unlock(&lock); > + > + return result; > +} > + > +bool virtio_add_dmabuf(QemuUUID *uuid, int udmabuf_fd) > +{ > + bool result; > + VirtioSharedObject *vso; > + if (udmabuf_fd < 0) { > + return false; > + } > + vso =3D g_new(VirtioSharedObject, 1); > + vso->type =3D TYPE_DMABUF; > + vso->value =3D GINT_TO_POINTER(udmabuf_fd); > + result =3D virtio_add_resource(uuid, vso); > + > + return result; > Just realized that the result variable is not required anymore with the last change. Not sure if it is worth sending a new review for this... I can take it into account for a follow-up refactor for the next update I make on the file. Or just send a separate trivial patch. > +} > + > +bool virtio_add_vhost_device(QemuUUID *uuid, struct vhost_dev *dev) > +{ > + bool result; > + VirtioSharedObject *vso; > + if (dev =3D=3D NULL) { > + return false; > + } > + vso =3D g_new(VirtioSharedObject, 1); > + vso->type =3D TYPE_VHOST_DEV; > + vso->value =3D dev; > + result =3D virtio_add_resource(uuid, vso); > + > + return result; > +} > + > +bool virtio_remove_resource(const QemuUUID *uuid) > +{ > + bool result; > + g_mutex_lock(&lock); > + result =3D g_hash_table_remove(resource_uuids, uuid); > + g_mutex_unlock(&lock); > + > + return result; > +} > + > +static VirtioSharedObject *get_shared_object(const QemuUUID *uuid) > +{ > + g_mutex_lock(&lock); > + if (resource_uuids =3D=3D NULL) { > + g_mutex_unlock(&lock); > + return NULL; > + } > + gpointer lookup_res =3D g_hash_table_lookup(resource_uuids, uuid); > + g_mutex_unlock(&lock); > + return (VirtioSharedObject*) lookup_res; > +} > + > +int virtio_lookup_dmabuf(const QemuUUID *uuid) > +{ > + VirtioSharedObject *vso =3D get_shared_object(uuid); > + if (vso =3D=3D NULL) { > + return -1; > + } > + assert(vso->type =3D=3D TYPE_DMABUF); > + return GPOINTER_TO_INT(vso->value); > +} > + > +struct vhost_dev *virtio_lookup_vhost_device(const QemuUUID *uuid) > +{ > + VirtioSharedObject *vso =3D get_shared_object(uuid); > + if (vso =3D=3D NULL) { > + return NULL; > + } > + assert(vso->type =3D=3D TYPE_VHOST_DEV); > + return (struct vhost_dev *) vso->value; > +} > + > +SharedObjectType virtio_object_type(const QemuUUID *uuid) > +{ > + VirtioSharedObject *vso =3D get_shared_object(uuid); > + if (vso =3D=3D NULL) { > + return TYPE_INVALID; > + } > + return vso->type; > +} > + > +void virtio_free_resources(void) > +{ > + g_mutex_lock(&lock); > + g_hash_table_destroy(resource_uuids); > + /* Reference count shall be 0 after the implicit unref on destroy */ > + resource_uuids =3D NULL; > + g_mutex_unlock(&lock); > +} > diff --git a/include/hw/virtio/virtio-dmabuf.h > b/include/hw/virtio/virtio-dmabuf.h > new file mode 100644 > index 0000000000..202eec5868 > --- /dev/null > +++ b/include/hw/virtio/virtio-dmabuf.h > @@ -0,0 +1,103 @@ > +/* > + * Virtio Shared dma-buf > + * > + * Copyright Red Hat, Inc. 2023 > + * > + * Authors: > + * Albert Esteve > + * > + * This work is licensed under the terms of the GNU GPL, version 2. > + * See the COPYING file in the top-level directory. > + */ > + > +#ifndef VIRTIO_DMABUF_H > +#define VIRTIO_DMABUF_H > + > +#include "qemu/osdep.h" > + > +#include > +#include "qemu/uuid.h" > +#include "vhost.h" > + > +typedef enum SharedObjectType { > + TYPE_INVALID =3D 0, > + TYPE_DMABUF, > + TYPE_VHOST_DEV, > +} SharedObjectType; > + > +typedef struct VirtioSharedObject { > + SharedObjectType type; > + gpointer value; > +} VirtioSharedObject; > + > +/** > + * virtio_add_dmabuf() - Add a new dma-buf resource to the lookup table > + * @uuid: new resource's UUID > + * @dmabuf_fd: the dma-buf descriptor that will be stored and shared wit= h > + * other virtio devices. The caller retains ownership over t= he > + * descriptor and its lifecycle. > + * > + * Note: @dmabuf_fd must be a valid (non-negative) file descriptor. > + * > + * Return: true if the UUID did not exist and the resource has been adde= d, > + * false if another resource with the same UUID already existed. > + * Note that if it finds a repeated UUID, the resource is not inserted i= n > + * the lookup table. > + */ > +bool virtio_add_dmabuf(QemuUUID *uuid, int dmabuf_fd); > + > +/** > + * virtio_add_vhost_device() - Add a new exporter vhost device that hold= s > the > + * resource with the associated UUID > + * @uuid: new resource's UUID > + * @dev: the pointer to the vhost device that holds the resource. The > caller > + * retains ownership over the device struct and its lifecycle. > + * > + * Return: true if the UUID did not exist and the device has been tracke= d, > + * false if another resource with the same UUID already existed. > + * Note that if it finds a repeated UUID, the resource is not inserted i= n > + * the lookup table. > + */ > +bool virtio_add_vhost_device(QemuUUID *uuid, struct vhost_dev *dev); > + > +/** > + * virtio_remove_resource() - Removes a resource from the lookup table > + * @uuid: resource's UUID > + * > + * Return: true if the UUID has been found and removed from the lookup > table. > + */ > +bool virtio_remove_resource(const QemuUUID *uuid); > + > +/** > + * virtio_lookup_dmabuf() - Looks for a dma-buf resource in the lookup > table > + * @uuid: resource's UUID > + * > + * Return: the dma-buf file descriptor integer, or -1 if the key is not > found. > + */ > +int virtio_lookup_dmabuf(const QemuUUID *uuid); > + > +/** > + * virtio_lookup_vhost_device() - Looks for an exporter vhost device in > the > + * lookup table > + * @uuid: resource's UUID > + * > + * Return: pointer to the vhost_dev struct, or NULL if the key is not > found. > + */ > +struct vhost_dev *virtio_lookup_vhost_device(const QemuUUID *uuid); > + > +/** > + * virtio_object_type() - Looks for the type of resource in the lookup > table > + * @uuid: resource's UUID > + * > + * Return: the type of resource associated with the UUID, or TYPE_INVALI= D > if > + * the key is not found. > + */ > +SharedObjectType virtio_object_type(const QemuUUID *uuid); > + > +/** > + * virtio_free_resources() - Destroys all keys and values of the shared > + * resources lookup table, and frees them > + */ > +void virtio_free_resources(void); > + > +#endif /* VIRTIO_DMABUF_H */ > diff --git a/tests/unit/meson.build b/tests/unit/meson.build > index 93977cc32d..425ecc30fb 100644 > --- a/tests/unit/meson.build > +++ b/tests/unit/meson.build > @@ -50,6 +50,7 @@ tests =3D { > 'test-qapi-util': [], > 'test-interval-tree': [], > 'test-xs-node': [qom], > + 'test-virtio-dmabuf': [meson.project_source_root() / > 'hw/display/virtio-dmabuf.c'], > } > > if have_system or have_tools > diff --git a/tests/unit/test-virtio-dmabuf.c > b/tests/unit/test-virtio-dmabuf.c > new file mode 100644 > index 0000000000..40fe262538 > --- /dev/null > +++ b/tests/unit/test-virtio-dmabuf.c > @@ -0,0 +1,137 @@ > +/* > + * QEMU tests for shared dma-buf API > + * > + * Copyright (c) 2023 Red Hat, Inc. > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2.1 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, see < > http://www.gnu.org/licenses/>. > + * > + */ > + > +#include "qemu/osdep.h" > +#include "hw/virtio/virtio-dmabuf.h" > + > + > +static void test_add_remove_resources(void) > +{ > + QemuUUID uuid; > + int i, dmabuf_fd; > + > + for (i =3D 0; i < 100; ++i) { > + qemu_uuid_generate(&uuid); > + dmabuf_fd =3D g_random_int_range(3, 500); > + /* Add a new resource */ > + g_assert(virtio_add_dmabuf(&uuid, dmabuf_fd)); > + g_assert_cmpint(virtio_lookup_dmabuf(&uuid), =3D=3D, dmabuf_fd); > + /* Remove the resource */ > + g_assert(virtio_remove_resource(&uuid)); > + /* Resource is not found anymore */ > + g_assert_cmpint(virtio_lookup_dmabuf(&uuid), =3D=3D, -1); > + } > +} > + > +static void test_add_remove_dev(void) > +{ > + QemuUUID uuid; > + struct vhost_dev *dev =3D g_new0(struct vhost_dev, 1); > + int i; > + > + for (i =3D 0; i < 100; ++i) { > + qemu_uuid_generate(&uuid); > + virtio_add_vhost_device(&uuid, dev); > + /* vhost device is found */ > + g_assert(virtio_lookup_vhost_device(&uuid) !=3D NULL); > + /* Remove the vhost device */ > + g_assert(virtio_remove_resource(&uuid)); > + /* vhost device is not found anymore */ > + g_assert(virtio_lookup_vhost_device(&uuid) =3D=3D NULL); > + } > + g_free(dev); > +} > + > +static void test_remove_invalid_resource(void) > +{ > + QemuUUID uuid; > + int i; > + > + for (i =3D 0; i < 20; ++i) { > + qemu_uuid_generate(&uuid); > + g_assert_cmpint(virtio_lookup_dmabuf(&uuid), =3D=3D, -1); > + /* Removing a resource that does not exist returns false */ > + g_assert_false(virtio_remove_resource(&uuid)); > + } > +} > + > +static void test_add_invalid_resource(void) > +{ > + QemuUUID uuid; > + struct vhost_dev *dev =3D NULL; > + int i, dmabuf_fd =3D -2, alt_dmabuf =3D 2; > + > + for (i =3D 0; i < 20; ++i) { > + qemu_uuid_generate(&uuid); > + /* Add a new resource with invalid (negative) resource fd */ > + g_assert_false(virtio_add_dmabuf(&uuid, dmabuf_fd)); > + /* Resource is not found */ > + g_assert_cmpint(virtio_lookup_dmabuf(&uuid), =3D=3D, -1); > + /* Add a new vhost device with invalid (NULL) pointer */ > + g_assert_false(virtio_add_vhost_device(&uuid, dev)); > + /* vhost device is not found */ > + g_assert(virtio_lookup_vhost_device(&uuid) =3D=3D NULL); > + } > + > + for (i =3D 0; i < 20; ++i) { > + /* Add a valid resource */ > + qemu_uuid_generate(&uuid); > + dmabuf_fd =3D g_random_int_range(3, 500); > + g_assert(virtio_add_dmabuf(&uuid, dmabuf_fd)); > + g_assert_cmpint(virtio_lookup_dmabuf(&uuid), =3D=3D, dmabuf_fd); > + /* Add a new resource with repeated uuid returns false */ > + g_assert_false(virtio_add_dmabuf(&uuid, alt_dmabuf)); > + /* The value for the uuid key is not replaced */ > + g_assert_cmpint(virtio_lookup_dmabuf(&uuid), =3D=3D, dmabuf_fd); > + } > +} > + > +static void test_free_resources(void) > +{ > + QemuUUID uuids[20]; > + int i, dmabuf_fd; > + > + for (i =3D 0; i < ARRAY_SIZE(uuids); ++i) { > + qemu_uuid_generate(&uuids[i]); > + dmabuf_fd =3D g_random_int_range(3, 500); > + g_assert(virtio_add_dmabuf(&uuids[i], dmabuf_fd)); > + g_assert_cmpint(virtio_lookup_dmabuf(&uuids[i]), =3D=3D, dmabuf_= fd); > + } > + virtio_free_resources(); > + for (i =3D 0; i < ARRAY_SIZE(uuids); ++i) { > + /* None of the resources is found after free'd */ > + g_assert_cmpint(virtio_lookup_dmabuf(&uuids[i]), =3D=3D, -1); > + } > + > +} > + > +int main(int argc, char **argv) > +{ > + g_test_init(&argc, &argv, NULL); > + g_test_add_func("/virtio-dmabuf/add_rm_res", > test_add_remove_resources); > + g_test_add_func("/virtio-dmabuf/add_rm_dev", test_add_remove_dev= ); > + g_test_add_func("/virtio-dmabuf/rm_invalid_res", > + test_remove_invalid_resource); > + g_test_add_func("/virtio-dmabuf/add_invalid_res", > + test_add_invalid_resource); > + g_test_add_func("/virtio-dmabuf/free_res", test_free_resources); > + > + return g_test_run(); > +} > -- > 2.41.0 > > --0000000000008065950604af8763 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable



<= div dir=3D"ltr" class=3D"gmail_attr">On Wed, Sep 6, 2023 at 1:15=E2=80=AFPM= Albert Esteve <aesteve@redhat.com= > wrote:
= This API manages objects (in this iteration,
dmabuf fds) that can be shared along different
virtio devices, associated to a UUID.

The API allows the different devices to add,
remove and/or retrieve the objects by simply
invoking the public functions that reside in the
virtio-dmabuf file.

For vhost backends, the API stores the pointer
to the backend holding the object.

Suggested-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Albert Esteve <aesteve@redhat.com>
---
=C2=A0MAINTAINERS=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0|=C2=A0 =C2=A07 ++
=C2=A0hw/display/meson.build=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 |=C2= =A0 =C2=A01 +
=C2=A0hw/display/virtio-dmabuf.c=C2=A0 =C2=A0 =C2=A0 =C2=A0 | 134 +++++++++= ++++++++++++++++++++
=C2=A0include/hw/virtio/virtio-dmabuf.h | 103 ++++++++++++++++++++++
=C2=A0tests/unit/meson.build=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 |=C2= =A0 =C2=A01 +
=C2=A0tests/unit/test-virtio-dmabuf.c=C2=A0 =C2=A0| 137 +++++++++++++++++++= +++++++++++
=C2=A06 files changed, 383 insertions(+)
=C2=A0create mode 100644 hw/display/virtio-dmabuf.c
=C2=A0create mode 100644 include/hw/virtio/virtio-dmabuf.h
=C2=A0create mode 100644 tests/unit/test-virtio-dmabuf.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 3b29568ed4..fb0f7b823f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2150,6 +2150,13 @@ T: git https://gitlab.com/cohuck/qemu.git s390-next
=C2=A0T: git
https://github.com/borntraeger/qemu.git s390= -next
=C2=A0L: qemu-s3= 90x@nongnu.org

+virtio-dmabuf
+M: Albert Esteve <aesteve@redhat.com>
+S: Supported
+F: hw/display/virtio-dmabuf.c
+F: include/hw/virtio/virtio-dmabuf.h
+F: tests/unit/test-virtio-dmabuf.c
+
=C2=A0virtiofs
=C2=A0M: Stefan Hajnoczi <stefanha@redhat.com>
=C2=A0S: Supported
diff --git a/hw/display/meson.build b/hw/display/meson.build
index 413ba4ab24..05619c6968 100644
--- a/hw/display/meson.build
+++ b/hw/display/meson.build
@@ -37,6 +37,7 @@ system_ss.add(when: 'CONFIG_MACFB', if_true: file= s('macfb.c'))
=C2=A0system_ss.add(when: 'CONFIG_NEXTCUBE', if_true: files('ne= xt-fb.c'))

=C2=A0system_ss.add(when: 'CONFIG_VGA', if_true: files('vga.c&#= 39;))
+system_ss.add(when: 'CONFIG_VIRTIO', if_true: files('virtio-dm= abuf.c'))

=C2=A0if (config_all_devices.has_key('CONFIG_VGA_CIRRUS') or
=C2=A0 =C2=A0 =C2=A0config_all_devices.has_key('CONFIG_VGA_PCI') or=
diff --git a/hw/display/virtio-dmabuf.c b/hw/display/virtio-dmabuf.c
new file mode 100644
index 0000000000..268ffe81ec
--- /dev/null
+++ b/hw/display/virtio-dmabuf.c
@@ -0,0 +1,134 @@
+/*
+ * Virtio Shared dma-buf
+ *
+ * Copyright Red Hat, Inc. 2023
+ *
+ * Authors:
+ *=C2=A0 =C2=A0 =C2=A0Albert Esteve <aesteve@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or late= r.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "hw/virtio/virtio-dmabuf.h"
+
+
+static GMutex lock;
+static GHashTable *resource_uuids;
+
+/*
+ * uuid_equal_func: wrapper for UUID is_equal function to
+ * satisfy g_hash_table_new expected parameters signatures.
+ */
+static int uuid_equal_func(const void *lhv, const void *rhv)
+{
+=C2=A0 =C2=A0 return qemu_uuid_is_equal(lhv, rhv);
+}
+
+static bool virtio_add_resource(QemuUUID *uuid, VirtioSharedObject *value)=
+{
+=C2=A0 =C2=A0 bool result;
+=C2=A0 =C2=A0 g_mutex_lock(&lock);
+=C2=A0 =C2=A0 if (resource_uuids =3D=3D NULL) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 resource_uuids =3D g_hash_table_new_full(
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 qemu_uuid_hash, uuid_equal_func,= NULL, g_free);
+=C2=A0 =C2=A0 }
+=C2=A0 =C2=A0 if (g_hash_table_lookup(resource_uuids, uuid) !=3D NULL) { +=C2=A0 =C2=A0 =C2=A0 =C2=A0 g_mutex_unlock(&lock);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 return false;
+=C2=A0 =C2=A0 }
+=C2=A0 =C2=A0 result =3D g_hash_table_insert(resource_uuids, uuid, value);=
+=C2=A0 =C2=A0 g_mutex_unlock(&lock);
+
+=C2=A0 =C2=A0 return result;
+}
+
+bool virtio_add_dmabuf(QemuUUID *uuid, int udmabuf_fd)
+{
+=C2=A0 =C2=A0 bool result;
+=C2=A0 =C2=A0 VirtioSharedObject *vso;
+=C2=A0 =C2=A0 if (udmabuf_fd < 0) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 return false;
+=C2=A0 =C2=A0 }
+=C2=A0 =C2=A0 vso =3D g_new(VirtioSharedObject, 1);
+=C2=A0 =C2=A0 vso->type =3D TYPE_DMABUF;
+=C2=A0 =C2=A0 vso->value =3D GINT_TO_POINTER(udmabuf_fd);
+=C2=A0 =C2=A0 result =3D virtio_add_resource(uuid, vso);
+
+=C2=A0 =C2=A0 return result;

Just real= ized that the result variable is not required anymore
with the la= st change.

Not sure if it is worth sending a new r= eview for this...
I can take it into account for a follow-up refa= ctor for the next
update I make on the file. Or just send a separ= ate trivial patch.
=C2=A0
+}
+
+bool virtio_add_vhost_device(QemuUUID *uuid, struct vhost_dev *dev)
+{
+=C2=A0 =C2=A0 bool result;
+=C2=A0 =C2=A0 VirtioSharedObject *vso;
+=C2=A0 =C2=A0 if (dev =3D=3D NULL) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 return false;
+=C2=A0 =C2=A0 }
+=C2=A0 =C2=A0 vso =3D g_new(VirtioSharedObject, 1);
+=C2=A0 =C2=A0 vso->type =3D TYPE_VHOST_DEV;
+=C2=A0 =C2=A0 vso->value =3D dev;
+=C2=A0 =C2=A0 result =3D virtio_add_resource(uuid, vso);
+
+=C2=A0 =C2=A0 return result;
+}
+
+bool virtio_remove_resource(const QemuUUID *uuid)
+{
+=C2=A0 =C2=A0 bool result;
+=C2=A0 =C2=A0 g_mutex_lock(&lock);
+=C2=A0 =C2=A0 result =3D g_hash_table_remove(resource_uuids, uuid);
+=C2=A0 =C2=A0 g_mutex_unlock(&lock);
+
+=C2=A0 =C2=A0 return result;
+}
+
+static VirtioSharedObject *get_shared_object(const QemuUUID *uuid)
+{
+=C2=A0 =C2=A0 g_mutex_lock(&lock);
+=C2=A0 =C2=A0 if (resource_uuids =3D=3D NULL) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 g_mutex_unlock(&lock);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 return NULL;
+=C2=A0 =C2=A0 }
+=C2=A0 =C2=A0 gpointer lookup_res =3D g_hash_table_lookup(resource_uuids, = uuid);
+=C2=A0 =C2=A0 g_mutex_unlock(&lock);
+=C2=A0 =C2=A0 return (VirtioSharedObject*) lookup_res;
+}
+
+int virtio_lookup_dmabuf(const QemuUUID *uuid)
+{
+=C2=A0 =C2=A0 VirtioSharedObject *vso =3D get_shared_object(uuid);
+=C2=A0 =C2=A0 if (vso =3D=3D NULL) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 return -1;
+=C2=A0 =C2=A0 }
+=C2=A0 =C2=A0 assert(vso->type =3D=3D TYPE_DMABUF);
+=C2=A0 =C2=A0 return GPOINTER_TO_INT(vso->value);
+}
+
+struct vhost_dev *virtio_lookup_vhost_device(const QemuUUID *uuid)
+{
+=C2=A0 =C2=A0 VirtioSharedObject *vso =3D get_shared_object(uuid);
+=C2=A0 =C2=A0 if (vso =3D=3D NULL) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 return NULL;
+=C2=A0 =C2=A0 }
+=C2=A0 =C2=A0 assert(vso->type =3D=3D TYPE_VHOST_DEV);
+=C2=A0 =C2=A0 return (struct vhost_dev *) vso->value;
+}
+
+SharedObjectType virtio_object_type(const QemuUUID *uuid)
+{
+=C2=A0 =C2=A0 VirtioSharedObject *vso =3D get_shared_object(uuid);
+=C2=A0 =C2=A0 if (vso =3D=3D NULL) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 return TYPE_INVALID;
+=C2=A0 =C2=A0 }
+=C2=A0 =C2=A0 return vso->type;
+}
+
+void virtio_free_resources(void)
+{
+=C2=A0 =C2=A0 g_mutex_lock(&lock);
+=C2=A0 =C2=A0 g_hash_table_destroy(resource_uuids);
+=C2=A0 =C2=A0 /* Reference count shall be 0 after the implicit unref on de= stroy */
+=C2=A0 =C2=A0 resource_uuids =3D NULL;
+=C2=A0 =C2=A0 g_mutex_unlock(&lock);
+}
diff --git a/include/hw/virtio/virtio-dmabuf.h b/include/hw/virtio/virtio-d= mabuf.h
new file mode 100644
index 0000000000..202eec5868
--- /dev/null
+++ b/include/hw/virtio/virtio-dmabuf.h
@@ -0,0 +1,103 @@
+/*
+ * Virtio Shared dma-buf
+ *
+ * Copyright Red Hat, Inc. 2023
+ *
+ * Authors:
+ *=C2=A0 =C2=A0 =C2=A0Albert Esteve <aesteve@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef VIRTIO_DMABUF_H
+#define VIRTIO_DMABUF_H
+
+#include "qemu/osdep.h"
+
+#include <glib.h>
+#include "qemu/uuid.h"
+#include "vhost.h"
+
+typedef enum SharedObjectType {
+=C2=A0 =C2=A0 TYPE_INVALID =3D 0,
+=C2=A0 =C2=A0 TYPE_DMABUF,
+=C2=A0 =C2=A0 TYPE_VHOST_DEV,
+} SharedObjectType;
+
+typedef struct VirtioSharedObject {
+=C2=A0 =C2=A0 SharedObjectType type;
+=C2=A0 =C2=A0 gpointer value;
+} VirtioSharedObject;
+
+/**
+ * virtio_add_dmabuf() - Add a new dma-buf resource to the lookup table + * @uuid: new resource's UUID
+ * @dmabuf_fd: the dma-buf descriptor that will be stored and shared with<= br> + *=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0other virtio devices. Th= e caller retains ownership over the
+ *=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0descriptor and its lifec= ycle.
+ *
+ * Note: @dmabuf_fd must be a valid (non-negative) file descriptor.
+ *
+ * Return: true if the UUID did not exist and the resource has been added,=
+ * false if another resource with the same UUID already existed.
+ * Note that if it finds a repeated UUID, the resource is not inserted in<= br> + * the lookup table.
+ */
+bool virtio_add_dmabuf(QemuUUID *uuid, int dmabuf_fd);
+
+/**
+ * virtio_add_vhost_device() - Add a new exporter vhost device that holds = the
+ * resource with the associated UUID
+ * @uuid: new resource's UUID
+ * @dev: the pointer to the vhost device that holds the resource. The call= er
+ *=C2=A0 =C2=A0 =C2=A0 =C2=A0retains ownership over the device struct and = its lifecycle.
+ *
+ * Return: true if the UUID did not exist and the device has been tracked,=
+ * false if another resource with the same UUID already existed.
+ * Note that if it finds a repeated UUID, the resource is not inserted in<= br> + * the lookup table.
+ */
+bool virtio_add_vhost_device(QemuUUID *uuid, struct vhost_dev *dev);
+
+/**
+ * virtio_remove_resource() - Removes a resource from the lookup table
+ * @uuid: resource's UUID
+ *
+ * Return: true if the UUID has been found and removed from the lookup tab= le.
+ */
+bool virtio_remove_resource(const QemuUUID *uuid);
+
+/**
+ * virtio_lookup_dmabuf() - Looks for a dma-buf resource in the lookup tab= le
+ * @uuid: resource's UUID
+ *
+ * Return: the dma-buf file descriptor integer, or -1 if the key is not fo= und.
+ */
+int virtio_lookup_dmabuf(const QemuUUID *uuid);
+
+/**
+ * virtio_lookup_vhost_device() - Looks for an exporter vhost device in th= e
+ * lookup table
+ * @uuid: resource's UUID
+ *
+ * Return: pointer to the vhost_dev struct, or NULL if the key is not foun= d.
+ */
+struct vhost_dev *virtio_lookup_vhost_device(const QemuUUID *uuid);
+
+/**
+ * virtio_object_type() - Looks for the type of resource in the lookup tab= le
+ * @uuid: resource's UUID
+ *
+ * Return: the type of resource associated with the UUID, or TYPE_INVALID = if
+ * the key is not found.
+ */
+SharedObjectType virtio_object_type(const QemuUUID *uuid);
+
+/**
+ * virtio_free_resources() - Destroys all keys and values of the shared + * resources lookup table, and frees them
+ */
+void virtio_free_resources(void);
+
+#endif /* VIRTIO_DMABUF_H */
diff --git a/tests/unit/meson.build b/tests/unit/meson.build
index 93977cc32d..425ecc30fb 100644
--- a/tests/unit/meson.build
+++ b/tests/unit/meson.build
@@ -50,6 +50,7 @@ tests =3D {
=C2=A0 =C2=A0'test-qapi-util': [],
=C2=A0 =C2=A0'test-interval-tree': [],
=C2=A0 =C2=A0'test-xs-node': [qom],
+=C2=A0 'test-virtio-dmabuf': [meson.project_source_root() / 'h= w/display/virtio-dmabuf.c'],
=C2=A0}

=C2=A0if have_system or have_tools
diff --git a/tests/unit/test-virtio-dmabuf.c b/tests/unit/test-virtio-dmabu= f.c
new file mode 100644
index 0000000000..40fe262538
--- /dev/null
+++ b/tests/unit/test-virtio-dmabuf.c
@@ -0,0 +1,137 @@
+/*
+ * QEMU tests for shared dma-buf API
+ *
+ * Copyright (c) 2023 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.=C2=A0 See the GNU<= br> + * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/= licenses/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "hw/virtio/virtio-dmabuf.h"
+
+
+static void test_add_remove_resources(void)
+{
+=C2=A0 =C2=A0 QemuUUID uuid;
+=C2=A0 =C2=A0 int i, dmabuf_fd;
+
+=C2=A0 =C2=A0 for (i =3D 0; i < 100; ++i) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 qemu_uuid_generate(&uuid);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 dmabuf_fd =3D g_random_int_range(3, 500);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 /* Add a new resource */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 g_assert(virtio_add_dmabuf(&uuid, dmabuf_f= d));
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 g_assert_cmpint(virtio_lookup_dmabuf(&uuid= ), =3D=3D, dmabuf_fd);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 /* Remove the resource */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 g_assert(virtio_remove_resource(&uuid)); +=C2=A0 =C2=A0 =C2=A0 =C2=A0 /* Resource is not found anymore */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 g_assert_cmpint(virtio_lookup_dmabuf(&uuid= ), =3D=3D, -1);
+=C2=A0 =C2=A0 }
+}
+
+static void test_add_remove_dev(void)
+{
+=C2=A0 =C2=A0 QemuUUID uuid;
+=C2=A0 =C2=A0 struct vhost_dev *dev =3D g_new0(struct vhost_dev, 1);
+=C2=A0 =C2=A0 int i;
+
+=C2=A0 =C2=A0 for (i =3D 0; i < 100; ++i) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 qemu_uuid_generate(&uuid);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 virtio_add_vhost_device(&uuid, dev);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 /* vhost device is found */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 g_assert(virtio_lookup_vhost_device(&uuid)= !=3D NULL);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 /* Remove the vhost device */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 g_assert(virtio_remove_resource(&uuid)); +=C2=A0 =C2=A0 =C2=A0 =C2=A0 /* vhost device is not found anymore */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 g_assert(virtio_lookup_vhost_device(&uuid)= =3D=3D NULL);
+=C2=A0 =C2=A0 }
+=C2=A0 =C2=A0 g_free(dev);
+}
+
+static void test_remove_invalid_resource(void)
+{
+=C2=A0 =C2=A0 QemuUUID uuid;
+=C2=A0 =C2=A0 int i;
+
+=C2=A0 =C2=A0 for (i =3D 0; i < 20; ++i) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 qemu_uuid_generate(&uuid);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 g_assert_cmpint(virtio_lookup_dmabuf(&uuid= ), =3D=3D, -1);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 /* Removing a resource that does not exist ret= urns false */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 g_assert_false(virtio_remove_resource(&uui= d));
+=C2=A0 =C2=A0 }
+}
+
+static void test_add_invalid_resource(void)
+{
+=C2=A0 =C2=A0 QemuUUID uuid;
+=C2=A0 =C2=A0 struct vhost_dev *dev =3D NULL;
+=C2=A0 =C2=A0 int i, dmabuf_fd =3D -2, alt_dmabuf =3D 2;
+
+=C2=A0 =C2=A0 for (i =3D 0; i < 20; ++i) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 qemu_uuid_generate(&uuid);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 /* Add a new resource with invalid (negative) = resource fd */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 g_assert_false(virtio_add_dmabuf(&uuid, dm= abuf_fd));
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 /* Resource is not found */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 g_assert_cmpint(virtio_lookup_dmabuf(&uuid= ), =3D=3D, -1);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 /* Add a new vhost device with invalid (NULL) = pointer */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 g_assert_false(virtio_add_vhost_device(&uu= id, dev));
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 /* vhost device is not found */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 g_assert(virtio_lookup_vhost_device(&uuid)= =3D=3D NULL);
+=C2=A0 =C2=A0 }
+
+=C2=A0 =C2=A0 for (i =3D 0; i < 20; ++i) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 /* Add a valid resource */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 qemu_uuid_generate(&uuid);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 dmabuf_fd =3D g_random_int_range(3, 500);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 g_assert(virtio_add_dmabuf(&uuid, dmabuf_f= d));
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 g_assert_cmpint(virtio_lookup_dmabuf(&uuid= ), =3D=3D, dmabuf_fd);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 /* Add a new resource with repeated uuid retur= ns false */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 g_assert_false(virtio_add_dmabuf(&uuid, al= t_dmabuf));
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 /* The value for the uuid key is not replaced = */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 g_assert_cmpint(virtio_lookup_dmabuf(&uuid= ), =3D=3D, dmabuf_fd);
+=C2=A0 =C2=A0 }
+}
+
+static void test_free_resources(void)
+{
+=C2=A0 =C2=A0 QemuUUID uuids[20];
+=C2=A0 =C2=A0 int i, dmabuf_fd;
+
+=C2=A0 =C2=A0 for (i =3D 0; i < ARRAY_SIZE(uuids); ++i) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 qemu_uuid_generate(&uuids[i]);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 dmabuf_fd =3D g_random_int_range(3, 500);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 g_assert(virtio_add_dmabuf(&uuids[i], dmab= uf_fd));
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 g_assert_cmpint(virtio_lookup_dmabuf(&uuid= s[i]), =3D=3D, dmabuf_fd);
+=C2=A0 =C2=A0 }
+=C2=A0 =C2=A0 virtio_free_resources();
+=C2=A0 =C2=A0 for (i =3D 0; i < ARRAY_SIZE(uuids); ++i) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 /* None of the resources is found after free&#= 39;d */
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 g_assert_cmpint(virtio_lookup_dmabuf(&uuid= s[i]), =3D=3D, -1);
+=C2=A0 =C2=A0 }
+
+}
+
+int main(int argc, char **argv)
+{
+=C2=A0 =C2=A0 g_test_init(&argc, &argv, NULL);
+=C2=A0 =C2=A0 g_test_add_func("/virtio-dmabuf/add_rm_res", test_= add_remove_resources);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 g_test_add_func("/virtio-dmabuf/add_rm_de= v", test_add_remove_dev);
+=C2=A0 =C2=A0 g_test_add_func("/virtio-dmabuf/rm_invalid_res", +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 test= _remove_invalid_resource);
+=C2=A0 =C2=A0 g_test_add_func("/virtio-dmabuf/add_invalid_res",<= br> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 test= _add_invalid_resource);
+=C2=A0 =C2=A0 g_test_add_func("/virtio-dmabuf/free_res", test_fr= ee_resources);
+
+=C2=A0 =C2=A0 return g_test_run();
+}
--
2.41.0

--0000000000008065950604af8763--