From: Stefan Hajnoczi <stefanha@redhat.com>
To: qemu-devel@nongnu.org
Cc: Kevin Wolf <kwolf@redhat.com>,
Anthony Liguori <aliguori@us.ibm.com>,
Stefan Hajnoczi <stefanha@redhat.com>
Subject: [Qemu-devel] [PATCH 05/23] qcow2: Handle dependencies earlier
Date: Thu, 28 Mar 2013 17:40:19 +0100 [thread overview]
Message-ID: <1364488837-15916-6-git-send-email-stefanha@redhat.com> (raw)
In-Reply-To: <1364488837-15916-1-git-send-email-stefanha@redhat.com>
From: Kevin Wolf <kwolf@redhat.com>
Handling overlapping allocations isn't just a detail of cluster
allocation. It is rather one of three ways to get the host cluster
offset for a write request:
1. If a request overlaps an in-flight allocations, the cluster offset
can be taken from there (this is what handle_dependencies will evolve
into) or the request must just wait until the allocation has
completed. Accessing the L2 is not valid in this case, it has
outdated information.
2. Outside overlapping areas, check the clusters that can be written to
as they are, with no COW involved.
3. If a COW is required, allocate new clusters
Changing the code to reflect this doesn't change the behaviour because
overlaps cannot exist for clusters that are kept in step 2. It does
however make it easier for later patches to work on clusters that belong
to an allocation that is still in flight.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
block/qcow2-cluster.c | 59 +++++++++++++++++++++++++++++++++++++--------------
block/qcow2.h | 5 +++++
2 files changed, 48 insertions(+), 16 deletions(-)
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index d72d063..71e027a 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -824,16 +824,10 @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
uint64_t *host_offset, unsigned int *nb_clusters)
{
BDRVQcowState *s = bs->opaque;
- int ret;
trace_qcow2_do_alloc_clusters_offset(qemu_coroutine_self(), guest_offset,
*host_offset, *nb_clusters);
- ret = handle_dependencies(bs, guest_offset, nb_clusters);
- if (ret < 0) {
- return ret;
- }
-
/* Allocate new clusters */
trace_qcow2_cluster_alloc_phys(qemu_coroutine_self());
if (*host_offset == 0) {
@@ -845,7 +839,7 @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
*host_offset = cluster_offset;
return 0;
} else {
- ret = qcow2_alloc_clusters_at(bs, *host_offset, *nb_clusters);
+ int ret = qcow2_alloc_clusters_at(bs, *host_offset, *nb_clusters);
if (ret < 0) {
return ret;
}
@@ -885,20 +879,55 @@ int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
trace_qcow2_alloc_clusters_offset(qemu_coroutine_self(), offset,
n_start, n_end);
- /* Find L2 entry for the first involved cluster */
again:
- ret = get_cluster_table(bs, offset, &l2_table, &l2_index);
- if (ret < 0) {
- return ret;
- }
-
/*
* Calculate the number of clusters to look for. We stop at L2 table
* boundaries to keep things simple.
*/
+ l2_index = offset_to_l2_index(s, offset);
nb_clusters = MIN(size_to_clusters(s, n_end << BDRV_SECTOR_BITS),
s->l2_size - l2_index);
+ /*
+ * Now start gathering as many contiguous clusters as possible:
+ *
+ * 1. Check for overlaps with in-flight allocations
+ *
+ * a) Overlap not in the first cluster -> shorten this request and let
+ * the caller handle the rest in its next loop iteration.
+ *
+ * b) Real overlaps of two requests. Yield and restart the search for
+ * contiguous clusters (the situation could have changed while we
+ * were sleeping)
+ *
+ * c) TODO: Request starts in the same cluster as the in-flight
+ * allocation ends. Shorten the COW of the in-fight allocation, set
+ * cluster_offset to write to the same cluster and set up the right
+ * synchronisation between the in-flight request and the new one.
+ *
+ * 2. Count contiguous COPIED clusters.
+ * TODO: Consider cluster_offset if set in step 1c.
+ *
+ * 3. If the request still hasn't completed, allocate new clusters,
+ * considering any cluster_offset of steps 1c or 2.
+ */
+ ret = handle_dependencies(bs, offset, &nb_clusters);
+ if (ret == -EAGAIN) {
+ goto again;
+ } else if (ret < 0) {
+ return ret;
+ } else {
+ /* handle_dependencies() may have decreased cur_bytes (shortened
+ * the allocations below) so that the next dependency is processed
+ * correctly during the next loop iteration. */
+ }
+
+ /* Find L2 entry for the first involved cluster */
+ ret = get_cluster_table(bs, offset, &l2_table, &l2_index);
+ if (ret < 0) {
+ return ret;
+ }
+
cluster_offset = be64_to_cpu(l2_table[l2_index]);
/*
@@ -963,9 +992,7 @@ again:
/* Allocate, if necessary at a given offset in the image file */
ret = do_alloc_cluster_offset(bs, alloc_offset, &alloc_cluster_offset,
&nb_clusters);
- if (ret == -EAGAIN) {
- goto again;
- } else if (ret < 0) {
+ if (ret < 0) {
goto fail;
}
diff --git a/block/qcow2.h b/block/qcow2.h
index e4b5e11..0940b1b 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -277,6 +277,11 @@ static inline int size_to_l1(BDRVQcowState *s, int64_t size)
return (size + (1ULL << shift) - 1) >> shift;
}
+static inline int offset_to_l2_index(BDRVQcowState *s, int64_t offset)
+{
+ return (offset >> s->cluster_bits) & (s->l2_size - 1);
+}
+
static inline int64_t align_offset(int64_t offset, int n)
{
offset = (offset + n - 1) & ~(n - 1);
--
1.8.1.4
next prev parent reply other threads:[~2013-03-28 16:41 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-03-28 16:40 [Qemu-devel] [PULL 00/23] Block patches Stefan Hajnoczi
2013-03-28 16:40 ` [Qemu-devel] [PATCH 01/23] vl.c: call bdrv_init_with_whitelist() before cmdline parsing Stefan Hajnoczi
2013-03-28 16:40 ` [Qemu-devel] [PATCH 02/23] qemu-iotests: More concurrent allocation scenarios Stefan Hajnoczi
2013-03-28 16:40 ` [Qemu-devel] [PATCH 03/23] qcow2: Fix "total clusters" number in bdrv_check Stefan Hajnoczi
2013-03-28 16:40 ` [Qemu-devel] [PATCH 04/23] qcow2: Remove bogus unlock of s->lock Stefan Hajnoczi
2013-03-28 16:40 ` Stefan Hajnoczi [this message]
2013-03-28 16:40 ` [Qemu-devel] [PATCH 06/23] qcow2: Improve check for overlapping allocations Stefan Hajnoczi
2013-03-28 16:40 ` [Qemu-devel] [PATCH 07/23] qcow2: Change handle_dependency to byte granularity Stefan Hajnoczi
2013-03-28 16:40 ` [Qemu-devel] [PATCH 08/23] qcow2: Decouple cluster allocation from cluster reuse code Stefan Hajnoczi
2013-03-28 16:40 ` [Qemu-devel] [PATCH 09/23] qcow2: Factor out handle_alloc() Stefan Hajnoczi
2013-03-28 16:40 ` [Qemu-devel] [PATCH 10/23] qcow2: handle_alloc(): Get rid of nb_clusters parameter Stefan Hajnoczi
2013-03-28 16:40 ` [Qemu-devel] [PATCH 11/23] qcow2: handle_alloc(): Get rid of keep_clusters parameter Stefan Hajnoczi
2013-03-28 16:40 ` [Qemu-devel] [PATCH 12/23] qcow2: Finalise interface of handle_alloc() Stefan Hajnoczi
2013-03-28 16:40 ` [Qemu-devel] [PATCH 13/23] qcow2: Clean up handle_alloc() Stefan Hajnoczi
2013-03-28 16:40 ` [Qemu-devel] [PATCH 14/23] qcow2: Factor out handle_copied() Stefan Hajnoczi
2013-03-28 16:40 ` [Qemu-devel] [PATCH 15/23] qcow2: handle_copied(): Get rid of nb_clusters parameter Stefan Hajnoczi
2013-03-28 16:40 ` [Qemu-devel] [PATCH 16/23] qcow2: handle_copied(): Get rid of keep_clusters parameter Stefan Hajnoczi
2013-03-28 16:40 ` [Qemu-devel] [PATCH 17/23] qcow2: handle_copied(): Implement non-zero host_offset Stefan Hajnoczi
2013-03-28 16:40 ` [Qemu-devel] [PATCH 18/23] qcow2: Prepare handle_alloc/copied() for byte granularity Stefan Hajnoczi
2013-03-28 16:40 ` [Qemu-devel] [PATCH 19/23] qcow2: Use byte granularity in qcow2_alloc_cluster_offset() Stefan Hajnoczi
2013-03-28 16:40 ` [Qemu-devel] [PATCH 20/23] qcow2: Allow requests with multiple l2metas Stefan Hajnoczi
2013-03-28 16:40 ` [Qemu-devel] [PATCH 21/23] qcow2: Move cluster gathering to a non-looping loop Stefan Hajnoczi
2013-03-28 16:40 ` [Qemu-devel] [PATCH 22/23] qcow2: Gather clusters in a looping loop Stefan Hajnoczi
2013-03-28 16:40 ` [Qemu-devel] [PATCH 23/23] block: Fix direct use of protocols as driver for bdrv_open() Stefan Hajnoczi
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=1364488837-15916-6-git-send-email-stefanha@redhat.com \
--to=stefanha@redhat.com \
--cc=aliguori@us.ibm.com \
--cc=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).