[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v7 06/11] qcow2: prepare for tracking guest io requests in data_f
From: |
Vladimir Sementsov-Ogievskiy |
Subject: |
[PATCH v7 06/11] qcow2: prepare for tracking guest io requests in data_file |
Date: |
Sat, 4 Sep 2021 19:24:23 +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. Guest io
operations in data_file has 3 entry points:
qcow2_get_host_offset()
qcow2_alloc_host_offset()
qcow2_alloc_compressed_cluster_offset()
These functions provides the offset in data_file. So for now, add a
possibility for these function to start a BlockReq.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---
block/qcow2.h | 11 ++++++++---
block/qcow2-cluster.c | 45 ++++++++++++++++++++++++++++++++++++++++---
block/qcow2.c | 17 ++++++++--------
3 files changed, 59 insertions(+), 14 deletions(-)
diff --git a/block/qcow2.h b/block/qcow2.h
index 4859ca3d0d..7b9fafc6ec 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -29,6 +29,7 @@
#include "qemu/coroutine.h"
#include "qemu/units.h"
#include "block/block_int.h"
+#include "block/reqlist.h"
//#define DEBUG_ALLOC
//#define DEBUG_ALLOC2
@@ -420,6 +421,8 @@ typedef struct BDRVQcow2State {
* is to convert the image with the desired compression type set.
*/
Qcow2CompressionType compression_type;
+
+ BlockReqList guest_reqs;
} BDRVQcow2State;
typedef struct Qcow2COWRegion {
@@ -906,14 +909,16 @@ int qcow2_encrypt_sectors(BDRVQcow2State *s, int64_t
sector_num,
int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
unsigned int *bytes, uint64_t *host_offset,
- QCow2SubclusterType *subcluster_type);
+ QCow2SubclusterType *subcluster_type,
+ BlockReq **req);
int qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset,
unsigned int *bytes, uint64_t *host_offset,
- QCowL2Meta **m);
+ QCowL2Meta **m, BlockReq **req);
int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
uint64_t offset,
int compressed_size,
- uint64_t *host_offset);
+ uint64_t *host_offset,
+ BlockReq **req);
void qcow2_parse_compressed_cluster_descriptor(BDRVQcow2State *s,
uint64_t cluster_descriptor,
uint64_t *coffset,
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index bd0597842f..9887f80dcc 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -567,11 +567,17 @@ static int coroutine_fn
do_perform_cow_write(BlockDriverState *bs,
* file. The subcluster type is stored in *subcluster_type.
* Compressed clusters are always processed one by one.
*
+ * On success if req is non-NULL and resulting subcluster type is
+ * QCOW2_SUBCLUSTER_NORMAL or QCOW2_SUBCLUSTER_COMPRESSED req is allocated and
+ * initialized. For other cluster types req is set to NULL.
+ * On failure req is untouched.
+ *
* Returns 0 on success, -errno in error cases.
*/
int qcow2_get_host_offset(BlockDriverState *bs, uint64_t offset,
unsigned int *bytes, uint64_t *host_offset,
- QCow2SubclusterType *subcluster_type)
+ QCow2SubclusterType *subcluster_type,
+ BlockReq **req)
{
BDRVQcow2State *s = bs->opaque;
unsigned int l2_index, sc_index;
@@ -721,6 +727,21 @@ out:
*subcluster_type = type;
+ if (req) {
+ if (type == QCOW2_SUBCLUSTER_COMPRESSED) {
+ uint64_t coffset;
+ int csize;
+
+ qcow2_parse_compressed_cluster_descriptor(s, *host_offset,
&coffset,
+ &csize);
+ *req = reqlist_new_req(&s->guest_reqs, coffset, csize);
+ } else if (type == QCOW2_SUBCLUSTER_NORMAL) {
+ *req = reqlist_new_req(&s->guest_reqs, *host_offset, *bytes);
+ } else {
+ *req = NULL;
+ }
+ }
+
return 0;
fail:
@@ -809,11 +830,16 @@ static int get_cluster_table(BlockDriverState *bs,
uint64_t offset,
* already allocated at the offset, return an error.
*
* Return 0 on success and -errno in error cases
+ *
+ * On success if req is non-NULL req is allocated and initialized.
+ * On failure req is untouched.
+ *
*/
int qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
uint64_t offset,
int compressed_size,
- uint64_t *host_offset)
+ uint64_t *host_offset,
+ BlockReq **req)
{
BDRVQcow2State *s = bs->opaque;
int l2_index, ret;
@@ -868,6 +894,11 @@ int qcow2_alloc_compressed_cluster_offset(BlockDriverState
*bs,
qcow2_cache_put(s->l2_table_cache, (void **) &l2_slice);
*host_offset = cluster_offset & s->cluster_offset_mask;
+
+ if (req) {
+ *req = reqlist_new_req(&s->guest_reqs, *host_offset, compressed_size);
+ }
+
return 0;
}
@@ -1740,10 +1771,14 @@ out:
* is queued and will be reentered when the dependency has completed.
*
* Return 0 on success and -errno in error cases
+ *
+ * On success if req is non-NULL req is allocated and initialized.
+ * On failure req is untouched.
+ *
*/
int qcow2_alloc_host_offset(BlockDriverState *bs, uint64_t offset,
unsigned int *bytes, uint64_t *host_offset,
- QCowL2Meta **m)
+ QCowL2Meta **m, BlockReq **req)
{
BDRVQcow2State *s = bs->opaque;
uint64_t start, remaining;
@@ -1850,6 +1885,10 @@ again:
assert(offset_into_cluster(s, *host_offset) ==
offset_into_cluster(s, offset));
+ if (req) {
+ *req = reqlist_new_req(&s->guest_reqs, *host_offset, *bytes);
+ }
+
return 0;
}
diff --git a/block/qcow2.c b/block/qcow2.c
index 7fbcc600da..8aa5679fe9 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1833,6 +1833,7 @@ static int coroutine_fn qcow2_do_open(BlockDriverState
*bs, QDict *options,
#endif
qemu_co_queue_init(&s->thread_task_queue);
+ QLIST_INIT(&s->guest_reqs);
return ret;
@@ -2090,7 +2091,7 @@ static int coroutine_fn
qcow2_co_block_status(BlockDriverState *bs,
}
bytes = MIN(INT_MAX, count);
- ret = qcow2_get_host_offset(bs, offset, &bytes, &host_offset, &type);
+ ret = qcow2_get_host_offset(bs, offset, &bytes, &host_offset, &type, NULL);
qemu_co_mutex_unlock(&s->lock);
if (ret < 0) {
return ret;
@@ -2335,7 +2336,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);
+ &host_offset, &type, NULL);
qemu_co_mutex_unlock(&s->lock);
if (ret < 0) {
goto out;
@@ -2629,7 +2630,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);
+ &host_offset, &l2meta, NULL);
if (ret < 0) {
goto out_locked;
}
@@ -3170,7 +3171,7 @@ static int coroutine_fn preallocate_co(BlockDriverState
*bs, uint64_t offset,
while (bytes) {
cur_bytes = MIN(bytes, QEMU_ALIGN_DOWN(INT_MAX, s->cluster_size));
ret = qcow2_alloc_host_offset(bs, offset, &cur_bytes,
- &host_offset, &meta);
+ &host_offset, &meta, NULL);
if (ret < 0) {
error_setg_errno(errp, -ret, "Allocating clusters failed");
goto out;
@@ -3976,7 +3977,7 @@ static coroutine_fn int
qcow2_co_pwrite_zeroes(BlockDriverState *bs,
offset -= head;
bytes = s->subcluster_size;
nr = s->subcluster_size;
- ret = qcow2_get_host_offset(bs, offset, &nr, &off, &type);
+ ret = qcow2_get_host_offset(bs, offset, &nr, &off, &type, NULL);
if (ret < 0 ||
(type != QCOW2_SUBCLUSTER_UNALLOCATED_PLAIN &&
type != QCOW2_SUBCLUSTER_UNALLOCATED_ALLOC &&
@@ -4051,7 +4052,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);
+ ©_offset, &type, NULL);
if (ret < 0) {
goto out;
}
@@ -4138,7 +4139,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);
+ &host_offset, &l2meta, NULL);
if (ret < 0) {
goto fail;
}
@@ -4593,7 +4594,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);
+ &cluster_offset, NULL);
if (ret < 0) {
qemu_co_mutex_unlock(&s->lock);
goto fail;
--
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 <=
- [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, 2021/09/04
- [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