From nobody Thu Dec 18 13:37:25 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1530282367005512.5286349223891; Fri, 29 Jun 2018 07:26:07 -0700 (PDT) Received: from localhost ([::1]:42547 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fYuLW-0008Rn-RC for importer@patchew.org; Fri, 29 Jun 2018 10:25:58 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49570) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fYu6S-0003v8-0A for qemu-devel@nongnu.org; Fri, 29 Jun 2018 10:10:29 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fYu6P-0003tO-Kb for qemu-devel@nongnu.org; Fri, 29 Jun 2018 10:10:23 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:44852 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fYu6J-0003i8-Pl; Fri, 29 Jun 2018 10:10:16 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 734F8C12C9; Fri, 29 Jun 2018 14:10:15 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-116-232.ams2.redhat.com [10.36.116.232]) by smtp.corp.redhat.com (Postfix) with ESMTP id A142E1102E29; Fri, 29 Jun 2018 14:10:14 +0000 (UTC) From: Kevin Wolf To: qemu-block@nongnu.org Date: Fri, 29 Jun 2018 16:09:41 +0200 Message-Id: <20180629140959.6690-12-kwolf@redhat.com> In-Reply-To: <20180629140959.6690-1-kwolf@redhat.com> References: <20180629140959.6690-1-kwolf@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Fri, 29 Jun 2018 14:10:15 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Fri, 29 Jun 2018 14:10:15 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'kwolf@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PULL 11/29] file-posix: Make .bdrv_co_truncate asynchronous 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: kwolf@redhat.com, peter.maydell@linaro.org, qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This moves the code to resize an image file to the thread pool to avoid blocking. Creating large images with preallocation with blockdev-create is now actually a background job instead of blocking the monitor (and most other things) until the preallocation has completed. Signed-off-by: Kevin Wolf Reviewed-by: Stefan Hajnoczi --- include/block/raw-aio.h | 4 +- block/file-posix.c | 266 +++++++++++++++++++++++++++-----------------= ---- 2 files changed, 154 insertions(+), 116 deletions(-) diff --git a/include/block/raw-aio.h b/include/block/raw-aio.h index 8d698ccd31..6799614e56 100644 --- a/include/block/raw-aio.h +++ b/include/block/raw-aio.h @@ -26,6 +26,7 @@ #define QEMU_AIO_DISCARD 0x0010 #define QEMU_AIO_WRITE_ZEROES 0x0020 #define QEMU_AIO_COPY_RANGE 0x0040 +#define QEMU_AIO_TRUNCATE 0x0080 #define QEMU_AIO_TYPE_MASK \ (QEMU_AIO_READ | \ QEMU_AIO_WRITE | \ @@ -33,7 +34,8 @@ QEMU_AIO_FLUSH | \ QEMU_AIO_DISCARD | \ QEMU_AIO_WRITE_ZEROES | \ - QEMU_AIO_COPY_RANGE) + QEMU_AIO_COPY_RANGE | \ + QEMU_AIO_TRUNCATE) =20 /* AIO flags */ #define QEMU_AIO_MISALIGNED 0x1000 diff --git a/block/file-posix.c b/block/file-posix.c index 53c5833659..639265d53b 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -188,8 +188,16 @@ typedef struct RawPosixAIOData { #define aio_ioctl_cmd aio_nbytes /* for QEMU_AIO_IOCTL */ off_t aio_offset; int aio_type; - int aio_fd2; - off_t aio_offset2; + union { + struct { + int aio_fd2; + off_t aio_offset2; + }; + struct { + PreallocMode prealloc; + Error **errp; + }; + }; } RawPosixAIOData; =20 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) @@ -1539,6 +1547,122 @@ static ssize_t handle_aiocb_discard(RawPosixAIOData= *aiocb) return ret; } =20 +static int handle_aiocb_truncate(RawPosixAIOData *aiocb) +{ + int result =3D 0; + int64_t current_length =3D 0; + char *buf =3D NULL; + struct stat st; + int fd =3D aiocb->aio_fildes; + int64_t offset =3D aiocb->aio_offset; + Error **errp =3D aiocb->errp; + + if (fstat(fd, &st) < 0) { + result =3D -errno; + error_setg_errno(errp, -result, "Could not stat file"); + return result; + } + + current_length =3D st.st_size; + if (current_length > offset && aiocb->prealloc !=3D PREALLOC_MODE_OFF)= { + error_setg(errp, "Cannot use preallocation for shrinking files"); + return -ENOTSUP; + } + + switch (aiocb->prealloc) { +#ifdef CONFIG_POSIX_FALLOCATE + case PREALLOC_MODE_FALLOC: + /* + * Truncating before posix_fallocate() makes it about twice slower= on + * file systems that do not support fallocate(), trying to check i= f a + * block is allocated before allocating it, so don't do that here. + */ + if (offset !=3D current_length) { + result =3D -posix_fallocate(fd, current_length, + offset - current_length); + if (result !=3D 0) { + /* posix_fallocate() doesn't set errno. */ + error_setg_errno(errp, -result, + "Could not preallocate new data"); + } + } else { + result =3D 0; + } + goto out; +#endif + case PREALLOC_MODE_FULL: + { + int64_t num =3D 0, left =3D offset - current_length; + off_t seek_result; + + /* + * Knowing the final size from the beginning could allow the file + * system driver to do less allocations and possibly avoid + * fragmentation of the file. + */ + if (ftruncate(fd, offset) !=3D 0) { + result =3D -errno; + error_setg_errno(errp, -result, "Could not resize file"); + goto out; + } + + buf =3D g_malloc0(65536); + + seek_result =3D lseek(fd, current_length, SEEK_SET); + if (seek_result < 0) { + result =3D -errno; + error_setg_errno(errp, -result, + "Failed to seek to the old end of file"); + goto out; + } + + while (left > 0) { + num =3D MIN(left, 65536); + result =3D write(fd, buf, num); + if (result < 0) { + result =3D -errno; + error_setg_errno(errp, -result, + "Could not write zeros for preallocation"= ); + goto out; + } + left -=3D result; + } + if (result >=3D 0) { + result =3D fsync(fd); + if (result < 0) { + result =3D -errno; + error_setg_errno(errp, -result, + "Could not flush file to disk"); + goto out; + } + } + goto out; + } + case PREALLOC_MODE_OFF: + if (ftruncate(fd, offset) !=3D 0) { + result =3D -errno; + error_setg_errno(errp, -result, "Could not resize file"); + } + return result; + default: + result =3D -ENOTSUP; + error_setg(errp, "Unsupported preallocation mode: %s", + PreallocMode_str(aiocb->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 aio_worker(void *arg) { RawPosixAIOData *aiocb =3D arg; @@ -1582,6 +1706,9 @@ static int aio_worker(void *arg) case QEMU_AIO_COPY_RANGE: ret =3D handle_aiocb_copy_range(aiocb); break; + case QEMU_AIO_TRUNCATE: + ret =3D handle_aiocb_truncate(aiocb); + break; default: fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type); ret =3D -EINVAL; @@ -1765,117 +1892,25 @@ static void raw_close(BlockDriverState *bs) * * Returns: 0 on success, -errno on failure. */ -static int raw_regular_truncate(int fd, int64_t offset, PreallocMode preal= loc, - Error **errp) +static int coroutine_fn +raw_regular_truncate(BlockDriverState *bs, int fd, int64_t offset, + PreallocMode prealloc, Error **errp) { - int result =3D 0; - int64_t current_length =3D 0; - char *buf =3D NULL; - struct stat st; - - if (fstat(fd, &st) < 0) { - result =3D -errno; - error_setg_errno(errp, -result, "Could not stat file"); - return result; - } - - current_length =3D st.st_size; - if (current_length > offset && prealloc !=3D PREALLOC_MODE_OFF) { - error_setg(errp, "Cannot use preallocation for shrinking files"); - return -ENOTSUP; - } - - switch (prealloc) { -#ifdef CONFIG_POSIX_FALLOCATE - case PREALLOC_MODE_FALLOC: - /* - * Truncating before posix_fallocate() makes it about twice slower= on - * file systems that do not support fallocate(), trying to check i= f a - * block is allocated before allocating it, so don't do that here. - */ - if (offset !=3D current_length) { - result =3D -posix_fallocate(fd, current_length, offset - curre= nt_length); - if (result !=3D 0) { - /* posix_fallocate() doesn't set errno. */ - error_setg_errno(errp, -result, - "Could not preallocate new data"); - } - } else { - result =3D 0; - } - goto out; -#endif - case PREALLOC_MODE_FULL: - { - int64_t num =3D 0, left =3D offset - current_length; - off_t seek_result; - - /* - * Knowing the final size from the beginning could allow the file - * system driver to do less allocations and possibly avoid - * fragmentation of the file. - */ - if (ftruncate(fd, offset) !=3D 0) { - result =3D -errno; - error_setg_errno(errp, -result, "Could not resize file"); - goto out; - } - - buf =3D g_malloc0(65536); - - seek_result =3D lseek(fd, current_length, SEEK_SET); - if (seek_result < 0) { - result =3D -errno; - error_setg_errno(errp, -result, - "Failed to seek to the old end of file"); - goto out; - } - - while (left > 0) { - num =3D MIN(left, 65536); - result =3D write(fd, buf, num); - if (result < 0) { - result =3D -errno; - error_setg_errno(errp, -result, - "Could not write zeros for preallocation"= ); - goto out; - } - left -=3D result; - } - if (result >=3D 0) { - result =3D fsync(fd); - if (result < 0) { - result =3D -errno; - error_setg_errno(errp, -result, - "Could not flush file to disk"); - goto out; - } - } - goto out; - } - case PREALLOC_MODE_OFF: - if (ftruncate(fd, offset) !=3D 0) { - result =3D -errno; - error_setg_errno(errp, -result, "Could not resize file"); - } - return result; - default: - result =3D -ENOTSUP; - error_setg(errp, "Unsupported preallocation mode: %s", - PreallocMode_str(prealloc)); - return result; - } + RawPosixAIOData *acb =3D g_new(RawPosixAIOData, 1); + ThreadPool *pool; =20 -out: - if (result < 0) { - if (ftruncate(fd, current_length) < 0) { - error_report("Failed to restore old file length: %s", - strerror(errno)); - } - } + *acb =3D (RawPosixAIOData) { + .bs =3D bs, + .aio_fildes =3D fd, + .aio_type =3D QEMU_AIO_TRUNCATE, + .aio_offset =3D offset, + .prealloc =3D prealloc, + .errp =3D errp, + }; =20 - g_free(buf); - return result; + /* @bs can be NULL, bdrv_get_aio_context() returns the main context th= en */ + pool =3D aio_get_thread_pool(bdrv_get_aio_context(bs)); + return thread_pool_submit_co(pool, aio_worker, acb); } =20 static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offs= et, @@ -1892,7 +1927,7 @@ static int coroutine_fn raw_co_truncate(BlockDriverSt= ate *bs, int64_t offset, } =20 if (S_ISREG(st.st_mode)) { - return raw_regular_truncate(s->fd, offset, prealloc, errp); + return raw_regular_truncate(bs, s->fd, offset, prealloc, errp); } =20 if (prealloc !=3D PREALLOC_MODE_OFF) { @@ -2094,7 +2129,8 @@ static int64_t raw_get_allocated_file_size(BlockDrive= rState *bs) return (int64_t)st.st_blocks * 512; } =20 -static int raw_co_create(BlockdevCreateOptions *options, Error **errp) +static int coroutine_fn +raw_co_create(BlockdevCreateOptions *options, Error **errp) { BlockdevCreateOptionsFile *file_opts; int fd; @@ -2146,7 +2182,7 @@ static int raw_co_create(BlockdevCreateOptions *optio= ns, Error **errp) } =20 /* Clear the file by truncating it to 0 */ - result =3D raw_regular_truncate(fd, 0, PREALLOC_MODE_OFF, errp); + result =3D raw_regular_truncate(NULL, fd, 0, PREALLOC_MODE_OFF, errp); if (result < 0) { goto out_close; } @@ -2168,8 +2204,8 @@ static int raw_co_create(BlockdevCreateOptions *optio= ns, Error **errp) =20 /* Resize and potentially preallocate the file to the desired * final size */ - result =3D raw_regular_truncate(fd, file_opts->size, file_opts->preall= ocation, - errp); + result =3D raw_regular_truncate(NULL, fd, file_opts->size, + file_opts->preallocation, errp); if (result < 0) { goto out_close; } --=20 2.13.6