From patchwork Tue May 5 12:40:35 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Avi Kivity X-Patchwork-Id: 21849 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n45CetuF015111 for ; Tue, 5 May 2009 12:40:56 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752970AbZEEMkx (ORCPT ); Tue, 5 May 2009 08:40:53 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1753183AbZEEMkw (ORCPT ); Tue, 5 May 2009 08:40:52 -0400 Received: from mx2.redhat.com ([66.187.237.31]:33783 "EHLO mx2.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752359AbZEEMkv (ORCPT ); Tue, 5 May 2009 08:40:51 -0400 Received: from int-mx2.corp.redhat.com (int-mx2.corp.redhat.com [172.16.27.26]) by mx2.redhat.com (8.13.8/8.13.8) with ESMTP id n45CefPY025457; Tue, 5 May 2009 08:40:41 -0400 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx2.corp.redhat.com (8.13.1/8.13.1) with ESMTP id n45CeeRL023387; Tue, 5 May 2009 08:40:40 -0400 Received: from cleopatra.tlv.redhat.com (cleopatra.tlv.redhat.com [10.35.255.11]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id n45CebUs007985; Tue, 5 May 2009 08:40:37 -0400 Received: from localhost.localdomain (dhcp-1-197.tlv.redhat.com [10.35.1.197]) by cleopatra.tlv.redhat.com (Postfix) with ESMTP id C8B58A0042; Tue, 5 May 2009 15:40:36 +0300 (IDT) From: Avi Kivity To: Anthony Liguori Cc: qemu-devel@nongnu.org, kvm@vger.kernel.org Subject: [PATCH] Serialize qcow2 writes Date: Tue, 5 May 2009 15:40:35 +0300 Message-Id: <1241527235-19755-1-git-send-email-avi@redhat.com> X-Scanned-By: MIMEDefang 2.58 on 172.16.27.26 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Commit 641636d ("qcow2 corruption: Fix alloc_cluster_link_l2"; 4df8f71 on stable-0.10) exposes a bug with concurrent allocating qcow2 writes: the writes will trigger a call to free_any_clusters() and corrupt the image. As a temporary workaround until a real fix is written, this patch serializes writes to avoid the issue. With this, I can install Fedora 10 on a virtio disk. Signed-off-by: Avi Kivity --- block-qcow2.c | 27 ++++++++++++++++++++++++++- 1 files changed, 26 insertions(+), 1 deletions(-) diff --git a/block-qcow2.c b/block-qcow2.c index 1f33125..6685915 100644 --- a/block-qcow2.c +++ b/block-qcow2.c @@ -157,6 +157,8 @@ typedef struct BDRVQcowState { int snapshots_size; int nb_snapshots; QCowSnapshot *snapshots; + int write_in_progress; + TAILQ_HEAD(QCow2DeferredWrites, QCowAIOCB) deferred_writes; } BDRVQcowState; static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset); @@ -371,6 +373,9 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) if (qcow_read_snapshots(bs) < 0) goto fail; + s->write_in_progress = 0; + TAILQ_INIT(&s->deferred_writes); + #ifdef DEBUG_ALLOC check_refcounts(bs); #endif @@ -1274,6 +1279,7 @@ typedef struct QCowAIOCB { QEMUIOVector hd_qiov; QEMUBH *bh; QCowL2Meta l2meta; + TAILQ_ENTRY(QCowAIOCB) deferred_writes_link; } QCowAIOCB; static void qcow_aio_read_cb(void *opaque, int ret); @@ -1439,6 +1445,8 @@ static BlockDriverAIOCB *qcow_aio_readv(BlockDriverState *bs, return &acb->common; } +static void fire_deferred_writes(BDRVQcowState *s); + static void qcow_aio_write_cb(void *opaque, int ret) { QCowAIOCB *acb = opaque; @@ -1509,6 +1517,21 @@ done: qemu_vfree(acb->orig_buf); acb->common.cb(acb->common.opaque, ret); qemu_aio_release(acb); + + s->write_in_progress = 0; + fire_deferred_writes(s); +} + +static void fire_deferred_writes(BDRVQcowState *s) +{ + QCowAIOCB *acb; + + if (!s->write_in_progress && !TAILQ_EMPTY(&s->deferred_writes)) { + s->write_in_progress = 1; + acb = TAILQ_FIRST(&s->deferred_writes); + TAILQ_REMOVE(&s->deferred_writes, acb, deferred_writes_link); + qcow_aio_write_cb(acb, 0); + } } static BlockDriverAIOCB *qcow_aio_writev(BlockDriverState *bs, @@ -1524,7 +1547,9 @@ static BlockDriverAIOCB *qcow_aio_writev(BlockDriverState *bs, if (!acb) return NULL; - qcow_aio_write_cb(acb, 0); + TAILQ_INSERT_TAIL(&s->deferred_writes, acb, deferred_writes_link); + fire_deferred_writes(s); + return &acb->common; }