This patch introduces the per-superblock configuration
`bt_args` to get rid of the global `g_cfg`.

Signed-off-by: Hongzhen Luo <hongz...@linux.alibaba.com>
---
 dump/main.c              |   4 +-
 fsck/main.c              |   4 +-
 fuse/main.c              |   4 +-
 include/erofs/compress.h |   2 +-
 include/erofs/config.h   |  22 ++-
 include/erofs/internal.h |   2 +
 lib/blobchunk.c          |   3 +-
 lib/block_list.c         |  25 +--
 lib/compress.c           |  95 +++++++-----
 lib/compress_hints.c     |  18 ++-
 lib/compressor_liblzma.c |   4 +-
 lib/compressor_libzstd.c |   4 +-
 lib/config.c             |  82 ++++++----
 lib/inode.c              |  82 ++++++----
 lib/io.c                 |  31 +++-
 lib/xattr.c              |  64 ++++----
 mkfs/main.c              | 328 +++++++++++++++++++++------------------
 17 files changed, 456 insertions(+), 318 deletions(-)

diff --git a/dump/main.c b/dump/main.c
index e85b853..29ddc3b 100644
--- a/dump/main.c
+++ b/dump/main.c
@@ -676,7 +676,7 @@ int main(int argc, char **argv)
 {
        int err;
 
-       erofs_init_configure();
+       erofs_init_configure(&g_cfg);
        err = erofsdump_parse_options_cfg(argc, argv);
        if (err) {
                if (err == -EINVAL)
@@ -720,6 +720,6 @@ exit_dev_close:
        erofs_dev_close(&g_sbi);
 exit:
        erofs_blob_closeall(&g_sbi);
-       erofs_exit_configure();
+       erofs_exit_configure(&g_cfg);
        return err;
 }
diff --git a/fsck/main.c b/fsck/main.c
index 6096683..718051e 100644
--- a/fsck/main.c
+++ b/fsck/main.c
@@ -1049,7 +1049,7 @@ int main(int argc, char *argv[])
 {
        int err;
 
-       erofs_init_configure();
+       erofs_init_configure(&g_cfg);
 
        fsckcfg.physical_blocks = 0;
        fsckcfg.logical_blocks = 0;
@@ -1136,7 +1136,7 @@ exit_dev_close:
        erofs_dev_close(&g_sbi);
 exit:
        erofs_blob_closeall(&g_sbi);
-       erofs_exit_configure();
+       erofs_exit_configure(&g_cfg);
        return err ? 1 : 0;
 }
 
diff --git a/fuse/main.c b/fuse/main.c
index bb92a7b..4d0cdae 100644
--- a/fuse/main.c
+++ b/fuse/main.c
@@ -642,7 +642,7 @@ int main(int argc, char *argv[])
        } opts = {};
 #endif
 
-       erofs_init_configure();
+       erofs_init_configure(&g_cfg);
        fusecfg.debug_lvl = g_cfg.c_dbg_lvl;
        printf("erofsfuse %s\n", g_cfg.c_version);
 
@@ -752,6 +752,6 @@ err_fuse_free_args:
        free(opts.mountpoint);
        fuse_opt_free_args(&args);
 err:
-       erofs_exit_configure();
+       erofs_exit_configure(&g_cfg);
        return ret ? EXIT_FAILURE : EXIT_SUCCESS;
 }
diff --git a/include/erofs/compress.h b/include/erofs/compress.h
index c9831a7..4731a8b 100644
--- a/include/erofs/compress.h
+++ b/include/erofs/compress.h
@@ -25,7 +25,7 @@ int erofs_write_compressed_file(struct z_erofs_compress_ictx 
*ictx);
 
 int z_erofs_compress_init(struct erofs_sb_info *sbi,
                          struct erofs_buffer_head *bh);
-int z_erofs_compress_exit(void);
+int z_erofs_compress_exit(struct erofs_sb_info *sbi);
 
 const char *z_erofs_list_supported_algorithms(int i, unsigned int *mask);
 const struct erofs_algorithm *z_erofs_list_available_compressors(int *i);
diff --git a/include/erofs/config.h b/include/erofs/config.h
index 41d6c54..46f1111 100644
--- a/include/erofs/config.h
+++ b/include/erofs/config.h
@@ -98,9 +98,18 @@ struct erofs_configure {
 
 extern struct erofs_configure g_cfg;
 
-void erofs_init_configure(void);
-void erofs_show_config(void);
-void erofs_exit_configure(void);
+struct erofs_mkfs_buildtree_args {
+       struct erofs_configure *cfg;
+};
+
+struct erofs_sb_info;
+
+void erofs_init_configure(struct erofs_configure *cfg);
+void erofs_show_config(struct erofs_configure *cfg);
+void erofs_exit_configure(struct erofs_configure *cfg);
+void erofs_init_buildtree_cfg(struct erofs_sb_info *sbi,
+                             struct erofs_configure *cfg);
+void erofs_exit_buildtree_cfg(struct erofs_sb_info *sbi);
 
 /* (will be deprecated) temporary helper for updating global the cfg */
 struct erofs_configure *erofs_get_configure();
@@ -109,15 +118,16 @@ void erofs_set_fs_root(const char *rootdir);
 const char *erofs_fspath(const char *fullpath);
 
 #ifdef HAVE_LIBSELINUX
-int erofs_selabel_open(const char *file_contexts);
+int erofs_selabel_open(struct erofs_sb_info *sbi, const char *file_contexts);
 #else
-static inline int erofs_selabel_open(const char *file_contexts)
+static inline int erofs_selabel_open(struct erofs_sb_info *sbi,
+                                    const char *file_contexts)
 {
        return -EINVAL;
 }
 #endif
 
-void erofs_update_progressinfo(const char *fmt, ...);
+void erofs_update_progressinfo(struct erofs_sb_info *sbi, const char *fmt, 
...);
 char *erofs_trim_for_progressinfo(const char *str, int placeholder);
 unsigned int erofs_get_available_processors(void);
 
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 2edc1b4..71e1cb1 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -27,6 +27,7 @@ typedef unsigned short umode_t;
 #endif
 #include "atomic.h"
 #include "io.h"
+#include "config.h"
 
 #ifndef PATH_MAX
 #define PATH_MAX        4096    /* # chars in a path name including nul */
@@ -140,6 +141,7 @@ struct erofs_sb_info {
 #endif
        struct erofs_bufmgr *bmgr;
        bool useqpl;
+       struct erofs_mkfs_buildtree_args *bt_args;
 };
 
 #define EROFS_SUPER_END (EROFS_SUPER_OFFSET + sizeof(struct erofs_super_block))
diff --git a/lib/blobchunk.c b/lib/blobchunk.c
index 90e3b28..e6b278c 100644
--- a/lib/blobchunk.c
+++ b/lib/blobchunk.c
@@ -261,7 +261,8 @@ int erofs_blob_write_chunked_file(struct erofs_inode 
*inode, int fd,
                                  erofs_off_t startoff)
 {
        struct erofs_sb_info *sbi = inode->sbi;
-       unsigned int chunkbits = g_cfg.c_chunkbits;
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
+       unsigned int chunkbits = cfg->c_chunkbits;
        unsigned int count, unit;
        struct erofs_blobchunk *chunk, *lastch;
        struct erofs_inode_chunk_index *idx;
diff --git a/lib/block_list.c b/lib/block_list.c
index d745ea2..74365f3 100644
--- a/lib/block_list.c
+++ b/lib/block_list.c
@@ -42,14 +42,15 @@ void tarerofs_blocklist_write(erofs_blk_t blkaddr, 
erofs_blk_t nblocks,
 }
 
 #ifdef WITH_ANDROID
-static void blocklist_write(const char *path, erofs_blk_t blk_start,
+static void blocklist_write(struct erofs_sb_info *sbi, const char *path, 
erofs_blk_t blk_start,
                            erofs_blk_t nblocks, bool first_extent,
                            bool last_extent)
 {
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
        const char *fspath = erofs_fspath(path);
 
        if (first_extent) {
-               fprintf(block_list_fp, "/%s", g_cfg.mount_point);
+               fprintf(block_list_fp, "/%s", cfg->mount_point);
 
                if (fspath[0] != '/')
                        fprintf(block_list_fp, "/");
@@ -72,7 +73,9 @@ void erofs_droid_blocklist_write_extent(struct erofs_inode 
*inode,
                                        erofs_blk_t nblocks, bool first_extent,
                                        bool last_extent)
 {
-       if (!block_list_fp || !g_cfg.mount_point)
+       struct erofs_configure *cfg = inode->sbi->bt_args->cfg;
+
+       if (!block_list_fp || !cfg->mount_point)
                return;
 
        if (!nblocks) {
@@ -81,24 +84,28 @@ void erofs_droid_blocklist_write_extent(struct erofs_inode 
*inode,
                return;
        }
 
-       blocklist_write(inode->i_srcpath, blk_start, nblocks, first_extent,
-                       last_extent);
+       blocklist_write(inode->sbi, inode->i_srcpath, blk_start, nblocks,
+                       first_extent, last_extent);
 }
 
 void erofs_droid_blocklist_write(struct erofs_inode *inode,
                                 erofs_blk_t blk_start, erofs_blk_t nblocks)
 {
-       if (!block_list_fp || !g_cfg.mount_point || !nblocks)
+       struct erofs_configure *cfg = inode->sbi->bt_args->cfg;
+
+       if (!block_list_fp || !cfg->mount_point || !nblocks)
                return;
 
-       blocklist_write(inode->i_srcpath, blk_start, nblocks,
+       blocklist_write(inode->sbi, inode->i_srcpath, blk_start, nblocks,
                        true, !inode->idata_size);
 }
 
 void erofs_droid_blocklist_write_tail_end(struct erofs_inode *inode,
                                          erofs_blk_t blkaddr)
 {
-       if (!block_list_fp || !g_cfg.mount_point)
+       struct erofs_configure *cfg = inode->sbi->bt_args->cfg;
+
+       if (!block_list_fp || !cfg->mount_point)
                return;
 
        /* XXX: a bit hacky.. may need a better approach */
@@ -114,6 +121,6 @@ void erofs_droid_blocklist_write_tail_end(struct 
erofs_inode *inode,
                return;
        }
        if (blkaddr != NULL_ADDR)
-               blocklist_write(inode->i_srcpath, blkaddr, 1, true, true);
+               blocklist_write(inode->sbi, inode->i_srcpath, blkaddr, 1, true, 
true);
 }
 #endif
diff --git a/lib/compress.c b/lib/compress.c
index ea47927..d3fe50b 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -142,6 +142,7 @@ static void z_erofs_write_extent(struct 
z_erofs_compress_ictx *ctx,
        unsigned int d0 = 0, d1 = (clusterofs + count) / erofs_blksiz(sbi);
        struct z_erofs_lcluster_index di;
        unsigned int type, advise;
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
 
        DBG_BUGON(!count);
        di.di_clusterofs = cpu_to_le16(ctx->clusterofs);
@@ -152,7 +153,7 @@ static void z_erofs_write_extent(struct 
z_erofs_compress_ictx *ctx,
                 * A lcluster cannot have three parts with the middle one which
                 * is well-compressed for !ztailpacking cases.
                 */
-               DBG_BUGON(!e->raw && !g_cfg.c_ztailpacking && 
!g_cfg.c_fragments);
+               DBG_BUGON(!e->raw && !cfg->c_ztailpacking && !cfg->c_fragments);
                DBG_BUGON(e->partial);
                type = e->raw ? Z_EROFS_LCLUSTER_TYPE_PLAIN :
                        Z_EROFS_LCLUSTER_TYPE_HEAD1;
@@ -415,21 +416,23 @@ static int write_uncompressed_extent(struct 
z_erofs_compress_sctx *ctx,
 
 static unsigned int z_erofs_get_max_pclustersize(struct erofs_inode *inode)
 {
+       struct erofs_configure *cfg = inode->sbi->bt_args->cfg;
+
        if (erofs_is_packed_inode(inode)) {
-               return g_cfg.c_mkfs_pclustersize_packed;
+               return cfg->c_mkfs_pclustersize_packed;
 #ifndef NDEBUG
-       } else if (g_cfg.c_random_pclusterblks) {
+       } else if (cfg->c_random_pclusterblks) {
                unsigned int pclusterblks =
-                       g_cfg.c_mkfs_pclustersize_max >> inode->sbi->blkszbits;
+                       cfg->c_mkfs_pclustersize_max >> inode->sbi->blkszbits;
 
                return (1 + rand() % pclusterblks) << inode->sbi->blkszbits;
 #endif
-       } else if (g_cfg.c_compress_hints_file) {
+       } else if (cfg->c_compress_hints_file) {
                z_erofs_apply_compress_hints(inode);
                DBG_BUGON(!inode->z_physical_clusterblks);
                return inode->z_physical_clusterblks << inode->sbi->blkszbits;
        }
-       return g_cfg.c_mkfs_pclustersize_def;
+       return cfg->c_mkfs_pclustersize_def;
 }
 
 static int z_erofs_fill_inline_data(struct erofs_inode *inode, void *data,
@@ -515,15 +518,16 @@ static int __z_erofs_compress_one(struct 
z_erofs_compress_sctx *ctx,
        struct z_erofs_compress_ictx *ictx = ctx->ictx;
        struct erofs_inode *inode = ictx->inode;
        struct erofs_sb_info *sbi = inode->sbi;
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
        unsigned int blksz = erofs_blksiz(sbi);
        char *const dst = dstbuf + blksz;
        struct erofs_compress *const h = ctx->chandle;
        unsigned int len = ctx->tail - ctx->head;
        bool is_packed_inode = erofs_is_packed_inode(inode);
        bool tsg = (ctx->seg_idx + 1 >= ictx->seg_num), final = !ctx->remaining;
-       bool may_packing = (g_cfg.c_fragments && tsg && final &&
+       bool may_packing = (cfg->c_fragments && tsg && final &&
                            !is_packed_inode && !z_erofs_mt_enabled);
-       bool may_inline = (g_cfg.c_ztailpacking && tsg && final && 
!may_packing);
+       bool may_inline = (cfg->c_ztailpacking && tsg && final && !may_packing);
        unsigned int compressedsize;
        int ret;
 
@@ -543,7 +547,7 @@ static int __z_erofs_compress_one(struct 
z_erofs_compress_sctx *ctx,
                        goto nocompression;
        }
 
-       e->length = min(len, g_cfg.c_max_decompressed_extent_bytes);
+       e->length = min(len, cfg->c_max_decompressed_extent_bytes);
        ret = erofs_compress_destsize(h, ctx->queue + ctx->head,
                                      &e->length, dst, ctx->pclustersize);
        if (ret <= 0) {
@@ -1065,6 +1069,7 @@ int erofs_commit_compressed_file(struct 
z_erofs_compress_ictx *ictx,
 {
        struct erofs_inode *inode = ictx->inode;
        struct erofs_sb_info *sbi = inode->sbi;
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
        unsigned int legacymetasize;
        u8 *compressmeta;
        int ret;
@@ -1114,7 +1119,7 @@ int erofs_commit_compressed_file(struct 
z_erofs_compress_ictx *ictx,
                ret = erofs_bh_balloon(bh, erofs_pos(sbi, compressed_blocks));
                DBG_BUGON(ret != erofs_blksiz(sbi));
        } else {
-               if (!g_cfg.c_fragments && !g_cfg.c_dedupe)
+               if (!cfg->c_fragments && !cfg->c_dedupe)
                        DBG_BUGON(!inode->idata_size);
        }
 
@@ -1233,6 +1238,7 @@ void z_erofs_mt_workfn(struct erofs_work *work, void 
*tlsp)
        struct z_erofs_compress_ictx *ictx = sctx->ictx;
        struct erofs_inode *inode = ictx->inode;
        struct erofs_sb_info *sbi = inode->sbi;
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
        int ret = 0;
 
        ret = z_erofs_mt_wq_tls_init_compr(sbi, tls, cwork->alg_id,
@@ -1253,7 +1259,7 @@ void z_erofs_mt_workfn(struct erofs_work *work, void 
*tlsp)
        }
        sctx->memoff = 0;
 
-       ret = z_erofs_compress_segment(sctx, sctx->seg_idx * 
g_cfg.c_mkfs_segment_size,
+       ret = z_erofs_compress_segment(sctx, sctx->seg_idx * 
cfg->c_mkfs_segment_size,
                                       EROFS_NULL_ADDR);
 
 out:
@@ -1304,7 +1310,8 @@ int z_erofs_mt_compress(struct z_erofs_compress_ictx 
*ictx)
        struct erofs_compress_work *cur, *head = NULL, **last = &head;
        struct erofs_compress_cfg *ccfg = ictx->ccfg;
        struct erofs_inode *inode = ictx->inode;
-       int nsegs = DIV_ROUND_UP(inode->i_size, g_cfg.c_mkfs_segment_size);
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
+       int nsegs = DIV_ROUND_UP(inode->i_size, cfg->c_mkfs_segment_size);
        int i;
 
        ictx->seg_num = nsegs;
@@ -1338,9 +1345,9 @@ int z_erofs_mt_compress(struct z_erofs_compress_ictx 
*ictx)
                if (i == nsegs - 1)
                        cur->ctx.remaining = inode->i_size -
                                              inode->fragment_size -
-                                             i * g_cfg.c_mkfs_segment_size;
+                                             i * cfg->c_mkfs_segment_size;
                else
-                       cur->ctx.remaining = g_cfg.c_mkfs_segment_size;
+                       cur->ctx.remaining = cfg->c_mkfs_segment_size;
 
                cur->alg_id = ccfg->handle.alg->id;
                cur->alg_name = ccfg->handle.alg->name;
@@ -1418,13 +1425,14 @@ static struct z_erofs_compress_ictx g_ictx;
 void *erofs_begin_compressed_file(struct erofs_inode *inode, int fd, u64 fpos)
 {
        struct erofs_sb_info *sbi = inode->sbi;
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
        struct z_erofs_compress_ictx *ictx;
        int ret;
 
        /* initialize per-file compression setting */
        inode->z_advise = 0;
        inode->z_logical_clusterbits = sbi->blkszbits;
-       if (!g_cfg.c_legacy_compress && inode->z_logical_clusterbits <= 14) {
+       if (!cfg->c_legacy_compress && inode->z_logical_clusterbits <= 14) {
                if (inode->z_logical_clusterbits <= 12)
                        inode->z_advise |= Z_EROFS_ADVISE_COMPACTED_2B;
                inode->datalayout = EROFS_INODE_COMPRESSED_COMPACT;
@@ -1437,11 +1445,11 @@ void *erofs_begin_compressed_file(struct erofs_inode 
*inode, int fd, u64 fpos)
                if (inode->datalayout == EROFS_INODE_COMPRESSED_COMPACT)
                        inode->z_advise |= Z_EROFS_ADVISE_BIG_PCLUSTER_2;
        }
-       if (g_cfg.c_fragments && !g_cfg.c_dedupe)
+       if (cfg->c_fragments && !cfg->c_dedupe)
                inode->z_advise |= Z_EROFS_ADVISE_INTERLACED_PCLUSTER;
 
 #ifndef NDEBUG
-       if (g_cfg.c_random_algorithms) {
+       if (cfg->c_random_algorithms) {
                while (1) {
                        inode->z_algorithmtype[0] =
                                rand() % EROFS_MAX_COMPR_CFGS;
@@ -1478,7 +1486,7 @@ void *erofs_begin_compressed_file(struct erofs_inode 
*inode, int fd, u64 fpos)
         * Handle tails in advance to avoid writing duplicated
         * parts into the packed inode.
         */
-       if (g_cfg.c_fragments && !erofs_is_packed_inode(inode)) {
+       if (cfg->c_fragments && !erofs_is_packed_inode(inode)) {
                ret = z_erofs_fragments_dedupe(inode, fd, &ictx->tof_chksum);
                if (ret < 0)
                        goto err_free_ictx;
@@ -1490,7 +1498,7 @@ void *erofs_begin_compressed_file(struct erofs_inode 
*inode, int fd, u64 fpos)
        ictx->fix_dedupedfrag = false;
        ictx->fragemitted = false;
 
-       if (g_cfg.c_all_fragments && !erofs_is_packed_inode(inode) &&
+       if (cfg->c_all_fragments && !erofs_is_packed_inode(inode) &&
            !inode->fragment_size) {
                ret = z_erofs_pack_file_from_fd(inode, fd, ictx->tof_chksum);
                if (ret)
@@ -1580,6 +1588,7 @@ static int z_erofs_build_compr_cfgs(struct erofs_sb_info 
*sbi,
                                    struct erofs_buffer_head *sb_bh,
                                    u32 *max_dict_size)
 {
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
        struct erofs_buffer_head *bh = sb_bh;
        int ret = 0;
 
@@ -1593,7 +1602,7 @@ static int z_erofs_build_compr_cfgs(struct erofs_sb_info 
*sbi,
                                .max_distance =
                                        cpu_to_le16(sbi->lz4.max_distance),
                                .max_pclusterblks =
-                                       g_cfg.c_mkfs_pclustersize_max >> 
sbi->blkszbits,
+                                       cfg->c_mkfs_pclustersize_max >> 
sbi->blkszbits,
                        }
                };
 
@@ -1687,13 +1696,14 @@ int z_erofs_compress_init(struct erofs_sb_info *sbi, 
struct erofs_buffer_head *s
        int i, ret, id;
        u32 max_dict_size[Z_EROFS_COMPRESSION_MAX] = {};
        u32 available_compr_algs = 0;
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
 
-       for (i = 0; g_cfg.c_compr_opts[i].alg; ++i) {
+       for (i = 0; cfg->c_compr_opts[i].alg; ++i) {
                struct erofs_compress *c = &erofs_ccfg[i].handle;
 
-               ret = erofs_compressor_init(sbi, c, g_cfg.c_compr_opts[i].alg,
-                                           g_cfg.c_compr_opts[i].level,
-                                           g_cfg.c_compr_opts[i].dict_size);
+               ret = erofs_compressor_init(sbi, c, cfg->c_compr_opts[i].alg,
+                                           cfg->c_compr_opts[i].level,
+                                           cfg->c_compr_opts[i].dict_size);
                if (ret)
                        return ret;
 
@@ -1712,7 +1722,7 @@ int z_erofs_compress_init(struct erofs_sb_info *sbi, 
struct erofs_buffer_head *s
         * clear 0PADDING feature for old kernel compatibility.
         */
        if (!available_compr_algs ||
-           (g_cfg.c_legacy_compress && available_compr_algs == 1))
+           (cfg->c_legacy_compress && available_compr_algs == 1))
                erofs_sb_clear_lz4_0padding(sbi);
 
        if (!available_compr_algs)
@@ -1728,9 +1738,9 @@ int z_erofs_compress_init(struct erofs_sb_info *sbi, 
struct erofs_buffer_head *s
                }
                if (available_compr_algs & (1 << Z_EROFS_COMPRESSION_LZ4) &&
                    sbi->lz4.max_pclusterblks << sbi->blkszbits <
-                       g_cfg.c_mkfs_pclustersize_max) {
+                       cfg->c_mkfs_pclustersize_max) {
                        erofs_err("pclustersize %u is too large on incremental 
builds",
-                                 g_cfg.c_mkfs_pclustersize_max);
+                                 cfg->c_mkfs_pclustersize_max);
                        return -EOPNOTSUPP;
                }
        } else {
@@ -1741,17 +1751,17 @@ int z_erofs_compress_init(struct erofs_sb_info *sbi, 
struct erofs_buffer_head *s
         * if big pcluster is enabled, an extra CBLKCNT lcluster index needs
         * to be loaded in order to get those compressed block counts.
         */
-       if (g_cfg.c_mkfs_pclustersize_max > erofs_blksiz(sbi)) {
-               if (g_cfg.c_mkfs_pclustersize_max > Z_EROFS_PCLUSTER_MAX_SIZE) {
+       if (cfg->c_mkfs_pclustersize_max > erofs_blksiz(sbi)) {
+               if (cfg->c_mkfs_pclustersize_max > Z_EROFS_PCLUSTER_MAX_SIZE) {
                        erofs_err("unsupported pclustersize %u (too large)",
-                                 g_cfg.c_mkfs_pclustersize_max);
+                                 cfg->c_mkfs_pclustersize_max);
                        return -EINVAL;
                }
                erofs_sb_set_big_pcluster(sbi);
        }
-       if (g_cfg.c_mkfs_pclustersize_packed > g_cfg.c_mkfs_pclustersize_max) {
+       if (cfg->c_mkfs_pclustersize_packed > cfg->c_mkfs_pclustersize_max) {
                erofs_err("invalid pclustersize for the packed file %u",
-                         g_cfg.c_mkfs_pclustersize_packed);
+                         cfg->c_mkfs_pclustersize_packed);
                return -EINVAL;
        }
 
@@ -1763,19 +1773,19 @@ int z_erofs_compress_init(struct erofs_sb_info *sbi, 
struct erofs_buffer_head *s
 
        z_erofs_mt_enabled = false;
 #ifdef EROFS_MT_ENABLED
-       if (g_cfg.c_mt_workers >= 1 && (g_cfg.c_dedupe ||
-                                     (g_cfg.c_fragments && 
!g_cfg.c_all_fragments))) {
-               if (g_cfg.c_dedupe)
+       if (cfg->c_mt_workers >= 1 && (cfg->c_dedupe ||
+                                     (cfg->c_fragments && 
!cfg->c_all_fragments))) {
+               if (cfg->c_dedupe)
                        erofs_warn("multi-threaded dedupe is NOT implemented 
for now");
-               if (g_cfg.c_fragments)
+               if (cfg->c_fragments)
                        erofs_warn("multi-threaded fragments is NOT implemented 
for now");
-               g_cfg.c_mt_workers = 0;
+               cfg->c_mt_workers = 0;
        }
 
-       if (g_cfg.c_mt_workers >= 1) {
+       if (cfg->c_mt_workers >= 1) {
                ret = erofs_alloc_workqueue(&z_erofs_mt_ctrl.wq,
-                                           g_cfg.c_mt_workers,
-                                           g_cfg.c_mt_workers << 2,
+                                           cfg->c_mt_workers,
+                                           cfg->c_mt_workers << 2,
                                            z_erofs_mt_wq_tls_alloc,
                                            z_erofs_mt_wq_tls_free);
                z_erofs_mt_enabled = !ret;
@@ -1786,11 +1796,12 @@ int z_erofs_compress_init(struct erofs_sb_info *sbi, 
struct erofs_buffer_head *s
        return 0;
 }
 
-int z_erofs_compress_exit(void)
+int z_erofs_compress_exit(struct erofs_sb_info *sbi)
 {
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
        int i, ret;
 
-       for (i = 0; g_cfg.c_compr_opts[i].alg; ++i) {
+       for (i = 0; cfg->c_compr_opts[i].alg; ++i) {
                ret = erofs_compressor_exit(&erofs_ccfg[i].handle);
                if (ret)
                        return ret;
diff --git a/lib/compress_hints.c b/lib/compress_hints.c
index ae7c231..d0928f0 100644
--- a/lib/compress_hints.c
+++ b/lib/compress_hints.c
@@ -50,12 +50,13 @@ bool z_erofs_apply_compress_hints(struct erofs_inode *inode)
        const char *s;
        struct erofs_compress_hints *r;
        unsigned int pclusterblks, algorithmtype;
+       struct erofs_configure *cfg = inode->sbi->bt_args->cfg;
 
        if (inode->z_physical_clusterblks)
                return true;
 
        s = erofs_fspath(inode->i_srcpath);
-       pclusterblks = g_cfg.c_mkfs_pclustersize_def >> inode->sbi->blkszbits;
+       pclusterblks = cfg->c_mkfs_pclustersize_def >> inode->sbi->blkszbits;
        algorithmtype = 0;
 
        list_for_each_entry(r, &compress_hints_head, list) {
@@ -92,11 +93,12 @@ int erofs_load_compress_hints(struct erofs_sb_info *sbi)
        FILE *f;
        unsigned int line, max_pclustersize = 0;
        int ret = 0;
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
 
-       if (!g_cfg.c_compress_hints_file)
+       if (!cfg->c_compress_hints_file)
                return 0;
 
-       f = fopen(g_cfg.c_compress_hints_file, "r");
+       f = fopen(cfg->c_compress_hints_file, "r");
        if (!f)
                return -errno;
 
@@ -125,7 +127,7 @@ int erofs_load_compress_hints(struct erofs_sb_info *sbi)
                } else {
                        ccfg = atoi(alg);
                        if (ccfg >= EROFS_MAX_COMPR_CFGS ||
-                           !g_cfg.c_compr_opts[ccfg].alg) {
+                           !cfg->c_compr_opts[ccfg].alg) {
                                erofs_err("invalid compressing configuration 
\"%s\" at line %u",
                                          alg, line);
                                ret = -EINVAL;
@@ -136,7 +138,7 @@ int erofs_load_compress_hints(struct erofs_sb_info *sbi)
                if (pclustersize % erofs_blksiz(sbi)) {
                        erofs_warn("invalid physical clustersize %u, "
                                   "use default pclusterblks %u",
-                                  pclustersize, g_cfg.c_mkfs_pclustersize_def);
+                                  pclustersize, cfg->c_mkfs_pclustersize_def);
                        continue;
                }
                erofs_insert_compress_hints(pattern,
@@ -146,10 +148,10 @@ int erofs_load_compress_hints(struct erofs_sb_info *sbi)
                        max_pclustersize = pclustersize;
        }
 
-       if (g_cfg.c_mkfs_pclustersize_max < max_pclustersize) {
-               g_cfg.c_mkfs_pclustersize_max = max_pclustersize;
+       if (cfg->c_mkfs_pclustersize_max < max_pclustersize) {
+               cfg->c_mkfs_pclustersize_max = max_pclustersize;
                erofs_warn("update max pclustersize to %u",
-                          g_cfg.c_mkfs_pclustersize_max);
+                          cfg->c_mkfs_pclustersize_max);
        }
 out:
        fclose(f);
diff --git a/lib/compressor_liblzma.c b/lib/compressor_liblzma.c
index 4b0b069..7282fcd 100644
--- a/lib/compressor_liblzma.c
+++ b/lib/compressor_liblzma.c
@@ -70,12 +70,14 @@ static int erofs_compressor_liblzma_setlevel(struct 
erofs_compress *c,
 static int erofs_compressor_liblzma_setdictsize(struct erofs_compress *c,
                                                u32 dict_size)
 {
+       struct erofs_configure *cfg = c->sbi->bt_args->cfg;
+
        if (!dict_size) {
                if (erofs_compressor_lzma.default_dictsize) {
                        dict_size = erofs_compressor_lzma.default_dictsize;
                } else {
                        dict_size = min_t(u32, Z_EROFS_LZMA_MAX_DICT_SIZE,
-                                         g_cfg.c_mkfs_pclustersize_max << 3);
+                                         cfg->c_mkfs_pclustersize_max << 3);
                        if (dict_size < 32768)
                                dict_size = 32768;
                }
diff --git a/lib/compressor_libzstd.c b/lib/compressor_libzstd.c
index dfdb728..92bfc82 100644
--- a/lib/compressor_libzstd.c
+++ b/lib/compressor_libzstd.c
@@ -81,12 +81,14 @@ static int erofs_compressor_libzstd_setlevel(struct 
erofs_compress *c,
 static int erofs_compressor_libzstd_setdictsize(struct erofs_compress *c,
                                                u32 dict_size)
 {
+       struct erofs_configure *cfg = c->sbi->bt_args->cfg;
+
        if (!dict_size) {
                if (erofs_compressor_libzstd.default_dictsize) {
                        dict_size = erofs_compressor_libzstd.default_dictsize;
                } else {
                        dict_size = min_t(u32, Z_EROFS_ZSTD_MAX_DICT_SIZE,
-                                         g_cfg.c_mkfs_pclustersize_max << 3);
+                                         cfg->c_mkfs_pclustersize_max << 3);
                        dict_size = 1 << ilog2(dict_size);
                }
        }
diff --git a/lib/config.c b/lib/config.c
index 353411a..25447d5 100644
--- a/lib/config.c
+++ b/lib/config.c
@@ -22,26 +22,26 @@ struct erofs_configure g_cfg;
 struct erofs_sb_info g_sbi;
 bool erofs_stdout_tty;
 
-void erofs_init_configure(void)
+void erofs_init_configure(struct erofs_configure *cfg)
 {
-       memset(&g_cfg, 0, sizeof(g_cfg));
-
-       g_cfg.c_dbg_lvl  = EROFS_WARN;
-       g_cfg.c_version  = PACKAGE_VERSION;
-       g_cfg.c_dry_run  = false;
-       g_cfg.c_ignore_mtime = false;
-       g_cfg.c_force_inodeversion = 0;
-       g_cfg.c_inline_xattr_tolerance = 2;
-       g_cfg.c_unix_timestamp = -1;
-       g_cfg.c_uid = -1;
-       g_cfg.c_gid = -1;
-       g_cfg.c_max_decompressed_extent_bytes = -1;
+       memset(cfg, 0, sizeof(*cfg));
+
+       cfg->c_dbg_lvl  = EROFS_WARN;
+       cfg->c_version  = PACKAGE_VERSION;
+       cfg->c_dry_run  = false;
+       cfg->c_ignore_mtime = false;
+       cfg->c_force_inodeversion = 0;
+       cfg->c_inline_xattr_tolerance = 2;
+       cfg->c_unix_timestamp = -1;
+       cfg->c_uid = -1;
+       cfg->c_gid = -1;
+       cfg->c_max_decompressed_extent_bytes = -1;
        erofs_stdout_tty = isatty(STDOUT_FILENO);
 }
 
-void erofs_show_config(void)
+void erofs_show_config(struct erofs_configure *cfg)
 {
-       const struct erofs_configure *c = &g_cfg;
+       const struct erofs_configure *c = cfg;
 
        if (c->c_dbg_lvl < EROFS_INFO)
                return;
@@ -50,20 +50,20 @@ void erofs_show_config(void)
        erofs_dump("\tc_dry_run:           [%8d]\n", c->c_dry_run);
 }
 
-void erofs_exit_configure(void)
+void erofs_exit_configure(struct erofs_configure *cfg)
 {
        int i;
 
 #ifdef HAVE_LIBSELINUX
-       if (g_cfg.sehnd)
-               selabel_close(g_cfg.sehnd);
+       if (cfg->sehnd)
+               selabel_close(cfg->sehnd);
 #endif
-       if (g_cfg.c_img_path)
-               free(g_cfg.c_img_path);
-       if (g_cfg.c_src_path)
-               free(g_cfg.c_src_path);
-       for (i = 0; i < EROFS_MAX_COMPR_CFGS && g_cfg.c_compr_opts[i].alg; i++)
-               free(g_cfg.c_compr_opts[i].alg);
+       if (cfg->c_img_path)
+               free(cfg->c_img_path);
+       if (cfg->c_src_path)
+               free(cfg->c_src_path);
+       for (i = 0; i < EROFS_MAX_COMPR_CFGS && cfg->c_compr_opts[i].alg; i++)
+               free(cfg->c_compr_opts[i].alg);
 }
 
 struct erofs_configure *erofs_get_configure()
@@ -88,20 +88,22 @@ const char *erofs_fspath(const char *fullpath)
 }
 
 #ifdef HAVE_LIBSELINUX
-int erofs_selabel_open(const char *file_contexts)
+int erofs_selabel_open(struct erofs_sb_info *sbi, const char *file_contexts)
 {
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
+
        struct selinux_opt seopts[] = {
                { .type = SELABEL_OPT_PATH, .value = file_contexts }
        };
 
-       if (g_cfg.sehnd) {
+       if (cfg->sehnd) {
                erofs_info("ignore duplicated file contexts \"%s\"",
                           file_contexts);
                return -EBUSY;
        }
 
-       g_cfg.sehnd = selabel_open(SELABEL_CTX_FILE, seopts, 1);
-       if (!g_cfg.sehnd) {
+       cfg->sehnd = selabel_open(SELABEL_CTX_FILE, seopts, 1);
+       if (!cfg->sehnd) {
                erofs_err("failed to open file contexts \"%s\"",
                          file_contexts);
                return -EINVAL;
@@ -161,12 +163,13 @@ void erofs_msg(int dbglv, const char *fmt, ...)
        va_end(ap);
 }
 
-void erofs_update_progressinfo(const char *fmt, ...)
+void erofs_update_progressinfo(struct erofs_sb_info *sbi, const char *fmt, ...)
 {
        char msg[8192];
        va_list ap;
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
 
-       if (g_cfg.c_dbg_lvl >= EROFS_INFO || !g_cfg.c_showprogress)
+       if (cfg->c_dbg_lvl >= EROFS_INFO || !cfg->c_showprogress)
                return;
 
        va_start(ap, fmt);
@@ -191,3 +194,22 @@ unsigned int erofs_get_available_processors(void)
        return 0;
 #endif
 }
+
+void erofs_init_buildtree_cfg(struct erofs_sb_info *sbi,
+                             struct erofs_configure *cfg)
+{
+       sbi->bt_args = malloc(sizeof(struct erofs_mkfs_buildtree_args));
+       if (!sbi->bt_args) {
+               erofs_err("fail to prepare for erofs_mkfs_buildtree_args");
+               return;
+       }
+       sbi->bt_args->cfg = cfg;
+       erofs_init_configure(sbi->bt_args->cfg);
+}
+
+void erofs_exit_buildtree_cfg(struct erofs_sb_info *sbi)
+{
+       erofs_exit_configure(sbi->bt_args->cfg);
+       sbi->bt_args->cfg = NULL;
+       free(sbi->bt_args);
+}
diff --git a/lib/inode.c b/lib/inode.c
index c3d2edb..2f6e3a5 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -507,7 +507,9 @@ int erofs_write_file_from_buffer(struct erofs_inode *inode, 
char *buf)
 /* rules to decide whether a file could be compressed or not */
 static bool erofs_file_is_compressible(struct erofs_inode *inode)
 {
-       if (g_cfg.c_compress_hints_file)
+       struct erofs_configure *cfg = inode->sbi->bt_args->cfg;
+
+       if (cfg->c_compress_hints_file)
                return z_erofs_apply_compress_hints(inode);
        return true;
 }
@@ -557,11 +559,13 @@ static int write_uncompressed_file_from_fd(struct 
erofs_inode *inode, int fd)
 
 int erofs_write_unencoded_file(struct erofs_inode *inode, int fd, u64 fpos)
 {
-       if (g_cfg.c_chunkbits) {
-               inode->u.chunkbits = g_cfg.c_chunkbits;
+       struct erofs_configure *cfg = inode->sbi->bt_args->cfg;
+
+       if (cfg->c_chunkbits) {
+               inode->u.chunkbits = cfg->c_chunkbits;
                /* chunk indexes when explicitly specified */
                inode->u.chunkformat = 0;
-               if (g_cfg.c_force_chunkformat == FORCE_INODE_CHUNK_INDEXES)
+               if (cfg->c_force_chunkformat == FORCE_INODE_CHUNK_INDEXES)
                        inode->u.chunkformat = EROFS_CHUNK_FORMAT_INDEXES;
                return erofs_blob_write_chunked_file(inode, fd, fpos);
        }
@@ -748,6 +752,7 @@ static int erofs_prepare_inode_buffer(struct erofs_inode 
*inode)
        struct erofs_bufmgr *bmgr = inode->sbi->bmgr;
        unsigned int inodesize;
        struct erofs_buffer_head *bh, *ibh;
+       struct erofs_configure *cfg = inode->sbi->bt_args->cfg;
 
        DBG_BUGON(inode->bh || inode->bh_inline);
 
@@ -763,7 +768,7 @@ static int erofs_prepare_inode_buffer(struct erofs_inode 
*inode)
                goto noinline;
 
        if (!is_inode_layout_compression(inode)) {
-               if (!g_cfg.c_inline_data && S_ISREG(inode->i_mode)) {
+               if (!cfg->c_inline_data && S_ISREG(inode->i_mode)) {
                        inode->datalayout = EROFS_INODE_FLAT_PLAIN;
                        goto noinline;
                }
@@ -796,7 +801,7 @@ noinline:
                return PTR_ERR(bh);
        } else if (inode->idata_size) {
                if (is_inode_layout_compression(inode)) {
-                       DBG_BUGON(!g_cfg.c_ztailpacking);
+                       DBG_BUGON(!cfg->c_ztailpacking);
                        erofs_dbg("Inline %scompressed data (%u bytes) to %s",
                                  inode->compressed_idata ? "" : "un",
                                  inode->idata_size, inode->i_srcpath);
@@ -933,7 +938,9 @@ out:
 
 static bool erofs_should_use_inode_extended(struct erofs_inode *inode)
 {
-       if (g_cfg.c_force_inodeversion == FORCE_INODE_EXTENDED)
+       struct erofs_configure *cfg = inode->sbi->bt_args->cfg;
+
+       if (cfg->c_force_inodeversion == FORCE_INODE_EXTENDED)
                return true;
        if (inode->i_size > UINT_MAX)
                return true;
@@ -947,7 +954,7 @@ static bool erofs_should_use_inode_extended(struct 
erofs_inode *inode)
                return true;
        if ((inode->i_mtime != inode->sbi->build_time ||
             inode->i_mtime_nsec != inode->sbi->build_time_nsec) &&
-           !g_cfg.c_ignore_mtime)
+           !cfg->c_ignore_mtime)
                return true;
        return false;
 }
@@ -965,6 +972,7 @@ int erofs_droid_inode_fsconfig(struct erofs_inode *inode,
                               struct stat *st,
                               const char *path)
 {
+       struct erofs_configure *cfg = inode->sbi->bt_args->cfg;
        /* filesystem_config does not preserve file type bits */
        mode_t stat_file_type_mask = st->st_mode & S_IFMT;
        unsigned int uid = 0, gid = 0, mode = 0;
@@ -972,30 +980,30 @@ int erofs_droid_inode_fsconfig(struct erofs_inode *inode,
        char *decorated = NULL;
 
        inode->capabilities = 0;
-       if (!g_cfg.fs_config_file && !g_cfg.mount_point)
+       if (!cfg->fs_config_file && !cfg->mount_point)
                return 0;
        /* avoid loading special inodes */
        if (path == EROFS_PACKED_INODE)
                return 0;
 
-       if (!g_cfg.mount_point ||
+       if (!cfg->mount_point ||
        /* have to drop the mountpoint for rootdir of canned fsconfig */
-           (g_cfg.fs_config_file && erofs_fspath(path)[0] == '\0')) {
+           (cfg->fs_config_file && erofs_fspath(path)[0] == '\0')) {
                fspath = erofs_fspath(path);
        } else {
-               if (asprintf(&decorated, "%s/%s", g_cfg.mount_point,
+               if (asprintf(&decorated, "%s/%s", cfg->mount_point,
                             erofs_fspath(path)) <= 0)
                        return -ENOMEM;
                fspath = decorated;
        }
 
-       if (g_cfg.fs_config_file)
+       if (cfg->fs_config_file)
                canned_fs_config(fspath, S_ISDIR(st->st_mode),
-                                g_cfg.target_out_path,
+                                cfg->target_out_path,
                                 &uid, &gid, &mode, &inode->capabilities);
        else
                fs_config(fspath, S_ISDIR(st->st_mode),
-                         g_cfg.target_out_path,
+                         cfg->target_out_path,
                          &uid, &gid, &mode, &inode->capabilities);
 
        erofs_dbg("/%s -> mode = 0x%x, uid = 0x%x, gid = 0x%x, capabilities = 
0x%" PRIx64,
@@ -1022,25 +1030,26 @@ int __erofs_fill_inode(struct erofs_inode *inode, 
struct stat *st,
 {
        int err = erofs_droid_inode_fsconfig(inode, st, path);
        struct erofs_sb_info *sbi = inode->sbi;
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
 
        if (err)
                return err;
 
-       inode->i_uid = g_cfg.c_uid == -1 ? st->st_uid : g_cfg.c_uid;
-       inode->i_gid = g_cfg.c_gid == -1 ? st->st_gid : g_cfg.c_gid;
+       inode->i_uid = cfg->c_uid == -1 ? st->st_uid : cfg->c_uid;
+       inode->i_gid = cfg->c_gid == -1 ? st->st_gid : cfg->c_gid;
 
-       if (inode->i_uid + g_cfg.c_uid_offset < 0)
+       if (inode->i_uid + cfg->c_uid_offset < 0)
                erofs_err("uid overflow @ %s", path);
-       inode->i_uid += g_cfg.c_uid_offset;
+       inode->i_uid += cfg->c_uid_offset;
 
-       if (inode->i_gid + g_cfg.c_gid_offset < 0)
+       if (inode->i_gid + cfg->c_gid_offset < 0)
                erofs_err("gid overflow @ %s", path);
-       inode->i_gid += g_cfg.c_gid_offset;
+       inode->i_gid += cfg->c_gid_offset;
 
        inode->i_mtime = st->st_mtime;
        inode->i_mtime_nsec = ST_MTIM_NSEC(st);
 
-       switch (g_cfg.c_timeinherit) {
+       switch (cfg->c_timeinherit) {
        case TIMESTAMP_CLAMPING:
                if (inode->i_mtime < sbi->build_time)
                        break;
@@ -1057,6 +1066,8 @@ int __erofs_fill_inode(struct erofs_inode *inode, struct 
stat *st,
 static int erofs_fill_inode(struct erofs_inode *inode, struct stat *st,
                            const char *path)
 {
+       struct erofs_configure *cfg = inode->sbi->bt_args->cfg;
+
        int err = __erofs_fill_inode(inode, st, path);
 
        if (err)
@@ -1087,7 +1098,7 @@ static int erofs_fill_inode(struct erofs_inode *inode, 
struct stat *st,
                return -ENOMEM;
 
        if (erofs_should_use_inode_extended(inode)) {
-               if (g_cfg.c_force_inodeversion == FORCE_INODE_COMPACT) {
+               if (cfg->c_force_inodeversion == FORCE_INODE_COMPACT) {
                        erofs_err("file %s cannot be in compact form",
                                  inode->i_srcpath);
                        return -EINVAL;
@@ -1534,9 +1545,10 @@ static int erofs_rebuild_handle_directory(struct 
erofs_inode *dir,
                                          bool incremental)
 {
        struct erofs_sb_info *sbi = dir->sbi;
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
        struct erofs_dentry *d, *n;
        unsigned int nr_subdirs, i_nlink;
-       bool delwht = g_cfg.c_ovlfs_strip && dir->whiteouts;
+       bool delwht = cfg->c_ovlfs_strip && dir->whiteouts;
        int ret;
 
        nr_subdirs = 0;
@@ -1578,13 +1590,14 @@ static int erofs_rebuild_handle_directory(struct 
erofs_inode *dir,
 
 static int erofs_mkfs_handle_inode(struct erofs_inode *inode)
 {
+       struct erofs_configure *cfg = inode->sbi->bt_args->cfg;
        const char *relpath = erofs_fspath(inode->i_srcpath);
        char *trimmed;
        int ret;
 
        trimmed = erofs_trim_for_progressinfo(relpath[0] ? relpath : "/",
                                              sizeof("Processing  ...") - 1);
-       erofs_update_progressinfo("Processing %s ...", trimmed);
+       erofs_update_progressinfo(inode->sbi, "Processing %s ...", trimmed);
        free(trimmed);
 
        ret = erofs_scan_file_xattrs(inode);
@@ -1603,7 +1616,7 @@ static int erofs_mkfs_handle_inode(struct erofs_inode 
*inode)
                        if (ctx.fd < 0)
                                return -errno;
 
-                       if (g_cfg.c_compr_opts[0].alg &&
+                       if (cfg->c_compr_opts[0].alg &&
                            erofs_file_is_compressible(inode)) {
                                ctx.ictx = erofs_begin_compressed_file(inode,
                                                                ctx.fd, 0);
@@ -1623,16 +1636,17 @@ static int erofs_mkfs_handle_inode(struct erofs_inode 
*inode)
 static int erofs_rebuild_handle_inode(struct erofs_inode *inode,
                                      bool incremental)
 {
+       struct erofs_configure *cfg = inode->sbi->bt_args->cfg;
        char *trimmed;
        int ret;
 
        trimmed = erofs_trim_for_progressinfo(erofs_fspath(inode->i_srcpath),
                                              sizeof("Processing  ...") - 1);
-       erofs_update_progressinfo("Processing %s ...", trimmed);
+       erofs_update_progressinfo(inode->sbi, "Processing %s ...", trimmed);
        free(trimmed);
 
        if (erofs_should_use_inode_extended(inode)) {
-               if (g_cfg.c_force_inodeversion == FORCE_INODE_COMPACT) {
+               if (cfg->c_force_inodeversion == FORCE_INODE_COMPACT) {
                        erofs_err("file %s cannot be in compact form",
                                  inode->i_srcpath);
                        return -EINVAL;
@@ -1650,7 +1664,7 @@ static int erofs_rebuild_handle_inode(struct erofs_inode 
*inode,
        }
 
        /* strip all unnecessary overlayfs xattrs when ovlfs_strip is enabled */
-       if (g_cfg.c_ovlfs_strip)
+       if (cfg->c_ovlfs_strip)
                erofs_clear_opaque_xattr(inode);
        else if (inode->whiteouts)
                erofs_set_origin_xattr(inode);
@@ -1669,7 +1683,7 @@ static int erofs_rebuild_handle_inode(struct erofs_inode 
*inode,
                        if (ctx.fd < 0)
                                return ret;
 
-                       if (g_cfg.c_compr_opts[0].alg &&
+                       if (cfg->c_compr_opts[0].alg &&
                            erofs_file_is_compressible(inode)) {
                                ctx.ictx = erofs_begin_compressed_file(inode,
                                                        ctx.fd, ctx.fpos);
@@ -1702,6 +1716,7 @@ static int erofs_mkfs_dump_tree(struct erofs_inode *root, 
bool rebuild,
                                bool incremental)
 {
        struct erofs_sb_info *sbi = root->sbi;
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
        struct erofs_inode *dumpdir = erofs_igrab(root);
        int err;
 
@@ -1713,8 +1728,8 @@ static int erofs_mkfs_dump_tree(struct erofs_inode *root, 
bool rebuild,
                root->i_ino[1] = sbi->root_nid;
                list_del(&root->i_hash);
                erofs_insert_ihash(root);
-       } else if (g_cfg.c_root_xattr_isize) {
-               root->xattr_isize = g_cfg.c_root_xattr_isize;
+       } else if (cfg->c_root_xattr_isize) {
+               root->xattr_isize = cfg->c_root_xattr_isize;
        }
 
        err = !rebuild ? erofs_mkfs_handle_inode(root) :
@@ -1886,6 +1901,7 @@ int erofs_rebuild_dump_tree(struct erofs_inode *root, 
bool incremental)
 struct erofs_inode *erofs_mkfs_build_special_from_fd(struct erofs_sb_info *sbi,
                                                     int fd, const char *name)
 {
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
        struct stat st;
        struct erofs_inode *inode;
        void *ictx;
@@ -1919,7 +1935,7 @@ struct erofs_inode 
*erofs_mkfs_build_special_from_fd(struct erofs_sb_info *sbi,
                inode->nid = inode->sbi->packed_nid;
        }
 
-       if (g_cfg.c_compr_opts[0].alg &&
+       if (cfg->c_compr_opts[0].alg &&
            erofs_file_is_compressible(inode)) {
                ictx = erofs_begin_compressed_file(inode, fd, 0);
                if (IS_ERR(ictx))
diff --git a/lib/io.c b/lib/io.c
index 6d2c708..f284a35 100644
--- a/lib/io.c
+++ b/lib/io.c
@@ -28,7 +28,11 @@
 
 int erofs_io_fstat(struct erofs_vfile *vf, struct stat *buf)
 {
-       if (__erofs_unlikely(g_cfg.c_dry_run)) {
+       struct erofs_sb_info *sbi = container_of(vf, struct erofs_sb_info,
+                                                bdev);
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
+
+       if (__erofs_unlikely(cfg->c_dry_run)) {
                buf->st_size = 0;
                buf->st_mode = S_IFREG | 0777;
                return 0;
@@ -42,9 +46,12 @@ int erofs_io_fstat(struct erofs_vfile *vf, struct stat *buf)
 ssize_t erofs_io_pwrite(struct erofs_vfile *vf, const void *buf,
                        u64 pos, size_t len)
 {
+       struct erofs_sb_info *sbi = container_of(vf, struct erofs_sb_info,
+                                                bdev);
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
        ssize_t ret, written = 0;
 
-       if (__erofs_unlikely(g_cfg.c_dry_run))
+       if (__erofs_unlikely(cfg->c_dry_run))
                return 0;
 
        if (vf->ops)
@@ -76,9 +83,12 @@ ssize_t erofs_io_pwrite(struct erofs_vfile *vf, const void 
*buf,
 
 int erofs_io_fsync(struct erofs_vfile *vf)
 {
+       struct erofs_sb_info *sbi = container_of(vf, struct erofs_sb_info,
+                                                bdev);
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
        int ret;
 
-       if (__erofs_unlikely(g_cfg.c_dry_run))
+       if (__erofs_unlikely(cfg->c_dry_run))
                return 0;
 
        if (vf->ops)
@@ -95,10 +105,13 @@ int erofs_io_fsync(struct erofs_vfile *vf)
 ssize_t erofs_io_fallocate(struct erofs_vfile *vf, u64 offset,
                           size_t len, bool zeroout)
 {
+       struct erofs_sb_info *sbi = container_of(vf, struct erofs_sb_info,
+                                                bdev);
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
        static const char zero[EROFS_MAX_BLOCK_SIZE] = {0};
        ssize_t ret;
 
-       if (__erofs_unlikely(g_cfg.c_dry_run))
+       if (__erofs_unlikely(cfg->c_dry_run))
                return 0;
 
        if (vf->ops)
@@ -123,8 +136,11 @@ int erofs_io_ftruncate(struct erofs_vfile *vf, u64 length)
 {
        int ret;
        struct stat st;
+       struct erofs_sb_info *sbi = container_of(vf, struct erofs_sb_info,
+                                                bdev);
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
 
-       if (__erofs_unlikely(g_cfg.c_dry_run))
+       if (__erofs_unlikely(cfg->c_dry_run))
                return 0;
 
        if (vf->ops)
@@ -143,9 +159,12 @@ int erofs_io_ftruncate(struct erofs_vfile *vf, u64 length)
 
 ssize_t erofs_io_pread(struct erofs_vfile *vf, void *buf, u64 pos, size_t len)
 {
+       struct erofs_sb_info *sbi = container_of(vf, struct erofs_sb_info,
+                                                bdev);
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
        ssize_t ret, read = 0;
 
-       if (__erofs_unlikely(g_cfg.c_dry_run))
+       if (__erofs_unlikely(cfg->c_dry_run))
                return 0;
 
        if (vf->ops)
diff --git a/lib/xattr.c b/lib/xattr.c
index b22a76f..b932426 100644
--- a/lib/xattr.c
+++ b/lib/xattr.c
@@ -293,26 +293,29 @@ out:
        return ERR_PTR(ret);
 }
 
-static struct xattr_item *erofs_get_selabel_xattr(const char *srcpath,
+static struct xattr_item *erofs_get_selabel_xattr(struct erofs_sb_info *sbi,
+                                                 const char *srcpath,
                                                  mode_t mode)
 {
 #ifdef HAVE_LIBSELINUX
-       if (g_cfg.sehnd) {
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
+
+       if (cfg->sehnd) {
                char *secontext;
                int ret;
                unsigned int len[2];
                char *kvbuf, *fspath;
                struct xattr_item *item;
 
-               if (g_cfg.mount_point)
-                       ret = asprintf(&fspath, "/%s/%s", g_cfg.mount_point,
+               if (cfg->mount_point)
+                       ret = asprintf(&fspath, "/%s/%s", cfg->mount_point,
                                       erofs_fspath(srcpath));
                else
                        ret = asprintf(&fspath, "/%s", erofs_fspath(srcpath));
                if (ret <= 0)
                        return ERR_PTR(-ENOMEM);
 
-               ret = selabel_lookup(g_cfg.sehnd, &secontext, fspath, mode);
+               ret = selabel_lookup(cfg->sehnd, &secontext, fspath, mode);
                free(fspath);
 
                if (ret) {
@@ -364,12 +367,15 @@ static int shared_xattr_add(struct xattr_item *item)
        return ++shared_xattrs_count;
 }
 
-static int erofs_xattr_add(struct list_head *ixattrs, struct xattr_item *item)
+static int erofs_xattr_add(struct erofs_sb_info *sbi, struct list_head 
*ixattrs,
+                          struct xattr_item *item)
 {
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
+
        if (ixattrs)
                return inode_xattr_add(ixattrs, item);
 
-       if (item->count == g_cfg.c_inline_xattr_tolerance + 1) {
+       if (item->count == cfg->c_inline_xattr_tolerance + 1) {
                int ret = shared_xattr_add(item);
 
                if (ret < 0)
@@ -378,18 +384,20 @@ static int erofs_xattr_add(struct list_head *ixattrs, 
struct xattr_item *item)
        return 0;
 }
 
-static bool erofs_is_skipped_xattr(const char *key)
+static bool erofs_is_skipped_xattr(struct erofs_sb_info *sbi, const char *key)
 {
 #ifdef HAVE_LIBSELINUX
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
+
        /* if sehnd is valid, selabels will be overridden */
-       if (g_cfg.sehnd && !strcmp(key, XATTR_SECURITY_PREFIX "selinux"))
+       if (cfg->sehnd && !strcmp(key, XATTR_SECURITY_PREFIX "selinux"))
                return true;
 #endif
        return false;
 }
 
-static int read_xattrs_from_file(const char *path, mode_t mode,
-                                struct list_head *ixattrs)
+static int read_xattrs_from_file(struct erofs_sb_info *sbi, const char *path,
+                                mode_t mode, struct list_head *ixattrs)
 {
 #ifdef HAVE_LLISTXATTR
        ssize_t kllen = llistxattr(path, NULL, 0);
@@ -441,7 +449,7 @@ static int read_xattrs_from_file(const char *path, mode_t 
mode,
 
        for (key = keylst; key != klend; key += keylen + 1) {
                keylen = strlen(key);
-               if (erofs_is_skipped_xattr(key))
+               if (erofs_is_skipped_xattr(sbi, key))
                        continue;
 
                item = parse_one_xattr(path, key, keylen);
@@ -453,7 +461,7 @@ static int read_xattrs_from_file(const char *path, mode_t 
mode,
                if (!item)
                        continue;
 
-               ret = erofs_xattr_add(ixattrs, item);
+               ret = erofs_xattr_add(sbi, ixattrs, item);
                if (ret < 0)
                        goto err;
        }
@@ -461,11 +469,11 @@ static int read_xattrs_from_file(const char *path, mode_t 
mode,
 
 out:
        /* if some selabel is avilable, need to add right now */
-       item = erofs_get_selabel_xattr(path, mode);
+       item = erofs_get_selabel_xattr(sbi, path, mode);
        if (IS_ERR(item))
                return PTR_ERR(item);
        if (item)
-               ret = erofs_xattr_add(ixattrs, item);
+               ret = erofs_xattr_add(sbi, ixattrs, item);
        return ret;
 
 err:
@@ -497,7 +505,7 @@ int erofs_setxattr(struct erofs_inode *inode, char *key,
        }
        DBG_BUGON(!item);
 
-       return erofs_xattr_add(&inode->i_xattrs, item);
+       return erofs_xattr_add(inode->sbi, &inode->i_xattrs, item);
 }
 
 static void erofs_removexattr(struct erofs_inode *inode, const char *key)
@@ -562,7 +570,7 @@ static int erofs_droid_xattr_set_caps(struct erofs_inode 
*inode)
        }
        DBG_BUGON(!item);
 
-       return erofs_xattr_add(&inode->i_xattrs, item);
+       return erofs_xattr_add(inode->sbi, &inode->i_xattrs, item);
 }
 #else
 static int erofs_droid_xattr_set_caps(struct erofs_inode *inode)
@@ -575,12 +583,14 @@ int erofs_scan_file_xattrs(struct erofs_inode *inode)
 {
        int ret;
        struct list_head *ixattrs = &inode->i_xattrs;
+       struct erofs_configure *cfg = inode->sbi->bt_args->cfg;
 
        /* check if xattr is disabled */
-       if (g_cfg.c_inline_xattr_tolerance < 0)
+       if (cfg->c_inline_xattr_tolerance < 0)
                return 0;
 
-       ret = read_xattrs_from_file(inode->i_srcpath, inode->i_mode, ixattrs);
+       ret = read_xattrs_from_file(inode->sbi, inode->i_srcpath,
+                                   inode->i_mode, ixattrs);
        if (ret < 0)
                return ret;
 
@@ -705,7 +715,7 @@ out:
        return ret;
 }
 
-static int erofs_count_all_xattrs_from_path(const char *path)
+static int erofs_count_all_xattrs_from_path(struct erofs_sb_info *sbi, const 
char *path)
 {
        int ret;
        DIR *_dir;
@@ -750,14 +760,14 @@ static int erofs_count_all_xattrs_from_path(const char 
*path)
                        goto fail;
                }
 
-               ret = read_xattrs_from_file(buf, st.st_mode, NULL);
+               ret = read_xattrs_from_file(sbi, buf, st.st_mode, NULL);
                if (ret)
                        goto fail;
 
                if (!S_ISDIR(st.st_mode))
                        continue;
 
-               ret = erofs_count_all_xattrs_from_path(buf);
+               ret = erofs_count_all_xattrs_from_path(sbi, buf);
                if (ret)
                        goto fail;
        }
@@ -883,10 +893,11 @@ int erofs_build_shared_xattrs_from_path(struct 
erofs_sb_info *sbi, const char *p
        unsigned int p, i;
        erofs_off_t off;
        erofs_off_t shared_xattrs_size = 0;
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
 
        /* check if xattr or shared xattr is disabled */
-       if (g_cfg.c_inline_xattr_tolerance < 0 ||
-           g_cfg.c_inline_xattr_tolerance == INT_MAX)
+       if (cfg->c_inline_xattr_tolerance < 0 ||
+           cfg->c_inline_xattr_tolerance == INT_MAX)
                return 0;
 
        if (shared_xattrs_count) {
@@ -894,7 +905,7 @@ int erofs_build_shared_xattrs_from_path(struct 
erofs_sb_info *sbi, const char *p
                return -EINVAL;
        }
 
-       ret = erofs_count_all_xattrs_from_path(path);
+       ret = erofs_count_all_xattrs_from_path(sbi, path);
        if (ret)
                return ret;
 
@@ -957,6 +968,7 @@ out:
 
 char *erofs_export_xattr_ibody(struct erofs_inode *inode)
 {
+       struct erofs_configure *cfg = inode->sbi->bt_args->cfg;
        struct list_head *ixattrs = &inode->i_xattrs;
        unsigned int size = inode->xattr_isize;
        struct inode_xattr_node *node, *n;
@@ -972,7 +984,7 @@ char *erofs_export_xattr_ibody(struct erofs_inode *inode)
        header = (struct erofs_xattr_ibody_header *)buf;
        header->h_shared_count = 0;
 
-       if (g_cfg.c_xattr_name_filter) {
+       if (cfg->c_xattr_name_filter) {
                u32 name_filter = 0;
                int hashbit;
                unsigned int base_len;
diff --git a/mkfs/main.c b/mkfs/main.c
index 8ca1050..edfb4c2 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -215,10 +215,12 @@ static void usage(int argc, char **argv)
        );
 }
 
-static void version(void)
+static void version(struct erofs_sb_info *sbi)
 {
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
+
        printf("mkfs.erofs (erofs-utils) %s\navailable compressors: ",
-              g_cfg.c_version);
+              cfg->c_version);
        print_available_compressors(stdout, ", ");
 }
 
@@ -240,32 +242,41 @@ static LIST_HEAD(rebuild_src_list);
 static u8 fixeduuid[16];
 static bool valid_fixeduuid;
 
-static int erofs_mkfs_feat_set_legacy_compress(bool en, const char *val,
+static int erofs_mkfs_feat_set_legacy_compress(struct erofs_sb_info *sbi,
+                                              bool en, const char *val,
                                               unsigned int vallen)
 {
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
+
        if (vallen)
                return -EINVAL;
        /* disable compacted indexes and 0padding */
-       g_cfg.c_legacy_compress = en;
+       cfg->c_legacy_compress = en;
        return 0;
 }
 
-static int erofs_mkfs_feat_set_ztailpacking(bool en, const char *val,
+static int erofs_mkfs_feat_set_ztailpacking(struct erofs_sb_info *sbi,
+                                           bool en, const char *val,
                                            unsigned int vallen)
 {
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
+
        if (vallen)
                return -EINVAL;
-       g_cfg.c_ztailpacking = en;
+       cfg->c_ztailpacking = en;
        return 0;
 }
 
-static int erofs_mkfs_feat_set_fragments(bool en, const char *val,
+static int erofs_mkfs_feat_set_fragments(struct erofs_sb_info *sbi,
+                                        bool en, const char *val,
                                         unsigned int vallen)
 {
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
+
        if (!en) {
                if (vallen)
                        return -EINVAL;
-               g_cfg.c_fragments = false;
+               cfg->c_fragments = false;
                return 0;
        }
 
@@ -279,29 +290,36 @@ static int erofs_mkfs_feat_set_fragments(bool en, const 
char *val,
                }
                pclustersize_packed = i;
        }
-       g_cfg.c_fragments = true;
+       cfg->c_fragments = true;
        return 0;
 }
 
-static int erofs_mkfs_feat_set_all_fragments(bool en, const char *val,
+static int erofs_mkfs_feat_set_all_fragments(struct erofs_sb_info *sbi,
+                                            bool en, const char *val,
                                             unsigned int vallen)
 {
-       g_cfg.c_all_fragments = en;
-       return erofs_mkfs_feat_set_fragments(en, val, vallen);
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
+
+       cfg->c_all_fragments = en;
+       return erofs_mkfs_feat_set_fragments(sbi, en, val, vallen);
 }
 
-static int erofs_mkfs_feat_set_dedupe(bool en, const char *val,
+static int erofs_mkfs_feat_set_dedupe(struct erofs_sb_info *sbi,
+                                     bool en, const char *val,
                                      unsigned int vallen)
 {
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
+
        if (vallen)
                return -EINVAL;
-       g_cfg.c_dedupe = en;
+       cfg->c_dedupe = en;
        return 0;
 }
 
 static struct {
        char *feat;
-       int (*set)(bool en, const char *val, unsigned int len);
+       int (*set)(struct erofs_sb_info *sbi, bool en, const char *val,
+                  unsigned int len);
 } z_erofs_mkfs_features[] = {
        {"legacy-compress", erofs_mkfs_feat_set_legacy_compress},
        {"ztailpacking", erofs_mkfs_feat_set_ztailpacking},
@@ -311,8 +329,10 @@ static struct {
        {NULL, NULL},
 };
 
-static int parse_extended_opts(const char *opts)
+static int parse_extended_opts(struct erofs_sb_info *sbi, const char *opts)
 {
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
+
 #define MATCH_EXTENTED_OPT(opt, token, keylen) \
        (keylen == strlen(opt) && !memcmp(token, opt, keylen))
 
@@ -356,12 +376,12 @@ static int parse_extended_opts(const char *opts)
                if (MATCH_EXTENTED_OPT("force-inode-compact", token, keylen)) {
                        if (vallen)
                                return -EINVAL;
-                       g_cfg.c_force_inodeversion = FORCE_INODE_COMPACT;
-                       g_cfg.c_ignore_mtime = true;
+                       cfg->c_force_inodeversion = FORCE_INODE_COMPACT;
+                       cfg->c_ignore_mtime = true;
                } else if (MATCH_EXTENTED_OPT("force-inode-extended", token, 
keylen)) {
                        if (vallen)
                                return -EINVAL;
-                       g_cfg.c_force_inodeversion = FORCE_INODE_EXTENDED;
+                       cfg->c_force_inodeversion = FORCE_INODE_EXTENDED;
                } else if (MATCH_EXTENTED_OPT("nosbcrc", token, keylen)) {
                        if (vallen)
                                return -EINVAL;
@@ -369,23 +389,23 @@ static int parse_extended_opts(const char *opts)
                } else if (MATCH_EXTENTED_OPT("noinline_data", token, keylen)) {
                        if (vallen)
                                return -EINVAL;
-                       g_cfg.c_inline_data = false;
+                       cfg->c_inline_data = false;
                } else if (MATCH_EXTENTED_OPT("inline_data", token, keylen)) {
                        if (vallen)
                                return -EINVAL;
-                       g_cfg.c_inline_data = !clear;
+                       cfg->c_inline_data = !clear;
                } else if (MATCH_EXTENTED_OPT("force-inode-blockmap", token, 
keylen)) {
                        if (vallen)
                                return -EINVAL;
-                       g_cfg.c_force_chunkformat = FORCE_INODE_BLOCK_MAP;
+                       cfg->c_force_chunkformat = FORCE_INODE_BLOCK_MAP;
                } else if (MATCH_EXTENTED_OPT("force-chunk-indexes", token, 
keylen)) {
                        if (vallen)
                                return -EINVAL;
-                       g_cfg.c_force_chunkformat = FORCE_INODE_CHUNK_INDEXES;
+                       cfg->c_force_chunkformat = FORCE_INODE_CHUNK_INDEXES;
                } else if (MATCH_EXTENTED_OPT("xattr-name-filter", token, 
keylen)) {
                        if (vallen)
                                return -EINVAL;
-                       g_cfg.c_xattr_name_filter = !clear;
+                       cfg->c_xattr_name_filter = !clear;
                } else {
                        int i, err;
 
@@ -393,7 +413,7 @@ static int parse_extended_opts(const char *opts)
                                if 
(!MATCH_EXTENTED_OPT(z_erofs_mkfs_features[i].feat,
                                                        token, keylen))
                                        continue;
-                               err = z_erofs_mkfs_features[i].set(!clear, 
value, vallen);
+                               err = z_erofs_mkfs_features[i].set(sbi, !clear, 
value, vallen);
                                if (err)
                                        return err;
                                break;
@@ -409,7 +429,7 @@ static int parse_extended_opts(const char *opts)
        return 0;
 }
 
-static int mkfs_apply_zfeature_bits(uintmax_t bits)
+static int mkfs_apply_zfeature_bits(struct erofs_sb_info *sbi, uintmax_t bits)
 {
        int i;
 
@@ -420,7 +440,7 @@ static int mkfs_apply_zfeature_bits(uintmax_t bits)
                        erofs_err("unsupported zfeature bit %u", i);
                        return -EINVAL;
                }
-               err = z_erofs_mkfs_features[i].set(bits & 1, NULL, 0);
+               err = z_erofs_mkfs_features[i].set(sbi, bits & 1, NULL, 0);
                if (err) {
                        erofs_err("failed to apply zfeature %s",
                                  z_erofs_mkfs_features[i].feat);
@@ -514,8 +534,9 @@ static int mkfs_parse_one_compress_alg(char *alg,
        return 0;
 }
 
-static int mkfs_parse_compress_algs(char *algs)
+static int mkfs_parse_compress_algs(struct erofs_sb_info *sbi, char *algs)
 {
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
        unsigned int i;
        char *s;
        int ret;
@@ -526,7 +547,7 @@ static int mkfs_parse_compress_algs(char *algs)
                        return -EINVAL;
                }
 
-               ret = mkfs_parse_one_compress_alg(s, &g_cfg.c_compr_opts[i]);
+               ret = mkfs_parse_one_compress_alg(s, &cfg->c_compr_opts[i]);
                if (ret)
                        return ret;
        }
@@ -546,19 +567,21 @@ static void erofs_rebuild_cleanup(void)
        rebuild_src_count = 0;
 }
 
-static int mkfs_parse_options_cfg(int argc, char *argv[])
+static int mkfs_parse_options_cfg(struct erofs_sb_info *sbi, int argc,
+                                 char *argv[])
 {
        char *endptr;
        int opt, i, err;
        bool quiet = false;
        int tarerofs_decoder = 0;
        bool has_timestamp = false;
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
 
        while ((opt = getopt_long(argc, argv, "C:E:L:T:U:b:d:x:z:Vh",
                                  long_options, NULL)) != -1) {
                switch (opt) {
                case 'z':
-                       i = mkfs_parse_compress_algs(optarg);
+                       i = mkfs_parse_compress_algs(sbi, optarg);
                        if (i)
                                return i;
                        break;
@@ -578,7 +601,7 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
                                erofs_err("invalid debug level %d", i);
                                return -EINVAL;
                        }
-                       g_cfg.c_dbg_lvl = i;
+                       cfg->c_dbg_lvl = i;
                        break;
 
                case 'x':
@@ -587,11 +610,11 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
                                erofs_err("invalid xattr tolerance %s", optarg);
                                return -EINVAL;
                        }
-                       g_cfg.c_inline_xattr_tolerance = i;
+                       cfg->c_inline_xattr_tolerance = i;
                        break;
 
                case 'E':
-                       opt = parse_extended_opts(optarg);
+                       opt = parse_extended_opts(sbi, optarg);
                        if (opt)
                                return opt;
                        break;
@@ -607,8 +630,8 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
                        break;
 
                case 'T':
-                       g_cfg.c_unix_timestamp = strtoull(optarg, &endptr, 0);
-                       if (g_cfg.c_unix_timestamp == -1 || *endptr != '\0') {
+                       cfg->c_unix_timestamp = strtoull(optarg, &endptr, 0);
+                       if (cfg->c_unix_timestamp == -1 || *endptr != '\0') {
                                erofs_err("invalid UNIX timestamp %s", optarg);
                                return -EINVAL;
                        }
@@ -639,37 +662,37 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
                        break;
 
                case 4:
-                       opt = erofs_selabel_open(optarg);
+                       opt = erofs_selabel_open(sbi, optarg);
                        if (opt && opt != -EBUSY)
                                return opt;
                        break;
                case 5:
-                       g_cfg.c_uid = strtoul(optarg, &endptr, 0);
-                       if (g_cfg.c_uid == -1 || *endptr != '\0') {
+                       cfg->c_uid = strtoul(optarg, &endptr, 0);
+                       if (cfg->c_uid == -1 || *endptr != '\0') {
                                erofs_err("invalid uid %s", optarg);
                                return -EINVAL;
                        }
                        break;
                case 6:
-                       g_cfg.c_gid = strtoul(optarg, &endptr, 0);
-                       if (g_cfg.c_gid == -1 || *endptr != '\0') {
+                       cfg->c_gid = strtoul(optarg, &endptr, 0);
+                       if (cfg->c_gid == -1 || *endptr != '\0') {
                                erofs_err("invalid gid %s", optarg);
                                return -EINVAL;
                        }
                        break;
                case 7:
-                       g_cfg.c_uid = g_cfg.c_gid = 0;
+                       cfg->c_uid = cfg->c_gid = 0;
                        break;
 #ifndef NDEBUG
                case 8:
-                       g_cfg.c_random_pclusterblks = true;
+                       cfg->c_random_pclusterblks = true;
                        break;
                case 18:
-                       g_cfg.c_random_algorithms = true;
+                       cfg->c_random_algorithms = true;
                        break;
 #endif
                case 9:
-                       g_cfg.c_max_decompressed_extent_bytes =
+                       cfg->c_max_decompressed_extent_bytes =
                                strtoul(optarg, &endptr, 0);
                        if (*endptr != '\0') {
                                erofs_err("invalid maximum uncompressed extent 
size %s",
@@ -678,24 +701,24 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
                        }
                        break;
                case 10:
-                       g_cfg.c_compress_hints_file = optarg;
+                       cfg->c_compress_hints_file = optarg;
                        break;
                case 512:
-                       g_cfg.mount_point = optarg;
+                       cfg->mount_point = optarg;
                        /* all trailing '/' should be deleted */
-                       opt = strlen(g_cfg.mount_point);
+                       opt = strlen(cfg->mount_point);
                        if (opt && optarg[opt - 1] == '/')
                                optarg[opt - 1] = '\0';
                        break;
 #ifdef WITH_ANDROID
                case 513:
-                       g_cfg.target_out_path = optarg;
+                       cfg->target_out_path = optarg;
                        break;
                case 514:
-                       g_cfg.fs_config_file = optarg;
+                       cfg->fs_config_file = optarg;
                        break;
                case 515:
-                       g_cfg.block_list_file = optarg;
+                       cfg->block_list_file = optarg;
                        break;
 #endif
                case 'C':
@@ -713,8 +736,8 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
                                erofs_err("invalid chunksize %s", optarg);
                                return -EINVAL;
                        }
-                       g_cfg.c_chunkbits = ilog2(i);
-                       if ((1 << g_cfg.c_chunkbits) != i) {
+                       cfg->c_chunkbits = ilog2(i);
+                       if ((1 << cfg->c_chunkbits) != i) {
                                erofs_err("chunksize %s must be a power of two",
                                          optarg);
                                return -EINVAL;
@@ -725,17 +748,17 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
                        quiet = true;
                        break;
                case 13:
-                       g_cfg.c_blobdev_path = optarg;
+                       cfg->c_blobdev_path = optarg;
                        break;
                case 14:
-                       g_cfg.c_ignore_mtime = true;
+                       cfg->c_ignore_mtime = true;
                        break;
                case 15:
-                       g_cfg.c_ignore_mtime = false;
+                       cfg->c_ignore_mtime = false;
                        break;
                case 16:
                        errno = 0;
-                       g_cfg.c_uid_offset = strtoll(optarg, &endptr, 0);
+                       cfg->c_uid_offset = strtoll(optarg, &endptr, 0);
                        if (errno || *endptr != '\0') {
                                erofs_err("invalid uid offset %s", optarg);
                                return -EINVAL;
@@ -743,7 +766,7 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
                        break;
                case 17:
                        errno = 0;
-                       g_cfg.c_gid_offset = strtoll(optarg, &endptr, 0);
+                       cfg->c_gid_offset = strtoll(optarg, &endptr, 0);
                        if (errno || *endptr != '\0') {
                                erofs_err("invalid gid offset %s", optarg);
                                return -EINVAL;
@@ -757,7 +780,7 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
                                          erofs_strerror(opt));
                                return opt;
                        }
-                       g_cfg.c_extra_ea_name_prefixes = true;
+                       cfg->c_extra_ea_name_prefixes = true;
                        break;
                case 20:
                        mkfs_parse_tar_cfg(optarg);
@@ -767,9 +790,9 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
                        break;
                case 516:
                        if (!optarg || !strcmp(optarg, "1"))
-                               g_cfg.c_ovlfs_strip = true;
+                               cfg->c_ovlfs_strip = true;
                        else
-                               g_cfg.c_ovlfs_strip = false;
+                               cfg->c_ovlfs_strip = false;
                        break;
                case 517:
                        g_sbi.bdev.offset = strtoull(optarg, &endptr, 0);
@@ -788,16 +811,16 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
                case 520: {
                        unsigned int processors;
 
-                       g_cfg.c_mt_workers = strtoul(optarg, &endptr, 0);
+                       cfg->c_mt_workers = strtoul(optarg, &endptr, 0);
                        if (errno || *endptr != '\0') {
                                erofs_err("invalid worker number %s", optarg);
                                return -EINVAL;
                        }
 
                        processors = erofs_get_available_processors();
-                       if (g_cfg.c_mt_workers > processors)
+                       if (cfg->c_mt_workers > processors)
                                erofs_warn("%d workers exceed %d processors, 
potentially impacting performance.",
-                                          g_cfg.c_mt_workers, processors);
+                                          cfg->c_mt_workers, processors);
                        break;
                }
 #endif
@@ -807,7 +830,7 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
                                erofs_err("invalid zfeature bits %s", optarg);
                                return -EINVAL;
                        }
-                       err = mkfs_apply_zfeature_bits(i);
+                       err = mkfs_apply_zfeature_bits(sbi, i);
                        if (err)
                                return err;
                        break;
@@ -828,20 +851,20 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
                        incremental_mode = (opt == 523);
                        break;
                case 524:
-                       g_cfg.c_root_xattr_isize = strtoull(optarg, &endptr, 0);
+                       cfg->c_root_xattr_isize = strtoull(optarg, &endptr, 0);
                        if (*endptr != '\0') {
                                erofs_err("invalid the minimum inline xattr 
size %s", optarg);
                                return -EINVAL;
                        }
                        break;
                case 525:
-                       g_cfg.c_timeinherit = TIMESTAMP_NONE;
+                       cfg->c_timeinherit = TIMESTAMP_NONE;
                        break;
                case 526:
-                       g_cfg.c_timeinherit = TIMESTAMP_FIXED;
+                       cfg->c_timeinherit = TIMESTAMP_FIXED;
                        break;
                case 'V':
-                       version();
+                       version(sbi);
                        exit(0);
                case 'h':
                        usage(argc, argv);
@@ -852,14 +875,14 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
                }
        }
 
-       if (g_cfg.c_blobdev_path && g_cfg.c_chunkbits < g_sbi.blkszbits) {
+       if (cfg->c_blobdev_path && cfg->c_chunkbits < g_sbi.blkszbits) {
                erofs_err("--blobdev must be used together with --chunksize");
                return -EINVAL;
        }
 
        /* TODO: can be implemented with (deviceslot) mapped_blkaddr */
-       if (g_cfg.c_blobdev_path &&
-           g_cfg.c_force_chunkformat == FORCE_INODE_BLOCK_MAP) {
+       if (cfg->c_blobdev_path &&
+           cfg->c_force_chunkformat == FORCE_INODE_BLOCK_MAP) {
                erofs_err("--blobdev cannot work with block map currently");
                return -EINVAL;
        }
@@ -869,8 +892,8 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
                return -EINVAL;
        }
 
-       g_cfg.c_img_path = strdup(argv[optind++]);
-       if (!g_cfg.c_img_path)
+       cfg->c_img_path = strdup(argv[optind++]);
+       if (!cfg->c_img_path)
                return -ENOMEM;
 
        if (optind >= argc) {
@@ -894,18 +917,18 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
        } else {
                struct stat st;
 
-               g_cfg.c_src_path = realpath(argv[optind++], NULL);
-               if (!g_cfg.c_src_path) {
+               cfg->c_src_path = realpath(argv[optind++], NULL);
+               if (!cfg->c_src_path) {
                        erofs_err("failed to parse source directory: %s",
                                  erofs_strerror(-errno));
                        return -ENOENT;
                }
 
                if (tar_mode) {
-                       int fd = open(g_cfg.c_src_path, O_RDONLY);
+                       int fd = open(cfg->c_src_path, O_RDONLY);
 
                        if (fd < 0) {
-                               erofs_err("failed to open file: %s", 
g_cfg.c_src_path);
+                               erofs_err("failed to open file: %s", 
cfg->c_src_path);
                                return -errno;
                        }
                        err = erofs_iostream_open(&erofstar.ios, fd,
@@ -924,17 +947,17 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
                                erofstar.ios.dumpfd = fd;
                        }
                } else {
-                       err = lstat(g_cfg.c_src_path, &st);
+                       err = lstat(cfg->c_src_path, &st);
                        if (err)
                                return -errno;
                        if (S_ISDIR(st.st_mode))
-                               erofs_set_fs_root(g_cfg.c_src_path);
+                               erofs_set_fs_root(cfg->c_src_path);
                        else
                                rebuild_mode = true;
                }
 
                if (rebuild_mode) {
-                       char *srcpath = g_cfg.c_src_path;
+                       char *srcpath = cfg->c_src_path;
                        struct erofs_sb_info *src;
 
                        do {
@@ -961,11 +984,11 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
                }
        }
        if (quiet) {
-               g_cfg.c_dbg_lvl = EROFS_ERR;
-               g_cfg.c_showprogress = false;
+               cfg->c_dbg_lvl = EROFS_ERR;
+               cfg->c_showprogress = false;
        }
 
-       if (g_cfg.c_compr_opts[0].alg && erofs_blksiz(&g_sbi) != getpagesize())
+       if (cfg->c_compr_opts[0].alg && erofs_blksiz(&g_sbi) != getpagesize())
                erofs_warn("Please note that subpage blocksize with compression 
isn't yet supported in kernel. "
                           "This compressed image will only work with bs = ps = 
%u bytes",
                           erofs_blksiz(&g_sbi));
@@ -977,12 +1000,12 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
                                  pclustersize_max);
                        return -EINVAL;
                }
-               g_cfg.c_mkfs_pclustersize_max = pclustersize_max;
-               g_cfg.c_mkfs_pclustersize_def = g_cfg.c_mkfs_pclustersize_max;
+               cfg->c_mkfs_pclustersize_max = pclustersize_max;
+               cfg->c_mkfs_pclustersize_def = cfg->c_mkfs_pclustersize_max;
        }
-       if (g_cfg.c_chunkbits && g_cfg.c_chunkbits < g_sbi.blkszbits) {
+       if (cfg->c_chunkbits && cfg->c_chunkbits < g_sbi.blkszbits) {
                erofs_err("chunksize %u must be larger than block size",
-                         1u << g_cfg.c_chunkbits);
+                         1u << cfg->c_chunkbits);
                return -EINVAL;
        }
 
@@ -993,35 +1016,38 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
                                  pclustersize_packed);
                        return -EINVAL;
                }
-               g_cfg.c_mkfs_pclustersize_packed = pclustersize_packed;
+               cfg->c_mkfs_pclustersize_packed = pclustersize_packed;
        }
 
-       if (has_timestamp && g_cfg.c_timeinherit == TIMESTAMP_UNSPECIFIED)
-               g_cfg.c_timeinherit = TIMESTAMP_FIXED;
+       if (has_timestamp && cfg->c_timeinherit == TIMESTAMP_UNSPECIFIED)
+               cfg->c_timeinherit = TIMESTAMP_FIXED;
        return 0;
 }
 
-static void erofs_mkfs_default_options(void)
+static void erofs_mkfs_default_options(struct erofs_sb_info *sbi)
 {
-       g_cfg.c_showprogress = true;
-       g_cfg.c_legacy_compress = false;
-       g_cfg.c_inline_data = true;
-       g_cfg.c_xattr_name_filter = true;
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
+
+       cfg->c_showprogress = true;
+       cfg->c_legacy_compress = false;
+       cfg->c_inline_data = true;
+       cfg->c_xattr_name_filter = true;
 #ifdef EROFS_MT_ENABLED
-       g_cfg.c_mt_workers = erofs_get_available_processors();
-       g_cfg.c_mkfs_segment_size = 16ULL * 1024 * 1024;
+       cfg->c_mt_workers = erofs_get_available_processors();
+       cfg->c_mkfs_segment_size = 16ULL * 1024 * 1024;
 #endif
        g_sbi.blkszbits = ilog2(min_t(u32, getpagesize(), 
EROFS_MAX_BLOCK_SIZE));
-       g_cfg.c_mkfs_pclustersize_max = erofs_blksiz(&g_sbi);
-       g_cfg.c_mkfs_pclustersize_def = g_cfg.c_mkfs_pclustersize_max;
+       cfg->c_mkfs_pclustersize_max = erofs_blksiz(&g_sbi);
+       cfg->c_mkfs_pclustersize_def = cfg->c_mkfs_pclustersize_max;
        g_sbi.feature_incompat = EROFS_FEATURE_INCOMPAT_ZERO_PADDING;
        g_sbi.feature_compat = EROFS_FEATURE_COMPAT_SB_CHKSUM |
                             EROFS_FEATURE_COMPAT_MTIME;
 }
 
 /* https://reproducible-builds.org/specs/source-date-epoch/ for more details */
-int parse_source_date_epoch(void)
+int parse_source_date_epoch(struct erofs_sb_info *sbi)
 {
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
        char *source_date_epoch;
        unsigned long long epoch = -1ULL;
        char *endptr;
@@ -1037,19 +1063,21 @@ int parse_source_date_epoch(void)
                return -EINVAL;
        }
 
-       if (g_cfg.c_force_inodeversion != FORCE_INODE_EXTENDED)
+       if (cfg->c_force_inodeversion != FORCE_INODE_EXTENDED)
                erofs_info("SOURCE_DATE_EPOCH is set, forcely generate extended 
inodes instead");
 
-       g_cfg.c_force_inodeversion = FORCE_INODE_EXTENDED;
-       g_cfg.c_unix_timestamp = epoch;
-       g_cfg.c_timeinherit = TIMESTAMP_CLAMPING;
+       cfg->c_force_inodeversion = FORCE_INODE_EXTENDED;
+       cfg->c_unix_timestamp = epoch;
+       cfg->c_timeinherit = TIMESTAMP_CLAMPING;
        return 0;
 }
 
-void erofs_show_progs(int argc, char *argv[])
+void erofs_show_progs(struct erofs_sb_info *sbi, int argc, char *argv[])
 {
-       if (g_cfg.c_dbg_lvl >= EROFS_WARN)
-               printf("%s %s\n", basename(argv[0]), g_cfg.c_version);
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
+
+       if (cfg->c_dbg_lvl >= EROFS_WARN)
+               printf("%s %s\n", basename(argv[0]), cfg->c_version);
 }
 
 static int erofs_mkfs_rebuild_load_trees(struct erofs_inode *root)
@@ -1131,12 +1159,13 @@ static int erofs_mkfs_rebuild_load_trees(struct 
erofs_inode *root)
        return 0;
 }
 
-static void erofs_mkfs_showsummaries(erofs_blk_t nblocks)
+static void erofs_mkfs_showsummaries(struct erofs_sb_info *sbi, erofs_blk_t 
nblocks)
 {
+       struct erofs_configure *cfg = sbi->bt_args->cfg;
        char uuid_str[37] = {};
        char *incr = incremental_mode ? "new" : "total";
 
-       if (!(g_cfg.c_dbg_lvl > EROFS_ERR && g_cfg.c_showprogress))
+       if (!(cfg->c_dbg_lvl > EROFS_ERR && cfg->c_showprogress))
                return;
 
        erofs_uuid_unparse_lower(g_sbi.uuid, uuid_str);
@@ -1161,33 +1190,36 @@ int main(int argc, char **argv)
        FILE *packedfile = NULL;
        FILE *blklst = NULL;
        u32 crc;
+       struct erofs_configure *cfg = NULL;
 
-       erofs_init_configure();
-       erofs_mkfs_default_options();
+       erofs_init_buildtree_cfg(&g_sbi, &g_cfg);
+       erofs_mkfs_default_options(&g_sbi);
 
-       err = mkfs_parse_options_cfg(argc, argv);
-       erofs_show_progs(argc, argv);
+       cfg = g_sbi.bt_args->cfg;
+       BUG_ON(!cfg);
+       err = mkfs_parse_options_cfg(&g_sbi, argc, argv);
+       erofs_show_progs(&g_sbi, argc, argv);
        if (err) {
                if (err == -EINVAL)
                        fprintf(stderr, "Try '%s --help' for more 
information.\n", argv[0]);
                return 1;
        }
 
-       err = parse_source_date_epoch();
+       err = parse_source_date_epoch(&g_sbi);
        if (err) {
                fprintf(stderr, "Try '%s --help' for more information.\n", 
argv[0]);
                return 1;
        }
 
-       if (g_cfg.c_unix_timestamp != -1) {
-               g_sbi.build_time      = g_cfg.c_unix_timestamp;
+       if (cfg->c_unix_timestamp != -1) {
+               g_sbi.build_time      = cfg->c_unix_timestamp;
                g_sbi.build_time_nsec = 0;
        } else if (!gettimeofday(&t, NULL)) {
                g_sbi.build_time      = t.tv_sec;
                g_sbi.build_time_nsec = t.tv_usec;
        }
 
-       err = erofs_dev_open(&g_sbi, g_cfg.c_img_path, O_RDWR |
+       err = erofs_dev_open(&g_sbi, cfg->c_img_path, O_RDWR |
                                (incremental_mode ? 0 : O_TRUNC));
        if (err) {
                fprintf(stderr, "Try '%s --help' for more information.\n", 
argv[0]);
@@ -1195,24 +1227,24 @@ int main(int argc, char **argv)
        }
 
 #ifdef WITH_ANDROID
-       if (g_cfg.fs_config_file &&
-           load_canned_fs_config(g_cfg.fs_config_file) < 0) {
-               erofs_err("failed to load fs config %s", g_cfg.fs_config_file);
+       if (cfg->fs_config_file &&
+           load_canned_fs_config(cfg->fs_config_file) < 0) {
+               erofs_err("failed to load fs config %s", cfg->fs_config_file);
                return 1;
        }
 
-       if (g_cfg.block_list_file) {
-               blklst = fopen(g_cfg.block_list_file, "w");
+       if (cfg->block_list_file) {
+               blklst = fopen(cfg->block_list_file, "w");
                if (!blklst || erofs_blocklist_open(blklst, false)) {
-                       erofs_err("failed to open %s", g_cfg.block_list_file);
+                       erofs_err("failed to open %s", cfg->block_list_file);
                        return 1;
                }
        }
 #endif
-       erofs_show_config();
-       if (g_cfg.c_fragments || g_cfg.c_extra_ea_name_prefixes) {
-               if (!g_cfg.c_mkfs_pclustersize_packed)
-                       g_cfg.c_mkfs_pclustersize_packed = 
g_cfg.c_mkfs_pclustersize_def;
+       erofs_show_config(cfg);
+       if (cfg->c_fragments || cfg->c_extra_ea_name_prefixes) {
+               if (!cfg->c_mkfs_pclustersize_packed)
+                       cfg->c_mkfs_pclustersize_packed = 
cfg->c_mkfs_pclustersize_def;
 
                packedfile = erofs_packedfile_init();
                if (IS_ERR(packedfile)) {
@@ -1221,7 +1253,7 @@ int main(int argc, char **argv)
                }
        }
 
-       if (g_cfg.c_fragments) {
+       if (cfg->c_fragments) {
                err = z_erofs_fragments_init();
                if (err) {
                        erofs_err("failed to initialize fragments");
@@ -1230,7 +1262,7 @@ int main(int argc, char **argv)
        }
 
 #ifndef NDEBUG
-       if (g_cfg.c_random_pclusterblks)
+       if (cfg->c_random_pclusterblks)
                srand(time(NULL));
 #endif
        if (tar_mode) {
@@ -1325,7 +1357,7 @@ int main(int argc, char **argv)
        err = erofs_load_compress_hints(&g_sbi);
        if (err) {
                erofs_err("failed to load compress hints %s",
-                         g_cfg.c_compress_hints_file);
+                         cfg->c_compress_hints_file);
                goto exit;
        }
 
@@ -1336,10 +1368,10 @@ int main(int argc, char **argv)
                goto exit;
        }
 
-       if (g_cfg.c_dedupe) {
-               if (!g_cfg.c_compr_opts[0].alg) {
+       if (cfg->c_dedupe) {
+               if (!cfg->c_compr_opts[0].alg) {
                        erofs_err("Compression is not enabled.  Turn on 
chunk-based data deduplication instead.");
-                       g_cfg.c_chunkbits = g_sbi.blkszbits;
+                       cfg->c_chunkbits = g_sbi.blkszbits;
                } else {
                        err = z_erofs_dedupe_init(erofs_blksiz(&g_sbi));
                        if (err) {
@@ -1350,14 +1382,14 @@ int main(int argc, char **argv)
                }
        }
 
-       if (g_cfg.c_chunkbits) {
-               err = erofs_blob_init(g_cfg.c_blobdev_path, 1 << 
g_cfg.c_chunkbits);
+       if (cfg->c_chunkbits) {
+               err = erofs_blob_init(cfg->c_blobdev_path, 1 << 
cfg->c_chunkbits);
                if (err)
                        return 1;
        }
 
        if (((erofstar.index_mode && !erofstar.headeronly_mode) &&
-           !erofstar.mapfile) || g_cfg.c_blobdev_path) {
+           !erofstar.mapfile) || cfg->c_blobdev_path) {
                err = erofs_mkfs_init_devices(&g_sbi, 1);
                if (err) {
                        erofs_err("failed to generate device table: %s",
@@ -1397,17 +1429,17 @@ int main(int argc, char **argv)
                if (err)
                        goto exit;
        } else {
-               err = erofs_build_shared_xattrs_from_path(&g_sbi, 
g_cfg.c_src_path);
+               err = erofs_build_shared_xattrs_from_path(&g_sbi, 
cfg->c_src_path);
                if (err) {
                        erofs_err("failed to build shared xattrs: %s",
                                  erofs_strerror(err));
                        goto exit;
                }
 
-               if (g_cfg.c_extra_ea_name_prefixes)
+               if (cfg->c_extra_ea_name_prefixes)
                        erofs_xattr_write_name_prefixes(&g_sbi, packedfile);
 
-               root = erofs_mkfs_build_tree_from_path(&g_sbi, 
g_cfg.c_src_path);
+               root = erofs_mkfs_build_tree_from_path(&g_sbi, cfg->c_src_path);
                if (IS_ERR(root)) {
                        err = PTR_ERR(root);
                        goto exit;
@@ -1418,13 +1450,13 @@ int main(int argc, char **argv)
                g_sbi.devs[0].blocks = BLK_ROUND_UP(&g_sbi, erofstar.offset);
 
        if (erofs_sb_has_fragments(&g_sbi)) {
-               erofs_update_progressinfo("Handling packed data ...");
+               erofs_update_progressinfo(&g_sbi, "Handling packed data ...");
                err = erofs_flush_packed_inode(&g_sbi);
                if (err)
                        goto exit;
        }
 
-       if (erofstar.index_mode || g_cfg.c_chunkbits || g_sbi.extra_devices) {
+       if (erofstar.index_mode || cfg->c_chunkbits || g_sbi.extra_devices) {
                err = erofs_mkfs_dump_blobs(&g_sbi);
                if (err)
                        goto exit;
@@ -1458,7 +1490,7 @@ int main(int argc, char **argv)
 exit:
        if (root)
                erofs_iput(root);
-       z_erofs_compress_exit();
+       z_erofs_compress_exit(&g_sbi);
        z_erofs_dedupe_exit();
        blklst = erofs_blocklist_close();
        if (blklst)
@@ -1466,15 +1498,14 @@ exit:
        erofs_dev_close(&g_sbi);
        erofs_cleanup_compress_hints();
        erofs_cleanup_exclude_rules();
-       if (g_cfg.c_chunkbits)
+       if (cfg->c_chunkbits)
                erofs_blob_exit();
-       if (g_cfg.c_fragments)
+       if (cfg->c_fragments)
                z_erofs_fragments_exit();
        erofs_packedfile_exit();
        erofs_xattr_cleanup_name_prefixes();
        erofs_rebuild_cleanup();
        erofs_diskbuf_exit();
-       erofs_exit_configure();
        if (tar_mode) {
                erofs_iostream_close(&erofstar.ios);
                if (erofstar.ios.dumpfd >= 0)
@@ -1486,8 +1517,9 @@ exit:
                          erofs_strerror(err));
                return 1;
        }
-       erofs_update_progressinfo("Build completed.\n");
-       erofs_mkfs_showsummaries(nblocks);
+       erofs_update_progressinfo(&g_sbi, "Build completed.\n");
+       erofs_mkfs_showsummaries(&g_sbi, nblocks);
+       erofs_exit_buildtree_cfg(&g_sbi);
        erofs_put_super(&g_sbi);
        return 0;
 }
-- 
2.43.5


Reply via email to