mirror of https://github.com/xemu-project/xemu.git
block: Fix early failure in multiwrite
bdrv_aio_writev may call the callback immediately (and it will commonly do so in error cases). Current code doesn't consider this. For details see the comment added by this patch. Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
c2abccecd9
commit
453f9a1652
35
block.c
35
block.c
|
@ -2183,8 +2183,29 @@ int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs)
|
||||||
// Check for mergable requests
|
// Check for mergable requests
|
||||||
num_reqs = multiwrite_merge(bs, reqs, num_reqs, mcb);
|
num_reqs = multiwrite_merge(bs, reqs, num_reqs, mcb);
|
||||||
|
|
||||||
// Run the aio requests
|
/*
|
||||||
|
* Run the aio requests. As soon as one request can't be submitted
|
||||||
|
* successfully, fail all requests that are not yet submitted (we must
|
||||||
|
* return failure for all requests anyway)
|
||||||
|
*
|
||||||
|
* num_requests cannot be set to the right value immediately: If
|
||||||
|
* bdrv_aio_writev fails for some request, num_requests would be too high
|
||||||
|
* and therefore multiwrite_cb() would never recognize the multiwrite
|
||||||
|
* request as completed. We also cannot use the loop variable i to set it
|
||||||
|
* when the first request fails because the callback may already have been
|
||||||
|
* called for previously submitted requests. Thus, num_requests must be
|
||||||
|
* incremented for each request that is submitted.
|
||||||
|
*
|
||||||
|
* The problem that callbacks may be called early also means that we need
|
||||||
|
* to take care that num_requests doesn't become 0 before all requests are
|
||||||
|
* submitted - multiwrite_cb() would consider the multiwrite request
|
||||||
|
* completed. A dummy request that is "completed" by a manual call to
|
||||||
|
* multiwrite_cb() takes care of this.
|
||||||
|
*/
|
||||||
|
mcb->num_requests = 1;
|
||||||
|
|
||||||
for (i = 0; i < num_reqs; i++) {
|
for (i = 0; i < num_reqs; i++) {
|
||||||
|
mcb->num_requests++;
|
||||||
acb = bdrv_aio_writev(bs, reqs[i].sector, reqs[i].qiov,
|
acb = bdrv_aio_writev(bs, reqs[i].sector, reqs[i].qiov,
|
||||||
reqs[i].nb_sectors, multiwrite_cb, mcb);
|
reqs[i].nb_sectors, multiwrite_cb, mcb);
|
||||||
|
|
||||||
|
@ -2192,22 +2213,24 @@ int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs)
|
||||||
// We can only fail the whole thing if no request has been
|
// We can only fail the whole thing if no request has been
|
||||||
// submitted yet. Otherwise we'll wait for the submitted AIOs to
|
// submitted yet. Otherwise we'll wait for the submitted AIOs to
|
||||||
// complete and report the error in the callback.
|
// complete and report the error in the callback.
|
||||||
if (mcb->num_requests == 0) {
|
if (i == 0) {
|
||||||
reqs[i].error = -EIO;
|
|
||||||
goto fail;
|
goto fail;
|
||||||
} else {
|
} else {
|
||||||
mcb->num_requests++;
|
|
||||||
multiwrite_cb(mcb, -EIO);
|
multiwrite_cb(mcb, -EIO);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
mcb->num_requests++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Complete the dummy request */
|
||||||
|
multiwrite_cb(mcb, 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
|
for (i = 0; i < mcb->num_callbacks; i++) {
|
||||||
|
reqs[i].error = -EIO;
|
||||||
|
}
|
||||||
qemu_free(mcb);
|
qemu_free(mcb);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue