]>
Commit | Line | Data |
---|---|---|
881cfd17 KW |
1 | /* |
2 | * Block node draining tests | |
3 | * | |
4 | * Copyright (c) 2017 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 "sysemu/block-backend.h" | |
28 | #include "qapi/error.h" | |
29 | ||
30 | typedef struct BDRVTestState { | |
31 | int drain_count; | |
32 | } BDRVTestState; | |
33 | ||
34 | static void coroutine_fn bdrv_test_co_drain_begin(BlockDriverState *bs) | |
35 | { | |
36 | BDRVTestState *s = bs->opaque; | |
37 | s->drain_count++; | |
38 | } | |
39 | ||
40 | static void coroutine_fn bdrv_test_co_drain_end(BlockDriverState *bs) | |
41 | { | |
42 | BDRVTestState *s = bs->opaque; | |
43 | s->drain_count--; | |
44 | } | |
45 | ||
46 | static void bdrv_test_close(BlockDriverState *bs) | |
47 | { | |
48 | BDRVTestState *s = bs->opaque; | |
49 | g_assert_cmpint(s->drain_count, >, 0); | |
50 | } | |
51 | ||
52 | static int coroutine_fn bdrv_test_co_preadv(BlockDriverState *bs, | |
53 | uint64_t offset, uint64_t bytes, | |
54 | QEMUIOVector *qiov, int flags) | |
55 | { | |
56 | /* We want this request to stay until the polling loop in drain waits for | |
57 | * it to complete. We need to sleep a while as bdrv_drain_invoke() comes | |
58 | * first and polls its result, too, but it shouldn't accidentally complete | |
59 | * this request yet. */ | |
60 | qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000); | |
61 | ||
62 | return 0; | |
63 | } | |
64 | ||
65 | static BlockDriver bdrv_test = { | |
66 | .format_name = "test", | |
67 | .instance_size = sizeof(BDRVTestState), | |
68 | ||
69 | .bdrv_close = bdrv_test_close, | |
70 | .bdrv_co_preadv = bdrv_test_co_preadv, | |
71 | ||
72 | .bdrv_co_drain_begin = bdrv_test_co_drain_begin, | |
73 | .bdrv_co_drain_end = bdrv_test_co_drain_end, | |
74 | }; | |
75 | ||
76 | static void aio_ret_cb(void *opaque, int ret) | |
77 | { | |
78 | int *aio_ret = opaque; | |
79 | *aio_ret = ret; | |
80 | } | |
81 | ||
82 | static void test_drv_cb_drain_all(void) | |
83 | { | |
84 | BlockBackend *blk; | |
85 | BlockDriverState *bs; | |
86 | BDRVTestState *s; | |
87 | BlockAIOCB *acb; | |
88 | int aio_ret; | |
89 | ||
90 | QEMUIOVector qiov; | |
91 | struct iovec iov = { | |
92 | .iov_base = NULL, | |
93 | .iov_len = 0, | |
94 | }; | |
95 | qemu_iovec_init_external(&qiov, &iov, 1); | |
96 | ||
97 | blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); | |
98 | bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR, | |
99 | &error_abort); | |
100 | s = bs->opaque; | |
101 | blk_insert_bs(blk, bs, &error_abort); | |
102 | ||
103 | /* Simple bdrv_drain_all_begin/end pair, check that CBs are called */ | |
104 | g_assert_cmpint(s->drain_count, ==, 0); | |
105 | bdrv_drain_all_begin(); | |
106 | g_assert_cmpint(s->drain_count, ==, 1); | |
107 | bdrv_drain_all_end(); | |
108 | g_assert_cmpint(s->drain_count, ==, 0); | |
109 | ||
110 | /* Now do the same while a request is pending */ | |
111 | aio_ret = -EINPROGRESS; | |
112 | acb = blk_aio_preadv(blk, 0, &qiov, 0, aio_ret_cb, &aio_ret); | |
113 | g_assert(acb != NULL); | |
114 | g_assert_cmpint(aio_ret, ==, -EINPROGRESS); | |
115 | ||
116 | g_assert_cmpint(s->drain_count, ==, 0); | |
117 | bdrv_drain_all_begin(); | |
118 | g_assert_cmpint(aio_ret, ==, 0); | |
119 | g_assert_cmpint(s->drain_count, ==, 1); | |
120 | bdrv_drain_all_end(); | |
121 | g_assert_cmpint(s->drain_count, ==, 0); | |
122 | ||
123 | bdrv_unref(bs); | |
124 | blk_unref(blk); | |
125 | } | |
126 | ||
127 | int main(int argc, char **argv) | |
128 | { | |
129 | bdrv_init(); | |
130 | qemu_init_main_loop(&error_abort); | |
131 | ||
132 | g_test_init(&argc, &argv, NULL); | |
133 | ||
134 | g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all); | |
135 | ||
136 | return g_test_run(); | |
137 | } |