qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

mirror: Wait only for in-flight operations

mirror_wait_for_free_in_flight_slot() just picks a random operation to
wait for. However, a MirrorOp is already in s->ops_in_flight when
mirror_co_read() waits for free slots, so if not enough slots are
immediately available, an operation can end up waiting for itself, or
two or more operations can wait for each other to complete, which
results in a hang.

Fix this by adding a flag to MirrorOp that tells us if the request is
already in flight (and therefore occupies slots that it will later
free), and picking only such operations for waiting.

Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1794692
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-Id: <20200326153628.4869-3-kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>

+8 -1
+8 -1
block/mirror.c
··· 102 102 103 103 bool is_pseudo_op; 104 104 bool is_active_write; 105 + bool is_in_flight; 105 106 CoQueue waiting_requests; 106 107 Coroutine *co; 107 108 ··· 293 294 * caller of this function. Since there is only one pseudo op 294 295 * at any given time, we will always find some real operation 295 296 * to wait on. */ 296 - if (!op->is_pseudo_op && op->is_active_write == active) { 297 + if (!op->is_pseudo_op && op->is_in_flight && 298 + op->is_active_write == active) 299 + { 297 300 qemu_co_queue_wait(&op->waiting_requests, NULL); 298 301 return; 299 302 } ··· 367 370 /* Copy the dirty cluster. */ 368 371 s->in_flight++; 369 372 s->bytes_in_flight += op->bytes; 373 + op->is_in_flight = true; 370 374 trace_mirror_one_iteration(s, op->offset, op->bytes); 371 375 372 376 ret = bdrv_co_preadv(s->mirror_top_bs->backing, op->offset, op->bytes, ··· 382 386 op->s->in_flight++; 383 387 op->s->bytes_in_flight += op->bytes; 384 388 *op->bytes_handled = op->bytes; 389 + op->is_in_flight = true; 385 390 386 391 ret = blk_co_pwrite_zeroes(op->s->target, op->offset, op->bytes, 387 392 op->s->unmap ? BDRV_REQ_MAY_UNMAP : 0); ··· 396 401 op->s->in_flight++; 397 402 op->s->bytes_in_flight += op->bytes; 398 403 *op->bytes_handled = op->bytes; 404 + op->is_in_flight = true; 399 405 400 406 ret = blk_co_pdiscard(op->s->target, op->offset, op->bytes); 401 407 mirror_write_complete(op, ret); ··· 1319 1325 .offset = offset, 1320 1326 .bytes = bytes, 1321 1327 .is_active_write = true, 1328 + .is_in_flight = true, 1322 1329 }; 1323 1330 qemu_co_queue_init(&op->waiting_requests); 1324 1331 QTAILQ_INSERT_TAIL(&s->ops_in_flight, op, next);