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 <[email protected]>
---
 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


Reply via email to