[PATCH] erofs-utils: mkfs: add `--sort=none`

Gao Xiang hsiangkao at linux.alibaba.com
Mon Sep 23 17:49:29 AEST 2024


Currently, `--tar=f` writes file data twice due to unseekable streams
and EROFS data ordering requirements.  Some use cases may need to avoid
unnecessary data writes for performance and do NOT require a strict
data ordering.

It adds `--sort=none` to address this.  The image is still reproducible;
it simply means no specific file data ordering is implied.

Currently, It comes into effect if `-E^inline_data` is specified and no
compression is applied.

Signed-off-by: Gao Xiang <hsiangkao at linux.alibaba.com>
---
 include/erofs/inode.h |  1 +
 include/erofs/tar.h   |  1 +
 lib/inode.c           | 19 +++++++++----------
 lib/tar.c             | 36 ++++++++++++++++++++++++++++++++++++
 man/mkfs.erofs.1      | 13 ++++++++++++-
 mkfs/main.c           |  6 ++++++
 6 files changed, 65 insertions(+), 11 deletions(-)

diff --git a/include/erofs/inode.h b/include/erofs/inode.h
index 604161c..eb8f45b 100644
--- a/include/erofs/inode.h
+++ b/include/erofs/inode.h
@@ -34,6 +34,7 @@ erofs_nid_t erofs_lookupnid(struct erofs_inode *inode);
 int erofs_iflush(struct erofs_inode *inode);
 struct erofs_dentry *erofs_d_alloc(struct erofs_inode *parent,
 				   const char *name);
+int erofs_allocate_inode_bh_data(struct erofs_inode *inode, erofs_blk_t nblocks);
 bool erofs_dentry_is_wht(struct erofs_sb_info *sbi, struct erofs_dentry *d);
 int erofs_rebuild_dump_tree(struct erofs_inode *dir, bool incremental);
 int erofs_init_empty_dir(struct erofs_inode *dir);
diff --git a/include/erofs/tar.h b/include/erofs/tar.h
index 42fbb00..6981f9e 100644
--- a/include/erofs/tar.h
+++ b/include/erofs/tar.h
@@ -52,6 +52,7 @@ struct erofs_tarfile {
 	u64 offset;
 	bool index_mode, headeronly_mode, rvsp_mode, aufs;
 	bool ddtaridx_mode;
+	bool try_no_reorder;
 };
 
 void erofs_iostream_close(struct erofs_iostream *ios);
diff --git a/lib/inode.c b/lib/inode.c
index bc3cb76..f08f395 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -171,14 +171,12 @@ struct erofs_dentry *erofs_d_alloc(struct erofs_inode *parent,
 	return d;
 }
 
-/* allocate main data for a inode */
-static int __allocate_inode_bh_data(struct erofs_inode *inode,
-				    unsigned long nblocks,
-				    int type)
+/* allocate main data for an inode */
+int erofs_allocate_inode_bh_data(struct erofs_inode *inode, erofs_blk_t nblocks)
 {
 	struct erofs_bufmgr *bmgr = inode->sbi->bmgr;
 	struct erofs_buffer_head *bh;
-	int ret;
+	int ret, type;
 
 	if (!nblocks) {
 		/* it has only tail-end data */
@@ -187,6 +185,7 @@ static int __allocate_inode_bh_data(struct erofs_inode *inode,
 	}
 
 	/* allocate main data buffer */
+	type = S_ISDIR(inode->i_mode) ? DIRA : DATA;
 	bh = erofs_balloc(bmgr, type, erofs_pos(inode->sbi, nblocks), 0, 0);
 	if (IS_ERR(bh))
 		return PTR_ERR(bh);
@@ -431,7 +430,7 @@ static int erofs_write_dir_file(struct erofs_inode *dir)
 	q = used = blkno = 0;
 
 	/* allocate dir main data */
-	ret = __allocate_inode_bh_data(dir, erofs_blknr(sbi, dir->i_size), DIRA);
+	ret = erofs_allocate_inode_bh_data(dir, erofs_blknr(sbi, dir->i_size));
 	if (ret)
 		return ret;
 
@@ -487,7 +486,7 @@ int erofs_write_file_from_buffer(struct erofs_inode *inode, char *buf)
 
 	inode->datalayout = EROFS_INODE_FLAT_INLINE;
 
-	ret = __allocate_inode_bh_data(inode, nblocks, DATA);
+	ret = erofs_allocate_inode_bh_data(inode, nblocks);
 	if (ret)
 		return ret;
 
@@ -514,15 +513,15 @@ static bool erofs_file_is_compressible(struct erofs_inode *inode)
 
 static int write_uncompressed_file_from_fd(struct erofs_inode *inode, int fd)
 {
-	int ret;
+	struct erofs_sb_info *sbi = inode->sbi;
 	erofs_blk_t nblocks, i;
 	unsigned int len;
-	struct erofs_sb_info *sbi = inode->sbi;
+	int ret;
 
 	inode->datalayout = EROFS_INODE_FLAT_INLINE;
 	nblocks = inode->i_size >> sbi->blkszbits;
 
-	ret = __allocate_inode_bh_data(inode, nblocks, DATA);
+	ret = erofs_allocate_inode_bh_data(inode, nblocks);
 	if (ret)
 		return ret;
 
diff --git a/lib/tar.c b/lib/tar.c
index 6d35292..3c56d43 100644
--- a/lib/tar.c
+++ b/lib/tar.c
@@ -586,6 +586,38 @@ void tarerofs_remove_inode(struct erofs_inode *inode)
 	--inode->i_parent->i_nlink;
 }
 
+static int tarerofs_write_uncompressed_file(struct erofs_inode *inode,
+					    struct erofs_tarfile *tar)
+{
+	struct erofs_sb_info *sbi = inode->sbi;
+	erofs_blk_t nblocks;
+	erofs_off_t pos;
+	void *buf;
+	int ret;
+
+	inode->datalayout = EROFS_INODE_FLAT_PLAIN;
+	nblocks = DIV_ROUND_UP(inode->i_size, 1U << sbi->blkszbits);
+
+	ret = erofs_allocate_inode_bh_data(inode, nblocks);
+	if (ret)
+		return ret;
+
+	for (pos = 0; pos < inode->i_size; pos += ret) {
+		ret = erofs_iostream_read(&tar->ios, &buf, inode->i_size - pos);
+		if (ret < 0)
+			break;
+		if (erofs_dev_write(sbi, buf,
+				    erofs_pos(sbi, inode->u.i_blkaddr) + pos,
+				    ret)) {
+			ret = -EIO;
+			break;
+		}
+	}
+	inode->idata_size = 0;
+	inode->datasource = EROFS_INODE_DATA_SOURCE_NONE;
+	return 0;
+}
+
 static int tarerofs_write_file_data(struct erofs_inode *inode,
 				    struct erofs_tarfile *tar)
 {
@@ -1012,6 +1044,10 @@ new_inode:
 				if (!ret && erofs_iostream_lskip(&tar->ios,
 								 inode->i_size))
 					ret = -EIO;
+			} else if (tar->try_no_reorder &&
+				   !cfg.c_compr_opts[0].alg &&
+				   !cfg.c_inline_data) {
+				ret = tarerofs_write_uncompressed_file(inode, tar);
 			} else {
 				ret = tarerofs_write_file_data(inode, tar);
 			}
diff --git a/man/mkfs.erofs.1 b/man/mkfs.erofs.1
index d599fac..abdd9b9 100644
--- a/man/mkfs.erofs.1
+++ b/man/mkfs.erofs.1
@@ -192,7 +192,18 @@ Use extended inodes instead of compact inodes if the file modification time
 would overflow compact inodes. This is the default. Overrides
 .BR --ignore-mtime .
 .TP
-.BI "\-\-tar, \-\-tar="MODE
+.BI "\-\-sort=" MODE
+Inode data sorting order for tarballs as input.
+
+\fIMODE\fR may be one of \fBnone\fR or \fBpath\fR.
+
+\fBnone\fR: No particular data order is specified for the target image to
+avoid unnecessary overhead; Currently, it takes effect if `-E^inline_data` is
+specified and no compression is applied.
+
+\fBpath\fR: Data order strictly follows the tree generation order. (default)
+.TP
+.BI "\-\-tar, \-\-tar=" MODE
 Treat \fISOURCE\fR as a tarball or tarball-like "headerball" rather than as a
 directory.
 
diff --git a/mkfs/main.c b/mkfs/main.c
index 8f1fdbc..d422787 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -84,6 +84,7 @@ static struct option long_options[] = {
 	{"root-xattr-isize", required_argument, NULL, 524},
 	{"mkfs-time", no_argument, NULL, 525},
 	{"all-time", no_argument, NULL, 526},
+	{"sort", required_argument, NULL, 527},
 	{0, 0, 0, 0},
 };
 
@@ -180,6 +181,7 @@ static void usage(int argc, char **argv)
 		" --offset=#            skip # bytes at the beginning of IMAGE.\n"
 		" --root-xattr-isize=#  ensure the inline xattr size of the root directory is # bytes at least\n"
 		" --aufs                replace aufs special files with overlayfs metadata\n"
+		" --sort=<path,none>    data sorting order for tarballs as input (default: path)\n"
 		" --tar=X               generate a full or index-only image from a tarball(-ish) source\n"
 		"                       (X = f|i|headerball; f=full mode, i=index mode,\n"
 		"                                            headerball=file data is omited in the source stream)\n"
@@ -840,6 +842,10 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
 		case 526:
 			cfg.c_timeinherit = TIMESTAMP_FIXED;
 			break;
+		case 527:
+			if (!strcmp(optarg, "none"))
+				erofstar.try_no_reorder = true;
+			break;
 		case 'V':
 			version();
 			exit(0);
-- 
2.43.5



More information about the Linux-erofs mailing list