1 /*
2  * QTest testcase for Vhost-user Block Device
3  *
4  * Based on tests/qtest//virtio-blk-test.c
5 
6  * Copyright (c) 2014 SUSE LINUX Products GmbH
7  * Copyright (c) 2014 Marc Marí
8  * Copyright (c) 2020 Coiby Xu
9  *
10  * This work is licensed under the terms of the GNU GPL, version 2 or later.
11  * See the COPYING file in the top-level directory.
12  */
13 
14 #include "qemu/osdep.h"
15 #include "libqtest-single.h"
16 #include "qemu/bswap.h"
17 #include "qemu/module.h"
18 #include "standard-headers/linux/virtio_blk.h"
19 #include "standard-headers/linux/virtio_pci.h"
20 #include "libqos/qgraph.h"
21 #include "libqos/vhost-user-blk.h"
22 #include "libqos/libqos-pc.h"
23 
24 #define TEST_IMAGE_SIZE         (64 * 1024 * 1024)
25 #define QVIRTIO_BLK_TIMEOUT_US  (30 * 1000 * 1000)
26 #define PCI_SLOT_HP             0x06
27 
28 typedef struct {
29     pid_t pid;
30 } QemuStorageDaemonState;
31 
32 typedef struct QVirtioBlkReq {
33     uint32_t type;
34     uint32_t ioprio;
35     uint64_t sector;
36     char *data;
37     uint8_t status;
38 } QVirtioBlkReq;
39 
40 #if HOST_BIG_ENDIAN
41 static const bool host_is_big_endian = true;
42 #else
43 static const bool host_is_big_endian; /* false */
44 #endif
45 
virtio_blk_fix_request(QVirtioDevice * d,QVirtioBlkReq * req)46 static inline void virtio_blk_fix_request(QVirtioDevice *d, QVirtioBlkReq *req)
47 {
48     if (qvirtio_is_big_endian(d) != host_is_big_endian) {
49         req->type = bswap32(req->type);
50         req->ioprio = bswap32(req->ioprio);
51         req->sector = bswap64(req->sector);
52     }
53 }
54 
virtio_blk_fix_dwz_hdr(QVirtioDevice * d,struct virtio_blk_discard_write_zeroes * dwz_hdr)55 static inline void virtio_blk_fix_dwz_hdr(QVirtioDevice *d,
56     struct virtio_blk_discard_write_zeroes *dwz_hdr)
57 {
58     if (qvirtio_is_big_endian(d) != host_is_big_endian) {
59         dwz_hdr->sector = bswap64(dwz_hdr->sector);
60         dwz_hdr->num_sectors = bswap32(dwz_hdr->num_sectors);
61         dwz_hdr->flags = bswap32(dwz_hdr->flags);
62     }
63 }
64 
virtio_blk_request(QGuestAllocator * alloc,QVirtioDevice * d,QVirtioBlkReq * req,uint64_t data_size)65 static uint64_t virtio_blk_request(QGuestAllocator *alloc, QVirtioDevice *d,
66                                    QVirtioBlkReq *req, uint64_t data_size)
67 {
68     uint64_t addr;
69     uint8_t status = 0xFF;
70     QTestState *qts = global_qtest;
71 
72     switch (req->type) {
73     case VIRTIO_BLK_T_IN:
74     case VIRTIO_BLK_T_OUT:
75         g_assert_cmpuint(data_size % 512, ==, 0);
76         break;
77     case VIRTIO_BLK_T_DISCARD:
78     case VIRTIO_BLK_T_WRITE_ZEROES:
79         g_assert_cmpuint(data_size %
80                          sizeof(struct virtio_blk_discard_write_zeroes), ==, 0);
81         break;
82     default:
83         g_assert_cmpuint(data_size, ==, 0);
84     }
85 
86     addr = guest_alloc(alloc, sizeof(*req) + data_size);
87 
88     virtio_blk_fix_request(d, req);
89 
90     qtest_memwrite(qts, addr, req, 16);
91     qtest_memwrite(qts, addr + 16, req->data, data_size);
92     qtest_memwrite(qts, addr + 16 + data_size, &status, sizeof(status));
93 
94     return addr;
95 }
96 
test_invalid_discard_write_zeroes(QVirtioDevice * dev,QGuestAllocator * alloc,QTestState * qts,QVirtQueue * vq,uint32_t type)97 static void test_invalid_discard_write_zeroes(QVirtioDevice *dev,
98                                               QGuestAllocator *alloc,
99                                               QTestState *qts,
100                                               QVirtQueue *vq,
101                                               uint32_t type)
102 {
103     QVirtioBlkReq req;
104     struct virtio_blk_discard_write_zeroes dwz_hdr;
105     struct virtio_blk_discard_write_zeroes dwz_hdr2[2];
106     uint64_t req_addr;
107     uint32_t free_head;
108     uint8_t status;
109 
110     /* More than one dwz is not supported */
111     req.type = type;
112     req.data = (char *) dwz_hdr2;
113     dwz_hdr2[0].sector = 0;
114     dwz_hdr2[0].num_sectors = 1;
115     dwz_hdr2[0].flags = 0;
116     dwz_hdr2[1].sector = 1;
117     dwz_hdr2[1].num_sectors = 1;
118     dwz_hdr2[1].flags = 0;
119 
120     virtio_blk_fix_dwz_hdr(dev, &dwz_hdr2[0]);
121     virtio_blk_fix_dwz_hdr(dev, &dwz_hdr2[1]);
122 
123     req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr2));
124 
125     free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
126     qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr2), false, true);
127     qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr2), 1, true,
128                    false);
129 
130     qvirtqueue_kick(qts, dev, vq, free_head);
131 
132     qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
133                            QVIRTIO_BLK_TIMEOUT_US);
134     status = readb(req_addr + 16 + sizeof(dwz_hdr2));
135     g_assert_cmpint(status, ==, VIRTIO_BLK_S_UNSUPP);
136 
137     guest_free(alloc, req_addr);
138 
139     /* num_sectors must be less than config->max_write_zeroes_sectors */
140     req.type = type;
141     req.data = (char *) &dwz_hdr;
142     dwz_hdr.sector = 0;
143     dwz_hdr.num_sectors = 0xffffffff;
144     dwz_hdr.flags = 0;
145 
146     virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
147 
148     req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
149 
150     free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
151     qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
152     qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true,
153                    false);
154 
155     qvirtqueue_kick(qts, dev, vq, free_head);
156 
157     qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
158                            QVIRTIO_BLK_TIMEOUT_US);
159     status = readb(req_addr + 16 + sizeof(dwz_hdr));
160     g_assert_cmpint(status, ==, VIRTIO_BLK_S_IOERR);
161 
162     guest_free(alloc, req_addr);
163 
164     /* sector must be less than the device capacity */
165     req.type = type;
166     req.data = (char *) &dwz_hdr;
167     dwz_hdr.sector = TEST_IMAGE_SIZE / 512 + 1;
168     dwz_hdr.num_sectors = 1;
169     dwz_hdr.flags = 0;
170 
171     virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
172 
173     req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
174 
175     free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
176     qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
177     qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true,
178                    false);
179 
180     qvirtqueue_kick(qts, dev, vq, free_head);
181 
182     qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
183                            QVIRTIO_BLK_TIMEOUT_US);
184     status = readb(req_addr + 16 + sizeof(dwz_hdr));
185     g_assert_cmpint(status, ==, VIRTIO_BLK_S_IOERR);
186 
187     guest_free(alloc, req_addr);
188 
189     /* reserved flag bits must be zero */
190     req.type = type;
191     req.data = (char *) &dwz_hdr;
192     dwz_hdr.sector = 0;
193     dwz_hdr.num_sectors = 1;
194     dwz_hdr.flags = ~VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP;
195 
196     virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
197 
198     req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
199 
200     free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
201     qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
202     qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true,
203                    false);
204 
205     qvirtqueue_kick(qts, dev, vq, free_head);
206 
207     qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
208                            QVIRTIO_BLK_TIMEOUT_US);
209     status = readb(req_addr + 16 + sizeof(dwz_hdr));
210     g_assert_cmpint(status, ==, VIRTIO_BLK_S_UNSUPP);
211 
212     guest_free(alloc, req_addr);
213 }
214 
215 /* Returns the request virtqueue so the caller can perform further tests */
test_basic(QVirtioDevice * dev,QGuestAllocator * alloc)216 static QVirtQueue *test_basic(QVirtioDevice *dev, QGuestAllocator *alloc)
217 {
218     QVirtioBlkReq req;
219     uint64_t req_addr;
220     uint64_t capacity;
221     uint64_t features;
222     uint32_t free_head;
223     uint8_t status;
224     char *data;
225     QTestState *qts = global_qtest;
226     QVirtQueue *vq;
227 
228     features = qvirtio_get_features(dev);
229     features = features & ~(QVIRTIO_F_BAD_FEATURE |
230                     (1u << VIRTIO_RING_F_INDIRECT_DESC) |
231                     (1u << VIRTIO_RING_F_EVENT_IDX) |
232                     (1u << VIRTIO_BLK_F_SCSI));
233     qvirtio_set_features(dev, features);
234 
235     capacity = qvirtio_config_readq(dev, 0);
236     g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
237 
238     vq = qvirtqueue_setup(dev, alloc, 0);
239 
240     qvirtio_set_driver_ok(dev);
241 
242     /* Write and read with 3 descriptor layout */
243     /* Write request */
244     req.type = VIRTIO_BLK_T_OUT;
245     req.ioprio = 1;
246     req.sector = 0;
247     req.data = g_malloc0(512);
248     strcpy(req.data, "TEST");
249 
250     req_addr = virtio_blk_request(alloc, dev, &req, 512);
251 
252     g_free(req.data);
253 
254     free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
255     qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
256     qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
257 
258     qvirtqueue_kick(qts, dev, vq, free_head);
259 
260     qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
261                            QVIRTIO_BLK_TIMEOUT_US);
262     status = readb(req_addr + 528);
263     g_assert_cmpint(status, ==, 0);
264 
265     guest_free(alloc, req_addr);
266 
267     /* Read request */
268     req.type = VIRTIO_BLK_T_IN;
269     req.ioprio = 1;
270     req.sector = 0;
271     req.data = g_malloc0(512);
272 
273     req_addr = virtio_blk_request(alloc, dev, &req, 512);
274 
275     g_free(req.data);
276 
277     free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
278     qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
279     qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
280 
281     qvirtqueue_kick(qts, dev, vq, free_head);
282 
283     qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
284                            QVIRTIO_BLK_TIMEOUT_US);
285     status = readb(req_addr + 528);
286     g_assert_cmpint(status, ==, 0);
287 
288     data = g_malloc0(512);
289     qtest_memread(qts, req_addr + 16, data, 512);
290     g_assert_cmpstr(data, ==, "TEST");
291     g_free(data);
292 
293     guest_free(alloc, req_addr);
294 
295     if (features & (1u << VIRTIO_BLK_F_WRITE_ZEROES)) {
296         struct virtio_blk_discard_write_zeroes dwz_hdr;
297         void *expected;
298 
299         /*
300          * WRITE_ZEROES request on the same sector of previous test where
301          * we wrote "TEST".
302          */
303         req.type = VIRTIO_BLK_T_WRITE_ZEROES;
304         req.data = (char *) &dwz_hdr;
305         dwz_hdr.sector = 0;
306         dwz_hdr.num_sectors = 1;
307         dwz_hdr.flags = 0;
308 
309         virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
310 
311         req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
312 
313         free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
314         qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
315         qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true,
316                        false);
317 
318         qvirtqueue_kick(qts, dev, vq, free_head);
319 
320         qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
321                                QVIRTIO_BLK_TIMEOUT_US);
322         status = readb(req_addr + 16 + sizeof(dwz_hdr));
323         g_assert_cmpint(status, ==, 0);
324 
325         guest_free(alloc, req_addr);
326 
327         /* Read request to check if the sector contains all zeroes */
328         req.type = VIRTIO_BLK_T_IN;
329         req.ioprio = 1;
330         req.sector = 0;
331         req.data = g_malloc0(512);
332 
333         req_addr = virtio_blk_request(alloc, dev, &req, 512);
334 
335         g_free(req.data);
336 
337         free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
338         qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
339         qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
340 
341         qvirtqueue_kick(qts, dev, vq, free_head);
342 
343         qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
344                                QVIRTIO_BLK_TIMEOUT_US);
345         status = readb(req_addr + 528);
346         g_assert_cmpint(status, ==, 0);
347 
348         data = g_malloc(512);
349         expected = g_malloc0(512);
350         qtest_memread(qts, req_addr + 16, data, 512);
351         g_assert_cmpmem(data, 512, expected, 512);
352         g_free(expected);
353         g_free(data);
354 
355         guest_free(alloc, req_addr);
356 
357         test_invalid_discard_write_zeroes(dev, alloc, qts, vq,
358                                           VIRTIO_BLK_T_WRITE_ZEROES);
359     }
360 
361     if (features & (1u << VIRTIO_BLK_F_DISCARD)) {
362         struct virtio_blk_discard_write_zeroes dwz_hdr;
363 
364         req.type = VIRTIO_BLK_T_DISCARD;
365         req.data = (char *) &dwz_hdr;
366         dwz_hdr.sector = 0;
367         dwz_hdr.num_sectors = 1;
368         dwz_hdr.flags = 0;
369 
370         virtio_blk_fix_dwz_hdr(dev, &dwz_hdr);
371 
372         req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
373 
374         free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
375         qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true);
376         qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr),
377                        1, true, false);
378 
379         qvirtqueue_kick(qts, dev, vq, free_head);
380 
381         qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
382                                QVIRTIO_BLK_TIMEOUT_US);
383         status = readb(req_addr + 16 + sizeof(dwz_hdr));
384         g_assert_cmpint(status, ==, 0);
385 
386         guest_free(alloc, req_addr);
387 
388         test_invalid_discard_write_zeroes(dev, alloc, qts, vq,
389                                           VIRTIO_BLK_T_DISCARD);
390     }
391 
392     if (features & (1u << VIRTIO_F_ANY_LAYOUT)) {
393         /* Write and read with 2 descriptor layout */
394         /* Write request */
395         req.type = VIRTIO_BLK_T_OUT;
396         req.ioprio = 1;
397         req.sector = 1;
398         req.data = g_malloc0(512);
399         strcpy(req.data, "TEST");
400 
401         req_addr = virtio_blk_request(alloc, dev, &req, 512);
402 
403         g_free(req.data);
404 
405         free_head = qvirtqueue_add(qts, vq, req_addr, 528, false, true);
406         qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
407         qvirtqueue_kick(qts, dev, vq, free_head);
408 
409         qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
410                                QVIRTIO_BLK_TIMEOUT_US);
411         status = readb(req_addr + 528);
412         g_assert_cmpint(status, ==, 0);
413 
414         guest_free(alloc, req_addr);
415 
416         /* Read request */
417         req.type = VIRTIO_BLK_T_IN;
418         req.ioprio = 1;
419         req.sector = 1;
420         req.data = g_malloc0(512);
421 
422         req_addr = virtio_blk_request(alloc, dev, &req, 512);
423 
424         g_free(req.data);
425 
426         free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
427         qvirtqueue_add(qts, vq, req_addr + 16, 513, true, false);
428 
429         qvirtqueue_kick(qts, dev, vq, free_head);
430 
431         qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
432                                QVIRTIO_BLK_TIMEOUT_US);
433         status = readb(req_addr + 528);
434         g_assert_cmpint(status, ==, 0);
435 
436         data = g_malloc0(512);
437         qtest_memread(qts, req_addr + 16, data, 512);
438         g_assert_cmpstr(data, ==, "TEST");
439         g_free(data);
440 
441         guest_free(alloc, req_addr);
442     }
443 
444     return vq;
445 }
446 
basic(void * obj,void * data,QGuestAllocator * t_alloc)447 static void basic(void *obj, void *data, QGuestAllocator *t_alloc)
448 {
449     QVhostUserBlk *blk_if = obj;
450     QVirtQueue *vq;
451 
452     vq = test_basic(blk_if->vdev, t_alloc);
453     qvirtqueue_cleanup(blk_if->vdev->bus, vq, t_alloc);
454 
455 }
456 
indirect(void * obj,void * u_data,QGuestAllocator * t_alloc)457 static void indirect(void *obj, void *u_data, QGuestAllocator *t_alloc)
458 {
459     QVirtQueue *vq;
460     QVhostUserBlk *blk_if = obj;
461     QVirtioDevice *dev = blk_if->vdev;
462     QVirtioBlkReq req;
463     QVRingIndirectDesc *indirect;
464     uint64_t req_addr;
465     uint64_t capacity;
466     uint64_t features;
467     uint32_t free_head;
468     uint8_t status;
469     char *data;
470     QTestState *qts = global_qtest;
471 
472     features = qvirtio_get_features(dev);
473     g_assert_cmphex(features & (1u << VIRTIO_RING_F_INDIRECT_DESC), !=, 0);
474     features = features & ~(QVIRTIO_F_BAD_FEATURE |
475                             (1u << VIRTIO_RING_F_EVENT_IDX) |
476                             (1u << VIRTIO_BLK_F_SCSI));
477     qvirtio_set_features(dev, features);
478 
479     capacity = qvirtio_config_readq(dev, 0);
480     g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
481 
482     vq = qvirtqueue_setup(dev, t_alloc, 0);
483     qvirtio_set_driver_ok(dev);
484 
485     /* Write request */
486     req.type = VIRTIO_BLK_T_OUT;
487     req.ioprio = 1;
488     req.sector = 0;
489     req.data = g_malloc0(512);
490     strcpy(req.data, "TEST");
491 
492     req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
493 
494     g_free(req.data);
495 
496     indirect = qvring_indirect_desc_setup(qts, dev, t_alloc, 2);
497     qvring_indirect_desc_add(dev, qts, indirect, req_addr, 528, false);
498     qvring_indirect_desc_add(dev, qts, indirect, req_addr + 528, 1, true);
499     free_head = qvirtqueue_add_indirect(qts, vq, indirect);
500     qvirtqueue_kick(qts, dev, vq, free_head);
501 
502     qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
503                            QVIRTIO_BLK_TIMEOUT_US);
504     status = readb(req_addr + 528);
505     g_assert_cmpint(status, ==, 0);
506 
507     g_free(indirect);
508     guest_free(t_alloc, req_addr);
509 
510     /* Read request */
511     req.type = VIRTIO_BLK_T_IN;
512     req.ioprio = 1;
513     req.sector = 0;
514     req.data = g_malloc0(512);
515     strcpy(req.data, "TEST");
516 
517     req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
518 
519     g_free(req.data);
520 
521     indirect = qvring_indirect_desc_setup(qts, dev, t_alloc, 2);
522     qvring_indirect_desc_add(dev, qts, indirect, req_addr, 16, false);
523     qvring_indirect_desc_add(dev, qts, indirect, req_addr + 16, 513, true);
524     free_head = qvirtqueue_add_indirect(qts, vq, indirect);
525     qvirtqueue_kick(qts, dev, vq, free_head);
526 
527     qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
528                            QVIRTIO_BLK_TIMEOUT_US);
529     status = readb(req_addr + 528);
530     g_assert_cmpint(status, ==, 0);
531 
532     data = g_malloc0(512);
533     qtest_memread(qts, req_addr + 16, data, 512);
534     g_assert_cmpstr(data, ==, "TEST");
535     g_free(data);
536 
537     g_free(indirect);
538     guest_free(t_alloc, req_addr);
539     qvirtqueue_cleanup(dev->bus, vq, t_alloc);
540 }
541 
idx(void * obj,void * u_data,QGuestAllocator * t_alloc)542 static void idx(void *obj, void *u_data, QGuestAllocator *t_alloc)
543 {
544     QVirtQueue *vq;
545     QVhostUserBlkPCI *blk = obj;
546     QVirtioPCIDevice *pdev = &blk->pci_vdev;
547     QVirtioDevice *dev = &pdev->vdev;
548     QVirtioBlkReq req;
549     uint64_t req_addr;
550     uint64_t capacity;
551     uint64_t features;
552     uint32_t free_head;
553     uint32_t write_head;
554     uint32_t desc_idx;
555     uint8_t status;
556     char *data;
557     QOSGraphObject *blk_object = obj;
558     QPCIDevice *pci_dev = blk_object->get_driver(blk_object, "pci-device");
559     QTestState *qts = global_qtest;
560 
561     if (qpci_check_buggy_msi(pci_dev)) {
562         return;
563     }
564 
565     qpci_msix_enable(pdev->pdev);
566     qvirtio_pci_set_msix_configuration_vector(pdev, t_alloc, 0);
567 
568     features = qvirtio_get_features(dev);
569     features = features & ~(QVIRTIO_F_BAD_FEATURE |
570                             (1u << VIRTIO_RING_F_INDIRECT_DESC) |
571                             (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
572                             (1u << VIRTIO_BLK_F_SCSI));
573     qvirtio_set_features(dev, features);
574 
575     capacity = qvirtio_config_readq(dev, 0);
576     g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
577 
578     vq = qvirtqueue_setup(dev, t_alloc, 0);
579     qvirtqueue_pci_msix_setup(pdev, (QVirtQueuePCI *)vq, t_alloc, 1);
580 
581     qvirtio_set_driver_ok(dev);
582 
583     /*
584      * libvhost-user signals the call fd in VHOST_USER_SET_VRING_CALL, make
585      * sure to wait for the isr here so we don't race and confuse it later on.
586      */
587     qvirtio_wait_queue_isr(qts, dev, vq, QVIRTIO_BLK_TIMEOUT_US);
588 
589     /* Write request */
590     req.type = VIRTIO_BLK_T_OUT;
591     req.ioprio = 1;
592     req.sector = 0;
593     req.data = g_malloc0(512);
594     strcpy(req.data, "TEST");
595 
596     req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
597 
598     g_free(req.data);
599 
600     free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
601     qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
602     qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
603     qvirtqueue_kick(qts, dev, vq, free_head);
604 
605     qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
606                            QVIRTIO_BLK_TIMEOUT_US);
607 
608     /* Write request */
609     req.type = VIRTIO_BLK_T_OUT;
610     req.ioprio = 1;
611     req.sector = 1;
612     req.data = g_malloc0(512);
613     strcpy(req.data, "TEST");
614 
615     req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
616 
617     g_free(req.data);
618 
619     /* Notify after processing the third request */
620     qvirtqueue_set_used_event(qts, vq, 2);
621     free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
622     qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true);
623     qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
624     qvirtqueue_kick(qts, dev, vq, free_head);
625     write_head = free_head;
626 
627     /* No notification expected */
628     status = qvirtio_wait_status_byte_no_isr(qts, dev,
629                                              vq, req_addr + 528,
630                                              QVIRTIO_BLK_TIMEOUT_US);
631     g_assert_cmpint(status, ==, 0);
632 
633     guest_free(t_alloc, req_addr);
634 
635     /* Read request */
636     req.type = VIRTIO_BLK_T_IN;
637     req.ioprio = 1;
638     req.sector = 1;
639     req.data = g_malloc0(512);
640 
641     req_addr = virtio_blk_request(t_alloc, dev, &req, 512);
642 
643     g_free(req.data);
644 
645     free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true);
646     qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true);
647     qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false);
648 
649     qvirtqueue_kick(qts, dev, vq, free_head);
650 
651     /* We get just one notification for both requests */
652     qvirtio_wait_used_elem(qts, dev, vq, write_head, NULL,
653                            QVIRTIO_BLK_TIMEOUT_US);
654     g_assert(qvirtqueue_get_buf(qts, vq, &desc_idx, NULL));
655     g_assert_cmpint(desc_idx, ==, free_head);
656 
657     status = readb(req_addr + 528);
658     g_assert_cmpint(status, ==, 0);
659 
660     data = g_malloc0(512);
661     qtest_memread(qts, req_addr + 16, data, 512);
662     g_assert_cmpstr(data, ==, "TEST");
663     g_free(data);
664 
665     guest_free(t_alloc, req_addr);
666 
667     /* End test */
668     qpci_msix_disable(pdev->pdev);
669 
670     qvirtqueue_cleanup(dev->bus, vq, t_alloc);
671 }
672 
pci_hotplug(void * obj,void * data,QGuestAllocator * t_alloc)673 static void pci_hotplug(void *obj, void *data, QGuestAllocator *t_alloc)
674 {
675     QVirtioPCIDevice *dev1 = obj;
676     QVirtioPCIDevice *dev;
677     QTestState *qts = dev1->pdev->bus->qts;
678 
679     if (dev1->pdev->bus->not_hotpluggable) {
680         g_test_skip("pci bus does not support hotplug");
681         return;
682     }
683 
684     /* plug secondary disk */
685     qtest_qmp_device_add(qts, "vhost-user-blk-pci", "drv1",
686                          "{'addr': %s, 'chardev': 'char2'}",
687                          stringify(PCI_SLOT_HP) ".0");
688 
689     dev = virtio_pci_new(dev1->pdev->bus,
690                          &(QPCIAddress) { .devfn = QPCI_DEVFN(PCI_SLOT_HP, 0)
691                                         });
692     g_assert_nonnull(dev);
693     g_assert_cmpint(dev->vdev.device_type, ==, VIRTIO_ID_BLOCK);
694     qvirtio_pci_device_disable(dev);
695     qos_object_destroy((QOSGraphObject *)dev);
696 
697     /* unplug secondary disk */
698     qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP);
699 }
700 
multiqueue(void * obj,void * data,QGuestAllocator * t_alloc)701 static void multiqueue(void *obj, void *data, QGuestAllocator *t_alloc)
702 {
703     QVirtioPCIDevice *pdev1 = obj;
704     QVirtioDevice *dev1 = &pdev1->vdev;
705     QVirtioPCIDevice *pdev8;
706     QVirtioDevice *dev8;
707     QTestState *qts = pdev1->pdev->bus->qts;
708     uint64_t features;
709     uint16_t num_queues;
710 
711     if (pdev1->pdev->bus->not_hotpluggable) {
712         g_test_skip("bus pci.0 does not support hotplug");
713         return;
714     }
715 
716     /*
717      * The primary device has 1 queue and VIRTIO_BLK_F_MQ is not enabled. The
718      * VIRTIO specification allows VIRTIO_BLK_F_MQ to be enabled when there is
719      * only 1 virtqueue, but --device vhost-user-blk-pci doesn't do this (which
720      * is also spec-compliant).
721      */
722     features = qvirtio_get_features(dev1);
723     g_assert_cmpint(features & (1u << VIRTIO_BLK_F_MQ), ==, 0);
724     features = features & ~(QVIRTIO_F_BAD_FEATURE |
725                             (1u << VIRTIO_RING_F_INDIRECT_DESC) |
726                             (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
727                             (1u << VIRTIO_BLK_F_SCSI));
728     qvirtio_set_features(dev1, features);
729 
730     /* Hotplug a secondary device with 8 queues */
731     qtest_qmp_device_add(qts, "vhost-user-blk-pci", "drv1",
732                          "{'addr': %s, 'chardev': 'char2', 'num-queues': 8}",
733                          stringify(PCI_SLOT_HP) ".0");
734 
735     pdev8 = virtio_pci_new(pdev1->pdev->bus,
736                            &(QPCIAddress) {
737                                .devfn = QPCI_DEVFN(PCI_SLOT_HP, 0)
738                            });
739     g_assert_nonnull(pdev8);
740     g_assert_cmpint(pdev8->vdev.device_type, ==, VIRTIO_ID_BLOCK);
741 
742     qos_object_start_hw(&pdev8->obj);
743 
744     dev8 = &pdev8->vdev;
745     features = qvirtio_get_features(dev8);
746     g_assert_cmpint(features & (1u << VIRTIO_BLK_F_MQ),
747                     ==,
748                     (1u << VIRTIO_BLK_F_MQ));
749     features = features & ~(QVIRTIO_F_BAD_FEATURE |
750                             (1u << VIRTIO_RING_F_INDIRECT_DESC) |
751                             (1u << VIRTIO_F_NOTIFY_ON_EMPTY) |
752                             (1u << VIRTIO_BLK_F_SCSI) |
753                             (1u << VIRTIO_BLK_F_MQ));
754     qvirtio_set_features(dev8, features);
755 
756     num_queues = qvirtio_config_readw(dev8,
757             offsetof(struct virtio_blk_config, num_queues));
758     g_assert_cmpint(num_queues, ==, 8);
759 
760     qvirtio_pci_device_disable(pdev8);
761     qos_object_destroy(&pdev8->obj);
762 
763     /* unplug secondary disk */
764     qpci_unplug_acpi_device_test(qts, "drv1", PCI_SLOT_HP);
765 }
766 
767 /*
768  * Check that setting the vring addr on a non-existent virtqueue does
769  * not crash.
770  */
test_nonexistent_virtqueue(void * obj,void * data,QGuestAllocator * t_alloc)771 static void test_nonexistent_virtqueue(void *obj, void *data,
772                                        QGuestAllocator *t_alloc)
773 {
774     QVhostUserBlkPCI *blk = obj;
775     QVirtioPCIDevice *pdev = &blk->pci_vdev;
776     QPCIBar bar0;
777     QPCIDevice *dev;
778 
779     dev = qpci_device_find(pdev->pdev->bus, QPCI_DEVFN(4, 0));
780     g_assert(dev != NULL);
781     qpci_device_enable(dev);
782 
783     bar0 = qpci_iomap(dev, 0, NULL);
784 
785     qpci_io_writeb(dev, bar0, VIRTIO_PCI_QUEUE_SEL, 2);
786     qpci_io_writel(dev, bar0, VIRTIO_PCI_QUEUE_PFN, 1);
787 
788     g_free(dev);
789 }
790 
qtest_qemu_storage_daemon_binary(void)791 static const char *qtest_qemu_storage_daemon_binary(void)
792 {
793     const char *qemu_storage_daemon_bin;
794 
795     qemu_storage_daemon_bin = getenv("QTEST_QEMU_STORAGE_DAEMON_BINARY");
796     if (!qemu_storage_daemon_bin) {
797         fprintf(stderr, "Environment variable "
798                         "QTEST_QEMU_STORAGE_DAEMON_BINARY required\n");
799         exit(0);
800     }
801 
802     /* If we've got a path to the binary, check whether we can access it */
803     if (strchr(qemu_storage_daemon_bin, '/') &&
804         access(qemu_storage_daemon_bin, X_OK) != 0) {
805         fprintf(stderr, "ERROR: '%s' is not accessible\n",
806                 qemu_storage_daemon_bin);
807         exit(1);
808     }
809 
810     return qemu_storage_daemon_bin;
811 }
812 
813 /* g_test_queue_destroy() cleanup function for files */
destroy_file(void * path)814 static void destroy_file(void *path)
815 {
816     unlink(path);
817     g_free(path);
818     qos_invalidate_command_line();
819 }
820 
drive_create(void)821 static char *drive_create(void)
822 {
823     int fd, ret;
824     /** vhost-user-blk won't recognize drive located in /tmp */
825     char *t_path = g_strdup("qtest.XXXXXX");
826 
827     /** Create a temporary raw image */
828     fd = mkstemp(t_path);
829     g_assert_cmpint(fd, >=, 0);
830     ret = ftruncate(fd, TEST_IMAGE_SIZE);
831     g_assert_cmpint(ret, ==, 0);
832     close(fd);
833 
834     g_test_queue_destroy(destroy_file, t_path);
835     return t_path;
836 }
837 
create_listen_socket(int * fd)838 static char *create_listen_socket(int *fd)
839 {
840     int tmp_fd;
841     char *path;
842 
843     /* No race because our pid makes the path unique */
844     path = g_strdup_printf("%s/qtest-%d-sock.XXXXXX",
845                            g_get_tmp_dir(), getpid());
846     tmp_fd = mkstemp(path);
847     g_assert_cmpint(tmp_fd, >=, 0);
848     close(tmp_fd);
849     unlink(path);
850 
851     *fd = qtest_socket_server(path);
852     g_test_queue_destroy(destroy_file, path);
853     return path;
854 }
855 
856 /*
857  * g_test_queue_destroy() and qtest_add_abrt_handler() cleanup function for
858  * qemu-storage-daemon.
859  */
quit_storage_daemon(void * data)860 static void quit_storage_daemon(void *data)
861 {
862     QemuStorageDaemonState *qsd = data;
863     int wstatus;
864     pid_t pid;
865 
866     /*
867      * If we were invoked as a g_test_queue_destroy() cleanup function we need
868      * to remove the abrt handler to avoid being called again if the code below
869      * aborts. Also, we must not leave the abrt handler installed after
870      * cleanup.
871      */
872     qtest_remove_abrt_handler(data);
873 
874     /* Before quitting storage-daemon, quit qemu to avoid dubious messages */
875     qtest_kill_qemu(global_qtest);
876 
877     kill(qsd->pid, SIGTERM);
878     pid = waitpid(qsd->pid, &wstatus, 0);
879     g_assert_cmpint(pid, ==, qsd->pid);
880     if (!WIFEXITED(wstatus)) {
881         fprintf(stderr, "%s: expected qemu-storage-daemon to exit\n",
882                 __func__);
883         abort();
884     }
885     if (WEXITSTATUS(wstatus) != 0) {
886         fprintf(stderr, "%s: expected qemu-storage-daemon to exit "
887                 "successfully, got %d\n",
888                 __func__, WEXITSTATUS(wstatus));
889         abort();
890     }
891 
892     g_free(data);
893 }
894 
start_vhost_user_blk(GString * cmd_line,int vus_instances,int num_queues)895 static void start_vhost_user_blk(GString *cmd_line, int vus_instances,
896                                  int num_queues)
897 {
898     const char *vhost_user_blk_bin = qtest_qemu_storage_daemon_binary();
899     int i;
900     gchar *img_path;
901     GString *storage_daemon_command = g_string_new(NULL);
902     QemuStorageDaemonState *qsd;
903 
904     g_string_append_printf(storage_daemon_command,
905                            "exec %s ",
906                            vhost_user_blk_bin);
907 
908     g_string_append_printf(cmd_line,
909             " -object memory-backend-shm,id=mem,size=256M "
910             " -M memory-backend=mem -m 256M ");
911 
912     for (i = 0; i < vus_instances; i++) {
913         int fd;
914         char *sock_path = create_listen_socket(&fd);
915 
916         /* create image file */
917         img_path = drive_create();
918         g_string_append_printf(storage_daemon_command,
919             "--blockdev driver=file,node-name=disk%d,filename=%s "
920             "--export type=vhost-user-blk,id=disk%d,addr.type=fd,addr.str=%d,"
921             "node-name=disk%i,writable=on,num-queues=%d ",
922             i, img_path, i, fd, i, num_queues);
923 
924         g_string_append_printf(cmd_line, "-chardev socket,id=char%d,path=%s ",
925                                i + 1, sock_path);
926     }
927 
928     g_test_message("starting vhost-user backend: %s",
929                    storage_daemon_command->str);
930     pid_t pid = fork();
931     if (pid == 0) {
932         /*
933          * Close standard file descriptors so tap-driver.pl pipe detects when
934          * our parent terminates.
935          */
936         close(0);
937         close(1);
938         open("/dev/null", O_RDONLY);
939         open("/dev/null", O_WRONLY);
940 
941         execlp("/bin/sh", "sh", "-c", storage_daemon_command->str, NULL);
942         exit(1);
943     }
944     g_string_free(storage_daemon_command, true);
945 
946     qsd = g_new(QemuStorageDaemonState, 1);
947     qsd->pid = pid;
948 
949     /* Make sure qemu-storage-daemon is stopped */
950     qtest_add_abrt_handler(quit_storage_daemon, qsd);
951     g_test_queue_destroy(quit_storage_daemon, qsd);
952 }
953 
vhost_user_blk_test_setup(GString * cmd_line,void * arg)954 static void *vhost_user_blk_test_setup(GString *cmd_line, void *arg)
955 {
956     start_vhost_user_blk(cmd_line, 1, 1);
957     return arg;
958 }
959 
960 /*
961  * Setup for hotplug.
962  *
963  * Since vhost-user server only serves one vhost-user client one time,
964  * another export
965  *
966  */
vhost_user_blk_hotplug_test_setup(GString * cmd_line,void * arg)967 static void *vhost_user_blk_hotplug_test_setup(GString *cmd_line, void *arg)
968 {
969     /* "-chardev socket,id=char2" is used for pci_hotplug*/
970     start_vhost_user_blk(cmd_line, 2, 1);
971     return arg;
972 }
973 
vhost_user_blk_multiqueue_test_setup(GString * cmd_line,void * arg)974 static void *vhost_user_blk_multiqueue_test_setup(GString *cmd_line, void *arg)
975 {
976     start_vhost_user_blk(cmd_line, 2, 8);
977     return arg;
978 }
979 
register_vhost_user_blk_test(void)980 static void register_vhost_user_blk_test(void)
981 {
982     QOSGraphTestOptions opts = {
983         .before = vhost_user_blk_test_setup,
984     };
985 
986     if (!getenv("QTEST_QEMU_STORAGE_DAEMON_BINARY")) {
987         g_test_message("QTEST_QEMU_STORAGE_DAEMON_BINARY not defined, "
988                        "skipping vhost-user-blk-test");
989         return;
990     }
991 
992     /*
993      * tests for vhost-user-blk and vhost-user-blk-pci
994      * The tests are borrowed from tests/virtio-blk-test.c. But some tests
995      * regarding block_resize don't work for vhost-user-blk.
996      * vhost-user-blk device doesn't have -drive, so tests containing
997      * block_resize are also abandoned,
998      *  - config
999      *  - resize
1000      */
1001     qos_add_test("basic", "vhost-user-blk", basic, &opts);
1002     qos_add_test("indirect", "vhost-user-blk", indirect, &opts);
1003     qos_add_test("idx", "vhost-user-blk-pci", idx, &opts);
1004     qos_add_test("nxvirtq", "vhost-user-blk-pci",
1005                  test_nonexistent_virtqueue, &opts);
1006 
1007     opts.before = vhost_user_blk_hotplug_test_setup;
1008     qos_add_test("hotplug", "vhost-user-blk-pci", pci_hotplug, &opts);
1009 
1010     opts.before = vhost_user_blk_multiqueue_test_setup;
1011     qos_add_test("multiqueue", "vhost-user-blk-pci", multiqueue, &opts);
1012 }
1013 
1014 libqos_init(register_vhost_user_blk_test);
1015