From patchwork Tue Jul 11 16:08:05 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Max Reitz X-Patchwork-Id: 9835293 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 933B4602BD for ; Tue, 11 Jul 2017 17:07:10 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7C5DC28210 for ; Tue, 11 Jul 2017 17:07:10 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 705DE28437; Tue, 11 Jul 2017 17:07:10 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 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 mail.wl.linuxfoundation.org (Postfix) with ESMTPS id BC1E728210 for ; Tue, 11 Jul 2017 17:07:09 +0000 (UTC) Received: from localhost ([::1]:47655 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dUycu-000246-Ta for patchwork-qemu-devel@patchwork.kernel.org; Tue, 11 Jul 2017 13:07:08 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47178) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dUxmT-0002J4-BS for qemu-devel@nongnu.org; Tue, 11 Jul 2017 12:12:58 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dUxmS-0007PJ-2Q for qemu-devel@nongnu.org; Tue, 11 Jul 2017 12:12:57 -0400 Received: from mx1.redhat.com ([209.132.183.28]:54610) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1dUxmL-0007K2-R8; Tue, 11 Jul 2017 12:12:50 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id D3CD24E4D4; Tue, 11 Jul 2017 16:12:48 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com D3CD24E4D4 Authentication-Results: ext-mx09.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx09.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=mreitz@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com D3CD24E4D4 Received: from localhost (ovpn-204-123.brq.redhat.com [10.40.204.123]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 2F6F25D9C8; Tue, 11 Jul 2017 16:12:47 +0000 (UTC) From: Max Reitz To: qemu-block@nongnu.org Date: Tue, 11 Jul 2017 18:08:05 +0200 Message-Id: <20170711160814.20941-77-mreitz@redhat.com> In-Reply-To: <20170711160814.20941-1-mreitz@redhat.com> References: <20170711160814.20941-1-mreitz@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.38]); Tue, 11 Jul 2017 16:12:49 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PULL 76/85] block/file-posix: Generalize raw_regular_truncate 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: qemu-devel@nongnu.org, Max Reitz Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP Currently, raw_regular_truncate() is intended for setting the size of a newly created file. However, we also want to use it for truncating an existing file in which case only the newly added space (when growing) should be preallocated. This also means that if resizing failed, we should try to restore the original file size. This is important when using preallocation. Signed-off-by: Max Reitz Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Stefan Hajnoczi Message-id: 20170613202107.10125-8-mreitz@redhat.com Signed-off-by: Max Reitz --- block/file-posix.c | 61 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 11 deletions(-) diff --git a/block/file-posix.c b/block/file-posix.c index deefd6e..59154ea 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -1624,11 +1624,31 @@ static void raw_close(BlockDriverState *bs) } } +/** + * Truncates the given regular file @fd to @offset and, when growing, fills the + * new space according to @prealloc. + * + * Returns: 0 on success, -errno on failure. + */ static int raw_regular_truncate(int fd, int64_t offset, PreallocMode prealloc, Error **errp) { int result = 0; - char *buf; + int64_t current_length = 0; + char *buf = NULL; + struct stat st; + + if (fstat(fd, &st) < 0) { + result = -errno; + error_setg_errno(errp, -result, "Could not stat file"); + return result; + } + + current_length = st.st_size; + if (current_length > offset && prealloc != PREALLOC_MODE_OFF) { + error_setg(errp, "Cannot use preallocation for shrinking files"); + return -ENOTSUP; + } switch (prealloc) { #ifdef CONFIG_POSIX_FALLOCATE @@ -1638,17 +1658,17 @@ static int raw_regular_truncate(int fd, int64_t offset, PreallocMode prealloc, * file systems that do not support fallocate(), trying to check if a * block is allocated before allocating it, so don't do that here. */ - result = -posix_fallocate(fd, 0, offset); + result = -posix_fallocate(fd, current_length, offset - current_length); if (result != 0) { /* posix_fallocate() doesn't set errno. */ error_setg_errno(errp, -result, - "Could not preallocate data for the new file"); + "Could not preallocate new data"); } - return result; + goto out; #endif case PREALLOC_MODE_FULL: { - int64_t num = 0, left = offset; + int64_t num = 0, left = offset - current_length; /* * Knowing the final size from the beginning could allow the file @@ -1658,19 +1678,27 @@ static int raw_regular_truncate(int fd, int64_t offset, PreallocMode prealloc, if (ftruncate(fd, offset) != 0) { result = -errno; error_setg_errno(errp, -result, "Could not resize file"); - return result; + goto out; } buf = g_malloc0(65536); + result = lseek(fd, current_length, SEEK_SET); + if (result < 0) { + result = -errno; + error_setg_errno(errp, -result, + "Failed to seek to the old end of file"); + goto out; + } + while (left > 0) { num = MIN(left, 65536); result = write(fd, buf, num); if (result < 0) { result = -errno; error_setg_errno(errp, -result, - "Could not write to the new file"); - break; + "Could not write zeros for preallocation"); + goto out; } left -= result; } @@ -1679,11 +1707,11 @@ static int raw_regular_truncate(int fd, int64_t offset, PreallocMode prealloc, if (result < 0) { result = -errno; error_setg_errno(errp, -result, - "Could not flush new file to disk"); + "Could not flush file to disk"); + goto out; } } - g_free(buf); - return result; + goto out; } case PREALLOC_MODE_OFF: if (ftruncate(fd, offset) != 0) { @@ -1697,6 +1725,17 @@ static int raw_regular_truncate(int fd, int64_t offset, PreallocMode prealloc, PreallocMode_lookup[prealloc]); return result; } + +out: + if (result < 0) { + if (ftruncate(fd, current_length) < 0) { + error_report("Failed to restore old file length: %s", + strerror(errno)); + } + } + + g_free(buf); + return result; } static int raw_truncate(BlockDriverState *bs, int64_t offset,