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