xref: /openbmc/qemu/util/yank.c (revision 25d75c99)
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 
yank_instance_equal(const YankInstance * a,const YankInstance * b)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 
yank_find_entry(const YankInstance * instance)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 
yank_register_instance(const YankInstance * instance,Error ** errp)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 
yank_unregister_instance(const YankInstance * instance)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 
yank_register_function(const YankInstance * instance,YankFn * func,void * opaque)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 
yank_unregister_function(const YankInstance * instance,YankFn * func,void * opaque)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 
qmp_yank(YankInstanceList * instances,Error ** errp)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 
qmp_query_yank(Error ** errp)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 
yank_init(void)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