From: Kevin Wolf <kwolf@redhat.com>
To: qemu-devel@nongnu.org
Cc: kwolf@redhat.com
Subject: [Qemu-devel] [RFC PATCH 08/16] qcow2: Reading from areas not in L2 tables yet
Date: Tue, 18 Sep 2012 13:40:34 +0200 [thread overview]
Message-ID: <1347968442-8860-9-git-send-email-kwolf@redhat.com> (raw)
In-Reply-To: <1347968442-8860-1-git-send-email-kwolf@redhat.com>
In preparation of delayed COW (i.e. completing the guest write request
before the associated COWs have completed) we must make sure that after
the guest data has written the new data is read back, even if the COW
hasn't completed and the new cluster isn't linked in the L2 table yet.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
block/qcow2-cluster.c | 39 +++++++++++++++++++++++++++++++++++++++
block/qcow2.c | 2 ++
block/qcow2.h | 19 +++++++++++++++++++
3 files changed, 60 insertions(+), 0 deletions(-)
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 468ef1b..a89d68d 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -372,6 +372,40 @@ out:
return ret;
}
+static bool overlaps_allocation(BlockDriverState *bs, uint64_t start,
+ int *num, uint64_t *cluster_offset)
+{
+ BDRVQcowState *s = bs->opaque;
+ QCowL2Meta *m;
+ uint64_t end = start + (*num << BDRV_SECTOR_BITS);
+
+ QLIST_FOREACH(m, &s->cluster_allocs, next_in_flight) {
+
+ uint64_t old_start = l2meta_req_start(m);
+ uint64_t old_end = l2meta_req_end(m);
+
+ /* If the write hasn't completed yet and the allocating request can't
+ * have completed yet therefore, we're free to read the old data. */
+ if (!m->is_written) {
+ continue;
+ }
+
+ if (start >= old_start && start < old_end) {
+ /* Start of the new request overlaps: Read from the newly allocated
+ * cluster even if it isn't in the L2 table yet. */
+ *num = MIN(*num, (old_end - start) >> BDRV_SECTOR_BITS);
+ *cluster_offset = m->alloc_offset
+ + ((start - old_start) & ~(s->cluster_size - 1));
+ return true;
+ } else if (start < old_start && end > old_start) {
+ /* Overlap somewhere after the start. Shorten this request so that
+ * no overlap occurs. */
+ *num = MIN(*num, (old_start - start) >> BDRV_SECTOR_BITS);
+ }
+ }
+
+ return false;
+}
/*
* get_cluster_offset
@@ -398,6 +432,11 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
uint64_t nb_available, nb_needed;
int ret;
+ /* Check overlap with not yet completed allocations */
+ if (overlaps_allocation(bs, offset, num, cluster_offset)) {
+ return QCOW2_CLUSTER_NORMAL;
+ }
+
index_in_cluster = (offset >> 9) & (s->cluster_sectors - 1);
nb_needed = *num + index_in_cluster;
diff --git a/block/qcow2.c b/block/qcow2.c
index 6515fdd..2e32136 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -831,6 +831,8 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
}
if (l2meta != NULL) {
+ l2meta->is_written = true;
+
ret = qcow2_alloc_cluster_link_l2(bs, l2meta);
if (ret < 0) {
goto fail;
diff --git a/block/qcow2.h b/block/qcow2.h
index a60fcb4..504dbad 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -229,6 +229,14 @@ typedef struct QCowL2Meta
int nb_clusters;
/**
+ * true if the guest data (but not necessarily the related COW) has been
+ * written to disk, so that read requests can (and after having completed
+ * this request actually _must_) read the new data instead of reading the
+ * old data that the L2 table still refers to.
+ */
+ bool is_written;
+
+ /**
* Requests that overlap with this allocation and wait to be restarted
* when the allocating request has completed.
*/
@@ -298,6 +306,17 @@ static inline bool qcow2_need_accurate_refcounts(BDRVQcowState *s)
return !(s->incompatible_features & QCOW2_INCOMPAT_DIRTY);
}
+static inline uint64_t l2meta_req_start(QCowL2Meta *m)
+{
+ return (m->offset + m->cow_start.offset)
+ + (m->cow_start.nb_sectors << BDRV_SECTOR_BITS);
+}
+
+static inline uint64_t l2meta_req_end(QCowL2Meta *m)
+{
+ return m->offset + (m->nb_available << BDRV_SECTOR_BITS);
+}
+
// FIXME Need qcow2_ prefix to global functions
/* qcow2.c functions */
--
1.7.6.5
next prev parent reply other threads:[~2012-09-18 11:40 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-09-18 11:40 [Qemu-devel] [RFC PATCH 00/16] qcow2: Delayed COW Kevin Wolf
2012-09-18 11:40 ` [Qemu-devel] [RFC PATCH 01/16] qcow2: Round QCowL2Meta.offset down to cluster boundary Kevin Wolf
2012-09-18 11:40 ` [Qemu-devel] [RFC PATCH 02/16] qcow2: Introduce Qcow2COWRegion Kevin Wolf
2012-09-18 11:40 ` [Qemu-devel] [RFC PATCH 03/16] qcow2: Allocate l2meta dynamically Kevin Wolf
2012-09-18 11:40 ` [Qemu-devel] [RFC PATCH 04/16] qcow2: Drop l2meta.cluster_offset Kevin Wolf
2012-09-18 11:40 ` [Qemu-devel] [RFC PATCH 05/16] qcow2: Allocate l2meta only for cluster allocations Kevin Wolf
2012-09-18 11:40 ` [Qemu-devel] [RFC PATCH 06/16] qcow2: Enable dirty flag in qcow2_alloc_cluster_link_l2 Kevin Wolf
2012-09-18 11:40 ` [Qemu-devel] [RFC PATCH 07/16] qcow2: Factor out handle_dependencies() Kevin Wolf
2012-09-18 11:40 ` Kevin Wolf [this message]
2012-09-18 11:40 ` [Qemu-devel] [RFC PATCH 09/16] qcow2: Move COW and L2 update into own coroutine Kevin Wolf
2012-09-18 14:24 ` Paolo Bonzini
2012-09-18 14:44 ` Kevin Wolf
2012-09-18 14:59 ` Paolo Bonzini
2012-09-18 11:40 ` [Qemu-devel] [RFC PATCH 10/16] qcow2: Delay the COW Kevin Wolf
2012-09-18 14:27 ` Paolo Bonzini
2012-09-18 14:49 ` Kevin Wolf
2012-09-19 18:47 ` Blue Swirl
2012-09-20 6:58 ` Kevin Wolf
2012-09-18 11:40 ` [Qemu-devel] [RFC PATCH 11/16] qcow2: Add error handling to the l2meta coroutine Kevin Wolf
2012-09-18 14:29 ` Paolo Bonzini
2012-09-18 11:40 ` [Qemu-devel] [RFC PATCH 12/16] qcow2: Handle dependencies earlier Kevin Wolf
2012-09-18 11:40 ` [Qemu-devel] [RFC PATCH 13/16] qcow2: Change handle_dependency to byte granularity Kevin Wolf
2012-09-18 11:40 ` [Qemu-devel] [RFC PATCH 14/16] qcow2: Execute run_dependent_requests() without lock Kevin Wolf
2012-09-18 14:33 ` Paolo Bonzini
2012-09-18 14:54 ` Kevin Wolf
2012-09-18 11:40 ` [Qemu-devel] [RFC PATCH 15/16] qcow2: Cancel COW when overwritten Kevin Wolf
2012-09-18 14:44 ` Paolo Bonzini
2012-09-18 15:02 ` Kevin Wolf
2012-09-18 15:05 ` Paolo Bonzini
2012-09-18 15:08 ` Paolo Bonzini
2012-09-18 11:40 ` [Qemu-devel] [RFC PATCH 16/16] [BROKEN] qcow2: Overwrite COW and allocate new cluster at the same time Kevin Wolf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1347968442-8860-9-git-send-email-kwolf@redhat.com \
--to=kwolf@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).