[PATCH] erofs-utils: mkfs: add support to issue directory data separately
Gao Xiang
hsiangkao at linux.alibaba.com
Fri Nov 21 18:57:44 AEDT 2025
Especially since compressed directory data could be in the packing
inode, it would be better to compress them together.
It improves the overall compressed directory access performance.
Signed-off-by: Gao Xiang <hsiangkao at linux.alibaba.com>
---
include/erofs/importer.h | 2 ++
lib/inode.c | 68 ++++++++++++++++++++++++++++++++++++----
mkfs/main.c | 6 ++--
3 files changed, 68 insertions(+), 8 deletions(-)
diff --git a/include/erofs/importer.h b/include/erofs/importer.h
index e1734b995ae8..a9d9c569d157 100644
--- a/include/erofs/importer.h
+++ b/include/erofs/importer.h
@@ -44,6 +44,8 @@ struct erofs_importer_params {
char force_inodeversion;
bool ignore_mtime;
bool no_datainline;
+ /* Issue directory data (except inline data) separately from regular inodes */
+ bool grouped_dirdata;
bool hard_dereference;
bool ovlfs_strip;
bool dot_omitted;
diff --git a/lib/inode.c b/lib/inode.c
index d993c8fd7428..1d08e39317c0 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -1494,6 +1494,7 @@ enum erofs_mkfs_jobtype { /* ordered job types */
struct erofs_mkfs_jobitem {
enum erofs_mkfs_jobtype type;
+ unsigned int _usize;
union {
struct erofs_inode *inode;
struct erofs_mkfs_job_ndir_ctx ndir;
@@ -1529,6 +1530,11 @@ static int erofs_mkfs_jobfn(struct erofs_importer *im,
if (inode->datalayout == EROFS_INODE_FLAT_INLINE)
inode->idata_size = inode->i_size & (bsz - 1);
+ /*
+ * Directory on-disk inodes should be close to other inodes
+ * in the parent directory since parent directories should
+ * generally be prioritized.
+ */
ret = erofs_prepare_inode_buffer(im, inode);
if (ret)
return ret;
@@ -1657,6 +1663,48 @@ static void erofs_mkfs_flushjobs(struct erofs_sb_info *sbi)
}
#endif
+struct erofs_mkfs_pending_jobitem {
+ struct list_head list;
+ struct erofs_mkfs_jobitem item;
+};
+
+int erofs_mkfs_push_pending_job(struct list_head *pending,
+ enum erofs_mkfs_jobtype type,
+ void *elem, int size)
+{
+ struct erofs_mkfs_pending_jobitem *pji;
+
+ pji = malloc(sizeof(*pji));
+ if (!pji)
+ return -ENOMEM;
+
+ pji->item.type = type;
+ if (size)
+ memcpy(&pji->item.u, elem, size);
+ pji->item._usize = size;
+ list_add_tail(&pji->list, pending);
+ return 0;
+}
+
+int erofs_mkfs_flush_pending_jobs(struct erofs_importer *im,
+ struct list_head *q)
+{
+ struct erofs_mkfs_pending_jobitem *pji, *n;
+ int err2, err;
+
+ err = 0;
+ list_for_each_entry_safe(pji, n, q, list) {
+ list_del(&pji->list);
+
+ err2 = erofs_mkfs_go(im, pji->item.type, &pji->item.u,
+ pji->item._usize);
+ free(pji);
+ if (!err)
+ err = err2;
+ }
+ return err;
+}
+
static int erofs_mkfs_import_localdir(struct erofs_importer *im, struct erofs_inode *dir,
u64 *nr_subdirs, unsigned int *i_nlink)
{
@@ -1943,6 +1991,8 @@ static int erofs_mkfs_dump_tree(struct erofs_importer *im, bool rebuild,
struct erofs_inode *root = im->root;
struct erofs_sb_info *sbi = root->sbi;
struct erofs_inode *dumpdir = erofs_igrab(root);
+ bool grouped_dirdata = im->params->grouped_dirdata;
+ LIST_HEAD(pending_dirs);
int err, err2;
erofs_mark_parent_inode(root, root); /* rootdir mark */
@@ -2009,13 +2059,19 @@ static int erofs_mkfs_dump_tree(struct erofs_importer *im, bool rebuild,
}
*last = dumpdir; /* fixup the last (or the only) one */
dumpdir = head;
- err2 = erofs_mkfs_go(im, EROFS_MKFS_JOB_DIR_BH,
- &dir, sizeof(dir));
- if (err || err2)
- return err ? err : err2;
+ err2 = grouped_dirdata ?
+ erofs_mkfs_push_pending_job(&pending_dirs,
+ EROFS_MKFS_JOB_DIR_BH, &dir, sizeof(dir)) :
+ erofs_mkfs_go(im, EROFS_MKFS_JOB_DIR_BH,
+ &dir, sizeof(dir));
+ if (err || err2) {
+ if (!err)
+ err = err2;
+ break;
+ }
} while (dumpdir);
-
- return err;
+ err2 = erofs_mkfs_flush_pending_jobs(im, &pending_dirs);
+ return err ? err : err2;
}
struct erofs_mkfs_buildtree_ctx {
diff --git a/mkfs/main.c b/mkfs/main.c
index 76bf84348364..9719aec7952e 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -1410,10 +1410,12 @@ static int mkfs_parse_options_cfg(struct erofs_importer_params *params,
tarerofs_decoder = EROFS_IOS_DECODER_GZRAN;
break;
case 536:
- if (!optarg || strcmp(optarg, "1"))
+ if (!optarg || strcmp(optarg, "1")) {
params->compress_dir = true;
- else
+ params->grouped_dirdata = true;
+ } else {
params->compress_dir = false;
+ }
break;
case 537:
if (!optarg || strcmp(optarg, "1"))
--
2.43.5
More information about the Linux-erofs
mailing list