xref: /qemu/tests/qtest/drive_del-test.c (revision 27a4a30e)
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 
18 /* TODO actually test the results and get rid of this */
19 #define qmp_discard_response(q, ...) qobject_unref(qtest_qmp(q, __VA_ARGS__))
20 
21 static void drive_add(QTestState *qts)
22 {
23     char *resp = qtest_hmp(qts, "drive_add 0 if=none,id=drive0");
24 
25     g_assert_cmpstr(resp, ==, "OK\r\n");
26     g_free(resp);
27 }
28 
29 static void drive_del(QTestState *qts)
30 {
31     char *resp = qtest_hmp(qts, "drive_del drive0");
32 
33     g_assert_cmpstr(resp, ==, "");
34     g_free(resp);
35 }
36 
37 static void device_del(QTestState *qts)
38 {
39     QDict *response;
40 
41     /* Complication: ignore DEVICE_DELETED event */
42     qmp_discard_response(qts, "{'execute': 'device_del',"
43                          " 'arguments': { 'id': 'dev0' } }");
44     response = qtest_qmp_receive(qts);
45     g_assert(response);
46     g_assert(qdict_haskey(response, "return"));
47     qobject_unref(response);
48 }
49 
50 static void test_drive_without_dev(void)
51 {
52     QTestState *qts;
53 
54     /* Start with an empty drive */
55     qts = qtest_init("-drive if=none,id=drive0");
56 
57     /* Delete the drive */
58     drive_del(qts);
59 
60     /* Ensure re-adding the drive works - there should be no duplicate ID error
61      * because the old drive must be gone.
62      */
63     drive_add(qts);
64 
65     qtest_quit(qts);
66 }
67 
68 /*
69  * qvirtio_get_dev_type:
70  * Returns: the preferred virtio bus/device type for the current architecture.
71  * TODO: delete this
72  */
73 static const char *qvirtio_get_dev_type(void)
74 {
75     const char *arch = qtest_get_arch();
76 
77     if (g_str_equal(arch, "arm") || g_str_equal(arch, "aarch64")) {
78         return "device";  /* for virtio-mmio */
79     } else if (g_str_equal(arch, "s390x")) {
80         return "ccw";
81     } else {
82         return "pci";
83     }
84 }
85 
86 static void test_after_failed_device_add(void)
87 {
88     char driver[32];
89     QDict *response;
90     QTestState *qts;
91 
92     snprintf(driver, sizeof(driver), "virtio-blk-%s",
93              qvirtio_get_dev_type());
94 
95     qts = qtest_init("-drive if=none,id=drive0");
96 
97     /* Make device_add fail. If this leaks the virtio-blk device then a
98      * reference to drive0 will also be held (via qdev properties).
99      */
100     response = qtest_qmp(qts, "{'execute': 'device_add',"
101                               " 'arguments': {"
102                               "   'driver': %s,"
103                               "   'drive': 'drive0'"
104                               "}}", driver);
105     g_assert(response);
106     qmp_assert_error_class(response, "GenericError");
107 
108     /* Delete the drive */
109     drive_del(qts);
110 
111     /* Try to re-add the drive.  This fails with duplicate IDs if a leaked
112      * virtio-blk device exists that holds a reference to the old drive0.
113      */
114     drive_add(qts);
115 
116     qtest_quit(qts);
117 }
118 
119 static void test_drive_del_device_del(void)
120 {
121     QTestState *qts;
122 
123     /* Start with a drive used by a device that unplugs instantaneously */
124     qts = qtest_initf("-drive if=none,id=drive0,file=null-co://,"
125                       "file.read-zeroes=on,format=raw"
126                       " -device virtio-scsi-%s"
127                       " -device scsi-hd,drive=drive0,id=dev0",
128                       qvirtio_get_dev_type());
129 
130     /*
131      * Delete the drive, and then the device
132      * Doing it in this order takes notoriously tricky special paths
133      */
134     drive_del(qts);
135     device_del(qts);
136 
137     qtest_quit(qts);
138 }
139 
140 int main(int argc, char **argv)
141 {
142     g_test_init(&argc, &argv, NULL);
143 
144     qtest_add_func("/drive_del/without-dev", test_drive_without_dev);
145 
146     if (qvirtio_get_dev_type() != NULL) {
147         qtest_add_func("/drive_del/after_failed_device_add",
148                        test_after_failed_device_add);
149         qtest_add_func("/blockdev/drive_del_device_del",
150                        test_drive_del_device_del);
151     }
152 
153     return g_test_run();
154 }
155