From patchwork Wed Apr 27 07:08:45 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Denis V. Lunev" X-Patchwork-Id: 615440 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)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3qvrfy0y4sz9t3n for ; Wed, 27 Apr 2016 17:09:14 +1000 (AEST) Received: from localhost ([::1]:41323 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1avJay-0001zU-87 for incoming@patchwork.ozlabs.org; Wed, 27 Apr 2016 03:09:12 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:59471) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1avJaf-0001V1-Jr for qemu-devel@nongnu.org; Wed, 27 Apr 2016 03:08:54 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1avJac-0008JB-B3 for qemu-devel@nongnu.org; Wed, 27 Apr 2016 03:08:53 -0400 Received: from mailhub.sw.ru ([195.214.232.25]:34310 helo=relay.sw.ru) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1avJab-0008Iq-Uq for qemu-devel@nongnu.org; Wed, 27 Apr 2016 03:08:50 -0400 Received: from hades.sw.ru ([10.30.8.132]) by relay.sw.ru (8.13.4/8.13.4) with ESMTP id u3R78jft029265; Wed, 27 Apr 2016 10:08:46 +0300 (MSK) From: "Denis V. Lunev" To: qemu-devel@nongnu.org Date: Wed, 27 Apr 2016 10:08:45 +0300 Message-Id: <1461740925-20887-1-git-send-email-den@openvz.org> X-Mailer: git-send-email 2.5.0 X-detected-operating-system: by eggs.gnu.org: OpenBSD 3.x X-Received-From: 195.214.232.25 Subject: [Qemu-devel] [PATCH for 2.7 v2 1/1] qcow2: improve qcow2_co_write_zeroes() X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , den@openvz.org, Max Reitz Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" There is a possibility that qcow2_co_write_zeroes() will be called by with the partial block. This could be synthetically triggered with qemu-io -c "write -z 32k 4k" and can happen in the real life in qemu-nbd. The latter happens under the following conditions: (1) qemu-nbd is started with --detect-zeroes=on and is connected to the kernel NBD client (2) third party program opens kernel NBD device with O_DIRECT (3) third party program performs write operation with memory buffer not aligned to the page In this case qcow2_co_write_zeroes() is unable to perform the operation and mark entire cluster as zeroed and returns ENOTSUP. Thus the caller switches to non-optimized version and writes real zeroes to the disk. The patch creates a shortcut. If the block is full of zeroes at the moment, the request is extended to cover full block. User-visible situation with this block is not changed. Before the patch the block is filled in the image with real zeroes. After that patch the block is marked as zeroed in metadata. Thus any subsequent changes in backing store chain are not affected. Kewin, thank you for a cool suggestion. Signed-off-by: Denis V. Lunev CC: Kevin Wolf CC: Max Reitz --- Changes from v1: - description rewritten completely - new approach suggested by Kevin is implemented block/qcow2.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/block/qcow2.c b/block/qcow2.c index 470734b..405d1da 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2417,15 +2417,29 @@ static coroutine_fn int qcow2_co_write_zeroes(BlockDriverState *bs, int ret; BDRVQcow2State *s = bs->opaque; - /* Emulate misaligned zero writes */ - if (sector_num % s->cluster_sectors || nb_sectors % s->cluster_sectors) { - return -ENOTSUP; + int head = sector_num % s->cluster_sectors; + int tail = nb_sectors % s->cluster_sectors; + if (head != 0 || tail != 0) { + int nr; + BlockDriverState *file; + + sector_num -= head; + nb_sectors += head + tail; + + /* check the the request extended to the entire cluster is read + as all zeroes at the moment. If so we can mark entire cluster + as zeroed in the metadata */ + ret = bdrv_get_block_status_above(bs, NULL, sector_num, nb_sectors, + &nr, &file); + if (ret < 0 || !(ret & BDRV_BLOCK_ZERO) || sector_num == nr) { + /* Emulate misaligned zero writes */ + return -ENOTSUP; + } } /* Whatever is left can use real zero clusters */ qemu_co_mutex_lock(&s->lock); - ret = qcow2_zero_clusters(bs, sector_num << BDRV_SECTOR_BITS, - nb_sectors); + ret = qcow2_zero_clusters(bs, sector_num << BDRV_SECTOR_BITS, nb_sectors); qemu_co_mutex_unlock(&s->lock); return ret;