[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v7 07/11] qcow2: track guest io requests in data_file
From: |
Vladimir Sementsov-Ogievskiy |
Subject: |
[PATCH v7 07/11] qcow2: track guest io requests in data_file |
Date: |
Sat, 4 Sep 2021 19:24:24 +0300 |
We are going to fix a bug of reallocating host cluster that are under
guest operation. For this we need to track these operations.
So, we create BlockReq objects during guest writing and reading data.
That's important for synchronization with further host clusters
reallocation code that we create BlockReq object in same s->lock
critical section where we get an offset.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
block/qcow2.c | 58 +++++++++++++++++++++++++++++++++++++++------------
1 file changed, 45 insertions(+), 13 deletions(-)
diff --git a/block/qcow2.c b/block/qcow2.c
index 8aa5679fe9..aefe6558b6 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -2212,6 +2212,8 @@ typedef struct Qcow2AioTask {
QEMUIOVector *qiov;
uint64_t qiov_offset;
QCowL2Meta *l2meta; /* only for write */
+
+ BlockReq *req;
} Qcow2AioTask;
static coroutine_fn int qcow2_co_preadv_task_entry(AioTask *task);
@@ -2224,7 +2226,8 @@ static coroutine_fn int qcow2_add_task(BlockDriverState
*bs,
uint64_t bytes,
QEMUIOVector *qiov,
size_t qiov_offset,
- QCowL2Meta *l2meta)
+ QCowL2Meta *l2meta,
+ BlockReq *req)
{
Qcow2AioTask local_task;
Qcow2AioTask *task = pool ? g_new(Qcow2AioTask, 1) : &local_task;
@@ -2239,6 +2242,7 @@ static coroutine_fn int qcow2_add_task(BlockDriverState
*bs,
.bytes = bytes,
.qiov_offset = qiov_offset,
.l2meta = l2meta,
+ .req = req,
};
trace_qcow2_add_task(qemu_coroutine_self(), bs, pool,
@@ -2260,7 +2264,8 @@ static coroutine_fn int
qcow2_co_preadv_task(BlockDriverState *bs,
uint64_t host_offset,
uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov,
- size_t qiov_offset)
+ size_t qiov_offset,
+ BlockReq *req)
{
BDRVQcow2State *s = bs->opaque;
int ret;
@@ -2300,6 +2305,12 @@ static coroutine_fn int
qcow2_co_preadv_task(BlockDriverState *bs,
g_assert_not_reached();
}
+ if (req) {
+ WITH_QEMU_LOCK_GUARD(&s->lock) {
+ reqlist_free_req(req);
+ }
+ }
+
return ret;
}
@@ -2311,7 +2322,7 @@ static coroutine_fn int
qcow2_co_preadv_task_entry(AioTask *task)
return qcow2_co_preadv_task(t->bs, t->subcluster_type,
t->host_offset, t->offset, t->bytes,
- t->qiov, t->qiov_offset);
+ t->qiov, t->qiov_offset, t->req);
}
static coroutine_fn int qcow2_co_preadv_part(BlockDriverState *bs,
@@ -2327,6 +2338,8 @@ static coroutine_fn int
qcow2_co_preadv_part(BlockDriverState *bs,
AioTaskPool *aio = NULL;
while (bytes != 0 && aio_task_pool_status(aio) == 0) {
+ BlockReq *req = NULL;
+
/* prepare next request */
cur_bytes = MIN(bytes, INT_MAX);
if (s->crypto) {
@@ -2336,7 +2349,7 @@ static coroutine_fn int
qcow2_co_preadv_part(BlockDriverState *bs,
qemu_co_mutex_lock(&s->lock);
ret = qcow2_get_host_offset(bs, offset, &cur_bytes,
- &host_offset, &type, NULL);
+ &host_offset, &type, &req);
qemu_co_mutex_unlock(&s->lock);
if (ret < 0) {
goto out;
@@ -2354,7 +2367,7 @@ static coroutine_fn int
qcow2_co_preadv_part(BlockDriverState *bs,
}
ret = qcow2_add_task(bs, aio, qcow2_co_preadv_task_entry, type,
host_offset, offset, cur_bytes,
- qiov, qiov_offset, NULL);
+ qiov, qiov_offset, NULL, req);
if (ret < 0) {
goto out;
}
@@ -2523,7 +2536,8 @@ static coroutine_fn int
qcow2_co_pwritev_task(BlockDriverState *bs,
uint64_t offset, uint64_t bytes,
QEMUIOVector *qiov,
uint64_t qiov_offset,
- QCowL2Meta *l2meta)
+ QCowL2Meta *l2meta,
+ BlockReq *req)
{
int ret;
BDRVQcow2State *s = bs->opaque;
@@ -2582,6 +2596,9 @@ out_unlocked:
out_locked:
qcow2_handle_l2meta(bs, &l2meta, false);
+
+ reqlist_free_req(req);
+
qemu_co_mutex_unlock(&s->lock);
qemu_vfree(crypt_buf);
@@ -2597,7 +2614,7 @@ static coroutine_fn int
qcow2_co_pwritev_task_entry(AioTask *task)
return qcow2_co_pwritev_task(t->bs, t->host_offset,
t->offset, t->bytes, t->qiov, t->qiov_offset,
- t->l2meta);
+ t->l2meta, t->req);
}
static coroutine_fn int qcow2_co_pwritev_part(
@@ -2615,6 +2632,7 @@ static coroutine_fn int qcow2_co_pwritev_part(
trace_qcow2_writev_start_req(qemu_coroutine_self(), offset, bytes);
while (bytes != 0 && aio_task_pool_status(aio) == 0) {
+ BlockReq *req;
l2meta = NULL;
@@ -2630,7 +2648,7 @@ static coroutine_fn int qcow2_co_pwritev_part(
qemu_co_mutex_lock(&s->lock);
ret = qcow2_alloc_host_offset(bs, offset, &cur_bytes,
- &host_offset, &l2meta, NULL);
+ &host_offset, &l2meta, &req);
if (ret < 0) {
goto out_locked;
}
@@ -2638,6 +2656,7 @@ static coroutine_fn int qcow2_co_pwritev_part(
ret = qcow2_pre_write_overlap_check(bs, 0, host_offset,
cur_bytes, true);
if (ret < 0) {
+ reqlist_free_req(req);
goto out_locked;
}
@@ -2648,7 +2667,7 @@ static coroutine_fn int qcow2_co_pwritev_part(
}
ret = qcow2_add_task(bs, aio, qcow2_co_pwritev_task_entry, 0,
host_offset, offset,
- cur_bytes, qiov, qiov_offset, l2meta);
+ cur_bytes, qiov, qiov_offset, l2meta, req);
l2meta = NULL; /* l2meta is consumed by qcow2_co_pwritev_task() */
if (ret < 0) {
goto fail_nometa;
@@ -4045,6 +4064,7 @@ qcow2_co_copy_range_from(BlockDriverState *bs,
qemu_co_mutex_lock(&s->lock);
while (bytes != 0) {
+ BlockReq *req = NULL;
uint64_t copy_offset = 0;
QCow2SubclusterType type;
/* prepare next request */
@@ -4052,7 +4072,7 @@ qcow2_co_copy_range_from(BlockDriverState *bs,
cur_write_flags = write_flags;
ret = qcow2_get_host_offset(bs, src_offset, &cur_bytes,
- ©_offset, &type, NULL);
+ ©_offset, &type, &req);
if (ret < 0) {
goto out;
}
@@ -4080,6 +4100,7 @@ qcow2_co_copy_range_from(BlockDriverState *bs,
break;
case QCOW2_SUBCLUSTER_COMPRESSED:
+ reqlist_free_req(req);
ret = -ENOTSUP;
goto out;
@@ -4096,6 +4117,7 @@ qcow2_co_copy_range_from(BlockDriverState *bs,
dst, dst_offset,
cur_bytes, read_flags, cur_write_flags);
qemu_co_mutex_lock(&s->lock);
+ reqlist_free_req(req);
if (ret < 0) {
goto out;
}
@@ -4129,6 +4151,7 @@ qcow2_co_copy_range_to(BlockDriverState *bs,
qemu_co_mutex_lock(&s->lock);
while (bytes != 0) {
+ BlockReq *req;
l2meta = NULL;
@@ -4139,7 +4162,7 @@ qcow2_co_copy_range_to(BlockDriverState *bs,
* the refcnt, without copying user data.
* Or if src->bs == dst->bs->backing->bs, we could copy by discarding.
*/
ret = qcow2_alloc_host_offset(bs, dst_offset, &cur_bytes,
- &host_offset, &l2meta, NULL);
+ &host_offset, &l2meta, &req);
if (ret < 0) {
goto fail;
}
@@ -4147,6 +4170,7 @@ qcow2_co_copy_range_to(BlockDriverState *bs,
ret = qcow2_pre_write_overlap_check(bs, 0, host_offset, cur_bytes,
true);
if (ret < 0) {
+ reqlist_free_req(req);
goto fail;
}
@@ -4154,6 +4178,7 @@ qcow2_co_copy_range_to(BlockDriverState *bs,
ret = bdrv_co_copy_range_to(src, src_offset, s->data_file, host_offset,
cur_bytes, read_flags, write_flags);
qemu_co_mutex_lock(&s->lock);
+ reqlist_free_req(req);
if (ret < 0) {
goto fail;
}
@@ -4565,6 +4590,7 @@ qcow2_co_pwritev_compressed_task(BlockDriverState *bs,
ssize_t out_len;
uint8_t *buf, *out_buf;
uint64_t cluster_offset;
+ BlockReq *req = NULL;
assert(bytes == s->cluster_size || (bytes < s->cluster_size &&
(offset + bytes == bs->total_sectors << BDRV_SECTOR_BITS)));
@@ -4594,7 +4620,7 @@ qcow2_co_pwritev_compressed_task(BlockDriverState *bs,
qemu_co_mutex_lock(&s->lock);
ret = qcow2_alloc_compressed_cluster_offset(bs, offset, out_len,
- &cluster_offset, NULL);
+ &cluster_offset, &req);
if (ret < 0) {
qemu_co_mutex_unlock(&s->lock);
goto fail;
@@ -4614,6 +4640,11 @@ qcow2_co_pwritev_compressed_task(BlockDriverState *bs,
success:
ret = 0;
fail:
+ if (req) {
+ WITH_QEMU_LOCK_GUARD(&s->lock) {
+ reqlist_free_req(req);
+ }
+ }
qemu_vfree(buf);
g_free(out_buf);
return ret;
@@ -4676,7 +4707,8 @@ qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
}
ret = qcow2_add_task(bs, aio, qcow2_co_pwritev_compressed_task_entry,
- 0, 0, offset, chunk_size, qiov, qiov_offset,
NULL);
+ 0, 0, offset, chunk_size, qiov, qiov_offset, NULL,
+ NULL);
if (ret < 0) {
break;
}
--
2.29.2
- [PATCH v7 00/11] qcow2: fix parallel rewrite and discard (reqlist), Vladimir Sementsov-Ogievskiy, 2021/09/04
- [PATCH v7 02/11] block/reqlist: add reqlist_new_req() and reqlist_free_req(), Vladimir Sementsov-Ogievskiy, 2021/09/04
- [PATCH v7 01/11] block/reqlist: drop extra assertion, Vladimir Sementsov-Ogievskiy, 2021/09/04
- [PATCH v7 03/11] iotests: add qcow2-discard-during-rewrite, Vladimir Sementsov-Ogievskiy, 2021/09/04
- [PATCH v7 04/11] qcow2: introduce qcow2_parse_compressed_cluster_descriptor(), Vladimir Sementsov-Ogievskiy, 2021/09/04
- [PATCH v7 05/11] qcow2: refactor qcow2_co_preadv_task() to have one return, Vladimir Sementsov-Ogievskiy, 2021/09/04
- [PATCH v7 06/11] qcow2: prepare for tracking guest io requests in data_file, Vladimir Sementsov-Ogievskiy, 2021/09/04
- [PATCH v7 08/11] qcow2: introduce is_cluster_free() helper, Vladimir Sementsov-Ogievskiy, 2021/09/04
- [PATCH v7 07/11] qcow2: track guest io requests in data_file,
Vladimir Sementsov-Ogievskiy <=
- [PATCH v7 10/11] block/reqlist: implement reqlist_mark_req_invalid(), Vladimir Sementsov-Ogievskiy, 2021/09/04
- [PATCH v7 09/11] qcow2: don't reallocate host clusters under guest operation, Vladimir Sementsov-Ogievskiy, 2021/09/04
- [PATCH v7 11/11] qcow2: use reqlist_mark_req_invalid(), Vladimir Sementsov-Ogievskiy, 2021/09/04
- Re: [PATCH v7 00/11] qcow2: fix parallel rewrite and discard (reqlist), Vladimir Sementsov-Ogievskiy, 2021/09/22