]> git.proxmox.com Git - mirror_qemu.git/blame - tests/unit/test-block-iothread.c
block: Add blk_co_pwrite_compressed()
[mirror_qemu.git] / tests / unit / test-block-iothread.c
CommitLineData
4720cbee
KW
1/*
2 * Block tests for iothreads
3 *
4 * Copyright (c) 2018 Kevin Wolf <kwolf@redhat.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25#include "qemu/osdep.h"
26#include "block/block.h"
27#include "block/blockjob_int.h"
28#include "sysemu/block-backend.h"
29#include "qapi/error.h"
7e2f096a 30#include "qapi/qmp/qdict.h"
db725815 31#include "qemu/main-loop.h"
4720cbee
KW
32#include "iothread.h"
33
f7ef38dd
VSO
34static int coroutine_fn bdrv_test_co_preadv(BlockDriverState *bs,
35 int64_t offset, int64_t bytes,
36 QEMUIOVector *qiov,
37 BdrvRequestFlags flags)
38{
39 return 0;
40}
41
42static int coroutine_fn bdrv_test_co_pwritev(BlockDriverState *bs,
e75abeda 43 int64_t offset, int64_t bytes,
f7ef38dd 44 QEMUIOVector *qiov,
e75abeda 45 BdrvRequestFlags flags)
4720cbee
KW
46{
47 return 0;
48}
49
50static int coroutine_fn bdrv_test_co_pdiscard(BlockDriverState *bs,
0c802287 51 int64_t offset, int64_t bytes)
4720cbee
KW
52{
53 return 0;
54}
55
56static int coroutine_fn
c80d8b06 57bdrv_test_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
92b92799
KW
58 PreallocMode prealloc, BdrvRequestFlags flags,
59 Error **errp)
4720cbee
KW
60{
61 return 0;
62}
63
64static int coroutine_fn bdrv_test_co_block_status(BlockDriverState *bs,
65 bool want_zero,
66 int64_t offset, int64_t count,
67 int64_t *pnum, int64_t *map,
68 BlockDriverState **file)
69{
70 *pnum = count;
71 return 0;
72}
73
74static BlockDriver bdrv_test = {
75 .format_name = "test",
76 .instance_size = 1,
77
f7ef38dd
VSO
78 .bdrv_co_preadv = bdrv_test_co_preadv,
79 .bdrv_co_pwritev = bdrv_test_co_pwritev,
4720cbee
KW
80 .bdrv_co_pdiscard = bdrv_test_co_pdiscard,
81 .bdrv_co_truncate = bdrv_test_co_truncate,
82 .bdrv_co_block_status = bdrv_test_co_block_status,
83};
84
85static void test_sync_op_pread(BdrvChild *c)
86{
87 uint8_t buf[512];
88 int ret;
89
90 /* Success */
32cc71de 91 ret = bdrv_pread(c, 0, sizeof(buf), buf, 0);
353a5d84 92 g_assert_cmpint(ret, ==, 0);
4720cbee
KW
93
94 /* Early error: Negative offset */
32cc71de 95 ret = bdrv_pread(c, -2, sizeof(buf), buf, 0);
4720cbee
KW
96 g_assert_cmpint(ret, ==, -EIO);
97}
98
99static void test_sync_op_pwrite(BdrvChild *c)
100{
d8b2e563 101 uint8_t buf[512] = { 0 };
4720cbee
KW
102 int ret;
103
104 /* Success */
32cc71de 105 ret = bdrv_pwrite(c, 0, sizeof(buf), buf, 0);
353a5d84 106 g_assert_cmpint(ret, ==, 0);
4720cbee
KW
107
108 /* Early error: Negative offset */
32cc71de 109 ret = bdrv_pwrite(c, -2, sizeof(buf), buf, 0);
4720cbee
KW
110 g_assert_cmpint(ret, ==, -EIO);
111}
112
113static void test_sync_op_blk_pread(BlockBackend *blk)
114{
115 uint8_t buf[512];
116 int ret;
117
118 /* Success */
a9262f55 119 ret = blk_pread(blk, 0, sizeof(buf), buf, 0);
bf5b16fa 120 g_assert_cmpint(ret, ==, 0);
4720cbee
KW
121
122 /* Early error: Negative offset */
a9262f55 123 ret = blk_pread(blk, -2, sizeof(buf), buf, 0);
4720cbee
KW
124 g_assert_cmpint(ret, ==, -EIO);
125}
126
127static void test_sync_op_blk_pwrite(BlockBackend *blk)
128{
d8b2e563 129 uint8_t buf[512] = { 0 };
4720cbee
KW
130 int ret;
131
132 /* Success */
a9262f55 133 ret = blk_pwrite(blk, 0, sizeof(buf), buf, 0);
bf5b16fa 134 g_assert_cmpint(ret, ==, 0);
4720cbee
KW
135
136 /* Early error: Negative offset */
a9262f55 137 ret = blk_pwrite(blk, -2, sizeof(buf), buf, 0);
4720cbee
KW
138 g_assert_cmpint(ret, ==, -EIO);
139}
140
7c8cd723
AF
141static void test_sync_op_blk_preadv(BlockBackend *blk)
142{
143 uint8_t buf[512];
144 QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, sizeof(buf));
145 int ret;
146
147 /* Success */
148 ret = blk_preadv(blk, 0, sizeof(buf), &qiov, 0);
149 g_assert_cmpint(ret, ==, 0);
150
151 /* Early error: Negative offset */
152 ret = blk_preadv(blk, -2, sizeof(buf), &qiov, 0);
153 g_assert_cmpint(ret, ==, -EIO);
154}
155
156static void test_sync_op_blk_pwritev(BlockBackend *blk)
157{
158 uint8_t buf[512] = { 0 };
159 QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, sizeof(buf));
160 int ret;
161
162 /* Success */
163 ret = blk_pwritev(blk, 0, sizeof(buf), &qiov, 0);
164 g_assert_cmpint(ret, ==, 0);
165
166 /* Early error: Negative offset */
167 ret = blk_pwritev(blk, -2, sizeof(buf), &qiov, 0);
168 g_assert_cmpint(ret, ==, -EIO);
169}
170
d1d3fc3d
AF
171static void test_sync_op_blk_preadv_part(BlockBackend *blk)
172{
173 uint8_t buf[512];
174 QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, sizeof(buf));
175 int ret;
176
177 /* Success */
178 ret = blk_preadv_part(blk, 0, sizeof(buf), &qiov, 0, 0);
179 g_assert_cmpint(ret, ==, 0);
180
181 /* Early error: Negative offset */
182 ret = blk_preadv_part(blk, -2, sizeof(buf), &qiov, 0, 0);
183 g_assert_cmpint(ret, ==, -EIO);
184}
185
09cca043
AF
186static void test_sync_op_blk_pwritev_part(BlockBackend *blk)
187{
188 uint8_t buf[512] = { 0 };
189 QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, sizeof(buf));
190 int ret;
191
192 /* Success */
193 ret = blk_pwritev_part(blk, 0, sizeof(buf), &qiov, 0, 0);
194 g_assert_cmpint(ret, ==, 0);
195
196 /* Early error: Negative offset */
197 ret = blk_pwritev_part(blk, -2, sizeof(buf), &qiov, 0, 0);
198 g_assert_cmpint(ret, ==, -EIO);
199}
200
2c9715fa
AF
201static void test_sync_op_blk_pwrite_compressed(BlockBackend *blk)
202{
203 uint8_t buf[512] = { 0 };
204 int ret;
205
206 /* Late error: Not supported */
207 ret = blk_pwrite_compressed(blk, 0, sizeof(buf), buf);
208 g_assert_cmpint(ret, ==, -ENOTSUP);
209
210 /* Early error: Negative offset */
211 ret = blk_pwrite_compressed(blk, -2, sizeof(buf), buf);
212 g_assert_cmpint(ret, ==, -EIO);
213}
214
4720cbee
KW
215static void test_sync_op_load_vmstate(BdrvChild *c)
216{
217 uint8_t buf[512];
218 int ret;
219
220 /* Error: Driver does not support snapshots */
221 ret = bdrv_load_vmstate(c->bs, buf, 0, sizeof(buf));
222 g_assert_cmpint(ret, ==, -ENOTSUP);
223}
224
225static void test_sync_op_save_vmstate(BdrvChild *c)
226{
d8b2e563 227 uint8_t buf[512] = { 0 };
4720cbee
KW
228 int ret;
229
230 /* Error: Driver does not support snapshots */
231 ret = bdrv_save_vmstate(c->bs, buf, 0, sizeof(buf));
232 g_assert_cmpint(ret, ==, -ENOTSUP);
233}
234
235static void test_sync_op_pdiscard(BdrvChild *c)
236{
237 int ret;
238
239 /* Normal success path */
240 c->bs->open_flags |= BDRV_O_UNMAP;
241 ret = bdrv_pdiscard(c, 0, 512);
242 g_assert_cmpint(ret, ==, 0);
243
244 /* Early success: UNMAP not supported */
245 c->bs->open_flags &= ~BDRV_O_UNMAP;
246 ret = bdrv_pdiscard(c, 0, 512);
247 g_assert_cmpint(ret, ==, 0);
248
249 /* Early error: Negative offset */
250 ret = bdrv_pdiscard(c, -2, 512);
251 g_assert_cmpint(ret, ==, -EIO);
252}
253
254static void test_sync_op_blk_pdiscard(BlockBackend *blk)
255{
256 int ret;
257
258 /* Early success: UNMAP not supported */
259 ret = blk_pdiscard(blk, 0, 512);
260 g_assert_cmpint(ret, ==, 0);
261
262 /* Early error: Negative offset */
263 ret = blk_pdiscard(blk, -2, 512);
264 g_assert_cmpint(ret, ==, -EIO);
265}
266
267static void test_sync_op_truncate(BdrvChild *c)
268{
269 int ret;
270
271 /* Normal success path */
7b8e4857 272 ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, 0, NULL);
4720cbee
KW
273 g_assert_cmpint(ret, ==, 0);
274
275 /* Early error: Negative offset */
7b8e4857 276 ret = bdrv_truncate(c, -2, false, PREALLOC_MODE_OFF, 0, NULL);
4720cbee
KW
277 g_assert_cmpint(ret, ==, -EINVAL);
278
279 /* Error: Read-only image */
4720cbee
KW
280 c->bs->open_flags &= ~BDRV_O_RDWR;
281
7b8e4857 282 ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, 0, NULL);
4720cbee
KW
283 g_assert_cmpint(ret, ==, -EACCES);
284
4720cbee
KW
285 c->bs->open_flags |= BDRV_O_RDWR;
286}
287
288static void test_sync_op_block_status(BdrvChild *c)
289{
290 int ret;
291 int64_t n;
292
293 /* Normal success path */
294 ret = bdrv_is_allocated(c->bs, 0, 65536, &n);
295 g_assert_cmpint(ret, ==, 0);
296
297 /* Early success: No driver support */
298 bdrv_test.bdrv_co_block_status = NULL;
299 ret = bdrv_is_allocated(c->bs, 0, 65536, &n);
300 g_assert_cmpint(ret, ==, 1);
301
302 /* Early success: bytes = 0 */
303 ret = bdrv_is_allocated(c->bs, 0, 0, &n);
304 g_assert_cmpint(ret, ==, 0);
305
306 /* Early success: Offset > image size*/
307 ret = bdrv_is_allocated(c->bs, 0x1000000, 0x1000000, &n);
308 g_assert_cmpint(ret, ==, 0);
309}
310
311static void test_sync_op_flush(BdrvChild *c)
312{
313 int ret;
314
315 /* Normal success path */
316 ret = bdrv_flush(c->bs);
317 g_assert_cmpint(ret, ==, 0);
318
319 /* Early success: Read-only image */
4720cbee
KW
320 c->bs->open_flags &= ~BDRV_O_RDWR;
321
322 ret = bdrv_flush(c->bs);
323 g_assert_cmpint(ret, ==, 0);
324
4720cbee
KW
325 c->bs->open_flags |= BDRV_O_RDWR;
326}
327
328static void test_sync_op_blk_flush(BlockBackend *blk)
329{
330 BlockDriverState *bs = blk_bs(blk);
331 int ret;
332
333 /* Normal success path */
334 ret = blk_flush(blk);
335 g_assert_cmpint(ret, ==, 0);
336
337 /* Early success: Read-only image */
4720cbee
KW
338 bs->open_flags &= ~BDRV_O_RDWR;
339
340 ret = blk_flush(blk);
341 g_assert_cmpint(ret, ==, 0);
342
4720cbee
KW
343 bs->open_flags |= BDRV_O_RDWR;
344}
345
346static void test_sync_op_check(BdrvChild *c)
347{
348 BdrvCheckResult result;
349 int ret;
350
351 /* Error: Driver does not implement check */
352 ret = bdrv_check(c->bs, &result, 0);
353 g_assert_cmpint(ret, ==, -ENOTSUP);
354}
355
3b717194 356static void test_sync_op_activate(BdrvChild *c)
4720cbee
KW
357{
358 /* Early success: Image is not inactive */
a94750d9 359 bdrv_activate(c->bs, NULL);
4720cbee
KW
360}
361
362
363typedef struct SyncOpTest {
364 const char *name;
365 void (*fn)(BdrvChild *c);
366 void (*blkfn)(BlockBackend *blk);
367} SyncOpTest;
368
369const SyncOpTest sync_op_tests[] = {
370 {
371 .name = "/sync-op/pread",
372 .fn = test_sync_op_pread,
373 .blkfn = test_sync_op_blk_pread,
374 }, {
375 .name = "/sync-op/pwrite",
376 .fn = test_sync_op_pwrite,
377 .blkfn = test_sync_op_blk_pwrite,
7c8cd723
AF
378 }, {
379 .name = "/sync-op/preadv",
380 .fn = NULL,
381 .blkfn = test_sync_op_blk_preadv,
382 }, {
383 .name = "/sync-op/pwritev",
384 .fn = NULL,
385 .blkfn = test_sync_op_blk_pwritev,
d1d3fc3d
AF
386 }, {
387 .name = "/sync-op/preadv_part",
388 .fn = NULL,
389 .blkfn = test_sync_op_blk_preadv_part,
09cca043
AF
390 }, {
391 .name = "/sync-op/pwritev_part",
392 .fn = NULL,
393 .blkfn = test_sync_op_blk_pwritev_part,
2c9715fa
AF
394 }, {
395 .name = "/sync-op/pwrite_compressed",
396 .fn = NULL,
397 .blkfn = test_sync_op_blk_pwrite_compressed,
4720cbee
KW
398 }, {
399 .name = "/sync-op/load_vmstate",
400 .fn = test_sync_op_load_vmstate,
401 }, {
402 .name = "/sync-op/save_vmstate",
403 .fn = test_sync_op_save_vmstate,
404 }, {
405 .name = "/sync-op/pdiscard",
406 .fn = test_sync_op_pdiscard,
407 .blkfn = test_sync_op_blk_pdiscard,
408 }, {
409 .name = "/sync-op/truncate",
410 .fn = test_sync_op_truncate,
411 }, {
412 .name = "/sync-op/block_status",
413 .fn = test_sync_op_block_status,
414 }, {
415 .name = "/sync-op/flush",
416 .fn = test_sync_op_flush,
417 .blkfn = test_sync_op_blk_flush,
418 }, {
419 .name = "/sync-op/check",
420 .fn = test_sync_op_check,
421 }, {
3b717194
EGE
422 .name = "/sync-op/activate",
423 .fn = test_sync_op_activate,
4720cbee
KW
424 },
425};
426
427/* Test synchronous operations that run in a different iothread, so we have to
428 * poll for the coroutine there to return. */
429static void test_sync_op(const void *opaque)
430{
431 const SyncOpTest *t = opaque;
432 IOThread *iothread = iothread_new();
433 AioContext *ctx = iothread_get_aio_context(iothread);
434 BlockBackend *blk;
435 BlockDriverState *bs;
436 BdrvChild *c;
437
d861ab3a 438 blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
4720cbee
KW
439 bs = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort);
440 bs->total_sectors = 65536 / BDRV_SECTOR_SIZE;
441 blk_insert_bs(blk, bs, &error_abort);
442 c = QLIST_FIRST(&bs->parents);
443
97896a48 444 blk_set_aio_context(blk, ctx, &error_abort);
4720cbee 445 aio_context_acquire(ctx);
7c8cd723
AF
446 if (t->fn) {
447 t->fn(c);
448 }
4720cbee
KW
449 if (t->blkfn) {
450 t->blkfn(blk);
451 }
97896a48 452 blk_set_aio_context(blk, qemu_get_aio_context(), &error_abort);
1b285657 453 aio_context_release(ctx);
4720cbee
KW
454
455 bdrv_unref(bs);
456 blk_unref(blk);
457}
458
93c60f38
KW
459typedef struct TestBlockJob {
460 BlockJob common;
461 bool should_complete;
462 int n;
463} TestBlockJob;
464
465static int test_job_prepare(Job *job)
466{
467 g_assert(qemu_get_current_aio_context() == qemu_get_aio_context());
468 return 0;
469}
470
471static int coroutine_fn test_job_run(Job *job, Error **errp)
472{
473 TestBlockJob *s = container_of(job, TestBlockJob, common.job);
474
475 job_transition_to_ready(&s->common.job);
476 while (!s->should_complete) {
477 s->n++;
478 g_assert(qemu_get_current_aio_context() == job->aio_context);
479
480 /* Avoid job_sleep_ns() because it marks the job as !busy. We want to
481 * emulate some actual activity (probably some I/O) here so that the
482 * drain involved in AioContext switches has to wait for this activity
483 * to stop. */
484 qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 1000000);
485
486 job_pause_point(&s->common.job);
487 }
488
489 g_assert(qemu_get_current_aio_context() == job->aio_context);
490 return 0;
491}
492
493static void test_job_complete(Job *job, Error **errp)
494{
495 TestBlockJob *s = container_of(job, TestBlockJob, common.job);
496 s->should_complete = true;
497}
498
499BlockJobDriver test_job_driver = {
500 .job_driver = {
501 .instance_size = sizeof(TestBlockJob),
502 .free = block_job_free,
503 .user_resume = block_job_user_resume,
93c60f38
KW
504 .run = test_job_run,
505 .complete = test_job_complete,
506 .prepare = test_job_prepare,
507 },
508};
509
510static void test_attach_blockjob(void)
511{
512 IOThread *iothread = iothread_new();
513 AioContext *ctx = iothread_get_aio_context(iothread);
514 BlockBackend *blk;
515 BlockDriverState *bs;
516 TestBlockJob *tjob;
517
d861ab3a 518 blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
93c60f38
KW
519 bs = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort);
520 blk_insert_bs(blk, bs, &error_abort);
521
522 tjob = block_job_create("job0", &test_job_driver, NULL, bs,
523 0, BLK_PERM_ALL,
524 0, 0, NULL, NULL, &error_abort);
525 job_start(&tjob->common.job);
526
527 while (tjob->n == 0) {
528 aio_poll(qemu_get_aio_context(), false);
529 }
530
97896a48 531 blk_set_aio_context(blk, ctx, &error_abort);
93c60f38
KW
532
533 tjob->n = 0;
534 while (tjob->n == 0) {
535 aio_poll(qemu_get_aio_context(), false);
536 }
537
538 aio_context_acquire(ctx);
97896a48 539 blk_set_aio_context(blk, qemu_get_aio_context(), &error_abort);
93c60f38
KW
540 aio_context_release(ctx);
541
542 tjob->n = 0;
543 while (tjob->n == 0) {
544 aio_poll(qemu_get_aio_context(), false);
545 }
546
97896a48 547 blk_set_aio_context(blk, ctx, &error_abort);
93c60f38
KW
548
549 tjob->n = 0;
550 while (tjob->n == 0) {
551 aio_poll(qemu_get_aio_context(), false);
552 }
553
554 aio_context_acquire(ctx);
555 job_complete_sync(&tjob->common.job, &error_abort);
97896a48 556 blk_set_aio_context(blk, qemu_get_aio_context(), &error_abort);
93c60f38
KW
557 aio_context_release(ctx);
558
559 bdrv_unref(bs);
560 blk_unref(blk);
561}
562
7e2f096a
KW
563/*
564 * Test that changing the AioContext for one node in a tree (here through blk)
565 * changes all other nodes as well:
566 *
567 * blk
568 * |
569 * | bs_verify [blkverify]
570 * | / \
571 * | / \
572 * bs_a [bdrv_test] bs_b [bdrv_test]
573 *
574 */
575static void test_propagate_basic(void)
576{
577 IOThread *iothread = iothread_new();
578 AioContext *ctx = iothread_get_aio_context(iothread);
1b285657 579 AioContext *main_ctx;
7e2f096a
KW
580 BlockBackend *blk;
581 BlockDriverState *bs_a, *bs_b, *bs_verify;
582 QDict *options;
583
69dca43d
HR
584 /*
585 * Create bs_a and its BlockBackend. We cannot take the RESIZE
586 * permission because blkverify will not share it on the test
587 * image.
588 */
589 blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL & ~BLK_PERM_RESIZE,
590 BLK_PERM_ALL);
7e2f096a
KW
591 bs_a = bdrv_new_open_driver(&bdrv_test, "bs_a", BDRV_O_RDWR, &error_abort);
592 blk_insert_bs(blk, bs_a, &error_abort);
593
594 /* Create bs_b */
595 bs_b = bdrv_new_open_driver(&bdrv_test, "bs_b", BDRV_O_RDWR, &error_abort);
596
597 /* Create blkverify filter that references both bs_a and bs_b */
598 options = qdict_new();
599 qdict_put_str(options, "driver", "blkverify");
600 qdict_put_str(options, "test", "bs_a");
601 qdict_put_str(options, "raw", "bs_b");
602
603 bs_verify = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
604
605 /* Switch the AioContext */
97896a48 606 blk_set_aio_context(blk, ctx, &error_abort);
7e2f096a
KW
607 g_assert(blk_get_aio_context(blk) == ctx);
608 g_assert(bdrv_get_aio_context(bs_a) == ctx);
609 g_assert(bdrv_get_aio_context(bs_verify) == ctx);
610 g_assert(bdrv_get_aio_context(bs_b) == ctx);
611
612 /* Switch the AioContext back */
1b285657
HR
613 main_ctx = qemu_get_aio_context();
614 aio_context_acquire(ctx);
615 blk_set_aio_context(blk, main_ctx, &error_abort);
616 aio_context_release(ctx);
617 g_assert(blk_get_aio_context(blk) == main_ctx);
618 g_assert(bdrv_get_aio_context(bs_a) == main_ctx);
619 g_assert(bdrv_get_aio_context(bs_verify) == main_ctx);
620 g_assert(bdrv_get_aio_context(bs_b) == main_ctx);
7e2f096a
KW
621
622 bdrv_unref(bs_verify);
623 bdrv_unref(bs_b);
624 bdrv_unref(bs_a);
625 blk_unref(blk);
626}
627
628/*
629 * Test that diamonds in the graph don't lead to endless recursion:
630 *
631 * blk
632 * |
633 * bs_verify [blkverify]
634 * / \
635 * / \
636 * bs_b [raw] bs_c[raw]
637 * \ /
638 * \ /
639 * bs_a [bdrv_test]
640 */
641static void test_propagate_diamond(void)
642{
643 IOThread *iothread = iothread_new();
644 AioContext *ctx = iothread_get_aio_context(iothread);
1b285657 645 AioContext *main_ctx;
7e2f096a
KW
646 BlockBackend *blk;
647 BlockDriverState *bs_a, *bs_b, *bs_c, *bs_verify;
648 QDict *options;
649
650 /* Create bs_a */
651 bs_a = bdrv_new_open_driver(&bdrv_test, "bs_a", BDRV_O_RDWR, &error_abort);
652
653 /* Create bs_b and bc_c */
654 options = qdict_new();
655 qdict_put_str(options, "driver", "raw");
656 qdict_put_str(options, "file", "bs_a");
657 qdict_put_str(options, "node-name", "bs_b");
658 bs_b = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
659
660 options = qdict_new();
661 qdict_put_str(options, "driver", "raw");
662 qdict_put_str(options, "file", "bs_a");
663 qdict_put_str(options, "node-name", "bs_c");
664 bs_c = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
665
666 /* Create blkverify filter that references both bs_b and bs_c */
667 options = qdict_new();
668 qdict_put_str(options, "driver", "blkverify");
669 qdict_put_str(options, "test", "bs_b");
670 qdict_put_str(options, "raw", "bs_c");
671
672 bs_verify = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
69dca43d
HR
673 /*
674 * Do not take the RESIZE permission: This would require the same
675 * from bs_c and thus from bs_a; however, blkverify will not share
676 * it on bs_b, and thus it will not be available for bs_a.
677 */
678 blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL & ~BLK_PERM_RESIZE,
679 BLK_PERM_ALL);
7e2f096a
KW
680 blk_insert_bs(blk, bs_verify, &error_abort);
681
682 /* Switch the AioContext */
97896a48 683 blk_set_aio_context(blk, ctx, &error_abort);
7e2f096a
KW
684 g_assert(blk_get_aio_context(blk) == ctx);
685 g_assert(bdrv_get_aio_context(bs_verify) == ctx);
686 g_assert(bdrv_get_aio_context(bs_a) == ctx);
687 g_assert(bdrv_get_aio_context(bs_b) == ctx);
688 g_assert(bdrv_get_aio_context(bs_c) == ctx);
689
690 /* Switch the AioContext back */
1b285657
HR
691 main_ctx = qemu_get_aio_context();
692 aio_context_acquire(ctx);
693 blk_set_aio_context(blk, main_ctx, &error_abort);
694 aio_context_release(ctx);
695 g_assert(blk_get_aio_context(blk) == main_ctx);
696 g_assert(bdrv_get_aio_context(bs_verify) == main_ctx);
697 g_assert(bdrv_get_aio_context(bs_a) == main_ctx);
698 g_assert(bdrv_get_aio_context(bs_b) == main_ctx);
699 g_assert(bdrv_get_aio_context(bs_c) == main_ctx);
7e2f096a
KW
700
701 blk_unref(blk);
702 bdrv_unref(bs_verify);
703 bdrv_unref(bs_c);
704 bdrv_unref(bs_b);
705 bdrv_unref(bs_a);
706}
707
012056f4
KW
708static void test_propagate_mirror(void)
709{
710 IOThread *iothread = iothread_new();
711 AioContext *ctx = iothread_get_aio_context(iothread);
712 AioContext *main_ctx = qemu_get_aio_context();
087ba459 713 BlockDriverState *src, *target, *filter;
012056f4
KW
714 BlockBackend *blk;
715 Job *job;
716 Error *local_err = NULL;
717
718 /* Create src and target*/
719 src = bdrv_new_open_driver(&bdrv_test, "src", BDRV_O_RDWR, &error_abort);
720 target = bdrv_new_open_driver(&bdrv_test, "target", BDRV_O_RDWR,
721 &error_abort);
722
723 /* Start a mirror job */
724 mirror_start("job0", src, target, NULL, JOB_DEFAULT, 0, 0, 0,
cdf3bc93 725 MIRROR_SYNC_MODE_NONE, MIRROR_OPEN_BACKING_CHAIN, false,
012056f4
KW
726 BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT,
727 false, "filter_node", MIRROR_COPY_MODE_BACKGROUND,
728 &error_abort);
729 job = job_get("job0");
087ba459 730 filter = bdrv_find_node("filter_node");
012056f4
KW
731
732 /* Change the AioContext of src */
733 bdrv_try_set_aio_context(src, ctx, &error_abort);
734 g_assert(bdrv_get_aio_context(src) == ctx);
735 g_assert(bdrv_get_aio_context(target) == ctx);
087ba459 736 g_assert(bdrv_get_aio_context(filter) == ctx);
012056f4
KW
737 g_assert(job->aio_context == ctx);
738
739 /* Change the AioContext of target */
740 aio_context_acquire(ctx);
741 bdrv_try_set_aio_context(target, main_ctx, &error_abort);
742 aio_context_release(ctx);
743 g_assert(bdrv_get_aio_context(src) == main_ctx);
744 g_assert(bdrv_get_aio_context(target) == main_ctx);
087ba459 745 g_assert(bdrv_get_aio_context(filter) == main_ctx);
012056f4
KW
746
747 /* With a BlockBackend on src, changing target must fail */
d861ab3a 748 blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
012056f4
KW
749 blk_insert_bs(blk, src, &error_abort);
750
751 bdrv_try_set_aio_context(target, ctx, &local_err);
7b8eb7f8 752 error_free_or_abort(&local_err);
012056f4
KW
753
754 g_assert(blk_get_aio_context(blk) == main_ctx);
755 g_assert(bdrv_get_aio_context(src) == main_ctx);
756 g_assert(bdrv_get_aio_context(target) == main_ctx);
087ba459 757 g_assert(bdrv_get_aio_context(filter) == main_ctx);
012056f4
KW
758
759 /* ...unless we explicitly allow it */
760 aio_context_acquire(ctx);
761 blk_set_allow_aio_context_change(blk, true);
762 bdrv_try_set_aio_context(target, ctx, &error_abort);
763 aio_context_release(ctx);
764
765 g_assert(blk_get_aio_context(blk) == ctx);
766 g_assert(bdrv_get_aio_context(src) == ctx);
767 g_assert(bdrv_get_aio_context(target) == ctx);
087ba459 768 g_assert(bdrv_get_aio_context(filter) == ctx);
012056f4
KW
769
770 job_cancel_sync_all();
771
772 aio_context_acquire(ctx);
97896a48 773 blk_set_aio_context(blk, main_ctx, &error_abort);
012056f4
KW
774 bdrv_try_set_aio_context(target, main_ctx, &error_abort);
775 aio_context_release(ctx);
776
777 blk_unref(blk);
778 bdrv_unref(src);
779 bdrv_unref(target);
780}
781
48946d7d
KW
782static void test_attach_second_node(void)
783{
784 IOThread *iothread = iothread_new();
785 AioContext *ctx = iothread_get_aio_context(iothread);
786 AioContext *main_ctx = qemu_get_aio_context();
787 BlockBackend *blk;
788 BlockDriverState *bs, *filter;
789 QDict *options;
790
791 blk = blk_new(ctx, BLK_PERM_ALL, BLK_PERM_ALL);
792 bs = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort);
793 blk_insert_bs(blk, bs, &error_abort);
794
795 options = qdict_new();
796 qdict_put_str(options, "driver", "raw");
797 qdict_put_str(options, "file", "base");
798
799 filter = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
800 g_assert(blk_get_aio_context(blk) == ctx);
801 g_assert(bdrv_get_aio_context(bs) == ctx);
802 g_assert(bdrv_get_aio_context(filter) == ctx);
803
1b285657 804 aio_context_acquire(ctx);
48946d7d 805 blk_set_aio_context(blk, main_ctx, &error_abort);
1b285657 806 aio_context_release(ctx);
48946d7d
KW
807 g_assert(blk_get_aio_context(blk) == main_ctx);
808 g_assert(bdrv_get_aio_context(bs) == main_ctx);
809 g_assert(bdrv_get_aio_context(filter) == main_ctx);
810
811 bdrv_unref(filter);
812 bdrv_unref(bs);
813 blk_unref(blk);
814}
815
2e9cdab3
KW
816static void test_attach_preserve_blk_ctx(void)
817{
818 IOThread *iothread = iothread_new();
819 AioContext *ctx = iothread_get_aio_context(iothread);
820 BlockBackend *blk;
821 BlockDriverState *bs;
822
823 blk = blk_new(ctx, BLK_PERM_ALL, BLK_PERM_ALL);
824 bs = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort);
825 bs->total_sectors = 65536 / BDRV_SECTOR_SIZE;
826
827 /* Add node to BlockBackend that has an iothread context assigned */
828 blk_insert_bs(blk, bs, &error_abort);
829 g_assert(blk_get_aio_context(blk) == ctx);
830 g_assert(bdrv_get_aio_context(bs) == ctx);
831
832 /* Remove the node again */
1b285657 833 aio_context_acquire(ctx);
2e9cdab3 834 blk_remove_bs(blk);
1b285657 835 aio_context_release(ctx);
2e9cdab3 836 g_assert(blk_get_aio_context(blk) == ctx);
ad943dcb 837 g_assert(bdrv_get_aio_context(bs) == qemu_get_aio_context());
2e9cdab3
KW
838
839 /* Re-attach the node */
840 blk_insert_bs(blk, bs, &error_abort);
841 g_assert(blk_get_aio_context(blk) == ctx);
842 g_assert(bdrv_get_aio_context(bs) == ctx);
843
1b285657 844 aio_context_acquire(ctx);
2e9cdab3 845 blk_set_aio_context(blk, qemu_get_aio_context(), &error_abort);
1b285657 846 aio_context_release(ctx);
2e9cdab3
KW
847 bdrv_unref(bs);
848 blk_unref(blk);
849}
850
4720cbee
KW
851int main(int argc, char **argv)
852{
853 int i;
854
855 bdrv_init();
856 qemu_init_main_loop(&error_abort);
857
858 g_test_init(&argc, &argv, NULL);
859
860 for (i = 0; i < ARRAY_SIZE(sync_op_tests); i++) {
861 const SyncOpTest *t = &sync_op_tests[i];
862 g_test_add_data_func(t->name, t, test_sync_op);
863 }
864
93c60f38 865 g_test_add_func("/attach/blockjob", test_attach_blockjob);
48946d7d 866 g_test_add_func("/attach/second_node", test_attach_second_node);
2e9cdab3 867 g_test_add_func("/attach/preserve_blk_ctx", test_attach_preserve_blk_ctx);
7e2f096a
KW
868 g_test_add_func("/propagate/basic", test_propagate_basic);
869 g_test_add_func("/propagate/diamond", test_propagate_diamond);
012056f4 870 g_test_add_func("/propagate/mirror", test_propagate_mirror);
93c60f38 871
4720cbee
KW
872 return g_test_run();
873}