[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