1 /*
2 * Virtio Shared dma-buf
3 *
4 * Copyright Red Hat, Inc. 2023
5 *
6 * Authors:
7 * Albert Esteve <aesteve@redhat.com>
8 *
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
11 */
12
13 #include "qemu/osdep.h"
14
15 #include "hw/virtio/virtio-dmabuf.h"
16
17
18 static GMutex lock;
19 static GHashTable *resource_uuids;
20
21 /*
22 * uuid_equal_func: wrapper for UUID is_equal function to
23 * satisfy g_hash_table_new expected parameters signatures.
24 */
uuid_equal_func(const void * lhv,const void * rhv)25 static int uuid_equal_func(const void *lhv, const void *rhv)
26 {
27 return qemu_uuid_is_equal(lhv, rhv);
28 }
29
virtio_add_resource(QemuUUID * uuid,VirtioSharedObject * value)30 static bool virtio_add_resource(QemuUUID *uuid, VirtioSharedObject *value)
31 {
32 bool result = true;
33
34 g_mutex_lock(&lock);
35 if (resource_uuids == NULL) {
36 resource_uuids = g_hash_table_new_full(qemu_uuid_hash,
37 uuid_equal_func,
38 NULL,
39 g_free);
40 }
41 if (g_hash_table_lookup(resource_uuids, uuid) == NULL) {
42 g_hash_table_insert(resource_uuids, uuid, value);
43 } else {
44 result = false;
45 }
46 g_mutex_unlock(&lock);
47
48 return result;
49 }
50
virtio_add_dmabuf(QemuUUID * uuid,int udmabuf_fd)51 bool virtio_add_dmabuf(QemuUUID *uuid, int udmabuf_fd)
52 {
53 bool result;
54 VirtioSharedObject *vso;
55 if (udmabuf_fd < 0) {
56 return false;
57 }
58 vso = g_new(VirtioSharedObject, 1);
59 vso->type = TYPE_DMABUF;
60 vso->value = GINT_TO_POINTER(udmabuf_fd);
61 result = virtio_add_resource(uuid, vso);
62 if (!result) {
63 g_free(vso);
64 }
65
66 return result;
67 }
68
virtio_add_vhost_device(QemuUUID * uuid,struct vhost_dev * dev)69 bool virtio_add_vhost_device(QemuUUID *uuid, struct vhost_dev *dev)
70 {
71 bool result;
72 VirtioSharedObject *vso;
73 if (dev == NULL) {
74 return false;
75 }
76 vso = g_new(VirtioSharedObject, 1);
77 vso->type = TYPE_VHOST_DEV;
78 vso->value = dev;
79 result = virtio_add_resource(uuid, vso);
80 if (!result) {
81 g_free(vso);
82 }
83
84 return result;
85 }
86
virtio_remove_resource(const QemuUUID * uuid)87 bool virtio_remove_resource(const QemuUUID *uuid)
88 {
89 bool result;
90 g_mutex_lock(&lock);
91 result = g_hash_table_remove(resource_uuids, uuid);
92 g_mutex_unlock(&lock);
93
94 return result;
95 }
96
get_shared_object(const QemuUUID * uuid)97 static VirtioSharedObject *get_shared_object(const QemuUUID *uuid)
98 {
99 gpointer lookup_res = NULL;
100
101 g_mutex_lock(&lock);
102 if (resource_uuids != NULL) {
103 lookup_res = g_hash_table_lookup(resource_uuids, uuid);
104 }
105 g_mutex_unlock(&lock);
106
107 return (VirtioSharedObject *) lookup_res;
108 }
109
virtio_lookup_dmabuf(const QemuUUID * uuid)110 int virtio_lookup_dmabuf(const QemuUUID *uuid)
111 {
112 VirtioSharedObject *vso = get_shared_object(uuid);
113 if (vso == NULL) {
114 return -1;
115 }
116 assert(vso->type == TYPE_DMABUF);
117 return GPOINTER_TO_INT(vso->value);
118 }
119
virtio_lookup_vhost_device(const QemuUUID * uuid)120 struct vhost_dev *virtio_lookup_vhost_device(const QemuUUID *uuid)
121 {
122 VirtioSharedObject *vso = get_shared_object(uuid);
123 if (vso == NULL) {
124 return NULL;
125 }
126 assert(vso->type == TYPE_VHOST_DEV);
127 return (struct vhost_dev *) vso->value;
128 }
129
virtio_object_type(const QemuUUID * uuid)130 SharedObjectType virtio_object_type(const QemuUUID *uuid)
131 {
132 VirtioSharedObject *vso = get_shared_object(uuid);
133 if (vso == NULL) {
134 return TYPE_INVALID;
135 }
136 return vso->type;
137 }
138
virtio_free_resources(void)139 void virtio_free_resources(void)
140 {
141 g_mutex_lock(&lock);
142 g_hash_table_destroy(resource_uuids);
143 /* Reference count shall be 0 after the implicit unref on destroy */
144 resource_uuids = NULL;
145 g_mutex_unlock(&lock);
146 }
147