xref: /openbmc/qemu/tests/qtest/drive_del-test.c (revision f0984d40)
1 /*
2  * blockdev.c test cases
3  *
4  * Copyright (C) 2013-2014 Red Hat Inc.
5  *
6  * Authors:
7  *  Stefan Hajnoczi <stefanha@redhat.com>
8  *
9  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
10  * See the COPYING.LIB file in the top-level directory.
11  */
12 
13 #include "qemu/osdep.h"
14 #include "libqtest.h"
15 #include "libqos/virtio.h"
16 #include "qapi/qmp/qdict.h"
17 #include "qapi/qmp/qlist.h"
18 
19 static const char *qvirtio_get_dev_type(void);
20 
21 static bool look_for_drive0(QTestState *qts, const char *command, const char *key)
22 {
23     QDict *response;
24     QList *ret;
25     QListEntry *entry;
26     bool found;
27 
28     response = qtest_qmp(qts, "{'execute': %s}", command);
29     g_assert(response && qdict_haskey(response, "return"));
30     ret = qdict_get_qlist(response, "return");
31 
32     found = false;
33     QLIST_FOREACH_ENTRY(ret, entry) {
34         QDict *entry_dict = qobject_to(QDict, entry->value);
35         if (!strcmp(qdict_get_str(entry_dict, key), "drive0")) {
36             found = true;
37             break;
38         }
39     }
40 
41     qobject_unref(response);
42     return found;
43 }
44 
45 /*
46  * This covers the possible absence of a device due to QEMU build
47  * options.
48  */
49 static bool has_device_builtin(const char *dev)
50 {
51     gchar *device = g_strdup_printf("%s-%s", dev, qvirtio_get_dev_type());
52     bool rc = qtest_has_device(device);
53 
54     g_free(device);
55     return rc;
56 }
57 
58 static bool has_drive(QTestState *qts)
59 {
60     return look_for_drive0(qts, "query-block", "device");
61 }
62 
63 static bool has_blockdev(QTestState *qts)
64 {
65     return look_for_drive0(qts, "query-named-block-nodes", "node-name");
66 }
67 
68 static void blockdev_add_with_media(QTestState *qts)
69 {
70     QDict *response;
71 
72     response = qtest_qmp(qts,
73                          "{ 'execute': 'blockdev-add',"
74                          "  'arguments': {"
75                          "      'driver': 'raw',"
76                          "      'node-name': 'drive0',"
77                          "      'file': {"
78                          "          'driver': 'null-co',"
79                          "          'read-zeroes': true"
80                          "      }"
81                          "  }"
82                          "}");
83 
84     g_assert(response);
85     g_assert(qdict_haskey(response, "return"));
86     qobject_unref(response);
87     g_assert(has_blockdev(qts));
88 }
89 
90 static void drive_add(QTestState *qts)
91 {
92     char *resp = qtest_hmp(qts, "drive_add 0 if=none,id=drive0");
93 
94     g_assert_cmpstr(resp, ==, "OK\r\n");
95     g_assert(has_drive(qts));
96     g_free(resp);
97 }
98 
99 static void drive_add_with_media(QTestState *qts)
100 {
101     char *resp = qtest_hmp(qts,
102                            "drive_add 0 if=none,id=drive0,file=null-co://,"
103                            "file.read-zeroes=on,format=raw");
104 
105     g_assert_cmpstr(resp, ==, "OK\r\n");
106     g_assert(has_drive(qts));
107     g_free(resp);
108 }
109 
110 static void drive_del(QTestState *qts)
111 {
112     char *resp;
113 
114     g_assert(has_drive(qts));
115     resp = qtest_hmp(qts, "drive_del drive0");
116     g_assert_cmpstr(resp, ==, "");
117     g_assert(!has_drive(qts));
118     g_free(resp);
119 }
120 
121 /*
122  * qvirtio_get_dev_type:
123  * Returns: the preferred virtio bus/device type for the current architecture.
124  * TODO: delete this
125  */
126 static const char *qvirtio_get_dev_type(void)
127 {
128     const char *arch = qtest_get_arch();
129 
130     if (g_str_equal(arch, "arm") || g_str_equal(arch, "aarch64")) {
131         return "device";  /* for virtio-mmio */
132     } else if (g_str_equal(arch, "s390x")) {
133         return "ccw";
134     } else {
135         return "pci";
136     }
137 }
138 
139 static void device_add(QTestState *qts)
140 {
141     g_autofree char *driver = g_strdup_printf("virtio-blk-%s",
142                                               qvirtio_get_dev_type());
143     QDict *response =
144                qtest_qmp(qts, "{'execute': 'device_add',"
145                               " 'arguments': {"
146                               "   'driver': %s,"
147                               "   'drive': 'drive0',"
148                               "   'id': 'dev0'"
149                               "}}", driver);
150     g_assert(response);
151     g_assert(qdict_haskey(response, "return"));
152     qobject_unref(response);
153 }
154 
155 static void device_del(QTestState *qts, bool and_reset)
156 {
157     QDict *response;
158 
159     qtest_qmp_device_del_send(qts, "dev0");
160 
161     if (and_reset) {
162         response = qtest_qmp(qts, "{'execute': 'system_reset' }");
163         g_assert(response);
164         g_assert(qdict_haskey(response, "return"));
165         qobject_unref(response);
166     }
167 
168     qtest_qmp_eventwait(qts, "DEVICE_DELETED");
169 }
170 
171 static void test_drive_without_dev(void)
172 {
173     QTestState *qts;
174 
175     /* Start with an empty drive */
176     qts = qtest_init("-drive if=none,id=drive0");
177 
178     /* Delete the drive */
179     drive_del(qts);
180 
181     /* Ensure re-adding the drive works - there should be no duplicate ID error
182      * because the old drive must be gone.
183      */
184     drive_add(qts);
185 
186     qtest_quit(qts);
187 }
188 
189 static void test_after_failed_device_add(void)
190 {
191     char driver[32];
192     QDict *response;
193     QTestState *qts;
194 
195     snprintf(driver, sizeof(driver), "virtio-blk-%s",
196              qvirtio_get_dev_type());
197 
198     qts = qtest_init("-drive if=none,id=drive0");
199 
200     /* Make device_add fail. If this leaks the virtio-blk device then a
201      * reference to drive0 will also be held (via qdev properties).
202      */
203     response = qtest_qmp(qts, "{'execute': 'device_add',"
204                               " 'arguments': {"
205                               "   'driver': %s,"
206                               "   'drive': 'drive0'"
207                               "}}", driver);
208     g_assert(response);
209     qmp_expect_error_and_unref(response, "GenericError");
210 
211     /* Delete the drive */
212     drive_del(qts);
213 
214     /* Try to re-add the drive.  This fails with duplicate IDs if a leaked
215      * virtio-blk device exists that holds a reference to the old drive0.
216      */
217     drive_add(qts);
218 
219     qtest_quit(qts);
220 }
221 
222 static void test_drive_del_device_del(void)
223 {
224     QTestState *qts;
225 
226     if (!has_device_builtin("virtio-scsi")) {
227         g_test_skip("Device virtio-scsi is not available");
228         return;
229     }
230 
231     /* Start with a drive used by a device that unplugs instantaneously */
232     qts = qtest_initf("-drive if=none,id=drive0,file=null-co://,"
233                       "file.read-zeroes=on,format=raw"
234                       " -device virtio-scsi-%s"
235                       " -device scsi-hd,drive=drive0,id=dev0",
236                       qvirtio_get_dev_type());
237 
238     /*
239      * Delete the drive, and then the device
240      * Doing it in this order takes notoriously tricky special paths
241      */
242     drive_del(qts);
243     device_del(qts, false);
244     g_assert(!has_drive(qts));
245 
246     qtest_quit(qts);
247 }
248 
249 static void test_cli_device_del(void)
250 {
251     QTestState *qts;
252     const char *arch = qtest_get_arch();
253     const char *machine_addition = "";
254 
255     if (!has_device_builtin("virtio-blk")) {
256         g_test_skip("Device virtio-blk is not available");
257         return;
258     }
259 
260     if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
261         machine_addition = "-machine pc";
262     }
263 
264     /*
265      * -drive/-device and device_del.  Start with a drive used by a
266      * device that unplugs after reset.
267      */
268     qts = qtest_initf("%s -drive if=none,id=drive0,file=null-co://,"
269                       "file.read-zeroes=on,format=raw"
270                       " -device virtio-blk-%s,drive=drive0,id=dev0",
271                       machine_addition,
272                       qvirtio_get_dev_type());
273 
274     device_del(qts, true);
275     g_assert(!has_drive(qts));
276 
277     qtest_quit(qts);
278 }
279 
280 static void test_cli_device_del_q35(void)
281 {
282     QTestState *qts;
283 
284     if (!has_device_builtin("virtio-blk")) {
285         g_test_skip("Device virtio-blk is not available");
286         return;
287     }
288 
289     /*
290      * -drive/-device and device_del.  Start with a drive used by a
291      * device that unplugs after reset.
292      */
293     qts = qtest_initf("-drive if=none,id=drive0,file=null-co://,"
294                       "file.read-zeroes=on,format=raw "
295                       "-machine q35 -device pcie-root-port,id=p1 "
296                       "-device pcie-pci-bridge,bus=p1,id=b1 "
297                       "-device virtio-blk-%s,drive=drive0,bus=b1,id=dev0",
298                       qvirtio_get_dev_type());
299 
300     device_del(qts, true);
301     g_assert(!has_drive(qts));
302 
303     qtest_quit(qts);
304 }
305 
306 static void test_empty_device_del(void)
307 {
308     QTestState *qts;
309 
310     if (!has_device_builtin("virtio-scsi")) {
311         g_test_skip("Device virtio-scsi is not available");
312         return;
313     }
314 
315     /* device_del with no drive plugged.  */
316     qts = qtest_initf("-device virtio-scsi-%s -device scsi-cd,id=dev0",
317                       qvirtio_get_dev_type());
318 
319     device_del(qts, false);
320     qtest_quit(qts);
321 }
322 
323 static void test_device_add_and_del(void)
324 {
325     QTestState *qts;
326     const char *arch = qtest_get_arch();
327     const char *machine_addition = "";
328 
329     if (!has_device_builtin("virtio-blk")) {
330         g_test_skip("Device virtio-blk is not available");
331         return;
332     }
333 
334     if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
335         machine_addition = "-machine pc";
336     }
337 
338     /*
339      * -drive/device_add and device_del.  Start with a drive used by a
340      * device that unplugs after reset.
341      */
342     qts = qtest_initf("%s -drive if=none,id=drive0,file=null-co://,"
343                      "file.read-zeroes=on,format=raw", machine_addition);
344 
345     device_add(qts);
346     device_del(qts, true);
347     g_assert(!has_drive(qts));
348 
349     qtest_quit(qts);
350 }
351 
352 static void device_add_q35(QTestState *qts)
353 {
354     g_autofree char *driver = g_strdup_printf("virtio-blk-%s",
355                                               qvirtio_get_dev_type());
356     QDict *response =
357                qtest_qmp(qts, "{'execute': 'device_add',"
358                               " 'arguments': {"
359                               "   'driver': %s,"
360                               "   'drive': 'drive0',"
361                               "   'id': 'dev0',"
362                               "   'bus': 'b1'"
363                               "}}", driver);
364     g_assert(response);
365     g_assert(qdict_haskey(response, "return"));
366     qobject_unref(response);
367 }
368 
369 static void test_device_add_and_del_q35(void)
370 {
371     QTestState *qts;
372 
373     if (!has_device_builtin("virtio-blk")) {
374         g_test_skip("Device virtio-blk is not available");
375         return;
376     }
377 
378     /*
379      * -drive/device_add and device_del.  Start with a drive used by a
380      * device that unplugs after reset.
381      */
382     qts = qtest_initf("-machine q35 -device pcie-root-port,id=p1 "
383                      "-device pcie-pci-bridge,bus=p1,id=b1 "
384                      "-drive if=none,id=drive0,file=null-co://,"
385                      "file.read-zeroes=on,format=raw");
386 
387     device_add_q35(qts);
388     device_del(qts, true);
389     g_assert(!has_drive(qts));
390 
391     qtest_quit(qts);
392 }
393 
394 static void test_drive_add_device_add_and_del(void)
395 {
396     QTestState *qts;
397     const char *arch = qtest_get_arch();
398     const char *machine_addition = "";
399 
400     if (!has_device_builtin("virtio-blk")) {
401         g_test_skip("Device virtio-blk is not available");
402         return;
403     }
404 
405     if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
406         machine_addition = "-machine pc";
407     }
408 
409     qts = qtest_init(machine_addition);
410 
411     /*
412      * drive_add/device_add and device_del.  The drive is used by a
413      * device that unplugs after reset.
414      */
415     drive_add_with_media(qts);
416     device_add(qts);
417     device_del(qts, true);
418     g_assert(!has_drive(qts));
419 
420     qtest_quit(qts);
421 }
422 
423 static void test_drive_add_device_add_and_del_q35(void)
424 {
425     QTestState *qts;
426 
427     if (!has_device_builtin("virtio-blk")) {
428         g_test_skip("Device virtio-blk is not available");
429         return;
430     }
431 
432     qts = qtest_init("-machine q35 -device pcie-root-port,id=p1 "
433                      "-device pcie-pci-bridge,bus=p1,id=b1");
434 
435     /*
436      * drive_add/device_add and device_del.  The drive is used by a
437      * device that unplugs after reset.
438      */
439     drive_add_with_media(qts);
440     device_add_q35(qts);
441     device_del(qts, true);
442     g_assert(!has_drive(qts));
443 
444     qtest_quit(qts);
445 }
446 
447 static void test_blockdev_add_device_add_and_del(void)
448 {
449     QTestState *qts;
450     const char *arch = qtest_get_arch();
451     const char *machine_addition = "";
452 
453     if (!has_device_builtin("virtio-blk")) {
454         g_test_skip("Device virtio-blk is not available");
455         return;
456     }
457 
458     if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
459         machine_addition = "-machine pc";
460     }
461 
462     qts = qtest_init(machine_addition);
463 
464     /*
465      * blockdev_add/device_add and device_del. The drive is used by a
466      * device that unplugs after reset, but it doesn't go away.
467      */
468     blockdev_add_with_media(qts);
469     device_add(qts);
470     device_del(qts, true);
471     g_assert(has_blockdev(qts));
472 
473     qtest_quit(qts);
474 }
475 
476 static void test_blockdev_add_device_add_and_del_q35(void)
477 {
478     QTestState *qts;
479 
480     if (!has_device_builtin("virtio-blk")) {
481         g_test_skip("Device virtio-blk is not available");
482         return;
483     }
484 
485     qts = qtest_init("-machine q35 -device pcie-root-port,id=p1 "
486                      "-device pcie-pci-bridge,bus=p1,id=b1");
487 
488     /*
489      * blockdev_add/device_add and device_del. The drive is used by a
490      * device that unplugs after reset, but it doesn't go away.
491      */
492     blockdev_add_with_media(qts);
493     device_add_q35(qts);
494     device_del(qts, true);
495     g_assert(has_blockdev(qts));
496 
497     qtest_quit(qts);
498 }
499 
500 int main(int argc, char **argv)
501 {
502     g_test_init(&argc, &argv, NULL);
503 
504     qtest_add_func("/drive_del/without-dev", test_drive_without_dev);
505 
506     if (qvirtio_get_dev_type() != NULL) {
507         qtest_add_func("/drive_del/after_failed_device_add",
508                        test_after_failed_device_add);
509         qtest_add_func("/drive_del/drive_del_device_del",
510                        test_drive_del_device_del);
511         qtest_add_func("/device_del/drive/cli_device",
512                        test_cli_device_del);
513         qtest_add_func("/device_del/drive/device_add",
514                        test_device_add_and_del);
515         qtest_add_func("/device_del/drive/drive_add_device_add",
516                        test_drive_add_device_add_and_del);
517         qtest_add_func("/device_del/empty",
518                        test_empty_device_del);
519         qtest_add_func("/device_del/blockdev",
520                        test_blockdev_add_device_add_and_del);
521 
522         if (qtest_has_machine("q35")) {
523             qtest_add_func("/device_del/drive/cli_device_q35",
524                            test_cli_device_del_q35);
525             qtest_add_func("/device_del/drive/device_add_q35",
526                            test_device_add_and_del_q35);
527             qtest_add_func("/device_del/drive/drive_add_device_add_q35",
528                            test_drive_add_device_add_and_del_q35);
529             qtest_add_func("/device_del/blockdev_q35",
530                            test_blockdev_add_device_add_and_del_q35);
531         }
532     }
533 
534     return g_test_run();
535 }
536