]> Git Repo - qemu.git/blob - tests/libqos/libqos.c
ide: fix invalid TRIM range abortion for macio
[qemu.git] / tests / libqos / libqos.c
1 #include "qemu/osdep.h"
2 #include <sys/wait.h>
3
4 #include "libqtest.h"
5 #include "libqos/libqos.h"
6 #include "libqos/pci.h"
7 #include "qapi/qmp/qdict.h"
8
9 /*** Test Setup & Teardown ***/
10
11 /**
12  * Launch QEMU with the given command line,
13  * and then set up interrupts and our guest malloc interface.
14  * Never returns NULL:
15  * Terminates the application in case an error is encountered.
16  */
17 QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap)
18 {
19     char *cmdline;
20
21     QOSState *qs = g_new0(QOSState, 1);
22
23     cmdline = g_strdup_vprintf(cmdline_fmt, ap);
24     qs->qts = qtest_init(cmdline);
25     qs->ops = ops;
26     if (ops) {
27         qs->alloc = ops->init_allocator(qs->qts, ALLOC_NO_FLAGS);
28         qs->pcibus = ops->qpci_init(qs->qts, qs->alloc);
29     }
30
31     g_free(cmdline);
32     return qs;
33 }
34
35 /**
36  * Launch QEMU with the given command line,
37  * and then set up interrupts and our guest malloc interface.
38  */
39 QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...)
40 {
41     QOSState *qs;
42     va_list ap;
43
44     va_start(ap, cmdline_fmt);
45     qs = qtest_vboot(ops, cmdline_fmt, ap);
46     va_end(ap);
47
48     return qs;
49 }
50
51 /**
52  * Tear down the QEMU instance.
53  */
54 void qtest_common_shutdown(QOSState *qs)
55 {
56     if (qs->ops) {
57         if (qs->pcibus && qs->ops->qpci_free) {
58             qs->ops->qpci_free(qs->pcibus);
59             qs->pcibus = NULL;
60         }
61         if (qs->alloc && qs->ops->uninit_allocator) {
62             qs->ops->uninit_allocator(qs->alloc);
63             qs->alloc = NULL;
64         }
65     }
66     qtest_quit(qs->qts);
67     g_free(qs);
68 }
69
70 void qtest_shutdown(QOSState *qs)
71 {
72     if (qs->ops && qs->ops->shutdown) {
73         qs->ops->shutdown(qs);
74     } else {
75         qtest_common_shutdown(qs);
76     }
77 }
78
79 void set_context(QOSState *s)
80 {
81     global_qtest = s->qts;
82 }
83
84 static QDict *qmp_execute(QTestState *qts, const char *command)
85 {
86     return qtest_qmp(qts, "{ 'execute': %s }", command);
87 }
88
89 void migrate(QOSState *from, QOSState *to, const char *uri)
90 {
91     const char *st;
92     QDict *rsp, *sub;
93     bool running;
94
95     set_context(from);
96
97     /* Is the machine currently running? */
98     rsp = qmp_execute(from->qts, "query-status");
99     g_assert(qdict_haskey(rsp, "return"));
100     sub = qdict_get_qdict(rsp, "return");
101     g_assert(qdict_haskey(sub, "running"));
102     running = qdict_get_bool(sub, "running");
103     QDECREF(rsp);
104
105     /* Issue the migrate command. */
106     rsp = qtest_qmp(from->qts,
107                     "{ 'execute': 'migrate', 'arguments': { 'uri': %s }}",
108                     uri);
109     g_assert(qdict_haskey(rsp, "return"));
110     QDECREF(rsp);
111
112     /* Wait for STOP event, but only if we were running: */
113     if (running) {
114         qtest_qmp_eventwait(from->qts, "STOP");
115     }
116
117     /* If we were running, we can wait for an event. */
118     if (running) {
119         migrate_allocator(from->alloc, to->alloc);
120         set_context(to);
121         qtest_qmp_eventwait(to->qts, "RESUME");
122         return;
123     }
124
125     /* Otherwise, we need to wait: poll until migration is completed. */
126     while (1) {
127         rsp = qmp_execute(from->qts, "query-migrate");
128         g_assert(qdict_haskey(rsp, "return"));
129         sub = qdict_get_qdict(rsp, "return");
130         g_assert(qdict_haskey(sub, "status"));
131         st = qdict_get_str(sub, "status");
132
133         /* "setup", "active", "completed", "failed", "cancelled" */
134         if (strcmp(st, "completed") == 0) {
135             QDECREF(rsp);
136             break;
137         }
138
139         if ((strcmp(st, "setup") == 0) || (strcmp(st, "active") == 0)) {
140             QDECREF(rsp);
141             g_usleep(5000);
142             continue;
143         }
144
145         fprintf(stderr, "Migration did not complete, status: %s\n", st);
146         g_assert_not_reached();
147     }
148
149     migrate_allocator(from->alloc, to->alloc);
150     set_context(to);
151 }
152
153 bool have_qemu_img(void)
154 {
155     char *rpath;
156     const char *path = getenv("QTEST_QEMU_IMG");
157     if (!path) {
158         return false;
159     }
160
161     rpath = realpath(path, NULL);
162     if (!rpath) {
163         return false;
164     } else {
165         free(rpath);
166         return true;
167     }
168 }
169
170 void mkimg(const char *file, const char *fmt, unsigned size_mb)
171 {
172     gchar *cli;
173     bool ret;
174     int rc;
175     GError *err = NULL;
176     char *qemu_img_path;
177     gchar *out, *out2;
178     char *qemu_img_abs_path;
179
180     qemu_img_path = getenv("QTEST_QEMU_IMG");
181     g_assert(qemu_img_path);
182     qemu_img_abs_path = realpath(qemu_img_path, NULL);
183     g_assert(qemu_img_abs_path);
184
185     cli = g_strdup_printf("%s create -f %s %s %uM", qemu_img_abs_path,
186                           fmt, file, size_mb);
187     ret = g_spawn_command_line_sync(cli, &out, &out2, &rc, &err);
188     if (err) {
189         fprintf(stderr, "%s\n", err->message);
190         g_error_free(err);
191     }
192     g_assert(ret && !err);
193
194     /* In glib 2.34, we have g_spawn_check_exit_status. in 2.12, we don't.
195      * glib 2.43.91 implementation assumes that any non-zero is an error for
196      * windows, but uses extra precautions for Linux. However,
197      * 0 is only possible if the program exited normally, so that should be
198      * sufficient for our purposes on all platforms, here. */
199     if (rc) {
200         fprintf(stderr, "qemu-img returned status code %d\n", rc);
201     }
202     g_assert(!rc);
203
204     g_free(out);
205     g_free(out2);
206     g_free(cli);
207     free(qemu_img_abs_path);
208 }
209
210 void mkqcow2(const char *file, unsigned size_mb)
211 {
212     return mkimg(file, "qcow2", size_mb);
213 }
214
215 void prepare_blkdebug_script(const char *debug_fn, const char *event)
216 {
217     FILE *debug_file = fopen(debug_fn, "w");
218     int ret;
219
220     fprintf(debug_file, "[inject-error]\n");
221     fprintf(debug_file, "event = \"%s\"\n", event);
222     fprintf(debug_file, "errno = \"5\"\n");
223     fprintf(debug_file, "state = \"1\"\n");
224     fprintf(debug_file, "immediately = \"off\"\n");
225     fprintf(debug_file, "once = \"on\"\n");
226
227     fprintf(debug_file, "[set-state]\n");
228     fprintf(debug_file, "event = \"%s\"\n", event);
229     fprintf(debug_file, "new_state = \"2\"\n");
230     fflush(debug_file);
231     g_assert(!ferror(debug_file));
232
233     ret = fclose(debug_file);
234     g_assert(ret == 0);
235 }
236
237 void generate_pattern(void *buffer, size_t len, size_t cycle_len)
238 {
239     int i, j;
240     unsigned char *tx = (unsigned char *)buffer;
241     unsigned char p;
242     size_t *sx;
243
244     /* Write an indicative pattern that varies and is unique per-cycle */
245     p = rand() % 256;
246     for (i = 0; i < len; i++) {
247         tx[i] = p++ % 256;
248         if (i % cycle_len == 0) {
249             p = rand() % 256;
250         }
251     }
252
253     /* force uniqueness by writing an id per-cycle */
254     for (i = 0; i < len / cycle_len; i++) {
255         j = i * cycle_len;
256         if (j + sizeof(*sx) <= len) {
257             sx = (size_t *)&tx[j];
258             *sx = i;
259         }
260     }
261 }
This page took 0.039049 seconds and 4 git commands to generate.