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 <hsiang...@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