1 /* 2 * Copyright (c) 2018 Citrix Systems Inc. 3 * 4 * This work is licensed under the terms of the GNU GPL, version 2 or later. 5 * See the COPYING file in the top-level directory. 6 */ 7 8 #include "qemu/osdep.h" 9 #include "qemu/error-report.h" 10 #include "qapi/error.h" 11 #include "hw/xen/xen-backend.h" 12 #include "hw/xen/xen-bus.h" 13 14 typedef struct XenBackendImpl { 15 const char *type; 16 XenBackendDeviceCreate create; 17 XenBackendDeviceDestroy destroy; 18 } XenBackendImpl; 19 20 struct XenBackendInstance { 21 QLIST_ENTRY(XenBackendInstance) entry; 22 const XenBackendImpl *impl; 23 XenBus *xenbus; 24 char *name; 25 XenDevice *xendev; 26 }; 27 28 static GHashTable *xen_backend_table_get(void) 29 { 30 static GHashTable *table; 31 32 if (table == NULL) { 33 table = g_hash_table_new(g_str_hash, g_str_equal); 34 } 35 36 return table; 37 } 38 39 static void xen_backend_table_add(XenBackendImpl *impl) 40 { 41 g_hash_table_insert(xen_backend_table_get(), (void *)impl->type, impl); 42 } 43 44 static const char **xen_backend_table_keys(unsigned int *count) 45 { 46 return (const char **)g_hash_table_get_keys_as_array( 47 xen_backend_table_get(), count); 48 } 49 50 static const XenBackendImpl *xen_backend_table_lookup(const char *type) 51 { 52 return g_hash_table_lookup(xen_backend_table_get(), type); 53 } 54 55 void xen_backend_register(const XenBackendInfo *info) 56 { 57 XenBackendImpl *impl = g_new0(XenBackendImpl, 1); 58 59 g_assert(info->type); 60 61 if (xen_backend_table_lookup(info->type)) { 62 error_report("attempt to register duplicate Xen backend type '%s'", 63 info->type); 64 abort(); 65 } 66 67 if (!info->create) { 68 error_report("backend type '%s' has no creator", info->type); 69 abort(); 70 } 71 72 impl->type = info->type; 73 impl->create = info->create; 74 impl->destroy = info->destroy; 75 76 xen_backend_table_add(impl); 77 } 78 79 const char **xen_backend_get_types(unsigned int *count) 80 { 81 return xen_backend_table_keys(count); 82 } 83 84 static QLIST_HEAD(, XenBackendInstance) backend_list; 85 86 static void xen_backend_list_add(XenBackendInstance *backend) 87 { 88 QLIST_INSERT_HEAD(&backend_list, backend, entry); 89 } 90 91 static XenBackendInstance *xen_backend_list_find(XenDevice *xendev) 92 { 93 XenBackendInstance *backend; 94 95 QLIST_FOREACH(backend, &backend_list, entry) { 96 if (backend->xendev == xendev) { 97 return backend; 98 } 99 } 100 101 return NULL; 102 } 103 104 bool xen_backend_exists(const char *type, const char *name) 105 { 106 const XenBackendImpl *impl = xen_backend_table_lookup(type); 107 XenBackendInstance *backend; 108 109 if (!impl) { 110 return false; 111 } 112 113 QLIST_FOREACH(backend, &backend_list, entry) { 114 if (backend->impl == impl && !strcmp(backend->name, name)) { 115 return true; 116 } 117 } 118 119 return false; 120 } 121 122 static void xen_backend_list_remove(XenBackendInstance *backend) 123 { 124 QLIST_REMOVE(backend, entry); 125 } 126 127 void xen_backend_device_create(XenBus *xenbus, const char *type, 128 const char *name, QDict *opts, Error **errp) 129 { 130 ERRP_GUARD(); 131 const XenBackendImpl *impl = xen_backend_table_lookup(type); 132 XenBackendInstance *backend; 133 134 if (!impl) { 135 return; 136 } 137 138 backend = g_new0(XenBackendInstance, 1); 139 backend->xenbus = xenbus; 140 backend->name = g_strdup(name); 141 142 impl->create(backend, opts, errp); 143 144 backend->impl = impl; 145 xen_backend_list_add(backend); 146 } 147 148 XenBus *xen_backend_get_bus(XenBackendInstance *backend) 149 { 150 return backend->xenbus; 151 } 152 153 const char *xen_backend_get_name(XenBackendInstance *backend) 154 { 155 return backend->name; 156 } 157 158 void xen_backend_set_device(XenBackendInstance *backend, 159 XenDevice *xendev) 160 { 161 g_assert(!backend->xendev); 162 backend->xendev = xendev; 163 } 164 165 XenDevice *xen_backend_get_device(XenBackendInstance *backend) 166 { 167 return backend->xendev; 168 } 169 170 171 bool xen_backend_try_device_destroy(XenDevice *xendev, Error **errp) 172 { 173 XenBackendInstance *backend = xen_backend_list_find(xendev); 174 const XenBackendImpl *impl; 175 176 if (!backend) { 177 return false; 178 } 179 180 impl = backend->impl; 181 if (backend->xendev) { 182 impl->destroy(backend, errp); 183 } 184 185 xen_backend_list_remove(backend); 186 g_free(backend->name); 187 g_free(backend); 188 189 return true; 190 } 191