From patchwork Mon Apr 22 02:07:59 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Fam Zheng X-Patchwork-Id: 238278 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 D32932C0117 for ; Mon, 22 Apr 2013 12:09:04 +1000 (EST) Received: from localhost ([::1]:47890 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UU6Bi-0001oQ-U7 for incoming@patchwork.ozlabs.org; Sun, 21 Apr 2013 22:09:02 -0400 Received: from eggs.gnu.org ([208.118.235.92]:53961) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UU6BD-0001fr-RO for qemu-devel@nongnu.org; Sun, 21 Apr 2013 22:08:35 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UU6B9-0006QC-EJ for qemu-devel@nongnu.org; Sun, 21 Apr 2013 22:08:31 -0400 Received: from mx1.redhat.com ([209.132.183.28]:1683) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UU6B9-0006Pw-6a for qemu-devel@nongnu.org; Sun, 21 Apr 2013 22:08:27 -0400 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r3M28Q4w021453 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Sun, 21 Apr 2013 22:08:26 -0400 Received: from localhost.localdomain.com ([10.66.7.14]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id r3M28COv022349; Sun, 21 Apr 2013 22:08:24 -0400 From: Fam Zheng To: qemu-devel@nongnu.org Date: Mon, 22 Apr 2013 10:07:59 +0800 Message-Id: <1366596479-22212-6-git-send-email-famz@redhat.com> In-Reply-To: <1366596479-22212-1-git-send-email-famz@redhat.com> References: <1366596479-22212-1-git-send-email-famz@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.24 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: kwolf@redhat.com, Fam Zheng , stefanha@redhat.com Subject: [Qemu-devel] [PATCH v2 5/5] vmdk: add bdrv_co_write_zeroes 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 Use special offset to write zeroes efficiently, when zeroed-grain GTE is available. If zero-write an allocated cluster, cluster is leaked because its offset pointer is overwritten by "0x1". Signed-off-by: Fam Zheng --- block/vmdk.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 63 insertions(+), 19 deletions(-) diff --git a/block/vmdk.c b/block/vmdk.c index 632689b..7475090 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -814,6 +814,7 @@ static int get_whole_cluster(BlockDriverState *bs, static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data) { /* update L2 table */ + m_data->l2_offset = extent->l1_table[m_data->l1_index]; if (bdrv_pwrite_sync( extent->file, ((int64_t)m_data->l2_offset * 512) @@ -905,6 +906,12 @@ static int get_cluster_offset(BlockDriverState *bs, l2_index = ((offset >> 9) / extent->cluster_sectors) % extent->l2_size; *cluster_offset = le32_to_cpu(l2_table[l2_index]); + if (m_data) { + m_data->valid = 1; + m_data->l1_index = l1_index; + m_data->l2_index = l2_index; + m_data->offset = cpu_to_le32(*cluster_offset); + } if (extent->has_zero_grain && *cluster_offset == VMDK_GTE_ZEROED) { zeroed = true; } @@ -939,10 +946,6 @@ static int get_cluster_offset(BlockDriverState *bs, if (m_data) { m_data->offset = tmp; - m_data->l1_index = l1_index; - m_data->l2_index = l2_index; - m_data->l2_offset = l2_offset; - m_data->valid = 1; } } *cluster_offset <<= 9; @@ -1165,8 +1168,16 @@ static coroutine_fn int vmdk_co_read(BlockDriverState *bs, int64_t sector_num, return ret; } +/** + * params: + * - zeroed: buf is ignored (data is zero), use zeroed_grain GTE + * feature if possible, otherwise return -ENOTSUP. + * - zero_dry_run: used for zeroed == true only, don't update L2 table, just + * try if it's supported + */ static int vmdk_write(BlockDriverState *bs, int64_t sector_num, - const uint8_t *buf, int nb_sectors) + const uint8_t *buf, int nb_sectors, + bool zeroed, bool zero_dry_run) { BDRVVmdkState *s = bs->opaque; VmdkExtent *extent = NULL; @@ -1212,7 +1223,7 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num, &cluster_offset); } } - if (ret) { + if (ret == VMDK_ERROR) { return -EINVAL; } extent_begin_sector = extent->end_sector - extent->sectors; @@ -1222,17 +1233,34 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num, if (n > nb_sectors) { n = nb_sectors; } - - ret = vmdk_write_extent(extent, - cluster_offset, index_in_cluster * 512, - buf, n, sector_num); - if (ret) { - return ret; - } - if (m_data.valid) { - /* update L2 tables */ - if (vmdk_L2update(extent, &m_data) == -1) { - return -EIO; + if (zeroed) { + /* Do zeroed write, buf is ignored */ + if (extent->has_zero_grain && + index_in_cluster == 0 && + n >= extent->cluster_sectors) { + n = extent->cluster_sectors; + if (!zero_dry_run) { + m_data.offset = cpu_to_le32(VMDK_GTE_ZEROED); + /* update L2 tables */ + if (vmdk_L2update(extent, &m_data) == -1) { + return -EIO; + } + } + } else { + return -ENOTSUP; + } + } else { + ret = vmdk_write_extent(extent, + cluster_offset, index_in_cluster * 512, + buf, n, sector_num); + if (ret) { + return ret; + } + if (m_data.valid) { + /* update L2 tables */ + if (vmdk_L2update(extent, &m_data) == -1) { + return -EIO; + } } } nb_sectors -= n; @@ -1258,7 +1286,22 @@ static coroutine_fn int vmdk_co_write(BlockDriverState *bs, int64_t sector_num, int ret; BDRVVmdkState *s = bs->opaque; qemu_co_mutex_lock(&s->lock); - ret = vmdk_write(bs, sector_num, buf, nb_sectors); + ret = vmdk_write(bs, sector_num, buf, nb_sectors, false, false); + qemu_co_mutex_unlock(&s->lock); + return ret; +} + +static int coroutine_fn vmdk_co_write_zeroes(BlockDriverState *bs, + int64_t sector_num, + int nb_sectors) +{ + int ret; + BDRVVmdkState *s = bs->opaque; + qemu_co_mutex_lock(&s->lock); + ret = vmdk_write(bs, sector_num, NULL, nb_sectors, true, true); + if (!ret) { + ret = vmdk_write(bs, sector_num, NULL, nb_sectors, true, false); + } qemu_co_mutex_unlock(&s->lock); return ret; } @@ -1290,7 +1333,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize, header.version = zeroed_grain ? 2 : 1; header.flags = VMDK4_FLAG_RGD | VMDK4_FLAG_NL_DETECT | (compress ? VMDK4_FLAG_COMPRESS | VMDK4_FLAG_MARKER : 0) - | (zeroed_grain ? VMDK4_FLAG_ZG : 0); + | (zeroed_grain ? VMDK4_FLAG_ZERO_GRAIN : 0); header.compressAlgorithm = compress ? VMDK4_COMPRESSION_DEFLATE : 0; header.capacity = filesize / 512; header.granularity = 128; @@ -1738,6 +1781,7 @@ static BlockDriver bdrv_vmdk = { .bdrv_reopen_prepare = vmdk_reopen_prepare, .bdrv_read = vmdk_co_read, .bdrv_write = vmdk_co_write, + .bdrv_co_write_zeroes = vmdk_co_write_zeroes, .bdrv_close = vmdk_close, .bdrv_create = vmdk_create, .bdrv_co_flush_to_disk = vmdk_co_flush,