xref: /qemu/tests/unit/test-block-iothread.c (revision b49f4755)
1da668aa1SThomas Huth /*
2da668aa1SThomas Huth  * Block tests for iothreads
3da668aa1SThomas Huth  *
4da668aa1SThomas Huth  * Copyright (c) 2018 Kevin Wolf <kwolf@redhat.com>
5da668aa1SThomas Huth  *
6da668aa1SThomas Huth  * Permission is hereby granted, free of charge, to any person obtaining a copy
7da668aa1SThomas Huth  * of this software and associated documentation files (the "Software"), to deal
8da668aa1SThomas Huth  * in the Software without restriction, including without limitation the rights
9da668aa1SThomas Huth  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10da668aa1SThomas Huth  * copies of the Software, and to permit persons to whom the Software is
11da668aa1SThomas Huth  * furnished to do so, subject to the following conditions:
12da668aa1SThomas Huth  *
13da668aa1SThomas Huth  * The above copyright notice and this permission notice shall be included in
14da668aa1SThomas Huth  * all copies or substantial portions of the Software.
15da668aa1SThomas Huth  *
16da668aa1SThomas Huth  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17da668aa1SThomas Huth  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18da668aa1SThomas Huth  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19da668aa1SThomas Huth  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20da668aa1SThomas Huth  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21da668aa1SThomas Huth  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22da668aa1SThomas Huth  * THE SOFTWARE.
23da668aa1SThomas Huth  */
24da668aa1SThomas Huth 
25da668aa1SThomas Huth #include "qemu/osdep.h"
26da668aa1SThomas Huth #include "block/block.h"
27e2c1c34fSMarkus Armbruster #include "block/block_int-global-state.h"
28da668aa1SThomas Huth #include "block/blockjob_int.h"
29da668aa1SThomas Huth #include "sysemu/block-backend.h"
30da668aa1SThomas Huth #include "qapi/error.h"
31da668aa1SThomas Huth #include "qapi/qmp/qdict.h"
32da668aa1SThomas Huth #include "qemu/main-loop.h"
33da668aa1SThomas Huth #include "iothread.h"
34da668aa1SThomas Huth 
bdrv_test_co_preadv(BlockDriverState * bs,int64_t offset,int64_t bytes,QEMUIOVector * qiov,BdrvRequestFlags flags)35f7ef38ddSVladimir Sementsov-Ogievskiy static int coroutine_fn bdrv_test_co_preadv(BlockDriverState *bs,
36f7ef38ddSVladimir Sementsov-Ogievskiy                                             int64_t offset, int64_t bytes,
37f7ef38ddSVladimir Sementsov-Ogievskiy                                             QEMUIOVector *qiov,
38f7ef38ddSVladimir Sementsov-Ogievskiy                                             BdrvRequestFlags flags)
39f7ef38ddSVladimir Sementsov-Ogievskiy {
40f7ef38ddSVladimir Sementsov-Ogievskiy     return 0;
41f7ef38ddSVladimir Sementsov-Ogievskiy }
42f7ef38ddSVladimir Sementsov-Ogievskiy 
bdrv_test_co_pwritev(BlockDriverState * bs,int64_t offset,int64_t bytes,QEMUIOVector * qiov,BdrvRequestFlags flags)43f7ef38ddSVladimir Sementsov-Ogievskiy static int coroutine_fn bdrv_test_co_pwritev(BlockDriverState *bs,
44e75abedaSVladimir Sementsov-Ogievskiy                                              int64_t offset, int64_t bytes,
45f7ef38ddSVladimir Sementsov-Ogievskiy                                              QEMUIOVector *qiov,
46e75abedaSVladimir Sementsov-Ogievskiy                                              BdrvRequestFlags flags)
47da668aa1SThomas Huth {
48da668aa1SThomas Huth     return 0;
49da668aa1SThomas Huth }
50da668aa1SThomas Huth 
bdrv_test_co_pdiscard(BlockDriverState * bs,int64_t offset,int64_t bytes)51da668aa1SThomas Huth static int coroutine_fn bdrv_test_co_pdiscard(BlockDriverState *bs,
520c802287SVladimir Sementsov-Ogievskiy                                               int64_t offset, int64_t bytes)
53da668aa1SThomas Huth {
54da668aa1SThomas Huth     return 0;
55da668aa1SThomas Huth }
56da668aa1SThomas Huth 
57da668aa1SThomas Huth static int coroutine_fn
bdrv_test_co_truncate(BlockDriverState * bs,int64_t offset,bool exact,PreallocMode prealloc,BdrvRequestFlags flags,Error ** errp)58da668aa1SThomas Huth bdrv_test_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
59da668aa1SThomas Huth                       PreallocMode prealloc, BdrvRequestFlags flags,
60da668aa1SThomas Huth                       Error **errp)
61da668aa1SThomas Huth {
62da668aa1SThomas Huth     return 0;
63da668aa1SThomas Huth }
64da668aa1SThomas Huth 
bdrv_test_co_block_status(BlockDriverState * bs,bool want_zero,int64_t offset,int64_t count,int64_t * pnum,int64_t * map,BlockDriverState ** file)65da668aa1SThomas Huth static int coroutine_fn bdrv_test_co_block_status(BlockDriverState *bs,
66da668aa1SThomas Huth                                                   bool want_zero,
67da668aa1SThomas Huth                                                   int64_t offset, int64_t count,
68da668aa1SThomas Huth                                                   int64_t *pnum, int64_t *map,
69da668aa1SThomas Huth                                                   BlockDriverState **file)
70da668aa1SThomas Huth {
71da668aa1SThomas Huth     *pnum = count;
72da668aa1SThomas Huth     return 0;
73da668aa1SThomas Huth }
74da668aa1SThomas Huth 
75da668aa1SThomas Huth static BlockDriver bdrv_test = {
76da668aa1SThomas Huth     .format_name            = "test",
77da668aa1SThomas Huth     .instance_size          = 1,
78da668aa1SThomas Huth 
79f7ef38ddSVladimir Sementsov-Ogievskiy     .bdrv_co_preadv         = bdrv_test_co_preadv,
80f7ef38ddSVladimir Sementsov-Ogievskiy     .bdrv_co_pwritev        = bdrv_test_co_pwritev,
81da668aa1SThomas Huth     .bdrv_co_pdiscard       = bdrv_test_co_pdiscard,
82da668aa1SThomas Huth     .bdrv_co_truncate       = bdrv_test_co_truncate,
83da668aa1SThomas Huth     .bdrv_co_block_status   = bdrv_test_co_block_status,
84da668aa1SThomas Huth };
85da668aa1SThomas Huth 
test_sync_op_pread(BdrvChild * c)86da668aa1SThomas Huth static void test_sync_op_pread(BdrvChild *c)
87da668aa1SThomas Huth {
88da668aa1SThomas Huth     uint8_t buf[512];
89da668aa1SThomas Huth     int ret;
90da668aa1SThomas Huth 
91da668aa1SThomas Huth     /* Success */
9232cc71deSAlberto Faria     ret = bdrv_pread(c, 0, sizeof(buf), buf, 0);
93353a5d84SAlberto Faria     g_assert_cmpint(ret, ==, 0);
94da668aa1SThomas Huth 
95da668aa1SThomas Huth     /* Early error: Negative offset */
9632cc71deSAlberto Faria     ret = bdrv_pread(c, -2, sizeof(buf), buf, 0);
97da668aa1SThomas Huth     g_assert_cmpint(ret, ==, -EIO);
98da668aa1SThomas Huth }
99da668aa1SThomas Huth 
test_sync_op_pwrite(BdrvChild * c)100da668aa1SThomas Huth static void test_sync_op_pwrite(BdrvChild *c)
101da668aa1SThomas Huth {
102d8b2e563SEmanuele Giuseppe Esposito     uint8_t buf[512] = { 0 };
103da668aa1SThomas Huth     int ret;
104da668aa1SThomas Huth 
105da668aa1SThomas Huth     /* Success */
10632cc71deSAlberto Faria     ret = bdrv_pwrite(c, 0, sizeof(buf), buf, 0);
107353a5d84SAlberto Faria     g_assert_cmpint(ret, ==, 0);
108da668aa1SThomas Huth 
109da668aa1SThomas Huth     /* Early error: Negative offset */
11032cc71deSAlberto Faria     ret = bdrv_pwrite(c, -2, sizeof(buf), buf, 0);
111da668aa1SThomas Huth     g_assert_cmpint(ret, ==, -EIO);
112da668aa1SThomas Huth }
113da668aa1SThomas Huth 
test_sync_op_blk_pread(BlockBackend * blk)114da668aa1SThomas Huth static void test_sync_op_blk_pread(BlockBackend *blk)
115da668aa1SThomas Huth {
116da668aa1SThomas Huth     uint8_t buf[512];
117da668aa1SThomas Huth     int ret;
118da668aa1SThomas Huth 
119da668aa1SThomas Huth     /* Success */
120a9262f55SAlberto Faria     ret = blk_pread(blk, 0, sizeof(buf), buf, 0);
121bf5b16faSAlberto Faria     g_assert_cmpint(ret, ==, 0);
122da668aa1SThomas Huth 
123da668aa1SThomas Huth     /* Early error: Negative offset */
124a9262f55SAlberto Faria     ret = blk_pread(blk, -2, sizeof(buf), buf, 0);
125da668aa1SThomas Huth     g_assert_cmpint(ret, ==, -EIO);
126da668aa1SThomas Huth }
127da668aa1SThomas Huth 
test_sync_op_blk_pwrite(BlockBackend * blk)128da668aa1SThomas Huth static void test_sync_op_blk_pwrite(BlockBackend *blk)
129da668aa1SThomas Huth {
130d8b2e563SEmanuele Giuseppe Esposito     uint8_t buf[512] = { 0 };
131da668aa1SThomas Huth     int ret;
132da668aa1SThomas Huth 
133da668aa1SThomas Huth     /* Success */
134a9262f55SAlberto Faria     ret = blk_pwrite(blk, 0, sizeof(buf), buf, 0);
135bf5b16faSAlberto Faria     g_assert_cmpint(ret, ==, 0);
136da668aa1SThomas Huth 
137da668aa1SThomas Huth     /* Early error: Negative offset */
138a9262f55SAlberto Faria     ret = blk_pwrite(blk, -2, sizeof(buf), buf, 0);
139da668aa1SThomas Huth     g_assert_cmpint(ret, ==, -EIO);
140da668aa1SThomas Huth }
141da668aa1SThomas Huth 
test_sync_op_blk_preadv(BlockBackend * blk)1427c8cd723SAlberto Faria static void test_sync_op_blk_preadv(BlockBackend *blk)
1437c8cd723SAlberto Faria {
1447c8cd723SAlberto Faria     uint8_t buf[512];
1457c8cd723SAlberto Faria     QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, sizeof(buf));
1467c8cd723SAlberto Faria     int ret;
1477c8cd723SAlberto Faria 
1487c8cd723SAlberto Faria     /* Success */
1497c8cd723SAlberto Faria     ret = blk_preadv(blk, 0, sizeof(buf), &qiov, 0);
1507c8cd723SAlberto Faria     g_assert_cmpint(ret, ==, 0);
1517c8cd723SAlberto Faria 
1527c8cd723SAlberto Faria     /* Early error: Negative offset */
1537c8cd723SAlberto Faria     ret = blk_preadv(blk, -2, sizeof(buf), &qiov, 0);
1547c8cd723SAlberto Faria     g_assert_cmpint(ret, ==, -EIO);
1557c8cd723SAlberto Faria }
1567c8cd723SAlberto Faria 
test_sync_op_blk_pwritev(BlockBackend * blk)1577c8cd723SAlberto Faria static void test_sync_op_blk_pwritev(BlockBackend *blk)
1587c8cd723SAlberto Faria {
1597c8cd723SAlberto Faria     uint8_t buf[512] = { 0 };
1607c8cd723SAlberto Faria     QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, sizeof(buf));
1617c8cd723SAlberto Faria     int ret;
1627c8cd723SAlberto Faria 
1637c8cd723SAlberto Faria     /* Success */
1647c8cd723SAlberto Faria     ret = blk_pwritev(blk, 0, sizeof(buf), &qiov, 0);
1657c8cd723SAlberto Faria     g_assert_cmpint(ret, ==, 0);
1667c8cd723SAlberto Faria 
1677c8cd723SAlberto Faria     /* Early error: Negative offset */
1687c8cd723SAlberto Faria     ret = blk_pwritev(blk, -2, sizeof(buf), &qiov, 0);
1697c8cd723SAlberto Faria     g_assert_cmpint(ret, ==, -EIO);
1707c8cd723SAlberto Faria }
1717c8cd723SAlberto Faria 
test_sync_op_blk_preadv_part(BlockBackend * blk)172d1d3fc3dSAlberto Faria static void test_sync_op_blk_preadv_part(BlockBackend *blk)
173d1d3fc3dSAlberto Faria {
174d1d3fc3dSAlberto Faria     uint8_t buf[512];
175d1d3fc3dSAlberto Faria     QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, sizeof(buf));
176d1d3fc3dSAlberto Faria     int ret;
177d1d3fc3dSAlberto Faria 
178d1d3fc3dSAlberto Faria     /* Success */
179d1d3fc3dSAlberto Faria     ret = blk_preadv_part(blk, 0, sizeof(buf), &qiov, 0, 0);
180d1d3fc3dSAlberto Faria     g_assert_cmpint(ret, ==, 0);
181d1d3fc3dSAlberto Faria 
182d1d3fc3dSAlberto Faria     /* Early error: Negative offset */
183d1d3fc3dSAlberto Faria     ret = blk_preadv_part(blk, -2, sizeof(buf), &qiov, 0, 0);
184d1d3fc3dSAlberto Faria     g_assert_cmpint(ret, ==, -EIO);
185d1d3fc3dSAlberto Faria }
186d1d3fc3dSAlberto Faria 
test_sync_op_blk_pwritev_part(BlockBackend * blk)18709cca043SAlberto Faria static void test_sync_op_blk_pwritev_part(BlockBackend *blk)
18809cca043SAlberto Faria {
18909cca043SAlberto Faria     uint8_t buf[512] = { 0 };
19009cca043SAlberto Faria     QEMUIOVector qiov = QEMU_IOVEC_INIT_BUF(qiov, buf, sizeof(buf));
19109cca043SAlberto Faria     int ret;
19209cca043SAlberto Faria 
19309cca043SAlberto Faria     /* Success */
19409cca043SAlberto Faria     ret = blk_pwritev_part(blk, 0, sizeof(buf), &qiov, 0, 0);
19509cca043SAlberto Faria     g_assert_cmpint(ret, ==, 0);
19609cca043SAlberto Faria 
19709cca043SAlberto Faria     /* Early error: Negative offset */
19809cca043SAlberto Faria     ret = blk_pwritev_part(blk, -2, sizeof(buf), &qiov, 0, 0);
19909cca043SAlberto Faria     g_assert_cmpint(ret, ==, -EIO);
20009cca043SAlberto Faria }
20109cca043SAlberto Faria 
test_sync_op_blk_pwrite_compressed(BlockBackend * blk)2022c9715faSAlberto Faria static void test_sync_op_blk_pwrite_compressed(BlockBackend *blk)
2032c9715faSAlberto Faria {
2042c9715faSAlberto Faria     uint8_t buf[512] = { 0 };
2052c9715faSAlberto Faria     int ret;
2062c9715faSAlberto Faria 
2072c9715faSAlberto Faria     /* Late error: Not supported */
2082c9715faSAlberto Faria     ret = blk_pwrite_compressed(blk, 0, sizeof(buf), buf);
2092c9715faSAlberto Faria     g_assert_cmpint(ret, ==, -ENOTSUP);
2102c9715faSAlberto Faria 
2112c9715faSAlberto Faria     /* Early error: Negative offset */
2122c9715faSAlberto Faria     ret = blk_pwrite_compressed(blk, -2, sizeof(buf), buf);
2132c9715faSAlberto Faria     g_assert_cmpint(ret, ==, -EIO);
2142c9715faSAlberto Faria }
2152c9715faSAlberto Faria 
test_sync_op_blk_pwrite_zeroes(BlockBackend * blk)2161c95dc91SAlberto Faria static void test_sync_op_blk_pwrite_zeroes(BlockBackend *blk)
2171c95dc91SAlberto Faria {
2181c95dc91SAlberto Faria     int ret;
2191c95dc91SAlberto Faria 
2201c95dc91SAlberto Faria     /* Success */
2211c95dc91SAlberto Faria     ret = blk_pwrite_zeroes(blk, 0, 512, 0);
2221c95dc91SAlberto Faria     g_assert_cmpint(ret, ==, 0);
2231c95dc91SAlberto Faria 
2241c95dc91SAlberto Faria     /* Early error: Negative offset */
2251c95dc91SAlberto Faria     ret = blk_pwrite_zeroes(blk, -2, 512, 0);
2261c95dc91SAlberto Faria     g_assert_cmpint(ret, ==, -EIO);
2271c95dc91SAlberto Faria }
2281c95dc91SAlberto Faria 
test_sync_op_load_vmstate(BdrvChild * c)229da668aa1SThomas Huth static void test_sync_op_load_vmstate(BdrvChild *c)
230da668aa1SThomas Huth {
231da668aa1SThomas Huth     uint8_t buf[512];
232da668aa1SThomas Huth     int ret;
233da668aa1SThomas Huth 
234da668aa1SThomas Huth     /* Error: Driver does not support snapshots */
235da668aa1SThomas Huth     ret = bdrv_load_vmstate(c->bs, buf, 0, sizeof(buf));
236da668aa1SThomas Huth     g_assert_cmpint(ret, ==, -ENOTSUP);
237da668aa1SThomas Huth }
238da668aa1SThomas Huth 
test_sync_op_save_vmstate(BdrvChild * c)239da668aa1SThomas Huth static void test_sync_op_save_vmstate(BdrvChild *c)
240da668aa1SThomas Huth {
241d8b2e563SEmanuele Giuseppe Esposito     uint8_t buf[512] = { 0 };
242da668aa1SThomas Huth     int ret;
243da668aa1SThomas Huth 
244da668aa1SThomas Huth     /* Error: Driver does not support snapshots */
245da668aa1SThomas Huth     ret = bdrv_save_vmstate(c->bs, buf, 0, sizeof(buf));
246da668aa1SThomas Huth     g_assert_cmpint(ret, ==, -ENOTSUP);
247da668aa1SThomas Huth }
248da668aa1SThomas Huth 
test_sync_op_pdiscard(BdrvChild * c)249da668aa1SThomas Huth static void test_sync_op_pdiscard(BdrvChild *c)
250da668aa1SThomas Huth {
251da668aa1SThomas Huth     int ret;
252da668aa1SThomas Huth 
253da668aa1SThomas Huth     /* Normal success path */
254da668aa1SThomas Huth     c->bs->open_flags |= BDRV_O_UNMAP;
255da668aa1SThomas Huth     ret = bdrv_pdiscard(c, 0, 512);
256da668aa1SThomas Huth     g_assert_cmpint(ret, ==, 0);
257da668aa1SThomas Huth 
258da668aa1SThomas Huth     /* Early success: UNMAP not supported */
259da668aa1SThomas Huth     c->bs->open_flags &= ~BDRV_O_UNMAP;
260da668aa1SThomas Huth     ret = bdrv_pdiscard(c, 0, 512);
261da668aa1SThomas Huth     g_assert_cmpint(ret, ==, 0);
262da668aa1SThomas Huth 
263da668aa1SThomas Huth     /* Early error: Negative offset */
264da668aa1SThomas Huth     ret = bdrv_pdiscard(c, -2, 512);
265da668aa1SThomas Huth     g_assert_cmpint(ret, ==, -EIO);
266da668aa1SThomas Huth }
267da668aa1SThomas Huth 
test_sync_op_blk_pdiscard(BlockBackend * blk)268da668aa1SThomas Huth static void test_sync_op_blk_pdiscard(BlockBackend *blk)
269da668aa1SThomas Huth {
270da668aa1SThomas Huth     int ret;
271da668aa1SThomas Huth 
272da668aa1SThomas Huth     /* Early success: UNMAP not supported */
273da668aa1SThomas Huth     ret = blk_pdiscard(blk, 0, 512);
274da668aa1SThomas Huth     g_assert_cmpint(ret, ==, 0);
275da668aa1SThomas Huth 
276da668aa1SThomas Huth     /* Early error: Negative offset */
277da668aa1SThomas Huth     ret = blk_pdiscard(blk, -2, 512);
278da668aa1SThomas Huth     g_assert_cmpint(ret, ==, -EIO);
279da668aa1SThomas Huth }
280da668aa1SThomas Huth 
test_sync_op_truncate(BdrvChild * c)281da668aa1SThomas Huth static void test_sync_op_truncate(BdrvChild *c)
282da668aa1SThomas Huth {
283da668aa1SThomas Huth     int ret;
284da668aa1SThomas Huth 
285da668aa1SThomas Huth     /* Normal success path */
286da668aa1SThomas Huth     ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, 0, NULL);
287da668aa1SThomas Huth     g_assert_cmpint(ret, ==, 0);
288da668aa1SThomas Huth 
289da668aa1SThomas Huth     /* Early error: Negative offset */
290da668aa1SThomas Huth     ret = bdrv_truncate(c, -2, false, PREALLOC_MODE_OFF, 0, NULL);
291da668aa1SThomas Huth     g_assert_cmpint(ret, ==, -EINVAL);
292da668aa1SThomas Huth 
293da668aa1SThomas Huth     /* Error: Read-only image */
294da668aa1SThomas Huth     c->bs->open_flags &= ~BDRV_O_RDWR;
295da668aa1SThomas Huth 
296da668aa1SThomas Huth     ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, 0, NULL);
297da668aa1SThomas Huth     g_assert_cmpint(ret, ==, -EACCES);
298da668aa1SThomas Huth 
299da668aa1SThomas Huth     c->bs->open_flags |= BDRV_O_RDWR;
300da668aa1SThomas Huth }
301da668aa1SThomas Huth 
test_sync_op_blk_truncate(BlockBackend * blk)302015ed252SAlberto Faria static void test_sync_op_blk_truncate(BlockBackend *blk)
303015ed252SAlberto Faria {
304015ed252SAlberto Faria     int ret;
305015ed252SAlberto Faria 
306015ed252SAlberto Faria     /* Normal success path */
307015ed252SAlberto Faria     ret = blk_truncate(blk, 65536, false, PREALLOC_MODE_OFF, 0, NULL);
308015ed252SAlberto Faria     g_assert_cmpint(ret, ==, 0);
309015ed252SAlberto Faria 
310015ed252SAlberto Faria     /* Early error: Negative offset */
311015ed252SAlberto Faria     ret = blk_truncate(blk, -2, false, PREALLOC_MODE_OFF, 0, NULL);
312015ed252SAlberto Faria     g_assert_cmpint(ret, ==, -EINVAL);
313015ed252SAlberto Faria }
314015ed252SAlberto Faria 
3157ff9579eSKevin Wolf /* Disable TSA to make bdrv_test.bdrv_co_block_status writable */
test_sync_op_block_status(BdrvChild * c)3167ff9579eSKevin Wolf static void TSA_NO_TSA test_sync_op_block_status(BdrvChild *c)
317da668aa1SThomas Huth {
318da668aa1SThomas Huth     int ret;
319da668aa1SThomas Huth     int64_t n;
320da668aa1SThomas Huth 
321da668aa1SThomas Huth     /* Normal success path */
322da668aa1SThomas Huth     ret = bdrv_is_allocated(c->bs, 0, 65536, &n);
323da668aa1SThomas Huth     g_assert_cmpint(ret, ==, 0);
324da668aa1SThomas Huth 
325da668aa1SThomas Huth     /* Early success: No driver support */
326da668aa1SThomas Huth     bdrv_test.bdrv_co_block_status = NULL;
327da668aa1SThomas Huth     ret = bdrv_is_allocated(c->bs, 0, 65536, &n);
328da668aa1SThomas Huth     g_assert_cmpint(ret, ==, 1);
329da668aa1SThomas Huth 
330da668aa1SThomas Huth     /* Early success: bytes = 0 */
331da668aa1SThomas Huth     ret = bdrv_is_allocated(c->bs, 0, 0, &n);
332da668aa1SThomas Huth     g_assert_cmpint(ret, ==, 0);
333da668aa1SThomas Huth 
334da668aa1SThomas Huth     /* Early success: Offset > image size*/
335da668aa1SThomas Huth     ret = bdrv_is_allocated(c->bs, 0x1000000, 0x1000000, &n);
336da668aa1SThomas Huth     g_assert_cmpint(ret, ==, 0);
337da668aa1SThomas Huth }
338da668aa1SThomas Huth 
test_sync_op_flush(BdrvChild * c)339da668aa1SThomas Huth static void test_sync_op_flush(BdrvChild *c)
340da668aa1SThomas Huth {
341da668aa1SThomas Huth     int ret;
342da668aa1SThomas Huth 
343da668aa1SThomas Huth     /* Normal success path */
344da668aa1SThomas Huth     ret = bdrv_flush(c->bs);
345da668aa1SThomas Huth     g_assert_cmpint(ret, ==, 0);
346da668aa1SThomas Huth 
347da668aa1SThomas Huth     /* Early success: Read-only image */
348da668aa1SThomas Huth     c->bs->open_flags &= ~BDRV_O_RDWR;
349da668aa1SThomas Huth 
350da668aa1SThomas Huth     ret = bdrv_flush(c->bs);
351da668aa1SThomas Huth     g_assert_cmpint(ret, ==, 0);
352da668aa1SThomas Huth 
353da668aa1SThomas Huth     c->bs->open_flags |= BDRV_O_RDWR;
354da668aa1SThomas Huth }
355da668aa1SThomas Huth 
test_sync_op_blk_flush(BlockBackend * blk)356da668aa1SThomas Huth static void test_sync_op_blk_flush(BlockBackend *blk)
357da668aa1SThomas Huth {
358da668aa1SThomas Huth     BlockDriverState *bs = blk_bs(blk);
359da668aa1SThomas Huth     int ret;
360da668aa1SThomas Huth 
361da668aa1SThomas Huth     /* Normal success path */
362da668aa1SThomas Huth     ret = blk_flush(blk);
363da668aa1SThomas Huth     g_assert_cmpint(ret, ==, 0);
364da668aa1SThomas Huth 
365da668aa1SThomas Huth     /* Early success: Read-only image */
366da668aa1SThomas Huth     bs->open_flags &= ~BDRV_O_RDWR;
367da668aa1SThomas Huth 
368da668aa1SThomas Huth     ret = blk_flush(blk);
369da668aa1SThomas Huth     g_assert_cmpint(ret, ==, 0);
370da668aa1SThomas Huth 
371da668aa1SThomas Huth     bs->open_flags |= BDRV_O_RDWR;
372da668aa1SThomas Huth }
373da668aa1SThomas Huth 
test_sync_op_check(BdrvChild * c)374da668aa1SThomas Huth static void test_sync_op_check(BdrvChild *c)
375da668aa1SThomas Huth {
376da668aa1SThomas Huth     BdrvCheckResult result;
377da668aa1SThomas Huth     int ret;
378da668aa1SThomas Huth 
379da668aa1SThomas Huth     /* Error: Driver does not implement check */
380da668aa1SThomas Huth     ret = bdrv_check(c->bs, &result, 0);
381da668aa1SThomas Huth     g_assert_cmpint(ret, ==, -ENOTSUP);
382da668aa1SThomas Huth }
383da668aa1SThomas Huth 
test_sync_op_activate(BdrvChild * c)3843b717194SEmanuele Giuseppe Esposito static void test_sync_op_activate(BdrvChild *c)
385da668aa1SThomas Huth {
3862b3912f1SKevin Wolf     GLOBAL_STATE_CODE();
3872b3912f1SKevin Wolf     GRAPH_RDLOCK_GUARD_MAINLOOP();
3882b3912f1SKevin Wolf 
389da668aa1SThomas Huth     /* Early success: Image is not inactive */
390a94750d9SEmanuele Giuseppe Esposito     bdrv_activate(c->bs, NULL);
391da668aa1SThomas Huth }
392da668aa1SThomas Huth 
393da668aa1SThomas Huth 
394da668aa1SThomas Huth typedef struct SyncOpTest {
395da668aa1SThomas Huth     const char *name;
396da668aa1SThomas Huth     void (*fn)(BdrvChild *c);
397da668aa1SThomas Huth     void (*blkfn)(BlockBackend *blk);
398da668aa1SThomas Huth } SyncOpTest;
399da668aa1SThomas Huth 
400da668aa1SThomas Huth const SyncOpTest sync_op_tests[] = {
401da668aa1SThomas Huth     {
402da668aa1SThomas Huth         .name   = "/sync-op/pread",
403da668aa1SThomas Huth         .fn     = test_sync_op_pread,
404da668aa1SThomas Huth         .blkfn  = test_sync_op_blk_pread,
405da668aa1SThomas Huth     }, {
406da668aa1SThomas Huth         .name   = "/sync-op/pwrite",
407da668aa1SThomas Huth         .fn     = test_sync_op_pwrite,
408da668aa1SThomas Huth         .blkfn  = test_sync_op_blk_pwrite,
409da668aa1SThomas Huth     }, {
4107c8cd723SAlberto Faria         .name   = "/sync-op/preadv",
4117c8cd723SAlberto Faria         .fn     = NULL,
4127c8cd723SAlberto Faria         .blkfn  = test_sync_op_blk_preadv,
4137c8cd723SAlberto Faria     }, {
4147c8cd723SAlberto Faria         .name   = "/sync-op/pwritev",
4157c8cd723SAlberto Faria         .fn     = NULL,
4167c8cd723SAlberto Faria         .blkfn  = test_sync_op_blk_pwritev,
4177c8cd723SAlberto Faria     }, {
418d1d3fc3dSAlberto Faria         .name   = "/sync-op/preadv_part",
419d1d3fc3dSAlberto Faria         .fn     = NULL,
420d1d3fc3dSAlberto Faria         .blkfn  = test_sync_op_blk_preadv_part,
421d1d3fc3dSAlberto Faria     }, {
42209cca043SAlberto Faria         .name   = "/sync-op/pwritev_part",
42309cca043SAlberto Faria         .fn     = NULL,
42409cca043SAlberto Faria         .blkfn  = test_sync_op_blk_pwritev_part,
42509cca043SAlberto Faria     }, {
4262c9715faSAlberto Faria         .name   = "/sync-op/pwrite_compressed",
4272c9715faSAlberto Faria         .fn     = NULL,
4282c9715faSAlberto Faria         .blkfn  = test_sync_op_blk_pwrite_compressed,
4292c9715faSAlberto Faria     }, {
4301c95dc91SAlberto Faria         .name   = "/sync-op/pwrite_zeroes",
4311c95dc91SAlberto Faria         .fn     = NULL,
4321c95dc91SAlberto Faria         .blkfn  = test_sync_op_blk_pwrite_zeroes,
4331c95dc91SAlberto Faria     }, {
434da668aa1SThomas Huth         .name   = "/sync-op/load_vmstate",
435da668aa1SThomas Huth         .fn     = test_sync_op_load_vmstate,
436da668aa1SThomas Huth     }, {
437da668aa1SThomas Huth         .name   = "/sync-op/save_vmstate",
438da668aa1SThomas Huth         .fn     = test_sync_op_save_vmstate,
439da668aa1SThomas Huth     }, {
440da668aa1SThomas Huth         .name   = "/sync-op/pdiscard",
441da668aa1SThomas Huth         .fn     = test_sync_op_pdiscard,
442da668aa1SThomas Huth         .blkfn  = test_sync_op_blk_pdiscard,
443da668aa1SThomas Huth     }, {
444da668aa1SThomas Huth         .name   = "/sync-op/truncate",
445da668aa1SThomas Huth         .fn     = test_sync_op_truncate,
446015ed252SAlberto Faria         .blkfn  = test_sync_op_blk_truncate,
447da668aa1SThomas Huth     }, {
448da668aa1SThomas Huth         .name   = "/sync-op/block_status",
449da668aa1SThomas Huth         .fn     = test_sync_op_block_status,
450da668aa1SThomas Huth     }, {
451da668aa1SThomas Huth         .name   = "/sync-op/flush",
452da668aa1SThomas Huth         .fn     = test_sync_op_flush,
453da668aa1SThomas Huth         .blkfn  = test_sync_op_blk_flush,
454da668aa1SThomas Huth     }, {
455da668aa1SThomas Huth         .name   = "/sync-op/check",
456da668aa1SThomas Huth         .fn     = test_sync_op_check,
457da668aa1SThomas Huth     }, {
4583b717194SEmanuele Giuseppe Esposito         .name   = "/sync-op/activate",
4593b717194SEmanuele Giuseppe Esposito         .fn     = test_sync_op_activate,
460da668aa1SThomas Huth     },
461da668aa1SThomas Huth };
462da668aa1SThomas Huth 
463da668aa1SThomas Huth /* Test synchronous operations that run in a different iothread, so we have to
464da668aa1SThomas Huth  * poll for the coroutine there to return. */
test_sync_op(const void * opaque)465da668aa1SThomas Huth static void test_sync_op(const void *opaque)
466da668aa1SThomas Huth {
467da668aa1SThomas Huth     const SyncOpTest *t = opaque;
468da668aa1SThomas Huth     IOThread *iothread = iothread_new();
469da668aa1SThomas Huth     AioContext *ctx = iothread_get_aio_context(iothread);
470da668aa1SThomas Huth     BlockBackend *blk;
471da668aa1SThomas Huth     BlockDriverState *bs;
472da668aa1SThomas Huth     BdrvChild *c;
473da668aa1SThomas Huth 
474b59b4660SKevin Wolf     GLOBAL_STATE_CODE();
475b59b4660SKevin Wolf 
476da668aa1SThomas Huth     blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
477da668aa1SThomas Huth     bs = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort);
478da668aa1SThomas Huth     bs->total_sectors = 65536 / BDRV_SECTOR_SIZE;
479da668aa1SThomas Huth     blk_insert_bs(blk, bs, &error_abort);
480b59b4660SKevin Wolf 
481b59b4660SKevin Wolf     bdrv_graph_rdlock_main_loop();
482da668aa1SThomas Huth     c = QLIST_FIRST(&bs->parents);
483b59b4660SKevin Wolf     bdrv_graph_rdunlock_main_loop();
484da668aa1SThomas Huth 
485da668aa1SThomas Huth     blk_set_aio_context(blk, ctx, &error_abort);
4867c8cd723SAlberto Faria     if (t->fn) {
487da668aa1SThomas Huth         t->fn(c);
4887c8cd723SAlberto Faria     }
489da668aa1SThomas Huth     if (t->blkfn) {
490da668aa1SThomas Huth         t->blkfn(blk);
491da668aa1SThomas Huth     }
492da668aa1SThomas Huth     blk_set_aio_context(blk, qemu_get_aio_context(), &error_abort);
493da668aa1SThomas Huth 
494da668aa1SThomas Huth     bdrv_unref(bs);
495da668aa1SThomas Huth     blk_unref(blk);
496da668aa1SThomas Huth }
497da668aa1SThomas Huth 
498da668aa1SThomas Huth typedef struct TestBlockJob {
499da668aa1SThomas Huth     BlockJob common;
500da668aa1SThomas Huth     bool should_complete;
501da668aa1SThomas Huth     int n;
502da668aa1SThomas Huth } TestBlockJob;
503da668aa1SThomas Huth 
test_job_prepare(Job * job)504da668aa1SThomas Huth static int test_job_prepare(Job *job)
505da668aa1SThomas Huth {
506da668aa1SThomas Huth     g_assert(qemu_get_current_aio_context() == qemu_get_aio_context());
507da668aa1SThomas Huth     return 0;
508da668aa1SThomas Huth }
509da668aa1SThomas Huth 
test_job_run(Job * job,Error ** errp)510da668aa1SThomas Huth static int coroutine_fn test_job_run(Job *job, Error **errp)
511da668aa1SThomas Huth {
512da668aa1SThomas Huth     TestBlockJob *s = container_of(job, TestBlockJob, common.job);
513da668aa1SThomas Huth 
514da668aa1SThomas Huth     job_transition_to_ready(&s->common.job);
515da668aa1SThomas Huth     while (!s->should_complete) {
516da668aa1SThomas Huth         s->n++;
517da668aa1SThomas Huth         g_assert(qemu_get_current_aio_context() == job->aio_context);
518da668aa1SThomas Huth 
519da668aa1SThomas Huth         /* Avoid job_sleep_ns() because it marks the job as !busy. We want to
520da668aa1SThomas Huth          * emulate some actual activity (probably some I/O) here so that the
521da668aa1SThomas Huth          * drain involved in AioContext switches has to wait for this activity
522da668aa1SThomas Huth          * to stop. */
523da668aa1SThomas Huth         qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 1000000);
524da668aa1SThomas Huth 
525da668aa1SThomas Huth         job_pause_point(&s->common.job);
526da668aa1SThomas Huth     }
527da668aa1SThomas Huth 
528da668aa1SThomas Huth     g_assert(qemu_get_current_aio_context() == job->aio_context);
529da668aa1SThomas Huth     return 0;
530da668aa1SThomas Huth }
531da668aa1SThomas Huth 
test_job_complete(Job * job,Error ** errp)532da668aa1SThomas Huth static void test_job_complete(Job *job, Error **errp)
533da668aa1SThomas Huth {
534da668aa1SThomas Huth     TestBlockJob *s = container_of(job, TestBlockJob, common.job);
535da668aa1SThomas Huth     s->should_complete = true;
536da668aa1SThomas Huth }
537da668aa1SThomas Huth 
538da668aa1SThomas Huth BlockJobDriver test_job_driver = {
539da668aa1SThomas Huth     .job_driver = {
540da668aa1SThomas Huth         .instance_size  = sizeof(TestBlockJob),
541da668aa1SThomas Huth         .free           = block_job_free,
542da668aa1SThomas Huth         .user_resume    = block_job_user_resume,
543da668aa1SThomas Huth         .run            = test_job_run,
544da668aa1SThomas Huth         .complete       = test_job_complete,
545da668aa1SThomas Huth         .prepare        = test_job_prepare,
546da668aa1SThomas Huth     },
547da668aa1SThomas Huth };
548da668aa1SThomas Huth 
test_attach_blockjob(void)549da668aa1SThomas Huth static void test_attach_blockjob(void)
550da668aa1SThomas Huth {
551da668aa1SThomas Huth     IOThread *iothread = iothread_new();
552da668aa1SThomas Huth     AioContext *ctx = iothread_get_aio_context(iothread);
553da668aa1SThomas Huth     BlockBackend *blk;
554da668aa1SThomas Huth     BlockDriverState *bs;
555da668aa1SThomas Huth     TestBlockJob *tjob;
556da668aa1SThomas Huth 
557da668aa1SThomas Huth     blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL, BLK_PERM_ALL);
558da668aa1SThomas Huth     bs = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort);
559da668aa1SThomas Huth     blk_insert_bs(blk, bs, &error_abort);
560da668aa1SThomas Huth 
561da668aa1SThomas Huth     tjob = block_job_create("job0", &test_job_driver, NULL, bs,
562da668aa1SThomas Huth                             0, BLK_PERM_ALL,
563da668aa1SThomas Huth                             0, 0, NULL, NULL, &error_abort);
564da668aa1SThomas Huth     job_start(&tjob->common.job);
565da668aa1SThomas Huth 
566da668aa1SThomas Huth     while (tjob->n == 0) {
567da668aa1SThomas Huth         aio_poll(qemu_get_aio_context(), false);
568da668aa1SThomas Huth     }
569da668aa1SThomas Huth 
570da668aa1SThomas Huth     blk_set_aio_context(blk, ctx, &error_abort);
571da668aa1SThomas Huth 
572da668aa1SThomas Huth     tjob->n = 0;
573da668aa1SThomas Huth     while (tjob->n == 0) {
574da668aa1SThomas Huth         aio_poll(qemu_get_aio_context(), false);
575da668aa1SThomas Huth     }
576da668aa1SThomas Huth 
577da668aa1SThomas Huth     blk_set_aio_context(blk, qemu_get_aio_context(), &error_abort);
578da668aa1SThomas Huth 
579da668aa1SThomas Huth     tjob->n = 0;
580da668aa1SThomas Huth     while (tjob->n == 0) {
581da668aa1SThomas Huth         aio_poll(qemu_get_aio_context(), false);
582da668aa1SThomas Huth     }
583da668aa1SThomas Huth 
584da668aa1SThomas Huth     blk_set_aio_context(blk, ctx, &error_abort);
585da668aa1SThomas Huth 
586da668aa1SThomas Huth     tjob->n = 0;
587da668aa1SThomas Huth     while (tjob->n == 0) {
588da668aa1SThomas Huth         aio_poll(qemu_get_aio_context(), false);
589da668aa1SThomas Huth     }
590da668aa1SThomas Huth 
591191e7af3SEmanuele Giuseppe Esposito     WITH_JOB_LOCK_GUARD() {
592191e7af3SEmanuele Giuseppe Esposito         job_complete_sync_locked(&tjob->common.job, &error_abort);
593191e7af3SEmanuele Giuseppe Esposito     }
594da668aa1SThomas Huth     blk_set_aio_context(blk, qemu_get_aio_context(), &error_abort);
595da668aa1SThomas Huth 
596da668aa1SThomas Huth     bdrv_unref(bs);
597da668aa1SThomas Huth     blk_unref(blk);
598da668aa1SThomas Huth }
599da668aa1SThomas Huth 
600da668aa1SThomas Huth /*
601da668aa1SThomas Huth  * Test that changing the AioContext for one node in a tree (here through blk)
602da668aa1SThomas Huth  * changes all other nodes as well:
603da668aa1SThomas Huth  *
604da668aa1SThomas Huth  *  blk
605da668aa1SThomas Huth  *   |
606da668aa1SThomas Huth  *   |  bs_verify [blkverify]
607da668aa1SThomas Huth  *   |   /               \
608da668aa1SThomas Huth  *   |  /                 \
609da668aa1SThomas Huth  *  bs_a [bdrv_test]    bs_b [bdrv_test]
610da668aa1SThomas Huth  *
611da668aa1SThomas Huth  */
test_propagate_basic(void)612da668aa1SThomas Huth static void test_propagate_basic(void)
613da668aa1SThomas Huth {
614da668aa1SThomas Huth     IOThread *iothread = iothread_new();
615da668aa1SThomas Huth     AioContext *ctx = iothread_get_aio_context(iothread);
616da668aa1SThomas Huth     AioContext *main_ctx;
617da668aa1SThomas Huth     BlockBackend *blk;
618da668aa1SThomas Huth     BlockDriverState *bs_a, *bs_b, *bs_verify;
619da668aa1SThomas Huth     QDict *options;
620da668aa1SThomas Huth 
621da668aa1SThomas Huth     /*
622da668aa1SThomas Huth      * Create bs_a and its BlockBackend.  We cannot take the RESIZE
623da668aa1SThomas Huth      * permission because blkverify will not share it on the test
624da668aa1SThomas Huth      * image.
625da668aa1SThomas Huth      */
626da668aa1SThomas Huth     blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL & ~BLK_PERM_RESIZE,
627da668aa1SThomas Huth                   BLK_PERM_ALL);
628da668aa1SThomas Huth     bs_a = bdrv_new_open_driver(&bdrv_test, "bs_a", BDRV_O_RDWR, &error_abort);
629da668aa1SThomas Huth     blk_insert_bs(blk, bs_a, &error_abort);
630da668aa1SThomas Huth 
631da668aa1SThomas Huth     /* Create bs_b */
632da668aa1SThomas Huth     bs_b = bdrv_new_open_driver(&bdrv_test, "bs_b", BDRV_O_RDWR, &error_abort);
633da668aa1SThomas Huth 
634da668aa1SThomas Huth     /* Create blkverify filter that references both bs_a and bs_b */
635da668aa1SThomas Huth     options = qdict_new();
636da668aa1SThomas Huth     qdict_put_str(options, "driver", "blkverify");
637da668aa1SThomas Huth     qdict_put_str(options, "test", "bs_a");
638da668aa1SThomas Huth     qdict_put_str(options, "raw", "bs_b");
639da668aa1SThomas Huth 
640da668aa1SThomas Huth     bs_verify = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
641da668aa1SThomas Huth 
642da668aa1SThomas Huth     /* Switch the AioContext */
643da668aa1SThomas Huth     blk_set_aio_context(blk, ctx, &error_abort);
644da668aa1SThomas Huth     g_assert(blk_get_aio_context(blk) == ctx);
645da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(bs_a) == ctx);
646da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(bs_verify) == ctx);
647da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(bs_b) == ctx);
648da668aa1SThomas Huth 
649da668aa1SThomas Huth     /* Switch the AioContext back */
650da668aa1SThomas Huth     main_ctx = qemu_get_aio_context();
651da668aa1SThomas Huth     blk_set_aio_context(blk, main_ctx, &error_abort);
652da668aa1SThomas Huth     g_assert(blk_get_aio_context(blk) == main_ctx);
653da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(bs_a) == main_ctx);
654da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(bs_verify) == main_ctx);
655da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(bs_b) == main_ctx);
656da668aa1SThomas Huth 
657da668aa1SThomas Huth     bdrv_unref(bs_verify);
658da668aa1SThomas Huth     bdrv_unref(bs_b);
659da668aa1SThomas Huth     bdrv_unref(bs_a);
660da668aa1SThomas Huth     blk_unref(blk);
661da668aa1SThomas Huth }
662da668aa1SThomas Huth 
663da668aa1SThomas Huth /*
664da668aa1SThomas Huth  * Test that diamonds in the graph don't lead to endless recursion:
665da668aa1SThomas Huth  *
666da668aa1SThomas Huth  *              blk
667da668aa1SThomas Huth  *               |
668da668aa1SThomas Huth  *      bs_verify [blkverify]
669da668aa1SThomas Huth  *       /              \
670da668aa1SThomas Huth  *      /                \
671da668aa1SThomas Huth  *   bs_b [raw]         bs_c[raw]
672da668aa1SThomas Huth  *      \                /
673da668aa1SThomas Huth  *       \              /
674da668aa1SThomas Huth  *       bs_a [bdrv_test]
675da668aa1SThomas Huth  */
test_propagate_diamond(void)676da668aa1SThomas Huth static void test_propagate_diamond(void)
677da668aa1SThomas Huth {
678da668aa1SThomas Huth     IOThread *iothread = iothread_new();
679da668aa1SThomas Huth     AioContext *ctx = iothread_get_aio_context(iothread);
680da668aa1SThomas Huth     AioContext *main_ctx;
681da668aa1SThomas Huth     BlockBackend *blk;
682da668aa1SThomas Huth     BlockDriverState *bs_a, *bs_b, *bs_c, *bs_verify;
683da668aa1SThomas Huth     QDict *options;
684da668aa1SThomas Huth 
685da668aa1SThomas Huth     /* Create bs_a */
686da668aa1SThomas Huth     bs_a = bdrv_new_open_driver(&bdrv_test, "bs_a", BDRV_O_RDWR, &error_abort);
687da668aa1SThomas Huth 
688da668aa1SThomas Huth     /* Create bs_b and bc_c */
689da668aa1SThomas Huth     options = qdict_new();
690da668aa1SThomas Huth     qdict_put_str(options, "driver", "raw");
691da668aa1SThomas Huth     qdict_put_str(options, "file", "bs_a");
692da668aa1SThomas Huth     qdict_put_str(options, "node-name", "bs_b");
693da668aa1SThomas Huth     bs_b = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
694da668aa1SThomas Huth 
695da668aa1SThomas Huth     options = qdict_new();
696da668aa1SThomas Huth     qdict_put_str(options, "driver", "raw");
697da668aa1SThomas Huth     qdict_put_str(options, "file", "bs_a");
698da668aa1SThomas Huth     qdict_put_str(options, "node-name", "bs_c");
699da668aa1SThomas Huth     bs_c = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
700da668aa1SThomas Huth 
701da668aa1SThomas Huth     /* Create blkverify filter that references both bs_b and bs_c */
702da668aa1SThomas Huth     options = qdict_new();
703da668aa1SThomas Huth     qdict_put_str(options, "driver", "blkverify");
704da668aa1SThomas Huth     qdict_put_str(options, "test", "bs_b");
705da668aa1SThomas Huth     qdict_put_str(options, "raw", "bs_c");
706da668aa1SThomas Huth 
707da668aa1SThomas Huth     bs_verify = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
708da668aa1SThomas Huth     /*
709da668aa1SThomas Huth      * Do not take the RESIZE permission: This would require the same
710da668aa1SThomas Huth      * from bs_c and thus from bs_a; however, blkverify will not share
711da668aa1SThomas Huth      * it on bs_b, and thus it will not be available for bs_a.
712da668aa1SThomas Huth      */
713da668aa1SThomas Huth     blk = blk_new(qemu_get_aio_context(), BLK_PERM_ALL & ~BLK_PERM_RESIZE,
714da668aa1SThomas Huth                   BLK_PERM_ALL);
715da668aa1SThomas Huth     blk_insert_bs(blk, bs_verify, &error_abort);
716da668aa1SThomas Huth 
717da668aa1SThomas Huth     /* Switch the AioContext */
718da668aa1SThomas Huth     blk_set_aio_context(blk, ctx, &error_abort);
719da668aa1SThomas Huth     g_assert(blk_get_aio_context(blk) == ctx);
720da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(bs_verify) == ctx);
721da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(bs_a) == ctx);
722da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(bs_b) == ctx);
723da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(bs_c) == ctx);
724da668aa1SThomas Huth 
725da668aa1SThomas Huth     /* Switch the AioContext back */
726da668aa1SThomas Huth     main_ctx = qemu_get_aio_context();
727da668aa1SThomas Huth     blk_set_aio_context(blk, main_ctx, &error_abort);
728da668aa1SThomas Huth     g_assert(blk_get_aio_context(blk) == main_ctx);
729da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(bs_verify) == main_ctx);
730da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(bs_a) == main_ctx);
731da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(bs_b) == main_ctx);
732da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(bs_c) == main_ctx);
733da668aa1SThomas Huth 
734da668aa1SThomas Huth     blk_unref(blk);
735da668aa1SThomas Huth     bdrv_unref(bs_verify);
736da668aa1SThomas Huth     bdrv_unref(bs_c);
737da668aa1SThomas Huth     bdrv_unref(bs_b);
738da668aa1SThomas Huth     bdrv_unref(bs_a);
739da668aa1SThomas Huth }
740da668aa1SThomas Huth 
test_propagate_mirror(void)741da668aa1SThomas Huth static void test_propagate_mirror(void)
742da668aa1SThomas Huth {
743da668aa1SThomas Huth     IOThread *iothread = iothread_new();
744da668aa1SThomas Huth     AioContext *ctx = iothread_get_aio_context(iothread);
745da668aa1SThomas Huth     AioContext *main_ctx = qemu_get_aio_context();
746da668aa1SThomas Huth     BlockDriverState *src, *target, *filter;
747da668aa1SThomas Huth     BlockBackend *blk;
748da668aa1SThomas Huth     Job *job;
749da668aa1SThomas Huth     Error *local_err = NULL;
750da668aa1SThomas Huth 
751da668aa1SThomas Huth     /* Create src and target*/
752da668aa1SThomas Huth     src = bdrv_new_open_driver(&bdrv_test, "src", BDRV_O_RDWR, &error_abort);
753da668aa1SThomas Huth     target = bdrv_new_open_driver(&bdrv_test, "target", BDRV_O_RDWR,
754da668aa1SThomas Huth                                   &error_abort);
755da668aa1SThomas Huth 
756da668aa1SThomas Huth     /* Start a mirror job */
757da668aa1SThomas Huth     mirror_start("job0", src, target, NULL, JOB_DEFAULT, 0, 0, 0,
758da668aa1SThomas Huth                  MIRROR_SYNC_MODE_NONE, MIRROR_OPEN_BACKING_CHAIN, false,
759da668aa1SThomas Huth                  BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT,
760da668aa1SThomas Huth                  false, "filter_node", MIRROR_COPY_MODE_BACKGROUND,
761da668aa1SThomas Huth                  &error_abort);
762487b9187SKevin Wolf 
763191e7af3SEmanuele Giuseppe Esposito     WITH_JOB_LOCK_GUARD() {
764191e7af3SEmanuele Giuseppe Esposito         job = job_get_locked("job0");
765191e7af3SEmanuele Giuseppe Esposito     }
766da668aa1SThomas Huth     filter = bdrv_find_node("filter_node");
767da668aa1SThomas Huth 
768da668aa1SThomas Huth     /* Change the AioContext of src */
769142e6907SEmanuele Giuseppe Esposito     bdrv_try_change_aio_context(src, ctx, NULL, &error_abort);
770da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(src) == ctx);
771da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(target) == ctx);
772da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(filter) == ctx);
773da668aa1SThomas Huth     g_assert(job->aio_context == ctx);
774da668aa1SThomas Huth 
775da668aa1SThomas Huth     /* Change the AioContext of target */
776142e6907SEmanuele Giuseppe Esposito     bdrv_try_change_aio_context(target, main_ctx, NULL, &error_abort);
777da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(src) == main_ctx);
778da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(target) == main_ctx);
779da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(filter) == main_ctx);
780da668aa1SThomas Huth 
781da668aa1SThomas Huth     /* With a BlockBackend on src, changing target must fail */
782da668aa1SThomas Huth     blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
783da668aa1SThomas Huth     blk_insert_bs(blk, src, &error_abort);
784da668aa1SThomas Huth 
785142e6907SEmanuele Giuseppe Esposito     bdrv_try_change_aio_context(target, ctx, NULL, &local_err);
786da668aa1SThomas Huth     error_free_or_abort(&local_err);
787da668aa1SThomas Huth 
788da668aa1SThomas Huth     g_assert(blk_get_aio_context(blk) == main_ctx);
789da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(src) == main_ctx);
790da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(target) == main_ctx);
791da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(filter) == main_ctx);
792da668aa1SThomas Huth 
793da668aa1SThomas Huth     /* ...unless we explicitly allow it */
794da668aa1SThomas Huth     blk_set_allow_aio_context_change(blk, true);
795142e6907SEmanuele Giuseppe Esposito     bdrv_try_change_aio_context(target, ctx, NULL, &error_abort);
796da668aa1SThomas Huth 
797da668aa1SThomas Huth     g_assert(blk_get_aio_context(blk) == ctx);
798da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(src) == ctx);
799da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(target) == ctx);
800da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(filter) == ctx);
801da668aa1SThomas Huth 
802da668aa1SThomas Huth     job_cancel_sync_all();
803da668aa1SThomas Huth 
804da668aa1SThomas Huth     blk_set_aio_context(blk, main_ctx, &error_abort);
805142e6907SEmanuele Giuseppe Esposito     bdrv_try_change_aio_context(target, main_ctx, NULL, &error_abort);
806da668aa1SThomas Huth 
807da668aa1SThomas Huth     blk_unref(blk);
808da668aa1SThomas Huth     bdrv_unref(src);
809da668aa1SThomas Huth     bdrv_unref(target);
810da668aa1SThomas Huth }
811da668aa1SThomas Huth 
test_attach_second_node(void)812da668aa1SThomas Huth static void test_attach_second_node(void)
813da668aa1SThomas Huth {
814da668aa1SThomas Huth     IOThread *iothread = iothread_new();
815da668aa1SThomas Huth     AioContext *ctx = iothread_get_aio_context(iothread);
816da668aa1SThomas Huth     AioContext *main_ctx = qemu_get_aio_context();
817da668aa1SThomas Huth     BlockBackend *blk;
818da668aa1SThomas Huth     BlockDriverState *bs, *filter;
819da668aa1SThomas Huth     QDict *options;
820da668aa1SThomas Huth 
821da668aa1SThomas Huth     blk = blk_new(ctx, BLK_PERM_ALL, BLK_PERM_ALL);
822da668aa1SThomas Huth     bs = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort);
823da668aa1SThomas Huth     blk_insert_bs(blk, bs, &error_abort);
824da668aa1SThomas Huth 
825da668aa1SThomas Huth     options = qdict_new();
826da668aa1SThomas Huth     qdict_put_str(options, "driver", "raw");
827da668aa1SThomas Huth     qdict_put_str(options, "file", "base");
828da668aa1SThomas Huth 
829da668aa1SThomas Huth     filter = bdrv_open(NULL, NULL, options, BDRV_O_RDWR, &error_abort);
830c86422c5SEmanuele Giuseppe Esposito 
831da668aa1SThomas Huth     g_assert(blk_get_aio_context(blk) == ctx);
832da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(bs) == ctx);
833da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(filter) == ctx);
834da668aa1SThomas Huth 
835da668aa1SThomas Huth     blk_set_aio_context(blk, main_ctx, &error_abort);
836da668aa1SThomas Huth     g_assert(blk_get_aio_context(blk) == main_ctx);
837da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(bs) == main_ctx);
838da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(filter) == main_ctx);
839da668aa1SThomas Huth 
840da668aa1SThomas Huth     bdrv_unref(filter);
841da668aa1SThomas Huth     bdrv_unref(bs);
842da668aa1SThomas Huth     blk_unref(blk);
843da668aa1SThomas Huth }
844da668aa1SThomas Huth 
test_attach_preserve_blk_ctx(void)845da668aa1SThomas Huth static void test_attach_preserve_blk_ctx(void)
846da668aa1SThomas Huth {
847da668aa1SThomas Huth     IOThread *iothread = iothread_new();
848da668aa1SThomas Huth     AioContext *ctx = iothread_get_aio_context(iothread);
849da668aa1SThomas Huth     BlockBackend *blk;
850da668aa1SThomas Huth     BlockDriverState *bs;
851da668aa1SThomas Huth 
852da668aa1SThomas Huth     blk = blk_new(ctx, BLK_PERM_ALL, BLK_PERM_ALL);
853da668aa1SThomas Huth     bs = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort);
854da668aa1SThomas Huth     bs->total_sectors = 65536 / BDRV_SECTOR_SIZE;
855da668aa1SThomas Huth 
856da668aa1SThomas Huth     /* Add node to BlockBackend that has an iothread context assigned */
857da668aa1SThomas Huth     blk_insert_bs(blk, bs, &error_abort);
858da668aa1SThomas Huth     g_assert(blk_get_aio_context(blk) == ctx);
859da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(bs) == ctx);
860da668aa1SThomas Huth 
861da668aa1SThomas Huth     /* Remove the node again */
862da668aa1SThomas Huth     blk_remove_bs(blk);
863da668aa1SThomas Huth     g_assert(blk_get_aio_context(blk) == ctx);
864da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(bs) == qemu_get_aio_context());
865da668aa1SThomas Huth 
866da668aa1SThomas Huth     /* Re-attach the node */
867da668aa1SThomas Huth     blk_insert_bs(blk, bs, &error_abort);
868da668aa1SThomas Huth     g_assert(blk_get_aio_context(blk) == ctx);
869da668aa1SThomas Huth     g_assert(bdrv_get_aio_context(bs) == ctx);
870da668aa1SThomas Huth 
871da668aa1SThomas Huth     blk_set_aio_context(blk, qemu_get_aio_context(), &error_abort);
872da668aa1SThomas Huth     bdrv_unref(bs);
873da668aa1SThomas Huth     blk_unref(blk);
874da668aa1SThomas Huth }
875da668aa1SThomas Huth 
main(int argc,char ** argv)876da668aa1SThomas Huth int main(int argc, char **argv)
877da668aa1SThomas Huth {
878da668aa1SThomas Huth     int i;
879da668aa1SThomas Huth 
880da668aa1SThomas Huth     bdrv_init();
881da668aa1SThomas Huth     qemu_init_main_loop(&error_abort);
882da668aa1SThomas Huth 
883da668aa1SThomas Huth     g_test_init(&argc, &argv, NULL);
884da668aa1SThomas Huth 
885da668aa1SThomas Huth     for (i = 0; i < ARRAY_SIZE(sync_op_tests); i++) {
886da668aa1SThomas Huth         const SyncOpTest *t = &sync_op_tests[i];
887da668aa1SThomas Huth         g_test_add_data_func(t->name, t, test_sync_op);
888da668aa1SThomas Huth     }
889da668aa1SThomas Huth 
890da668aa1SThomas Huth     g_test_add_func("/attach/blockjob", test_attach_blockjob);
891da668aa1SThomas Huth     g_test_add_func("/attach/second_node", test_attach_second_node);
892da668aa1SThomas Huth     g_test_add_func("/attach/preserve_blk_ctx", test_attach_preserve_blk_ctx);
893da668aa1SThomas Huth     g_test_add_func("/propagate/basic", test_propagate_basic);
894da668aa1SThomas Huth     g_test_add_func("/propagate/diamond", test_propagate_diamond);
895da668aa1SThomas Huth     g_test_add_func("/propagate/mirror", test_propagate_mirror);
896da668aa1SThomas Huth 
897da668aa1SThomas Huth     return g_test_run();
898da668aa1SThomas Huth }
899