From: Nir Soffer <nirsof@gmail.com>
To: qemu-devel@nongnu.org
Cc: Kevin Wolf <kwolf@redhat.com>,
qemu-block@nongnu.org, Markus Armbruster <armbru@redhat.com>,
Max Reitz <mreitz@redhat.com>, Nir Soffer <nsoffer@redhat.com>
Subject: [PATCH 1/2] block: file-posix: Extract preallocate helpers
Date: Mon, 31 Aug 2020 17:01:26 +0300 [thread overview]
Message-ID: <20200831140127.657134-2-nsoffer@redhat.com> (raw)
In-Reply-To: <20200831140127.657134-1-nsoffer@redhat.com>
handle_aiocb_truncate() was too big and complex, implementing 3
different preallocation modes. In a future patch I want to introduce a
fallback from "falloc" to "full"; it will be too messy and error prone
with the current code.
Extract a helper for each of the preallocation modes (falloc, full, off)
and leave only the common preparation and cleanup code in
handle_aiocb_truncate().
Signed-off-by: Nir Soffer <nsoffer@redhat.com>
---
block/file-posix.c | 206 ++++++++++++++++++++++++++-------------------
1 file changed, 120 insertions(+), 86 deletions(-)
diff --git a/block/file-posix.c b/block/file-posix.c
index 9a00d4190a..341ffb1cb4 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -1832,12 +1832,128 @@ static int allocate_first_block(int fd, size_t max_size)
return ret;
}
+static int preallocate_falloc(int fd, int64_t current_length, int64_t offset,
+ Error **errp)
+{
+#ifdef CONFIG_POSIX_FALLOCATE
+ int result;
+
+ if (offset == current_length)
+ return 0;
+
+ /*
+ * Truncating before posix_fallocate() makes it about twice slower on
+ * 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, current_length,
+ offset - current_length);
+ if (result != 0) {
+ /* posix_fallocate() doesn't set errno. */
+ error_setg_errno(errp, -result,
+ "Could not preallocate new data");
+ return result;
+ }
+
+ if (current_length == 0) {
+ /*
+ * posix_fallocate() uses fallocate() if the filesystem supports
+ * it, or fallback to manually writing zeroes. If fallocate()
+ * was used, unaligned reads from the fallocated area in
+ * raw_probe_alignment() will succeed, hence we need to allocate
+ * the first block.
+ *
+ * Optimize future alignment probing; ignore failures.
+ */
+ allocate_first_block(fd, offset);
+ }
+
+ return 0;
+#else
+ return -ENOTSUP;
+#endif
+}
+
+static int preallocate_full(int fd, int64_t current_length, int64_t offset,
+ Error **errp)
+{
+ int64_t num = 0, left = offset - current_length;
+ off_t seek_result;
+ int result;
+ char *buf = NULL;
+
+ /*
+ * 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) != 0) {
+ result = -errno;
+ error_setg_errno(errp, -result, "Could not resize file");
+ goto out;
+ }
+
+ buf = g_malloc0(65536);
+
+ seek_result = lseek(fd, current_length, SEEK_SET);
+ if (seek_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) {
+ if (errno == EINTR) {
+ continue;
+ }
+ result = -errno;
+ error_setg_errno(errp, -result,
+ "Could not write zeros for preallocation");
+ goto out;
+ }
+ left -= result;
+ }
+
+ result = fsync(fd);
+ if (result < 0) {
+ result = -errno;
+ error_setg_errno(errp, -result, "Could not flush file to disk");
+ goto out;
+ }
+
+out:
+ g_free(buf);
+
+ return result;
+}
+
+static int preallocate_off(int fd, int64_t current_length, int64_t offset,
+ Error **errp)
+{
+ if (ftruncate(fd, offset) != 0) {
+ int result = -errno;
+ error_setg_errno(errp, -result, "Could not resize file");
+ return result;
+ }
+
+ if (current_length == 0 && offset > current_length) {
+ /* Optimize future alignment probing; ignore failures. */
+ allocate_first_block(fd, offset);
+ }
+
+ return 0;
+}
+
static int handle_aiocb_truncate(void *opaque)
{
RawPosixAIOData *aiocb = opaque;
int result = 0;
int64_t current_length = 0;
- char *buf = NULL;
struct stat st;
int fd = aiocb->aio_fildes;
int64_t offset = aiocb->aio_offset;
@@ -1859,95 +1975,14 @@ static int handle_aiocb_truncate(void *opaque)
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 if a
- * block is allocated before allocating it, so don't do that here.
- */
- if (offset != current_length) {
- 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 new data");
- } else if (current_length == 0) {
- /*
- * posix_fallocate() uses fallocate() if the filesystem
- * supports it, or fallback to manually writing zeroes. If
- * fallocate() was used, unaligned reads from the fallocated
- * area in raw_probe_alignment() will succeed, hence we need to
- * allocate the first block.
- *
- * Optimize future alignment probing; ignore failures.
- */
- allocate_first_block(fd, offset);
- }
- } else {
- result = 0;
- }
+ result = preallocate_falloc(fd, current_length, offset, errp);
goto out;
#endif
case PREALLOC_MODE_FULL:
- {
- int64_t num = 0, left = 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) != 0) {
- result = -errno;
- error_setg_errno(errp, -result, "Could not resize file");
- goto out;
- }
-
- buf = g_malloc0(65536);
-
- seek_result = lseek(fd, current_length, SEEK_SET);
- if (seek_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) {
- if (errno == EINTR) {
- continue;
- }
- result = -errno;
- error_setg_errno(errp, -result,
- "Could not write zeros for preallocation");
- goto out;
- }
- left -= result;
- }
- if (result >= 0) {
- result = fsync(fd);
- if (result < 0) {
- result = -errno;
- error_setg_errno(errp, -result,
- "Could not flush file to disk");
- goto out;
- }
- }
+ result = preallocate_full(fd, current_length, offset, errp);
goto out;
- }
case PREALLOC_MODE_OFF:
- if (ftruncate(fd, offset) != 0) {
- result = -errno;
- error_setg_errno(errp, -result, "Could not resize file");
- } else if (current_length == 0 && offset > current_length) {
- /* Optimize future alignment probing; ignore failures. */
- allocate_first_block(fd, offset);
- }
- return result;
+ return preallocate_off(fd, current_length, offset, errp);
default:
result = -ENOTSUP;
error_setg(errp, "Unsupported preallocation mode: %s",
@@ -1963,7 +1998,6 @@ out:
}
}
- g_free(buf);
return result;
}
--
2.26.2
next prev parent reply other threads:[~2020-08-31 14:02 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-08-31 14:01 [PATCH 0/2] Replace posix_fallocate() with falloate() Nir Soffer
2020-08-31 14:01 ` Nir Soffer [this message]
2020-09-01 10:24 ` [PATCH 1/2] block: file-posix: Extract preallocate helpers Alberto Garcia
2020-09-01 10:26 ` Alberto Garcia
2020-09-01 10:47 ` Nir Soffer
2020-08-31 14:01 ` [PATCH 2/2] block: file-posix: Replace posix_fallocate with fallocate Nir Soffer
2020-09-01 15:51 ` Alberto Garcia
2020-09-14 17:32 ` Daniel P. Berrangé
2020-09-15 8:55 ` Nir Soffer
2020-08-31 15:55 ` [PATCH 0/2] Replace posix_fallocate() with falloate() no-reply
2020-09-14 17:19 ` Nir Soffer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200831140127.657134-2-nsoffer@redhat.com \
--to=nirsof@gmail.com \
--cc=armbru@redhat.com \
--cc=kwolf@redhat.com \
--cc=mreitz@redhat.com \
--cc=nsoffer@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.