diff mbox series

[v7,07/11] qcow2: track guest io requests in data_file

Message ID 20210904162428.222008-8-vsementsov@virtuozzo.com (mailing list archive)
State New, archived
Headers show
Series qcow2: fix parallel rewrite and discard (reqlist) | expand

Commit Message

Vladimir Sementsov-Ogievskiy Sept. 4, 2021, 4:24 p.m. UTC
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 mbox series

Patch

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,
-                                    &copy_offset, &type, NULL);
+                                    &copy_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;
         }