From patchwork Mon Mar 25 17:30:04 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Wolf X-Patchwork-Id: 230865 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 0E7052C007C for ; Tue, 26 Mar 2013 05:00:41 +1100 (EST) Received: from localhost ([::1]:44490 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UKBGf-00084n-Mf for incoming@patchwork.ozlabs.org; Mon, 25 Mar 2013 13:33:09 -0400 Received: from eggs.gnu.org ([208.118.235.92]:47749) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UKBET-0004uG-Ke for qemu-devel@nongnu.org; Mon, 25 Mar 2013 13:30:56 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UKBEN-0003xN-LT for qemu-devel@nongnu.org; Mon, 25 Mar 2013 13:30:53 -0400 Received: from mx1.redhat.com ([209.132.183.28]:43505) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UKBEN-0003xB-5W for qemu-devel@nongnu.org; Mon, 25 Mar 2013 13:30:47 -0400 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r2PHUkY2011995 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Mon, 25 Mar 2013 13:30:46 -0400 Received: from dhcp-200-207.str.redhat.com (ovpn-116-73.ams2.redhat.com [10.36.116.73]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id r2PHUd7I010200; Mon, 25 Mar 2013 13:30:45 -0400 From: Kevin Wolf To: qemu-devel@nongnu.org Date: Mon, 25 Mar 2013 18:30:04 +0100 Message-Id: <1364232620-5293-4-git-send-email-kwolf@redhat.com> In-Reply-To: <1364232620-5293-1-git-send-email-kwolf@redhat.com> References: <1364232620-5293-1-git-send-email-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: kwolf@redhat.com, stefanha@redhat.com Subject: [Qemu-devel] [PATCH 03/19] qcow2: Handle dependencies earlier X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 --- 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);