1#include "qemu/osdep.h"
2#include <glib.h>
3#include <sys/wait.h>
4
5#include "libqtest.h"
6#include "libqos/libqos.h"
7#include "libqos/pci.h"
8
9
10
11
12
13
14
15QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap)
16{
17 char *cmdline;
18
19 struct QOSState *qs = g_malloc(sizeof(QOSState));
20
21 cmdline = g_strdup_vprintf(cmdline_fmt, ap);
22 qs->qts = qtest_start(cmdline);
23 qs->ops = ops;
24 qtest_irq_intercept_in(global_qtest, "ioapic");
25 if (ops && ops->init_allocator) {
26 qs->alloc = ops->init_allocator(ALLOC_NO_FLAGS);
27 }
28
29 g_free(cmdline);
30 return qs;
31}
32
33
34
35
36
37QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...)
38{
39 QOSState *qs;
40 va_list ap;
41
42 va_start(ap, cmdline_fmt);
43 qs = qtest_vboot(ops, cmdline_fmt, ap);
44 va_end(ap);
45
46 return qs;
47}
48
49
50
51
52void qtest_shutdown(QOSState *qs)
53{
54 if (qs->alloc && qs->ops && qs->ops->uninit_allocator) {
55 qs->ops->uninit_allocator(qs->alloc);
56 qs->alloc = NULL;
57 }
58 qtest_quit(qs->qts);
59 g_free(qs);
60}
61
62void set_context(QOSState *s)
63{
64 global_qtest = s->qts;
65}
66
67static QDict *qmp_execute(const char *command)
68{
69 char *fmt;
70 QDict *rsp;
71
72 fmt = g_strdup_printf("{ 'execute': '%s' }", command);
73 rsp = qmp(fmt);
74 g_free(fmt);
75
76 return rsp;
77}
78
79void migrate(QOSState *from, QOSState *to, const char *uri)
80{
81 const char *st;
82 char *s;
83 QDict *rsp, *sub;
84 bool running;
85
86 set_context(from);
87
88
89 rsp = qmp_execute("query-status");
90 g_assert(qdict_haskey(rsp, "return"));
91 sub = qdict_get_qdict(rsp, "return");
92 g_assert(qdict_haskey(sub, "running"));
93 running = qdict_get_bool(sub, "running");
94 QDECREF(rsp);
95
96
97 s = g_strdup_printf("{ 'execute': 'migrate',"
98 "'arguments': { 'uri': '%s' } }",
99 uri);
100 rsp = qmp(s);
101 g_free(s);
102 g_assert(qdict_haskey(rsp, "return"));
103 QDECREF(rsp);
104
105
106 if (running) {
107 qmp_eventwait("STOP");
108 }
109
110
111 if (running) {
112 migrate_allocator(from->alloc, to->alloc);
113 set_context(to);
114 qmp_eventwait("RESUME");
115 return;
116 }
117
118
119 while (1) {
120 rsp = qmp_execute("query-migrate");
121 g_assert(qdict_haskey(rsp, "return"));
122 sub = qdict_get_qdict(rsp, "return");
123 g_assert(qdict_haskey(sub, "status"));
124 st = qdict_get_str(sub, "status");
125
126
127 if (strcmp(st, "completed") == 0) {
128 QDECREF(rsp);
129 break;
130 }
131
132 if ((strcmp(st, "setup") == 0) || (strcmp(st, "active") == 0)) {
133 QDECREF(rsp);
134 g_usleep(5000);
135 continue;
136 }
137
138 fprintf(stderr, "Migration did not complete, status: %s\n", st);
139 g_assert_not_reached();
140 }
141
142 migrate_allocator(from->alloc, to->alloc);
143 set_context(to);
144}
145
146bool have_qemu_img(void)
147{
148 char *rpath;
149 const char *path = getenv("QTEST_QEMU_IMG");
150 if (!path) {
151 return false;
152 }
153
154 rpath = realpath(path, NULL);
155 if (!rpath) {
156 return false;
157 } else {
158 free(rpath);
159 return true;
160 }
161}
162
163void mkimg(const char *file, const char *fmt, unsigned size_mb)
164{
165 gchar *cli;
166 bool ret;
167 int rc;
168 GError *err = NULL;
169 char *qemu_img_path;
170 gchar *out, *out2;
171 char *qemu_img_abs_path;
172
173 qemu_img_path = getenv("QTEST_QEMU_IMG");
174 g_assert(qemu_img_path);
175 qemu_img_abs_path = realpath(qemu_img_path, NULL);
176 g_assert(qemu_img_abs_path);
177
178 cli = g_strdup_printf("%s create -f %s %s %uM", qemu_img_abs_path,
179 fmt, file, size_mb);
180 ret = g_spawn_command_line_sync(cli, &out, &out2, &rc, &err);
181 if (err) {
182 fprintf(stderr, "%s\n", err->message);
183 g_error_free(err);
184 }
185 g_assert(ret && !err);
186
187
188
189
190
191
192 if (rc) {
193 fprintf(stderr, "qemu-img returned status code %d\n", rc);
194 }
195 g_assert(!rc);
196
197 g_free(out);
198 g_free(out2);
199 g_free(cli);
200 free(qemu_img_abs_path);
201}
202
203void mkqcow2(const char *file, unsigned size_mb)
204{
205 return mkimg(file, "qcow2", size_mb);
206}
207
208void prepare_blkdebug_script(const char *debug_fn, const char *event)
209{
210 FILE *debug_file = fopen(debug_fn, "w");
211 int ret;
212
213 fprintf(debug_file, "[inject-error]\n");
214 fprintf(debug_file, "event = \"%s\"\n", event);
215 fprintf(debug_file, "errno = \"5\"\n");
216 fprintf(debug_file, "state = \"1\"\n");
217 fprintf(debug_file, "immediately = \"off\"\n");
218 fprintf(debug_file, "once = \"on\"\n");
219
220 fprintf(debug_file, "[set-state]\n");
221 fprintf(debug_file, "event = \"%s\"\n", event);
222 fprintf(debug_file, "new_state = \"2\"\n");
223 fflush(debug_file);
224 g_assert(!ferror(debug_file));
225
226 ret = fclose(debug_file);
227 g_assert(ret == 0);
228}
229
230void generate_pattern(void *buffer, size_t len, size_t cycle_len)
231{
232 int i, j;
233 unsigned char *tx = (unsigned char *)buffer;
234 unsigned char p;
235 size_t *sx;
236
237
238 p = rand() % 256;
239 for (i = 0; i < len; i++) {
240 tx[i] = p++ % 256;
241 if (i % cycle_len == 0) {
242 p = rand() % 256;
243 }
244 }
245
246
247 for (i = 0; i < len / cycle_len; i++) {
248 j = i * cycle_len;
249 if (j + sizeof(*sx) <= len) {
250 sx = (size_t *)&tx[j];
251 *sx = i;
252 }
253 }
254}
255