150186051SLukas Straub /*
250186051SLukas Straub * QEMU yank feature
350186051SLukas Straub *
450186051SLukas Straub * Copyright (c) Lukas Straub <lukasstraub2@web.de>
550186051SLukas Straub *
650186051SLukas Straub * This work is licensed under the terms of the GNU GPL, version 2 or later.
750186051SLukas Straub * See the COPYING file in the top-level directory.
850186051SLukas Straub */
950186051SLukas Straub
1050186051SLukas Straub #include "qemu/osdep.h"
1150186051SLukas Straub #include "qapi/error.h"
1250186051SLukas Straub #include "qemu/thread.h"
1350186051SLukas Straub #include "qemu/queue.h"
1450186051SLukas Straub #include "qemu/lockable.h"
1550186051SLukas Straub #include "qapi/qapi-commands-yank.h"
1650186051SLukas Straub #include "qapi/qapi-visit-yank.h"
1750186051SLukas Straub #include "qapi/clone-visitor.h"
1850186051SLukas Straub #include "qemu/yank.h"
1950186051SLukas Straub
2050186051SLukas Straub struct YankFuncAndParam {
2150186051SLukas Straub YankFn *func;
2250186051SLukas Straub void *opaque;
2350186051SLukas Straub QLIST_ENTRY(YankFuncAndParam) next;
2450186051SLukas Straub };
2550186051SLukas Straub
2650186051SLukas Straub struct YankInstanceEntry {
2750186051SLukas Straub YankInstance *instance;
2850186051SLukas Straub QLIST_HEAD(, YankFuncAndParam) yankfns;
2950186051SLukas Straub QLIST_ENTRY(YankInstanceEntry) next;
3050186051SLukas Straub };
3150186051SLukas Straub
3250186051SLukas Straub typedef struct YankFuncAndParam YankFuncAndParam;
3350186051SLukas Straub typedef struct YankInstanceEntry YankInstanceEntry;
3450186051SLukas Straub
3550186051SLukas Straub /*
3650186051SLukas Straub * This lock protects the yank_instance_list below. Because it's taken by
3750186051SLukas Straub * OOB-capable commands, it must be "fast", i.e. it may only be held for a
38*b0b1313eSMarkus Armbruster * bounded, short time. See docs/devel/qapi-code-gen.rst for additional
3950186051SLukas Straub * information.
4050186051SLukas Straub */
4150186051SLukas Straub static QemuMutex yank_lock;
4250186051SLukas Straub
4350186051SLukas Straub static QLIST_HEAD(, YankInstanceEntry) yank_instance_list
4450186051SLukas Straub = QLIST_HEAD_INITIALIZER(yank_instance_list);
4550186051SLukas Straub
yank_instance_equal(const YankInstance * a,const YankInstance * b)4650186051SLukas Straub static bool yank_instance_equal(const YankInstance *a, const YankInstance *b)
4750186051SLukas Straub {
4850186051SLukas Straub if (a->type != b->type) {
4950186051SLukas Straub return false;
5050186051SLukas Straub }
5150186051SLukas Straub
5250186051SLukas Straub switch (a->type) {
5350186051SLukas Straub case YANK_INSTANCE_TYPE_BLOCK_NODE:
5450186051SLukas Straub return g_str_equal(a->u.block_node.node_name,
5550186051SLukas Straub b->u.block_node.node_name);
5650186051SLukas Straub
5750186051SLukas Straub case YANK_INSTANCE_TYPE_CHARDEV:
5850186051SLukas Straub return g_str_equal(a->u.chardev.id, b->u.chardev.id);
5950186051SLukas Straub
6050186051SLukas Straub case YANK_INSTANCE_TYPE_MIGRATION:
6150186051SLukas Straub return true;
6250186051SLukas Straub
6350186051SLukas Straub default:
6450186051SLukas Straub abort();
6550186051SLukas Straub }
6650186051SLukas Straub }
6750186051SLukas Straub
yank_find_entry(const YankInstance * instance)6850186051SLukas Straub static YankInstanceEntry *yank_find_entry(const YankInstance *instance)
6950186051SLukas Straub {
7050186051SLukas Straub YankInstanceEntry *entry;
7150186051SLukas Straub
7250186051SLukas Straub QLIST_FOREACH(entry, &yank_instance_list, next) {
7350186051SLukas Straub if (yank_instance_equal(entry->instance, instance)) {
7450186051SLukas Straub return entry;
7550186051SLukas Straub }
7650186051SLukas Straub }
7750186051SLukas Straub return NULL;
7850186051SLukas Straub }
7950186051SLukas Straub
yank_register_instance(const YankInstance * instance,Error ** errp)8050186051SLukas Straub bool yank_register_instance(const YankInstance *instance, Error **errp)
8150186051SLukas Straub {
8250186051SLukas Straub YankInstanceEntry *entry;
8350186051SLukas Straub
8450186051SLukas Straub QEMU_LOCK_GUARD(&yank_lock);
8550186051SLukas Straub
8650186051SLukas Straub if (yank_find_entry(instance)) {
8750186051SLukas Straub error_setg(errp, "duplicate yank instance");
8850186051SLukas Straub return false;
8950186051SLukas Straub }
9050186051SLukas Straub
9150186051SLukas Straub entry = g_new0(YankInstanceEntry, 1);
9250186051SLukas Straub entry->instance = QAPI_CLONE(YankInstance, instance);
9350186051SLukas Straub QLIST_INIT(&entry->yankfns);
9450186051SLukas Straub QLIST_INSERT_HEAD(&yank_instance_list, entry, next);
9550186051SLukas Straub
9650186051SLukas Straub return true;
9750186051SLukas Straub }
9850186051SLukas Straub
yank_unregister_instance(const YankInstance * instance)9950186051SLukas Straub void yank_unregister_instance(const YankInstance *instance)
10050186051SLukas Straub {
10150186051SLukas Straub YankInstanceEntry *entry;
10250186051SLukas Straub
10350186051SLukas Straub QEMU_LOCK_GUARD(&yank_lock);
10450186051SLukas Straub entry = yank_find_entry(instance);
10550186051SLukas Straub assert(entry);
10650186051SLukas Straub
10750186051SLukas Straub assert(QLIST_EMPTY(&entry->yankfns));
10850186051SLukas Straub QLIST_REMOVE(entry, next);
10950186051SLukas Straub qapi_free_YankInstance(entry->instance);
11050186051SLukas Straub g_free(entry);
11150186051SLukas Straub }
11250186051SLukas Straub
yank_register_function(const YankInstance * instance,YankFn * func,void * opaque)11350186051SLukas Straub void yank_register_function(const YankInstance *instance,
11450186051SLukas Straub YankFn *func,
11550186051SLukas Straub void *opaque)
11650186051SLukas Straub {
11750186051SLukas Straub YankInstanceEntry *entry;
11850186051SLukas Straub YankFuncAndParam *func_entry;
11950186051SLukas Straub
12050186051SLukas Straub QEMU_LOCK_GUARD(&yank_lock);
12150186051SLukas Straub entry = yank_find_entry(instance);
12250186051SLukas Straub assert(entry);
12350186051SLukas Straub
12450186051SLukas Straub func_entry = g_new0(YankFuncAndParam, 1);
12550186051SLukas Straub func_entry->func = func;
12650186051SLukas Straub func_entry->opaque = opaque;
12750186051SLukas Straub
12850186051SLukas Straub QLIST_INSERT_HEAD(&entry->yankfns, func_entry, next);
12950186051SLukas Straub }
13050186051SLukas Straub
yank_unregister_function(const YankInstance * instance,YankFn * func,void * opaque)13150186051SLukas Straub void yank_unregister_function(const YankInstance *instance,
13250186051SLukas Straub YankFn *func,
13350186051SLukas Straub void *opaque)
13450186051SLukas Straub {
13550186051SLukas Straub YankInstanceEntry *entry;
13650186051SLukas Straub YankFuncAndParam *func_entry;
13750186051SLukas Straub
13850186051SLukas Straub QEMU_LOCK_GUARD(&yank_lock);
13950186051SLukas Straub entry = yank_find_entry(instance);
14050186051SLukas Straub assert(entry);
14150186051SLukas Straub
14250186051SLukas Straub QLIST_FOREACH(func_entry, &entry->yankfns, next) {
14350186051SLukas Straub if (func_entry->func == func && func_entry->opaque == opaque) {
14450186051SLukas Straub QLIST_REMOVE(func_entry, next);
14550186051SLukas Straub g_free(func_entry);
14650186051SLukas Straub return;
14750186051SLukas Straub }
14850186051SLukas Straub }
14950186051SLukas Straub
15050186051SLukas Straub abort();
15150186051SLukas Straub }
15250186051SLukas Straub
qmp_yank(YankInstanceList * instances,Error ** errp)15350186051SLukas Straub void qmp_yank(YankInstanceList *instances,
15450186051SLukas Straub Error **errp)
15550186051SLukas Straub {
15650186051SLukas Straub YankInstanceList *tail;
15750186051SLukas Straub YankInstanceEntry *entry;
15850186051SLukas Straub YankFuncAndParam *func_entry;
15950186051SLukas Straub
16050186051SLukas Straub QEMU_LOCK_GUARD(&yank_lock);
16150186051SLukas Straub for (tail = instances; tail; tail = tail->next) {
16250186051SLukas Straub entry = yank_find_entry(tail->value);
16350186051SLukas Straub if (!entry) {
16450186051SLukas Straub error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, "Instance not found");
16550186051SLukas Straub return;
16650186051SLukas Straub }
16750186051SLukas Straub }
16850186051SLukas Straub for (tail = instances; tail; tail = tail->next) {
16950186051SLukas Straub entry = yank_find_entry(tail->value);
17050186051SLukas Straub assert(entry);
17150186051SLukas Straub QLIST_FOREACH(func_entry, &entry->yankfns, next) {
17250186051SLukas Straub func_entry->func(func_entry->opaque);
17350186051SLukas Straub }
17450186051SLukas Straub }
17550186051SLukas Straub }
17650186051SLukas Straub
qmp_query_yank(Error ** errp)17750186051SLukas Straub YankInstanceList *qmp_query_yank(Error **errp)
17850186051SLukas Straub {
17950186051SLukas Straub YankInstanceEntry *entry;
18050186051SLukas Straub YankInstanceList *ret;
18150186051SLukas Straub
18250186051SLukas Straub ret = NULL;
18350186051SLukas Straub
18450186051SLukas Straub QEMU_LOCK_GUARD(&yank_lock);
18550186051SLukas Straub QLIST_FOREACH(entry, &yank_instance_list, next) {
18650186051SLukas Straub YankInstanceList *new_entry;
18750186051SLukas Straub new_entry = g_new0(YankInstanceList, 1);
18850186051SLukas Straub new_entry->value = QAPI_CLONE(YankInstance, entry->instance);
18950186051SLukas Straub new_entry->next = ret;
19050186051SLukas Straub ret = new_entry;
19150186051SLukas Straub }
19250186051SLukas Straub
19350186051SLukas Straub return ret;
19450186051SLukas Straub }
19550186051SLukas Straub
yank_init(void)19650186051SLukas Straub static void __attribute__((__constructor__)) yank_init(void)
19750186051SLukas Straub {
19850186051SLukas Straub qemu_mutex_init(&yank_lock);
19950186051SLukas Straub }
200