1*50186051SLukas Straub /* 2*50186051SLukas Straub * QEMU yank feature 3*50186051SLukas Straub * 4*50186051SLukas Straub * Copyright (c) Lukas Straub <lukasstraub2@web.de> 5*50186051SLukas Straub * 6*50186051SLukas Straub * This work is licensed under the terms of the GNU GPL, version 2 or later. 7*50186051SLukas Straub * See the COPYING file in the top-level directory. 8*50186051SLukas Straub */ 9*50186051SLukas Straub 10*50186051SLukas Straub #include "qemu/osdep.h" 11*50186051SLukas Straub #include "qapi/error.h" 12*50186051SLukas Straub #include "qemu/thread.h" 13*50186051SLukas Straub #include "qemu/queue.h" 14*50186051SLukas Straub #include "qemu/lockable.h" 15*50186051SLukas Straub #include "qapi/qapi-commands-yank.h" 16*50186051SLukas Straub #include "qapi/qapi-visit-yank.h" 17*50186051SLukas Straub #include "qapi/clone-visitor.h" 18*50186051SLukas Straub #include "qemu/yank.h" 19*50186051SLukas Straub 20*50186051SLukas Straub struct YankFuncAndParam { 21*50186051SLukas Straub YankFn *func; 22*50186051SLukas Straub void *opaque; 23*50186051SLukas Straub QLIST_ENTRY(YankFuncAndParam) next; 24*50186051SLukas Straub }; 25*50186051SLukas Straub 26*50186051SLukas Straub struct YankInstanceEntry { 27*50186051SLukas Straub YankInstance *instance; 28*50186051SLukas Straub QLIST_HEAD(, YankFuncAndParam) yankfns; 29*50186051SLukas Straub QLIST_ENTRY(YankInstanceEntry) next; 30*50186051SLukas Straub }; 31*50186051SLukas Straub 32*50186051SLukas Straub typedef struct YankFuncAndParam YankFuncAndParam; 33*50186051SLukas Straub typedef struct YankInstanceEntry YankInstanceEntry; 34*50186051SLukas Straub 35*50186051SLukas Straub /* 36*50186051SLukas Straub * This lock protects the yank_instance_list below. Because it's taken by 37*50186051SLukas Straub * OOB-capable commands, it must be "fast", i.e. it may only be held for a 38*50186051SLukas Straub * bounded, short time. See docs/devel/qapi-code-gen.txt for additional 39*50186051SLukas Straub * information. 40*50186051SLukas Straub */ 41*50186051SLukas Straub static QemuMutex yank_lock; 42*50186051SLukas Straub 43*50186051SLukas Straub static QLIST_HEAD(, YankInstanceEntry) yank_instance_list 44*50186051SLukas Straub = QLIST_HEAD_INITIALIZER(yank_instance_list); 45*50186051SLukas Straub 46*50186051SLukas Straub static bool yank_instance_equal(const YankInstance *a, const YankInstance *b) 47*50186051SLukas Straub { 48*50186051SLukas Straub if (a->type != b->type) { 49*50186051SLukas Straub return false; 50*50186051SLukas Straub } 51*50186051SLukas Straub 52*50186051SLukas Straub switch (a->type) { 53*50186051SLukas Straub case YANK_INSTANCE_TYPE_BLOCK_NODE: 54*50186051SLukas Straub return g_str_equal(a->u.block_node.node_name, 55*50186051SLukas Straub b->u.block_node.node_name); 56*50186051SLukas Straub 57*50186051SLukas Straub case YANK_INSTANCE_TYPE_CHARDEV: 58*50186051SLukas Straub return g_str_equal(a->u.chardev.id, b->u.chardev.id); 59*50186051SLukas Straub 60*50186051SLukas Straub case YANK_INSTANCE_TYPE_MIGRATION: 61*50186051SLukas Straub return true; 62*50186051SLukas Straub 63*50186051SLukas Straub default: 64*50186051SLukas Straub abort(); 65*50186051SLukas Straub } 66*50186051SLukas Straub } 67*50186051SLukas Straub 68*50186051SLukas Straub static YankInstanceEntry *yank_find_entry(const YankInstance *instance) 69*50186051SLukas Straub { 70*50186051SLukas Straub YankInstanceEntry *entry; 71*50186051SLukas Straub 72*50186051SLukas Straub QLIST_FOREACH(entry, &yank_instance_list, next) { 73*50186051SLukas Straub if (yank_instance_equal(entry->instance, instance)) { 74*50186051SLukas Straub return entry; 75*50186051SLukas Straub } 76*50186051SLukas Straub } 77*50186051SLukas Straub return NULL; 78*50186051SLukas Straub } 79*50186051SLukas Straub 80*50186051SLukas Straub bool yank_register_instance(const YankInstance *instance, Error **errp) 81*50186051SLukas Straub { 82*50186051SLukas Straub YankInstanceEntry *entry; 83*50186051SLukas Straub 84*50186051SLukas Straub QEMU_LOCK_GUARD(&yank_lock); 85*50186051SLukas Straub 86*50186051SLukas Straub if (yank_find_entry(instance)) { 87*50186051SLukas Straub error_setg(errp, "duplicate yank instance"); 88*50186051SLukas Straub return false; 89*50186051SLukas Straub } 90*50186051SLukas Straub 91*50186051SLukas Straub entry = g_new0(YankInstanceEntry, 1); 92*50186051SLukas Straub entry->instance = QAPI_CLONE(YankInstance, instance); 93*50186051SLukas Straub QLIST_INIT(&entry->yankfns); 94*50186051SLukas Straub QLIST_INSERT_HEAD(&yank_instance_list, entry, next); 95*50186051SLukas Straub 96*50186051SLukas Straub return true; 97*50186051SLukas Straub } 98*50186051SLukas Straub 99*50186051SLukas Straub void yank_unregister_instance(const YankInstance *instance) 100*50186051SLukas Straub { 101*50186051SLukas Straub YankInstanceEntry *entry; 102*50186051SLukas Straub 103*50186051SLukas Straub QEMU_LOCK_GUARD(&yank_lock); 104*50186051SLukas Straub entry = yank_find_entry(instance); 105*50186051SLukas Straub assert(entry); 106*50186051SLukas Straub 107*50186051SLukas Straub assert(QLIST_EMPTY(&entry->yankfns)); 108*50186051SLukas Straub QLIST_REMOVE(entry, next); 109*50186051SLukas Straub qapi_free_YankInstance(entry->instance); 110*50186051SLukas Straub g_free(entry); 111*50186051SLukas Straub } 112*50186051SLukas Straub 113*50186051SLukas Straub void yank_register_function(const YankInstance *instance, 114*50186051SLukas Straub YankFn *func, 115*50186051SLukas Straub void *opaque) 116*50186051SLukas Straub { 117*50186051SLukas Straub YankInstanceEntry *entry; 118*50186051SLukas Straub YankFuncAndParam *func_entry; 119*50186051SLukas Straub 120*50186051SLukas Straub QEMU_LOCK_GUARD(&yank_lock); 121*50186051SLukas Straub entry = yank_find_entry(instance); 122*50186051SLukas Straub assert(entry); 123*50186051SLukas Straub 124*50186051SLukas Straub func_entry = g_new0(YankFuncAndParam, 1); 125*50186051SLukas Straub func_entry->func = func; 126*50186051SLukas Straub func_entry->opaque = opaque; 127*50186051SLukas Straub 128*50186051SLukas Straub QLIST_INSERT_HEAD(&entry->yankfns, func_entry, next); 129*50186051SLukas Straub } 130*50186051SLukas Straub 131*50186051SLukas Straub void yank_unregister_function(const YankInstance *instance, 132*50186051SLukas Straub YankFn *func, 133*50186051SLukas Straub void *opaque) 134*50186051SLukas Straub { 135*50186051SLukas Straub YankInstanceEntry *entry; 136*50186051SLukas Straub YankFuncAndParam *func_entry; 137*50186051SLukas Straub 138*50186051SLukas Straub QEMU_LOCK_GUARD(&yank_lock); 139*50186051SLukas Straub entry = yank_find_entry(instance); 140*50186051SLukas Straub assert(entry); 141*50186051SLukas Straub 142*50186051SLukas Straub QLIST_FOREACH(func_entry, &entry->yankfns, next) { 143*50186051SLukas Straub if (func_entry->func == func && func_entry->opaque == opaque) { 144*50186051SLukas Straub QLIST_REMOVE(func_entry, next); 145*50186051SLukas Straub g_free(func_entry); 146*50186051SLukas Straub return; 147*50186051SLukas Straub } 148*50186051SLukas Straub } 149*50186051SLukas Straub 150*50186051SLukas Straub abort(); 151*50186051SLukas Straub } 152*50186051SLukas Straub 153*50186051SLukas Straub void qmp_yank(YankInstanceList *instances, 154*50186051SLukas Straub Error **errp) 155*50186051SLukas Straub { 156*50186051SLukas Straub YankInstanceList *tail; 157*50186051SLukas Straub YankInstanceEntry *entry; 158*50186051SLukas Straub YankFuncAndParam *func_entry; 159*50186051SLukas Straub 160*50186051SLukas Straub QEMU_LOCK_GUARD(&yank_lock); 161*50186051SLukas Straub for (tail = instances; tail; tail = tail->next) { 162*50186051SLukas Straub entry = yank_find_entry(tail->value); 163*50186051SLukas Straub if (!entry) { 164*50186051SLukas Straub error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, "Instance not found"); 165*50186051SLukas Straub return; 166*50186051SLukas Straub } 167*50186051SLukas Straub } 168*50186051SLukas Straub for (tail = instances; tail; tail = tail->next) { 169*50186051SLukas Straub entry = yank_find_entry(tail->value); 170*50186051SLukas Straub assert(entry); 171*50186051SLukas Straub QLIST_FOREACH(func_entry, &entry->yankfns, next) { 172*50186051SLukas Straub func_entry->func(func_entry->opaque); 173*50186051SLukas Straub } 174*50186051SLukas Straub } 175*50186051SLukas Straub } 176*50186051SLukas Straub 177*50186051SLukas Straub YankInstanceList *qmp_query_yank(Error **errp) 178*50186051SLukas Straub { 179*50186051SLukas Straub YankInstanceEntry *entry; 180*50186051SLukas Straub YankInstanceList *ret; 181*50186051SLukas Straub 182*50186051SLukas Straub ret = NULL; 183*50186051SLukas Straub 184*50186051SLukas Straub QEMU_LOCK_GUARD(&yank_lock); 185*50186051SLukas Straub QLIST_FOREACH(entry, &yank_instance_list, next) { 186*50186051SLukas Straub YankInstanceList *new_entry; 187*50186051SLukas Straub new_entry = g_new0(YankInstanceList, 1); 188*50186051SLukas Straub new_entry->value = QAPI_CLONE(YankInstance, entry->instance); 189*50186051SLukas Straub new_entry->next = ret; 190*50186051SLukas Straub ret = new_entry; 191*50186051SLukas Straub } 192*50186051SLukas Straub 193*50186051SLukas Straub return ret; 194*50186051SLukas Straub } 195*50186051SLukas Straub 196*50186051SLukas Straub static void __attribute__((__constructor__)) yank_init(void) 197*50186051SLukas Straub { 198*50186051SLukas Straub qemu_mutex_init(&yank_lock); 199*50186051SLukas Straub } 200