aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--block.c43
-rw-r--r--block/parallels.c17
-rw-r--r--block/qcow2.c23
-rw-r--r--block/qed-check.c1
-rw-r--r--block/qed-table.c26
-rw-r--r--block/qed.c13
-rw-r--r--block/vdi.c6
-rw-r--r--block/vhdx.c7
-rw-r--r--block/vmdk.c7
-rw-r--r--include/block/block_int.h5
10 files changed, 103 insertions, 45 deletions
diff --git a/block.c b/block.c
index 603befb325..8f1c43d037 100644
--- a/block.c
+++ b/block.c
@@ -3455,17 +3455,54 @@ static void bdrv_delete(BlockDriverState *bs)
* free of errors) or -errno when an internal error occurred. The results of the
* check are stored in res.
*/
-int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix)
+static int coroutine_fn bdrv_co_check(BlockDriverState *bs,
+ BdrvCheckResult *res, BdrvCheckMode fix)
{
if (bs->drv == NULL) {
return -ENOMEDIUM;
}
- if (bs->drv->bdrv_check == NULL) {
+ if (bs->drv->bdrv_co_check == NULL) {
return -ENOTSUP;
}
memset(res, 0, sizeof(*res));
- return bs->drv->bdrv_check(bs, res, fix);
+ return bs->drv->bdrv_co_check(bs, res, fix);
+}
+
+typedef struct CheckCo {
+ BlockDriverState *bs;
+ BdrvCheckResult *res;
+ BdrvCheckMode fix;
+ int ret;
+} CheckCo;
+
+static void bdrv_check_co_entry(void *opaque)
+{
+ CheckCo *cco = opaque;
+ cco->ret = bdrv_co_check(cco->bs, cco->res, cco->fix);
+}
+
+int bdrv_check(BlockDriverState *bs,
+ BdrvCheckResult *res, BdrvCheckMode fix)
+{
+ Coroutine *co;
+ CheckCo cco = {
+ .bs = bs,
+ .res = res,
+ .ret = -EINPROGRESS,
+ .fix = fix,
+ };
+
+ if (qemu_in_coroutine()) {
+ /* Fast-path if already in coroutine context */
+ bdrv_check_co_entry(&cco);
+ } else {
+ co = qemu_coroutine_create(bdrv_check_co_entry, &cco);
+ qemu_coroutine_enter(co);
+ BDRV_POLL_WHILE(bs, cco.ret == -EINPROGRESS);
+ }
+
+ return cco.ret;
}
/*
diff --git a/block/parallels.c b/block/parallels.c
index 81085795c2..c13cb619e6 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -378,8 +378,9 @@ static coroutine_fn int parallels_co_readv(BlockDriverState *bs,
}
-static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
- BdrvCheckMode fix)
+static int coroutine_fn parallels_co_check(BlockDriverState *bs,
+ BdrvCheckResult *res,
+ BdrvCheckMode fix)
{
BDRVParallelsState *s = bs->opaque;
int64_t size, prev_off, high_off;
@@ -394,6 +395,7 @@ static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
return size;
}
+ qemu_co_mutex_lock(&s->lock);
if (s->header_unclean) {
fprintf(stderr, "%s image was not closed correctly\n",
fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR");
@@ -442,11 +444,12 @@ static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
prev_off = off;
}
+ ret = 0;
if (flush_bat) {
ret = bdrv_pwrite_sync(bs->file, 0, s->header, s->header_size);
if (ret < 0) {
res->check_errors++;
- return ret;
+ goto out;
}
}
@@ -465,13 +468,15 @@ static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
if (ret < 0) {
error_report_err(local_err);
res->check_errors++;
- return ret;
+ goto out;
}
res->leaks_fixed += count;
}
}
- return 0;
+out:
+ qemu_co_mutex_unlock(&s->lock);
+ return ret;
}
@@ -799,7 +804,7 @@ static BlockDriver bdrv_parallels = {
.bdrv_co_writev = parallels_co_writev,
.supports_backing = true,
.bdrv_co_create_opts = parallels_co_create_opts,
- .bdrv_check = parallels_check,
+ .bdrv_co_check = parallels_co_check,
.create_opts = &parallels_create_opts,
};
diff --git a/block/qcow2.c b/block/qcow2.c
index ac8703fa47..9fb00f2373 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -541,8 +541,9 @@ int qcow2_mark_consistent(BlockDriverState *bs)
return 0;
}
-static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result,
- BdrvCheckMode fix)
+static int coroutine_fn qcow2_co_check_locked(BlockDriverState *bs,
+ BdrvCheckResult *result,
+ BdrvCheckMode fix)
{
int ret = qcow2_check_refcounts(bs, result, fix);
if (ret < 0) {
@@ -559,6 +560,19 @@ static int qcow2_check(BlockDriverState *bs, BdrvCheckResult *result,
return ret;
}
+static int coroutine_fn qcow2_co_check(BlockDriverState *bs,
+ BdrvCheckResult *result,
+ BdrvCheckMode fix)
+{
+ BDRVQcow2State *s = bs->opaque;
+ int ret;
+
+ qemu_co_mutex_lock(&s->lock);
+ ret = qcow2_co_check_locked(bs, result, fix);
+ qemu_co_mutex_unlock(&s->lock);
+ return ret;
+}
+
static int validate_table_offset(BlockDriverState *bs, uint64_t offset,
uint64_t entries, size_t entry_len)
{
@@ -1506,7 +1520,8 @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
(s->incompatible_features & QCOW2_INCOMPAT_DIRTY)) {
BdrvCheckResult result = {0};
- ret = qcow2_check(bs, &result, BDRV_FIX_ERRORS | BDRV_FIX_LEAKS);
+ ret = qcow2_co_check_locked(bs, &result,
+ BDRV_FIX_ERRORS | BDRV_FIX_LEAKS);
if (ret < 0 || result.check_errors) {
if (ret >= 0) {
ret = -EIO;
@@ -4413,7 +4428,7 @@ BlockDriver bdrv_qcow2 = {
.bdrv_inactivate = qcow2_inactivate,
.create_opts = &qcow2_create_opts,
- .bdrv_check = qcow2_check,
+ .bdrv_co_check = qcow2_co_check,
.bdrv_amend_options = qcow2_amend_options,
.bdrv_detach_aio_context = qcow2_detach_aio_context,
diff --git a/block/qed-check.c b/block/qed-check.c
index dcd4f036b8..0edac03159 100644
--- a/block/qed-check.c
+++ b/block/qed-check.c
@@ -217,6 +217,7 @@ static void qed_check_mark_clean(BDRVQEDState *s, BdrvCheckResult *result)
qed_write_header_sync(s);
}
+/* Called with table_lock held. */
int qed_check(BDRVQEDState *s, BdrvCheckResult *result, bool fix)
{
QEDCheck check = {
diff --git a/block/qed-table.c b/block/qed-table.c
index eead8b0fc7..7df5680adb 100644
--- a/block/qed-table.c
+++ b/block/qed-table.c
@@ -18,7 +18,7 @@
#include "qed.h"
#include "qemu/bswap.h"
-/* Called either from qed_check or with table_lock held. */
+/* Called with table_lock held. */
static int qed_read_table(BDRVQEDState *s, uint64_t offset, QEDTable *table)
{
QEMUIOVector qiov;
@@ -33,13 +33,9 @@ static int qed_read_table(BDRVQEDState *s, uint64_t offset, QEDTable *table)
trace_qed_read_table(s, offset, table);
- if (qemu_in_coroutine()) {
- qemu_co_mutex_unlock(&s->table_lock);
- }
+ qemu_co_mutex_unlock(&s->table_lock);
ret = bdrv_preadv(s->bs->file, offset, &qiov);
- if (qemu_in_coroutine()) {
- qemu_co_mutex_lock(&s->table_lock);
- }
+ qemu_co_mutex_lock(&s->table_lock);
if (ret < 0) {
goto out;
}
@@ -67,7 +63,7 @@ out:
* @n: Number of elements
* @flush: Whether or not to sync to disk
*
- * Called either from qed_check or with table_lock held.
+ * Called with table_lock held.
*/
static int qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
unsigned int index, unsigned int n, bool flush)
@@ -104,13 +100,9 @@ static int qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
/* Adjust for offset into table */
offset += start * sizeof(uint64_t);
- if (qemu_in_coroutine()) {
- qemu_co_mutex_unlock(&s->table_lock);
- }
+ qemu_co_mutex_unlock(&s->table_lock);
ret = bdrv_pwritev(s->bs->file, offset, &qiov);
- if (qemu_in_coroutine()) {
- qemu_co_mutex_lock(&s->table_lock);
- }
+ qemu_co_mutex_lock(&s->table_lock);
trace_qed_write_table_cb(s, table, flush, ret);
if (ret < 0) {
goto out;
@@ -134,7 +126,7 @@ int qed_read_l1_table_sync(BDRVQEDState *s)
return qed_read_table(s, s->header.l1_table_offset, s->l1_table);
}
-/* Called either from qed_check or with table_lock held. */
+/* Called with table_lock held. */
int qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n)
{
BLKDBG_EVENT(s->bs->file, BLKDBG_L1_UPDATE);
@@ -148,7 +140,7 @@ int qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
return qed_write_l1_table(s, index, n);
}
-/* Called either from qed_check or with table_lock held. */
+/* Called with table_lock held. */
int qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset)
{
int ret;
@@ -191,7 +183,7 @@ int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request, uint64_t offset
return qed_read_l2_table(s, request, offset);
}
-/* Called either from qed_check or with table_lock held. */
+/* Called with table_lock held. */
int qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
unsigned int index, unsigned int n, bool flush)
{
diff --git a/block/qed.c b/block/qed.c
index 5a5414bfc3..5e6a6bfaa0 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -1544,12 +1544,17 @@ static void coroutine_fn bdrv_qed_co_invalidate_cache(BlockDriverState *bs,
}
}
-static int bdrv_qed_check(BlockDriverState *bs, BdrvCheckResult *result,
- BdrvCheckMode fix)
+static int bdrv_qed_co_check(BlockDriverState *bs, BdrvCheckResult *result,
+ BdrvCheckMode fix)
{
BDRVQEDState *s = bs->opaque;
+ int ret;
- return qed_check(s, result, !!fix);
+ qemu_co_mutex_lock(&s->table_lock);
+ ret = qed_check(s, result, !!fix);
+ qemu_co_mutex_unlock(&s->table_lock);
+
+ return ret;
}
static QemuOptsList qed_create_opts = {
@@ -1609,7 +1614,7 @@ static BlockDriver bdrv_qed = {
.bdrv_refresh_limits = bdrv_qed_refresh_limits,
.bdrv_change_backing_file = bdrv_qed_change_backing_file,
.bdrv_co_invalidate_cache = bdrv_qed_co_invalidate_cache,
- .bdrv_check = bdrv_qed_check,
+ .bdrv_co_check = bdrv_qed_co_check,
.bdrv_detach_aio_context = bdrv_qed_detach_aio_context,
.bdrv_attach_aio_context = bdrv_qed_attach_aio_context,
.bdrv_co_drain_begin = bdrv_qed_co_drain_begin,
diff --git a/block/vdi.c b/block/vdi.c
index 68592cc58d..2b5ddd0666 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -263,8 +263,8 @@ static void vdi_header_print(VdiHeader *header)
}
#endif
-static int vdi_check(BlockDriverState *bs, BdrvCheckResult *res,
- BdrvCheckMode fix)
+static int coroutine_fn vdi_co_check(BlockDriverState *bs, BdrvCheckResult *res,
+ BdrvCheckMode fix)
{
/* TODO: additional checks possible. */
BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
@@ -908,7 +908,7 @@ static BlockDriver bdrv_vdi = {
.bdrv_get_info = vdi_get_info,
.create_opts = &vdi_create_opts,
- .bdrv_check = vdi_check,
+ .bdrv_co_check = vdi_co_check,
};
static void bdrv_vdi_init(void)
diff --git a/block/vhdx.c b/block/vhdx.c
index 3fbff5048b..d82350d07c 100644
--- a/block/vhdx.c
+++ b/block/vhdx.c
@@ -1944,8 +1944,9 @@ exit:
* r/w and any log has already been replayed, so there is nothing (currently)
* for us to do here
*/
-static int vhdx_check(BlockDriverState *bs, BdrvCheckResult *result,
- BdrvCheckMode fix)
+static int coroutine_fn vhdx_co_check(BlockDriverState *bs,
+ BdrvCheckResult *result,
+ BdrvCheckMode fix)
{
BDRVVHDXState *s = bs->opaque;
@@ -2006,7 +2007,7 @@ static BlockDriver bdrv_vhdx = {
.bdrv_co_writev = vhdx_co_writev,
.bdrv_co_create_opts = vhdx_co_create_opts,
.bdrv_get_info = vhdx_get_info,
- .bdrv_check = vhdx_check,
+ .bdrv_co_check = vhdx_co_check,
.bdrv_has_zero_init = bdrv_has_zero_init_1,
.create_opts = &vhdx_create_opts,
diff --git a/block/vmdk.c b/block/vmdk.c
index 67342ed69b..f94c49a9c0 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -2221,8 +2221,9 @@ static ImageInfo *vmdk_get_extent_info(VmdkExtent *extent)
return info;
}
-static int vmdk_check(BlockDriverState *bs, BdrvCheckResult *result,
- BdrvCheckMode fix)
+static int coroutine_fn vmdk_co_check(BlockDriverState *bs,
+ BdrvCheckResult *result,
+ BdrvCheckMode fix)
{
BDRVVmdkState *s = bs->opaque;
VmdkExtent *extent = NULL;
@@ -2391,7 +2392,7 @@ static BlockDriver bdrv_vmdk = {
.instance_size = sizeof(BDRVVmdkState),
.bdrv_probe = vmdk_probe,
.bdrv_open = vmdk_open,
- .bdrv_check = vmdk_check,
+ .bdrv_co_check = vmdk_co_check,
.bdrv_reopen_prepare = vmdk_reopen_prepare,
.bdrv_child_perm = bdrv_format_default_perms,
.bdrv_co_preadv = vmdk_co_preadv,
diff --git a/include/block/block_int.h b/include/block/block_int.h
index e391cae53b..a84cc04d55 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -307,8 +307,9 @@ struct BlockDriver {
* Returns 0 for completed check, -errno for internal errors.
* The check results are stored in result.
*/
- int (*bdrv_check)(BlockDriverState *bs, BdrvCheckResult *result,
- BdrvCheckMode fix);
+ int coroutine_fn (*bdrv_co_check)(BlockDriverState *bs,
+ BdrvCheckResult *result,
+ BdrvCheckMode fix);
int (*bdrv_amend_options)(BlockDriverState *bs, QemuOpts *opts,
BlockDriverAmendStatusCB *status_cb,