]>
Commit | Line | Data |
---|---|---|
881cfd17 KW |
1 | /* |
2 | * Block node draining tests | |
3 | * | |
4 | * Copyright (c) 2017 Kevin Wolf <[email protected]> | |
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" | |
7253220d | 27 | #include "block/blockjob_int.h" |
881cfd17 KW |
28 | #include "sysemu/block-backend.h" |
29 | #include "qapi/error.h" | |
bb675689 KW |
30 | #include "iothread.h" |
31 | ||
32 | static QemuEvent done_event; | |
881cfd17 KW |
33 | |
34 | typedef struct BDRVTestState { | |
35 | int drain_count; | |
bb675689 | 36 | AioContext *bh_indirection_ctx; |
881cfd17 KW |
37 | } BDRVTestState; |
38 | ||
39 | static void coroutine_fn bdrv_test_co_drain_begin(BlockDriverState *bs) | |
40 | { | |
41 | BDRVTestState *s = bs->opaque; | |
42 | s->drain_count++; | |
43 | } | |
44 | ||
45 | static void coroutine_fn bdrv_test_co_drain_end(BlockDriverState *bs) | |
46 | { | |
47 | BDRVTestState *s = bs->opaque; | |
48 | s->drain_count--; | |
49 | } | |
50 | ||
51 | static void bdrv_test_close(BlockDriverState *bs) | |
52 | { | |
53 | BDRVTestState *s = bs->opaque; | |
54 | g_assert_cmpint(s->drain_count, >, 0); | |
55 | } | |
56 | ||
bb675689 KW |
57 | static void co_reenter_bh(void *opaque) |
58 | { | |
59 | aio_co_wake(opaque); | |
60 | } | |
61 | ||
881cfd17 KW |
62 | static int coroutine_fn bdrv_test_co_preadv(BlockDriverState *bs, |
63 | uint64_t offset, uint64_t bytes, | |
64 | QEMUIOVector *qiov, int flags) | |
65 | { | |
bb675689 KW |
66 | BDRVTestState *s = bs->opaque; |
67 | ||
881cfd17 KW |
68 | /* We want this request to stay until the polling loop in drain waits for |
69 | * it to complete. We need to sleep a while as bdrv_drain_invoke() comes | |
70 | * first and polls its result, too, but it shouldn't accidentally complete | |
71 | * this request yet. */ | |
72 | qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000); | |
73 | ||
bb675689 KW |
74 | if (s->bh_indirection_ctx) { |
75 | aio_bh_schedule_oneshot(s->bh_indirection_ctx, co_reenter_bh, | |
76 | qemu_coroutine_self()); | |
77 | qemu_coroutine_yield(); | |
78 | } | |
79 | ||
881cfd17 KW |
80 | return 0; |
81 | } | |
82 | ||
83 | static BlockDriver bdrv_test = { | |
84 | .format_name = "test", | |
85 | .instance_size = sizeof(BDRVTestState), | |
86 | ||
87 | .bdrv_close = bdrv_test_close, | |
88 | .bdrv_co_preadv = bdrv_test_co_preadv, | |
89 | ||
90 | .bdrv_co_drain_begin = bdrv_test_co_drain_begin, | |
91 | .bdrv_co_drain_end = bdrv_test_co_drain_end, | |
86e1c840 KW |
92 | |
93 | .bdrv_child_perm = bdrv_format_default_perms, | |
881cfd17 KW |
94 | }; |
95 | ||
96 | static void aio_ret_cb(void *opaque, int ret) | |
97 | { | |
98 | int *aio_ret = opaque; | |
99 | *aio_ret = ret; | |
100 | } | |
101 | ||
0582eb10 KW |
102 | typedef struct CallInCoroutineData { |
103 | void (*entry)(void); | |
104 | bool done; | |
105 | } CallInCoroutineData; | |
106 | ||
107 | static coroutine_fn void call_in_coroutine_entry(void *opaque) | |
108 | { | |
109 | CallInCoroutineData *data = opaque; | |
110 | ||
111 | data->entry(); | |
112 | data->done = true; | |
113 | } | |
114 | ||
115 | static void call_in_coroutine(void (*entry)(void)) | |
116 | { | |
117 | Coroutine *co; | |
118 | CallInCoroutineData data = { | |
119 | .entry = entry, | |
120 | .done = false, | |
121 | }; | |
122 | ||
123 | co = qemu_coroutine_create(call_in_coroutine_entry, &data); | |
124 | qemu_coroutine_enter(co); | |
125 | while (!data.done) { | |
126 | aio_poll(qemu_get_aio_context(), true); | |
127 | } | |
128 | } | |
129 | ||
86e1c840 KW |
130 | enum drain_type { |
131 | BDRV_DRAIN_ALL, | |
132 | BDRV_DRAIN, | |
d2a85d0f | 133 | BDRV_SUBTREE_DRAIN, |
6c429a6a | 134 | DRAIN_TYPE_MAX, |
86e1c840 KW |
135 | }; |
136 | ||
137 | static void do_drain_begin(enum drain_type drain_type, BlockDriverState *bs) | |
138 | { | |
139 | switch (drain_type) { | |
140 | case BDRV_DRAIN_ALL: bdrv_drain_all_begin(); break; | |
141 | case BDRV_DRAIN: bdrv_drained_begin(bs); break; | |
d2a85d0f | 142 | case BDRV_SUBTREE_DRAIN: bdrv_subtree_drained_begin(bs); break; |
86e1c840 KW |
143 | default: g_assert_not_reached(); |
144 | } | |
145 | } | |
146 | ||
147 | static void do_drain_end(enum drain_type drain_type, BlockDriverState *bs) | |
148 | { | |
149 | switch (drain_type) { | |
150 | case BDRV_DRAIN_ALL: bdrv_drain_all_end(); break; | |
151 | case BDRV_DRAIN: bdrv_drained_end(bs); break; | |
d2a85d0f | 152 | case BDRV_SUBTREE_DRAIN: bdrv_subtree_drained_end(bs); break; |
86e1c840 KW |
153 | default: g_assert_not_reached(); |
154 | } | |
155 | } | |
156 | ||
157 | static void test_drv_cb_common(enum drain_type drain_type, bool recursive) | |
881cfd17 KW |
158 | { |
159 | BlockBackend *blk; | |
86e1c840 KW |
160 | BlockDriverState *bs, *backing; |
161 | BDRVTestState *s, *backing_s; | |
881cfd17 KW |
162 | BlockAIOCB *acb; |
163 | int aio_ret; | |
164 | ||
165 | QEMUIOVector qiov; | |
166 | struct iovec iov = { | |
167 | .iov_base = NULL, | |
168 | .iov_len = 0, | |
169 | }; | |
170 | qemu_iovec_init_external(&qiov, &iov, 1); | |
171 | ||
172 | blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); | |
173 | bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR, | |
174 | &error_abort); | |
175 | s = bs->opaque; | |
176 | blk_insert_bs(blk, bs, &error_abort); | |
177 | ||
86e1c840 KW |
178 | backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort); |
179 | backing_s = backing->opaque; | |
180 | bdrv_set_backing_hd(bs, backing, &error_abort); | |
181 | ||
881cfd17 KW |
182 | /* Simple bdrv_drain_all_begin/end pair, check that CBs are called */ |
183 | g_assert_cmpint(s->drain_count, ==, 0); | |
86e1c840 KW |
184 | g_assert_cmpint(backing_s->drain_count, ==, 0); |
185 | ||
186 | do_drain_begin(drain_type, bs); | |
187 | ||
881cfd17 | 188 | g_assert_cmpint(s->drain_count, ==, 1); |
86e1c840 KW |
189 | g_assert_cmpint(backing_s->drain_count, ==, !!recursive); |
190 | ||
191 | do_drain_end(drain_type, bs); | |
192 | ||
881cfd17 | 193 | g_assert_cmpint(s->drain_count, ==, 0); |
86e1c840 | 194 | g_assert_cmpint(backing_s->drain_count, ==, 0); |
881cfd17 KW |
195 | |
196 | /* Now do the same while a request is pending */ | |
197 | aio_ret = -EINPROGRESS; | |
198 | acb = blk_aio_preadv(blk, 0, &qiov, 0, aio_ret_cb, &aio_ret); | |
199 | g_assert(acb != NULL); | |
200 | g_assert_cmpint(aio_ret, ==, -EINPROGRESS); | |
201 | ||
202 | g_assert_cmpint(s->drain_count, ==, 0); | |
86e1c840 KW |
203 | g_assert_cmpint(backing_s->drain_count, ==, 0); |
204 | ||
205 | do_drain_begin(drain_type, bs); | |
206 | ||
881cfd17 KW |
207 | g_assert_cmpint(aio_ret, ==, 0); |
208 | g_assert_cmpint(s->drain_count, ==, 1); | |
86e1c840 KW |
209 | g_assert_cmpint(backing_s->drain_count, ==, !!recursive); |
210 | ||
211 | do_drain_end(drain_type, bs); | |
212 | ||
881cfd17 | 213 | g_assert_cmpint(s->drain_count, ==, 0); |
86e1c840 | 214 | g_assert_cmpint(backing_s->drain_count, ==, 0); |
881cfd17 | 215 | |
86e1c840 | 216 | bdrv_unref(backing); |
881cfd17 KW |
217 | bdrv_unref(bs); |
218 | blk_unref(blk); | |
219 | } | |
220 | ||
86e1c840 KW |
221 | static void test_drv_cb_drain_all(void) |
222 | { | |
223 | test_drv_cb_common(BDRV_DRAIN_ALL, true); | |
224 | } | |
225 | ||
226 | static void test_drv_cb_drain(void) | |
227 | { | |
228 | test_drv_cb_common(BDRV_DRAIN, false); | |
229 | } | |
230 | ||
d2a85d0f KW |
231 | static void test_drv_cb_drain_subtree(void) |
232 | { | |
233 | test_drv_cb_common(BDRV_SUBTREE_DRAIN, true); | |
234 | } | |
235 | ||
6d0252f2 KW |
236 | static void test_drv_cb_co_drain_all(void) |
237 | { | |
238 | call_in_coroutine(test_drv_cb_drain_all); | |
239 | } | |
240 | ||
0582eb10 KW |
241 | static void test_drv_cb_co_drain(void) |
242 | { | |
243 | call_in_coroutine(test_drv_cb_drain); | |
244 | } | |
245 | ||
246 | static void test_drv_cb_co_drain_subtree(void) | |
247 | { | |
248 | call_in_coroutine(test_drv_cb_drain_subtree); | |
249 | } | |
250 | ||
89a6ceab KW |
251 | static void test_quiesce_common(enum drain_type drain_type, bool recursive) |
252 | { | |
253 | BlockBackend *blk; | |
254 | BlockDriverState *bs, *backing; | |
255 | ||
256 | blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); | |
257 | bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR, | |
258 | &error_abort); | |
259 | blk_insert_bs(blk, bs, &error_abort); | |
260 | ||
261 | backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort); | |
262 | bdrv_set_backing_hd(bs, backing, &error_abort); | |
263 | ||
264 | g_assert_cmpint(bs->quiesce_counter, ==, 0); | |
265 | g_assert_cmpint(backing->quiesce_counter, ==, 0); | |
266 | ||
267 | do_drain_begin(drain_type, bs); | |
268 | ||
269 | g_assert_cmpint(bs->quiesce_counter, ==, 1); | |
270 | g_assert_cmpint(backing->quiesce_counter, ==, !!recursive); | |
271 | ||
272 | do_drain_end(drain_type, bs); | |
273 | ||
274 | g_assert_cmpint(bs->quiesce_counter, ==, 0); | |
275 | g_assert_cmpint(backing->quiesce_counter, ==, 0); | |
276 | ||
277 | bdrv_unref(backing); | |
278 | bdrv_unref(bs); | |
279 | blk_unref(blk); | |
280 | } | |
281 | ||
282 | static void test_quiesce_drain_all(void) | |
283 | { | |
79ab8b21 | 284 | test_quiesce_common(BDRV_DRAIN_ALL, true); |
89a6ceab KW |
285 | } |
286 | ||
287 | static void test_quiesce_drain(void) | |
288 | { | |
289 | test_quiesce_common(BDRV_DRAIN, false); | |
290 | } | |
291 | ||
d2a85d0f KW |
292 | static void test_quiesce_drain_subtree(void) |
293 | { | |
294 | test_quiesce_common(BDRV_SUBTREE_DRAIN, true); | |
295 | } | |
296 | ||
6d0252f2 KW |
297 | static void test_quiesce_co_drain_all(void) |
298 | { | |
299 | call_in_coroutine(test_quiesce_drain_all); | |
300 | } | |
301 | ||
0582eb10 KW |
302 | static void test_quiesce_co_drain(void) |
303 | { | |
304 | call_in_coroutine(test_quiesce_drain); | |
305 | } | |
306 | ||
307 | static void test_quiesce_co_drain_subtree(void) | |
308 | { | |
309 | call_in_coroutine(test_quiesce_drain_subtree); | |
310 | } | |
311 | ||
6c429a6a KW |
312 | static void test_nested(void) |
313 | { | |
314 | BlockBackend *blk; | |
315 | BlockDriverState *bs, *backing; | |
316 | BDRVTestState *s, *backing_s; | |
317 | enum drain_type outer, inner; | |
318 | ||
319 | blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); | |
320 | bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR, | |
321 | &error_abort); | |
322 | s = bs->opaque; | |
323 | blk_insert_bs(blk, bs, &error_abort); | |
324 | ||
325 | backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort); | |
326 | backing_s = backing->opaque; | |
327 | bdrv_set_backing_hd(bs, backing, &error_abort); | |
328 | ||
329 | for (outer = 0; outer < DRAIN_TYPE_MAX; outer++) { | |
330 | for (inner = 0; inner < DRAIN_TYPE_MAX; inner++) { | |
79ab8b21 | 331 | int backing_quiesce = (outer != BDRV_DRAIN) + |
6c429a6a KW |
332 | (inner != BDRV_DRAIN); |
333 | ||
334 | g_assert_cmpint(bs->quiesce_counter, ==, 0); | |
335 | g_assert_cmpint(backing->quiesce_counter, ==, 0); | |
336 | g_assert_cmpint(s->drain_count, ==, 0); | |
337 | g_assert_cmpint(backing_s->drain_count, ==, 0); | |
338 | ||
339 | do_drain_begin(outer, bs); | |
340 | do_drain_begin(inner, bs); | |
341 | ||
79ab8b21 | 342 | g_assert_cmpint(bs->quiesce_counter, ==, 2); |
6c429a6a KW |
343 | g_assert_cmpint(backing->quiesce_counter, ==, backing_quiesce); |
344 | g_assert_cmpint(s->drain_count, ==, 2); | |
79ab8b21 | 345 | g_assert_cmpint(backing_s->drain_count, ==, backing_quiesce); |
6c429a6a KW |
346 | |
347 | do_drain_end(inner, bs); | |
348 | do_drain_end(outer, bs); | |
349 | ||
350 | g_assert_cmpint(bs->quiesce_counter, ==, 0); | |
351 | g_assert_cmpint(backing->quiesce_counter, ==, 0); | |
352 | g_assert_cmpint(s->drain_count, ==, 0); | |
353 | g_assert_cmpint(backing_s->drain_count, ==, 0); | |
354 | } | |
355 | } | |
356 | ||
357 | bdrv_unref(backing); | |
358 | bdrv_unref(bs); | |
359 | blk_unref(blk); | |
360 | } | |
361 | ||
27e64474 KW |
362 | static void test_multiparent(void) |
363 | { | |
364 | BlockBackend *blk_a, *blk_b; | |
365 | BlockDriverState *bs_a, *bs_b, *backing; | |
366 | BDRVTestState *a_s, *b_s, *backing_s; | |
367 | ||
368 | blk_a = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); | |
369 | bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR, | |
370 | &error_abort); | |
371 | a_s = bs_a->opaque; | |
372 | blk_insert_bs(blk_a, bs_a, &error_abort); | |
373 | ||
374 | blk_b = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); | |
375 | bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR, | |
376 | &error_abort); | |
377 | b_s = bs_b->opaque; | |
378 | blk_insert_bs(blk_b, bs_b, &error_abort); | |
379 | ||
380 | backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort); | |
381 | backing_s = backing->opaque; | |
382 | bdrv_set_backing_hd(bs_a, backing, &error_abort); | |
383 | bdrv_set_backing_hd(bs_b, backing, &error_abort); | |
384 | ||
385 | g_assert_cmpint(bs_a->quiesce_counter, ==, 0); | |
386 | g_assert_cmpint(bs_b->quiesce_counter, ==, 0); | |
387 | g_assert_cmpint(backing->quiesce_counter, ==, 0); | |
388 | g_assert_cmpint(a_s->drain_count, ==, 0); | |
389 | g_assert_cmpint(b_s->drain_count, ==, 0); | |
390 | g_assert_cmpint(backing_s->drain_count, ==, 0); | |
391 | ||
392 | do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a); | |
393 | ||
394 | g_assert_cmpint(bs_a->quiesce_counter, ==, 1); | |
395 | g_assert_cmpint(bs_b->quiesce_counter, ==, 1); | |
396 | g_assert_cmpint(backing->quiesce_counter, ==, 1); | |
397 | g_assert_cmpint(a_s->drain_count, ==, 1); | |
398 | g_assert_cmpint(b_s->drain_count, ==, 1); | |
399 | g_assert_cmpint(backing_s->drain_count, ==, 1); | |
400 | ||
401 | do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b); | |
402 | ||
403 | g_assert_cmpint(bs_a->quiesce_counter, ==, 2); | |
404 | g_assert_cmpint(bs_b->quiesce_counter, ==, 2); | |
405 | g_assert_cmpint(backing->quiesce_counter, ==, 2); | |
406 | g_assert_cmpint(a_s->drain_count, ==, 2); | |
407 | g_assert_cmpint(b_s->drain_count, ==, 2); | |
408 | g_assert_cmpint(backing_s->drain_count, ==, 2); | |
409 | ||
410 | do_drain_end(BDRV_SUBTREE_DRAIN, bs_b); | |
411 | ||
412 | g_assert_cmpint(bs_a->quiesce_counter, ==, 1); | |
413 | g_assert_cmpint(bs_b->quiesce_counter, ==, 1); | |
414 | g_assert_cmpint(backing->quiesce_counter, ==, 1); | |
415 | g_assert_cmpint(a_s->drain_count, ==, 1); | |
416 | g_assert_cmpint(b_s->drain_count, ==, 1); | |
417 | g_assert_cmpint(backing_s->drain_count, ==, 1); | |
418 | ||
419 | do_drain_end(BDRV_SUBTREE_DRAIN, bs_a); | |
420 | ||
421 | g_assert_cmpint(bs_a->quiesce_counter, ==, 0); | |
422 | g_assert_cmpint(bs_b->quiesce_counter, ==, 0); | |
423 | g_assert_cmpint(backing->quiesce_counter, ==, 0); | |
424 | g_assert_cmpint(a_s->drain_count, ==, 0); | |
425 | g_assert_cmpint(b_s->drain_count, ==, 0); | |
426 | g_assert_cmpint(backing_s->drain_count, ==, 0); | |
427 | ||
428 | bdrv_unref(backing); | |
429 | bdrv_unref(bs_a); | |
430 | bdrv_unref(bs_b); | |
431 | blk_unref(blk_a); | |
432 | blk_unref(blk_b); | |
433 | } | |
434 | ||
acebcf8d KW |
435 | static void test_graph_change(void) |
436 | { | |
437 | BlockBackend *blk_a, *blk_b; | |
438 | BlockDriverState *bs_a, *bs_b, *backing; | |
439 | BDRVTestState *a_s, *b_s, *backing_s; | |
440 | ||
441 | blk_a = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); | |
442 | bs_a = bdrv_new_open_driver(&bdrv_test, "test-node-a", BDRV_O_RDWR, | |
443 | &error_abort); | |
444 | a_s = bs_a->opaque; | |
445 | blk_insert_bs(blk_a, bs_a, &error_abort); | |
446 | ||
447 | blk_b = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); | |
448 | bs_b = bdrv_new_open_driver(&bdrv_test, "test-node-b", BDRV_O_RDWR, | |
449 | &error_abort); | |
450 | b_s = bs_b->opaque; | |
451 | blk_insert_bs(blk_b, bs_b, &error_abort); | |
452 | ||
453 | backing = bdrv_new_open_driver(&bdrv_test, "backing", 0, &error_abort); | |
454 | backing_s = backing->opaque; | |
455 | bdrv_set_backing_hd(bs_a, backing, &error_abort); | |
456 | ||
457 | g_assert_cmpint(bs_a->quiesce_counter, ==, 0); | |
458 | g_assert_cmpint(bs_b->quiesce_counter, ==, 0); | |
459 | g_assert_cmpint(backing->quiesce_counter, ==, 0); | |
460 | g_assert_cmpint(a_s->drain_count, ==, 0); | |
461 | g_assert_cmpint(b_s->drain_count, ==, 0); | |
462 | g_assert_cmpint(backing_s->drain_count, ==, 0); | |
463 | ||
464 | do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a); | |
465 | do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a); | |
466 | do_drain_begin(BDRV_SUBTREE_DRAIN, bs_a); | |
467 | do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b); | |
468 | do_drain_begin(BDRV_SUBTREE_DRAIN, bs_b); | |
469 | ||
470 | bdrv_set_backing_hd(bs_b, backing, &error_abort); | |
471 | g_assert_cmpint(bs_a->quiesce_counter, ==, 5); | |
472 | g_assert_cmpint(bs_b->quiesce_counter, ==, 5); | |
473 | g_assert_cmpint(backing->quiesce_counter, ==, 5); | |
474 | g_assert_cmpint(a_s->drain_count, ==, 5); | |
475 | g_assert_cmpint(b_s->drain_count, ==, 5); | |
476 | g_assert_cmpint(backing_s->drain_count, ==, 5); | |
477 | ||
478 | bdrv_set_backing_hd(bs_b, NULL, &error_abort); | |
479 | g_assert_cmpint(bs_a->quiesce_counter, ==, 3); | |
480 | g_assert_cmpint(bs_b->quiesce_counter, ==, 2); | |
481 | g_assert_cmpint(backing->quiesce_counter, ==, 3); | |
482 | g_assert_cmpint(a_s->drain_count, ==, 3); | |
483 | g_assert_cmpint(b_s->drain_count, ==, 2); | |
484 | g_assert_cmpint(backing_s->drain_count, ==, 3); | |
485 | ||
486 | bdrv_set_backing_hd(bs_b, backing, &error_abort); | |
487 | g_assert_cmpint(bs_a->quiesce_counter, ==, 5); | |
488 | g_assert_cmpint(bs_b->quiesce_counter, ==, 5); | |
489 | g_assert_cmpint(backing->quiesce_counter, ==, 5); | |
490 | g_assert_cmpint(a_s->drain_count, ==, 5); | |
491 | g_assert_cmpint(b_s->drain_count, ==, 5); | |
492 | g_assert_cmpint(backing_s->drain_count, ==, 5); | |
493 | ||
494 | do_drain_end(BDRV_SUBTREE_DRAIN, bs_b); | |
495 | do_drain_end(BDRV_SUBTREE_DRAIN, bs_b); | |
496 | do_drain_end(BDRV_SUBTREE_DRAIN, bs_a); | |
497 | do_drain_end(BDRV_SUBTREE_DRAIN, bs_a); | |
498 | do_drain_end(BDRV_SUBTREE_DRAIN, bs_a); | |
499 | ||
500 | g_assert_cmpint(bs_a->quiesce_counter, ==, 0); | |
501 | g_assert_cmpint(bs_b->quiesce_counter, ==, 0); | |
502 | g_assert_cmpint(backing->quiesce_counter, ==, 0); | |
503 | g_assert_cmpint(a_s->drain_count, ==, 0); | |
504 | g_assert_cmpint(b_s->drain_count, ==, 0); | |
505 | g_assert_cmpint(backing_s->drain_count, ==, 0); | |
506 | ||
507 | bdrv_unref(backing); | |
508 | bdrv_unref(bs_a); | |
509 | bdrv_unref(bs_b); | |
510 | blk_unref(blk_a); | |
511 | blk_unref(blk_b); | |
512 | } | |
513 | ||
bb675689 KW |
514 | struct test_iothread_data { |
515 | BlockDriverState *bs; | |
516 | enum drain_type drain_type; | |
517 | int *aio_ret; | |
518 | }; | |
519 | ||
520 | static void test_iothread_drain_entry(void *opaque) | |
521 | { | |
522 | struct test_iothread_data *data = opaque; | |
523 | ||
524 | aio_context_acquire(bdrv_get_aio_context(data->bs)); | |
525 | do_drain_begin(data->drain_type, data->bs); | |
526 | g_assert_cmpint(*data->aio_ret, ==, 0); | |
527 | do_drain_end(data->drain_type, data->bs); | |
528 | aio_context_release(bdrv_get_aio_context(data->bs)); | |
529 | ||
530 | qemu_event_set(&done_event); | |
531 | } | |
532 | ||
533 | static void test_iothread_aio_cb(void *opaque, int ret) | |
534 | { | |
535 | int *aio_ret = opaque; | |
536 | *aio_ret = ret; | |
537 | qemu_event_set(&done_event); | |
538 | } | |
539 | ||
540 | /* | |
541 | * Starts an AIO request on a BDS that runs in the AioContext of iothread 1. | |
542 | * The request involves a BH on iothread 2 before it can complete. | |
543 | * | |
544 | * @drain_thread = 0 means that do_drain_begin/end are called from the main | |
545 | * thread, @drain_thread = 1 means that they are called from iothread 1. Drain | |
546 | * for this BDS cannot be called from iothread 2 because only the main thread | |
547 | * may do cross-AioContext polling. | |
548 | */ | |
549 | static void test_iothread_common(enum drain_type drain_type, int drain_thread) | |
550 | { | |
551 | BlockBackend *blk; | |
552 | BlockDriverState *bs; | |
553 | BDRVTestState *s; | |
554 | BlockAIOCB *acb; | |
555 | int aio_ret; | |
556 | struct test_iothread_data data; | |
557 | ||
558 | IOThread *a = iothread_new(); | |
559 | IOThread *b = iothread_new(); | |
560 | AioContext *ctx_a = iothread_get_aio_context(a); | |
561 | AioContext *ctx_b = iothread_get_aio_context(b); | |
562 | ||
563 | QEMUIOVector qiov; | |
564 | struct iovec iov = { | |
565 | .iov_base = NULL, | |
566 | .iov_len = 0, | |
567 | }; | |
568 | qemu_iovec_init_external(&qiov, &iov, 1); | |
569 | ||
570 | /* bdrv_drain_all() may only be called from the main loop thread */ | |
571 | if (drain_type == BDRV_DRAIN_ALL && drain_thread != 0) { | |
572 | goto out; | |
573 | } | |
574 | ||
575 | blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); | |
576 | bs = bdrv_new_open_driver(&bdrv_test, "test-node", BDRV_O_RDWR, | |
577 | &error_abort); | |
578 | s = bs->opaque; | |
579 | blk_insert_bs(blk, bs, &error_abort); | |
580 | ||
581 | blk_set_aio_context(blk, ctx_a); | |
582 | aio_context_acquire(ctx_a); | |
583 | ||
584 | s->bh_indirection_ctx = ctx_b; | |
585 | ||
586 | aio_ret = -EINPROGRESS; | |
587 | if (drain_thread == 0) { | |
588 | acb = blk_aio_preadv(blk, 0, &qiov, 0, test_iothread_aio_cb, &aio_ret); | |
589 | } else { | |
590 | acb = blk_aio_preadv(blk, 0, &qiov, 0, aio_ret_cb, &aio_ret); | |
591 | } | |
592 | g_assert(acb != NULL); | |
593 | g_assert_cmpint(aio_ret, ==, -EINPROGRESS); | |
594 | ||
595 | aio_context_release(ctx_a); | |
596 | ||
597 | data = (struct test_iothread_data) { | |
598 | .bs = bs, | |
599 | .drain_type = drain_type, | |
600 | .aio_ret = &aio_ret, | |
601 | }; | |
602 | ||
603 | switch (drain_thread) { | |
604 | case 0: | |
605 | if (drain_type != BDRV_DRAIN_ALL) { | |
606 | aio_context_acquire(ctx_a); | |
607 | } | |
608 | ||
609 | /* The request is running on the IOThread a. Draining its block device | |
610 | * will make sure that it has completed as far as the BDS is concerned, | |
611 | * but the drain in this thread can continue immediately after | |
612 | * bdrv_dec_in_flight() and aio_ret might be assigned only slightly | |
613 | * later. */ | |
614 | qemu_event_reset(&done_event); | |
615 | do_drain_begin(drain_type, bs); | |
616 | g_assert_cmpint(bs->in_flight, ==, 0); | |
617 | ||
618 | if (drain_type != BDRV_DRAIN_ALL) { | |
619 | aio_context_release(ctx_a); | |
620 | } | |
621 | qemu_event_wait(&done_event); | |
622 | if (drain_type != BDRV_DRAIN_ALL) { | |
623 | aio_context_acquire(ctx_a); | |
624 | } | |
625 | ||
626 | g_assert_cmpint(aio_ret, ==, 0); | |
627 | do_drain_end(drain_type, bs); | |
628 | ||
629 | if (drain_type != BDRV_DRAIN_ALL) { | |
630 | aio_context_release(ctx_a); | |
631 | } | |
632 | break; | |
633 | case 1: | |
634 | qemu_event_reset(&done_event); | |
635 | aio_bh_schedule_oneshot(ctx_a, test_iothread_drain_entry, &data); | |
636 | qemu_event_wait(&done_event); | |
637 | break; | |
638 | default: | |
639 | g_assert_not_reached(); | |
640 | } | |
641 | ||
642 | aio_context_acquire(ctx_a); | |
643 | blk_set_aio_context(blk, qemu_get_aio_context()); | |
644 | aio_context_release(ctx_a); | |
645 | ||
646 | bdrv_unref(bs); | |
647 | blk_unref(blk); | |
648 | ||
649 | out: | |
650 | iothread_join(a); | |
651 | iothread_join(b); | |
652 | } | |
653 | ||
654 | static void test_iothread_drain_all(void) | |
655 | { | |
656 | test_iothread_common(BDRV_DRAIN_ALL, 0); | |
657 | test_iothread_common(BDRV_DRAIN_ALL, 1); | |
658 | } | |
659 | ||
660 | static void test_iothread_drain(void) | |
661 | { | |
662 | test_iothread_common(BDRV_DRAIN, 0); | |
663 | test_iothread_common(BDRV_DRAIN, 1); | |
664 | } | |
665 | ||
666 | static void test_iothread_drain_subtree(void) | |
667 | { | |
668 | test_iothread_common(BDRV_SUBTREE_DRAIN, 0); | |
669 | test_iothread_common(BDRV_SUBTREE_DRAIN, 1); | |
670 | } | |
671 | ||
7253220d KW |
672 | |
673 | typedef struct TestBlockJob { | |
674 | BlockJob common; | |
675 | bool should_complete; | |
676 | } TestBlockJob; | |
677 | ||
1908a559 | 678 | static void test_job_completed(Job *job, void *opaque) |
7253220d | 679 | { |
1266c9b9 | 680 | job_completed(job, 0, NULL); |
7253220d KW |
681 | } |
682 | ||
683 | static void coroutine_fn test_job_start(void *opaque) | |
684 | { | |
685 | TestBlockJob *s = opaque; | |
686 | ||
2e1795b5 | 687 | job_transition_to_ready(&s->common.job); |
7253220d | 688 | while (!s->should_complete) { |
89bd0305 KW |
689 | /* Avoid block_job_sleep_ns() because it marks the job as !busy. We |
690 | * want to emulate some actual activity (probably some I/O) here so | |
691 | * that drain has to wait for this acitivity to stop. */ | |
692 | qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 100000); | |
693 | job_pause_point(&s->common.job); | |
7253220d KW |
694 | } |
695 | ||
1908a559 | 696 | job_defer_to_main_loop(&s->common.job, test_job_completed, NULL); |
7253220d KW |
697 | } |
698 | ||
3453d972 | 699 | static void test_job_complete(Job *job, Error **errp) |
7253220d | 700 | { |
3453d972 | 701 | TestBlockJob *s = container_of(job, TestBlockJob, common.job); |
7253220d KW |
702 | s->should_complete = true; |
703 | } | |
704 | ||
705 | BlockJobDriver test_job_driver = { | |
33e9e9bd KW |
706 | .job_driver = { |
707 | .instance_size = sizeof(TestBlockJob), | |
80fa2c75 | 708 | .free = block_job_free, |
b15de828 | 709 | .user_resume = block_job_user_resume, |
b69f777d | 710 | .drain = block_job_drain, |
da01ff7f | 711 | .start = test_job_start, |
3453d972 | 712 | .complete = test_job_complete, |
33e9e9bd | 713 | }, |
7253220d KW |
714 | }; |
715 | ||
716 | static void test_blockjob_common(enum drain_type drain_type) | |
717 | { | |
718 | BlockBackend *blk_src, *blk_target; | |
719 | BlockDriverState *src, *target; | |
720 | BlockJob *job; | |
721 | int ret; | |
722 | ||
723 | src = bdrv_new_open_driver(&bdrv_test, "source", BDRV_O_RDWR, | |
724 | &error_abort); | |
725 | blk_src = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); | |
726 | blk_insert_bs(blk_src, src, &error_abort); | |
727 | ||
728 | target = bdrv_new_open_driver(&bdrv_test, "target", BDRV_O_RDWR, | |
729 | &error_abort); | |
730 | blk_target = blk_new(BLK_PERM_ALL, BLK_PERM_ALL); | |
731 | blk_insert_bs(blk_target, target, &error_abort); | |
732 | ||
75859b94 JS |
733 | job = block_job_create("job0", &test_job_driver, NULL, src, 0, BLK_PERM_ALL, |
734 | 0, 0, NULL, NULL, &error_abort); | |
7253220d | 735 | block_job_add_bdrv(job, "target", target, 0, BLK_PERM_ALL, &error_abort); |
da01ff7f | 736 | job_start(&job->job); |
7253220d | 737 | |
da01ff7f KW |
738 | g_assert_cmpint(job->job.pause_count, ==, 0); |
739 | g_assert_false(job->job.paused); | |
89bd0305 | 740 | g_assert_true(job->job.busy); /* We're in job_sleep_ns() */ |
7253220d KW |
741 | |
742 | do_drain_begin(drain_type, src); | |
743 | ||
744 | if (drain_type == BDRV_DRAIN_ALL) { | |
81193349 | 745 | /* bdrv_drain_all() drains both src and target */ |
da01ff7f | 746 | g_assert_cmpint(job->job.pause_count, ==, 2); |
7253220d | 747 | } else { |
da01ff7f | 748 | g_assert_cmpint(job->job.pause_count, ==, 1); |
7253220d | 749 | } |
89bd0305 | 750 | g_assert_true(job->job.paused); |
da01ff7f | 751 | g_assert_false(job->job.busy); /* The job is paused */ |
7253220d KW |
752 | |
753 | do_drain_end(drain_type, src); | |
754 | ||
da01ff7f KW |
755 | g_assert_cmpint(job->job.pause_count, ==, 0); |
756 | g_assert_false(job->job.paused); | |
89bd0305 | 757 | g_assert_true(job->job.busy); /* We're in qemu_co_sleep_ns() */ |
7253220d KW |
758 | |
759 | do_drain_begin(drain_type, target); | |
760 | ||
761 | if (drain_type == BDRV_DRAIN_ALL) { | |
81193349 | 762 | /* bdrv_drain_all() drains both src and target */ |
da01ff7f | 763 | g_assert_cmpint(job->job.pause_count, ==, 2); |
7253220d | 764 | } else { |
da01ff7f | 765 | g_assert_cmpint(job->job.pause_count, ==, 1); |
7253220d | 766 | } |
89bd0305 | 767 | g_assert_true(job->job.paused); |
da01ff7f | 768 | g_assert_false(job->job.busy); /* The job is paused */ |
7253220d KW |
769 | |
770 | do_drain_end(drain_type, target); | |
771 | ||
da01ff7f KW |
772 | g_assert_cmpint(job->job.pause_count, ==, 0); |
773 | g_assert_false(job->job.paused); | |
89bd0305 | 774 | g_assert_true(job->job.busy); /* We're in job_sleep_ns() */ |
7253220d | 775 | |
3d70ff53 | 776 | ret = job_complete_sync(&job->job, &error_abort); |
7253220d KW |
777 | g_assert_cmpint(ret, ==, 0); |
778 | ||
779 | blk_unref(blk_src); | |
780 | blk_unref(blk_target); | |
781 | bdrv_unref(src); | |
782 | bdrv_unref(target); | |
783 | } | |
784 | ||
785 | static void test_blockjob_drain_all(void) | |
786 | { | |
787 | test_blockjob_common(BDRV_DRAIN_ALL); | |
788 | } | |
789 | ||
790 | static void test_blockjob_drain(void) | |
791 | { | |
792 | test_blockjob_common(BDRV_DRAIN); | |
793 | } | |
794 | ||
d2a85d0f KW |
795 | static void test_blockjob_drain_subtree(void) |
796 | { | |
797 | test_blockjob_common(BDRV_SUBTREE_DRAIN); | |
798 | } | |
799 | ||
881cfd17 KW |
800 | int main(int argc, char **argv) |
801 | { | |
bb675689 KW |
802 | int ret; |
803 | ||
881cfd17 KW |
804 | bdrv_init(); |
805 | qemu_init_main_loop(&error_abort); | |
806 | ||
807 | g_test_init(&argc, &argv, NULL); | |
bb675689 | 808 | qemu_event_init(&done_event, false); |
881cfd17 KW |
809 | |
810 | g_test_add_func("/bdrv-drain/driver-cb/drain_all", test_drv_cb_drain_all); | |
86e1c840 | 811 | g_test_add_func("/bdrv-drain/driver-cb/drain", test_drv_cb_drain); |
d2a85d0f KW |
812 | g_test_add_func("/bdrv-drain/driver-cb/drain_subtree", |
813 | test_drv_cb_drain_subtree); | |
881cfd17 | 814 | |
6d0252f2 KW |
815 | g_test_add_func("/bdrv-drain/driver-cb/co/drain_all", |
816 | test_drv_cb_co_drain_all); | |
0582eb10 KW |
817 | g_test_add_func("/bdrv-drain/driver-cb/co/drain", test_drv_cb_co_drain); |
818 | g_test_add_func("/bdrv-drain/driver-cb/co/drain_subtree", | |
819 | test_drv_cb_co_drain_subtree); | |
820 | ||
821 | ||
89a6ceab KW |
822 | g_test_add_func("/bdrv-drain/quiesce/drain_all", test_quiesce_drain_all); |
823 | g_test_add_func("/bdrv-drain/quiesce/drain", test_quiesce_drain); | |
d2a85d0f KW |
824 | g_test_add_func("/bdrv-drain/quiesce/drain_subtree", |
825 | test_quiesce_drain_subtree); | |
89a6ceab | 826 | |
6d0252f2 KW |
827 | g_test_add_func("/bdrv-drain/quiesce/co/drain_all", |
828 | test_quiesce_co_drain_all); | |
0582eb10 KW |
829 | g_test_add_func("/bdrv-drain/quiesce/co/drain", test_quiesce_co_drain); |
830 | g_test_add_func("/bdrv-drain/quiesce/co/drain_subtree", | |
831 | test_quiesce_co_drain_subtree); | |
832 | ||
6c429a6a | 833 | g_test_add_func("/bdrv-drain/nested", test_nested); |
27e64474 | 834 | g_test_add_func("/bdrv-drain/multiparent", test_multiparent); |
acebcf8d | 835 | g_test_add_func("/bdrv-drain/graph-change", test_graph_change); |
6c429a6a | 836 | |
bb675689 KW |
837 | g_test_add_func("/bdrv-drain/iothread/drain_all", test_iothread_drain_all); |
838 | g_test_add_func("/bdrv-drain/iothread/drain", test_iothread_drain); | |
839 | g_test_add_func("/bdrv-drain/iothread/drain_subtree", | |
840 | test_iothread_drain_subtree); | |
841 | ||
7253220d KW |
842 | g_test_add_func("/bdrv-drain/blockjob/drain_all", test_blockjob_drain_all); |
843 | g_test_add_func("/bdrv-drain/blockjob/drain", test_blockjob_drain); | |
d2a85d0f KW |
844 | g_test_add_func("/bdrv-drain/blockjob/drain_subtree", |
845 | test_blockjob_drain_subtree); | |
7253220d | 846 | |
bb675689 KW |
847 | ret = g_test_run(); |
848 | qemu_event_destroy(&done_event); | |
849 | return ret; | |
881cfd17 | 850 | } |