[PATCH] erofs-utils: avoid flushing the image file on closing

Gao Xiang hsiangkao at linux.alibaba.com
Thu Sep 14 15:32:11 AEST 2023


Traditionally, truncating to small sizes will trigger some
flush-on-close semantics to avoid the notorious NULL files.

I'm not sure if it's our use case since:
  1) we're creating new image files instead of reusing old ones;
  2) it kills end-to-end performance in practice;
  3) other programs like GNU TAR doesn't work as this too for
     such meaningless comparsion;

Let's work around it now.

Signed-off-by: Gao Xiang <hsiangkao at linux.alibaba.com>
---
 configure.ac |  2 ++
 lib/io.c     | 40 ++++++++++++++++++++++++++++++++++------
 2 files changed, 36 insertions(+), 6 deletions(-)

diff --git a/configure.ac b/configure.ac
index a8cecd0..51ace67 100644
--- a/configure.ac
+++ b/configure.ac
@@ -190,6 +190,7 @@ AC_CHECK_HEADERS(m4_flatten([
 	sys/mman.h
 	sys/random.h
 	sys/stat.h
+	sys/statfs.h
 	sys/sysmacros.h
 	sys/time.h
 	unistd.h
@@ -249,6 +250,7 @@ AC_CHECK_FUNCS(m4_flatten([
 	ftello64
 	pread64
 	pwrite64
+	fstatfs
 	strdup
 	strerror
 	strrchr
diff --git a/lib/io.c b/lib/io.c
index 1545436..eb9d876 100644
--- a/lib/io.c
+++ b/lib/io.c
@@ -20,7 +20,9 @@
 #ifdef HAVE_LINUX_FALLOC_H
 #include <linux/falloc.h>
 #endif
-
+#ifdef HAVE_SYS_STATFS_H
+#include <sys/statfs.h>
+#endif
 #define EROFS_MODNAME	"erofs_io"
 #include "erofs/print.h"
 
@@ -55,9 +57,11 @@ void dev_close(struct erofs_sb_info *sbi)
 
 int dev_open(struct erofs_sb_info *sbi, const char *dev)
 {
+	bool again = false;
 	struct stat st;
 	int fd, ret;
 
+repeat:
 	fd = open(dev, O_RDWR | O_CREAT | O_BINARY, 0644);
 	if (fd < 0) {
 		erofs_err("failed to open(%s).", dev);
@@ -82,11 +86,35 @@ int dev_open(struct erofs_sb_info *sbi, const char *dev)
 		sbi->devsz = round_down(sbi->devsz, erofs_blksiz(sbi));
 		break;
 	case S_IFREG:
-		ret = ftruncate(fd, 0);
-		if (ret) {
-			erofs_err("failed to ftruncate(%s).", dev);
-			close(fd);
-			return -errno;
+		if (st.st_size) {
+#ifdef HAVE_SYS_STATFS_H
+			struct statfs stfs;
+
+			if (again)
+				return -ENOTEMPTY;
+
+#ifdef HAVE_FSTATFS
+			/*
+			 * fses like EXT4 and BTRFS will flush dirty blocks
+			 * after truncate(0) even after the writeback happens
+			 * (see kernel commit 7d8f9f7d150d and ccd2506bd431),
+			 * which is NOT our intention.  Let's work around this.
+			 */
+			if (!fstatfs(fd, &stfs) && (stfs.f_type == 0xEF53 ||
+					stfs.f_type == 0x9123683E)) {
+				close(fd);
+				unlink(dev);
+				again = true;
+				goto repeat;
+			}
+#endif
+#endif
+			ret = ftruncate(fd, 0);
+			if (ret) {
+				erofs_err("failed to ftruncate(%s).", dev);
+				close(fd);
+				return -errno;
+			}
 		}
 		/* INT64_MAX is the limit of kernel vfs */
 		sbi->devsz = INT64_MAX;
-- 
2.39.3



More information about the Linux-erofs mailing list