All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 0/3] Make erofs-utils more library friendly
@ 2021-11-21  5:39 Kelvin Zhang via Linux-erofs
  2021-11-21  5:39 ` [PATCH v1 1/4] Make erofs_devfd a parameter for most functions Kelvin Zhang via Linux-erofs
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: Kelvin Zhang via Linux-erofs @ 2021-11-21  5:39 UTC (permalink / raw)
  To: linux-erofs mailing list, Li Guifu, Miao Xie, Fang Wei
  Cc: Kelvin Zhang, Chao Yu

EROFS-utils contains several usage of global variables, namely

1. int erofs_devfd, stores the file descriptor to open'ed block devices.
This is referened in many places.
2. struct erofs_sb_info sbi; Stores parsed super block.

These global variables make embedding erofs library diffcult. To make
library usage easier, a series of 3 patches are drafted to refactor away
the global variables. Each patch has been built and tested by calling
mkfs.erofs and ensure the same output is generated.

Kelvin Zhang (3):
  Make erofs_devfd a parameter for most functions
  Mark certain callback function pointers as const
  Make super block info struct a paramater instead of globals

 Android.bp                 |  44 +++++++-
 dump/main.c                |  84 ++++++++------
 fsck/main.c                |  90 +++++++++------
 fuse/dir.c                 |   8 +-
 fuse/main.c                |  19 ++--
 include/erofs/blobchunk.h  |   7 +-
 include/erofs/cache.h      |  15 +--
 include/erofs/compress.h   |  10 +-
 include/erofs/config.h     |  15 +--
 include/erofs/decompress.h |   5 +-
 include/erofs/defs.h       |  21 ++++
 include/erofs/inode.h      |   9 +-
 include/erofs/internal.h   |  72 ++++++------
 include/erofs/io.h         |  48 +++++---
 include/erofs/iterate.h    |  35 ++++++
 include/erofs/xattr.h      |   2 +-
 iterate/main.c             |  51 +++++++++
 lib/blobchunk.c            |  11 +-
 lib/cache.c                |  33 +++---
 lib/compress.c             | 104 ++++++++++-------
 lib/compressor.c           |   9 +-
 lib/compressor.h           |  13 ++-
 lib/compressor_liblzma.c   |   4 +-
 lib/compressor_lz4.c       |   8 +-
 lib/compressor_lz4hc.c     |   6 +-
 lib/config.c               |  64 ++++++-----
 lib/data.c                 |  54 +++++----
 lib/decompress.c           |  12 +-
 lib/inode.c                | 129 ++++++++++++---------
 lib/io.c                   |  74 ++++++------
 lib/iterate.c              | 223 +++++++++++++++++++++++++++++++++++++
 lib/namei.c                |  44 +++++---
 lib/super.c                |  28 ++---
 lib/xattr.c                |  10 +-
 lib/zmap.c                 |  92 +++++++++------
 mkfs/main.c                |  92 +++++++--------
 36 files changed, 1069 insertions(+), 476 deletions(-)
 create mode 100644 include/erofs/iterate.h
 create mode 100644 iterate/main.c
 create mode 100644 lib/iterate.c

-- 
2.34.0.rc2.393.gf8c9666880-goog


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v1 1/4] Make erofs_devfd a parameter for most functions
  2021-11-21  5:39 [PATCH v1 0/3] Make erofs-utils more library friendly Kelvin Zhang via Linux-erofs
@ 2021-11-21  5:39 ` Kelvin Zhang via Linux-erofs
  2021-11-23  7:49   ` Gao Xiang
  2021-11-21  5:39 ` [PATCH v1 2/4] Mark certain callback function pointers as const Kelvin Zhang via Linux-erofs
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 8+ messages in thread
From: Kelvin Zhang via Linux-erofs @ 2021-11-21  5:39 UTC (permalink / raw)
  To: linux-erofs mailing list, Li Guifu, Miao Xie, Fang Wei
  Cc: Kelvin Zhang, Chao Yu

Test: extract system.img from
aosp_cf_x86_64_phone-target_files-7731383.zip , mount it, mkfs.erofs to
generate an EROFS image. Make sure the content is the same before/after
this patch. (Except super block, which has an UUID)

target_files.zip can be downloaded from
https://ci.android.com/builds/branches/aosp-master/grid?head=7934850&tail=7934850

Signed-off-by: Kelvin Zhang <zhangkelvin@google.com>
---
 dump/main.c               | 61 +++++++++++++++--------------
 fsck/main.c               | 65 ++++++++++++++++---------------
 fuse/dir.c                |  7 +++-
 fuse/main.c               | 18 +++++----
 include/erofs/blobchunk.h |  7 +++-
 include/erofs/cache.h     |  7 ++--
 include/erofs/compress.h  |  8 +++-
 include/erofs/config.h    | 15 ++++----
 include/erofs/defs.h      | 21 ++++++++++
 include/erofs/inode.h     |  6 ++-
 include/erofs/internal.h  | 52 +++++++++----------------
 include/erofs/io.h        | 48 ++++++++++++++---------
 lib/blobchunk.c           | 11 ++++--
 lib/cache.c               | 27 ++++++++-----
 lib/compress.c            | 54 ++++++++++++++------------
 lib/compressor_liblzma.c  |  2 +-
 lib/config.c              | 63 ++++++++++++++++++------------
 lib/data.c                | 30 +++++++++------
 lib/decompress.c          |  2 +-
 lib/inode.c               | 81 +++++++++++++++++++++++----------------
 lib/io.c                  | 74 +++++++++++++++++++----------------
 lib/namei.c               | 22 +++++------
 lib/super.c               | 28 +++++++-------
 lib/xattr.c               |  6 ++-
 lib/zmap.c                | 74 +++++++++++++++++++++--------------
 mkfs/main.c               | 39 ++++++++++---------
 26 files changed, 476 insertions(+), 352 deletions(-)

diff --git a/dump/main.c b/dump/main.c
index 401e684..8d0dbd0 100644
--- a/dump/main.c
+++ b/dump/main.c
@@ -85,7 +85,7 @@ static struct erofsdump_feature feature_lists[] = {
 	{ false, EROFS_FEATURE_INCOMPAT_CHUNKED_FILE, "chunked_file" },
 };
 
-static int erofs_read_dir(erofs_nid_t nid, erofs_nid_t parent_nid);
+static int erofs_read_dir(struct erofs_device fd, erofs_nid_t nid, erofs_nid_t parent_nid);
 static inline int erofs_checkdirent(struct erofs_dirent *de,
 		struct erofs_dirent *last_de,
 		u32 maxsize, const char *dname);
@@ -257,7 +257,8 @@ static inline int erofs_checkdirent(struct erofs_dirent *de,
 	return dname_len;
 }
 
-static int erofs_read_dirent(struct erofs_dirent *de,
+static int erofs_read_dirent(
+		struct erofs_device erofs_dev, struct erofs_dirent *de,
 		erofs_nid_t nid, erofs_nid_t parent_nid,
 		const char *dname)
 {
@@ -267,7 +268,7 @@ static int erofs_read_dirent(struct erofs_dirent *de,
 
 	stats.files++;
 	stats.file_category_stat[de->file_type]++;
-	err = erofs_read_inode_from_disk(&inode);
+	err = erofs_read_inode_from_disk(erofs_dev, &inode);
 	if (err) {
 		erofs_err("read file inode from disk failed!");
 		return err;
@@ -288,7 +289,7 @@ static int erofs_read_dirent(struct erofs_dirent *de,
 
 	if ((de->file_type == EROFS_FT_DIR)
 			&& de->nid != nid && de->nid != parent_nid) {
-		err = erofs_read_dir(de->nid, nid);
+		err = erofs_read_dir(erofs_dev, de->nid, nid);
 		if (err) {
 			erofs_err("parse dir nid %llu error occurred\n",
 					de->nid);
@@ -298,14 +299,14 @@ static int erofs_read_dirent(struct erofs_dirent *de,
 	return 0;
 }
 
-static int erofs_read_dir(erofs_nid_t nid, erofs_nid_t parent_nid)
+static int erofs_read_dir(struct erofs_device fd, erofs_nid_t nid, erofs_nid_t parent_nid)
 {
 	int err;
 	erofs_off_t offset;
 	char buf[EROFS_BLKSIZ];
 	struct erofs_inode vi = { .nid = nid };
 
-	err = erofs_read_inode_from_disk(&vi);
+	err = erofs_read_inode_from_disk(fd, &vi);
 	if (err)
 		return err;
 
@@ -317,7 +318,7 @@ static int erofs_read_dir(erofs_nid_t nid, erofs_nid_t parent_nid)
 		struct erofs_dirent *end;
 		unsigned int nameoff;
 
-		err = erofs_pread(&vi, buf, maxsize, offset);
+		err = erofs_pread(fd, &vi, buf, maxsize, offset);
 		if (err)
 			return err;
 
@@ -337,7 +338,7 @@ static int erofs_read_dir(erofs_nid_t nid, erofs_nid_t parent_nid)
 			ret = erofs_checkdirent(de, end, maxsize, dname);
 			if (ret < 0)
 				return ret;
-			ret = erofs_read_dirent(de, nid, parent_nid, dname);
+			ret = erofs_read_dirent(fd, de, nid, parent_nid, dname);
 			if (ret < 0)
 				return ret;
 			++de;
@@ -347,7 +348,7 @@ static int erofs_read_dir(erofs_nid_t nid, erofs_nid_t parent_nid)
 	return 0;
 }
 
-static int erofs_get_pathname(erofs_nid_t nid, erofs_nid_t parent_nid,
+static int erofs_get_pathname(struct erofs_device fd, erofs_nid_t nid, erofs_nid_t parent_nid,
 		erofs_nid_t target, char *path, unsigned int pos)
 {
 	int err;
@@ -359,7 +360,7 @@ static int erofs_get_pathname(erofs_nid_t nid, erofs_nid_t parent_nid,
 	if (target == sbi.root_nid)
 		return 0;
 
-	err = erofs_read_inode_from_disk(&inode);
+	err = erofs_read_inode_from_disk(fd, &inode);
 	if (err) {
 		erofs_err("read inode failed @ nid %llu", nid | 0ULL);
 		return err;
@@ -373,7 +374,7 @@ static int erofs_get_pathname(erofs_nid_t nid, erofs_nid_t parent_nid,
 		struct erofs_dirent *end;
 		unsigned int nameoff;
 
-		err = erofs_pread(&inode, buf, maxsize, offset);
+		err = erofs_pread(fd, &inode, buf, maxsize, offset);
 		if (err)
 			return err;
 
@@ -399,7 +400,7 @@ static int erofs_get_pathname(erofs_nid_t nid, erofs_nid_t parent_nid,
 					de->nid != parent_nid &&
 					de->nid != nid) {
 				memcpy(path + pos, dname, len);
-				err = erofs_get_pathname(de->nid, nid,
+				err = erofs_get_pathname(fd, de->nid, nid,
 						target, path, pos + len);
 				if (!err)
 					return 0;
@@ -412,15 +413,18 @@ static int erofs_get_pathname(erofs_nid_t nid, erofs_nid_t parent_nid,
 	return -1;
 }
 
-static int erofsdump_map_blocks(struct erofs_inode *inode,
-		struct erofs_map_blocks *map, int flags)
+static int erofsdump_map_blocks(
+	struct erofs_device erofs_dev,
+	struct erofs_inode *inode,
+	struct erofs_map_blocks *map,
+	int flags)
 {
 	if (erofs_inode_is_data_compressed(inode->datalayout))
-		return z_erofs_map_blocks_iter(inode, map, flags);
-	return erofs_map_blocks(inode, map, flags);
+		return z_erofs_map_blocks_iter(erofs_dev, inode, map, flags);
+	return erofs_map_blocks(erofs_dev, inode, map, flags);
 }
 
-static void erofsdump_show_fileinfo(bool show_extent)
+static void erofsdump_show_fileinfo(struct erofs_device fd, bool show_extent)
 {
 	int err, i;
 	erofs_off_t size;
@@ -435,7 +439,7 @@ static void erofsdump_show_fileinfo(bool show_extent)
 		.m_la = 0,
 	};
 
-	err = erofs_read_inode_from_disk(&inode);
+	err = erofs_read_inode_from_disk(fd, &inode);
 	if (err) {
 		erofs_err("read inode failed @ nid %llu", inode.nid | 0ULL);
 		return;
@@ -447,7 +451,7 @@ static void erofsdump_show_fileinfo(bool show_extent)
 		return;
 	}
 
-	err = erofs_get_pathname(sbi.root_nid, sbi.root_nid,
+	err = erofs_get_pathname(fd, sbi.root_nid, sbi.root_nid,
 				 inode.nid, path, 0);
 	if (err < 0) {
 		erofs_err("file path not found @ nid %llu", inode.nid | 0ULL);
@@ -480,7 +484,7 @@ static void erofsdump_show_fileinfo(bool show_extent)
 
 	fprintf(stdout, "\n Ext:   logical offset   |  length :     physical offset    |  length \n");
 	while (map.m_la < inode.i_size) {
-		err = erofsdump_map_blocks(&inode, &map,
+		err = erofsdump_map_blocks(fd, &inode, &map,
 				EROFS_GET_BLOCKS_FIEMAP);
 		if (err) {
 			erofs_err("get file blocks range failed");
@@ -580,11 +584,11 @@ static void erofsdump_file_statistic(void)
 			stats.compress_rate);
 }
 
-static void erofsdump_print_statistic(void)
+static void erofsdump_print_statistic(struct erofs_device fd)
 {
 	int err;
 
-	err = erofs_read_dir(sbi.root_nid, sbi.root_nid);
+	err = erofs_read_dir(fd, sbi.root_nid, sbi.root_nid);
 	if (err) {
 		erofs_err("read dir failed");
 		return;
@@ -638,8 +642,9 @@ static void erofsdump_show_superblock(void)
 int main(int argc, char **argv)
 {
 	int err;
+	struct erofs_device erofs_dev;
 
-	erofs_init_configure();
+	erofs_init_global_configure();
 	err = erofsdump_parse_options_cfg(argc, argv);
 	if (err) {
 		if (err == -EINVAL)
@@ -647,13 +652,13 @@ int main(int argc, char **argv)
 		goto exit;
 	}
 
-	err = dev_open_ro(cfg.c_img_path);
+	err = dev_open_ro(cfg.c_img_path, &erofs_dev);
 	if (err) {
 		erofs_err("failed to open image file");
 		goto exit;
 	}
 
-	err = erofs_read_superblock();
+	err = erofs_read_superblock(erofs_dev, &sbi);
 	if (err) {
 		erofs_err("failed to read superblock");
 		goto exit;
@@ -667,7 +672,7 @@ int main(int argc, char **argv)
 		erofsdump_show_superblock();
 
 	if (dumpcfg.show_statistics)
-		erofsdump_print_statistic();
+		erofsdump_print_statistic(erofs_dev);
 
 	if (dumpcfg.show_extent && !dumpcfg.show_inode) {
 		usage();
@@ -675,9 +680,9 @@ int main(int argc, char **argv)
 	}
 
 	if (dumpcfg.show_inode)
-		erofsdump_show_fileinfo(dumpcfg.show_extent);
+		erofsdump_show_fileinfo(erofs_dev, dumpcfg.show_extent);
 
 exit:
-	erofs_exit_configure();
+	erofs_exit_global_configure();
 	return err;
 }
diff --git a/fsck/main.c b/fsck/main.c
index d81d600..b69333b 100644
--- a/fsck/main.c
+++ b/fsck/main.c
@@ -6,11 +6,12 @@
 #include <stdlib.h>
 #include <getopt.h>
 #include <time.h>
+#include "erofs/config.h"
 #include "erofs/print.h"
 #include "erofs/io.h"
 #include "erofs/decompress.h"
 
-static void erofs_check_inode(erofs_nid_t pnid, erofs_nid_t nid);
+static void erofs_check_inode(struct erofs_device devfd, erofs_nid_t pnid, erofs_nid_t nid);
 
 struct erofsfsck_cfg {
 	bool corrupted;
@@ -90,14 +91,16 @@ static int erofsfsck_parse_options_cfg(int argc, char **argv)
 	return 0;
 }
 
-static int erofs_check_sb_chksum(void)
+static int erofs_check_sb_chksum(
+	struct erofs_device erofs_dev,
+	struct erofs_sb_info *sbi)
 {
 	int ret;
 	u8 buf[EROFS_BLKSIZ];
 	u32 crc;
 	struct erofs_super_block *sb;
 
-	ret = blk_read(buf, 0, 1);
+	ret = blk_read(erofs_dev, buf, 0, 1);
 	if (ret) {
 		erofs_err("failed to read superblock to check checksum: %d",
 			  ret);
@@ -108,9 +111,9 @@ static int erofs_check_sb_chksum(void)
 	sb->checksum = 0;
 
 	crc = erofs_crc32c(~0, (u8 *)sb, EROFS_BLKSIZ - EROFS_SUPER_OFFSET);
-	if (crc != sbi.checksum) {
+	if (crc != sbi->checksum) {
 		erofs_err("superblock chksum doesn't match: saved(%08xh) calculated(%08xh)",
-			  sbi.checksum, crc);
+			  sbi->checksum, crc);
 		fsckcfg.corrupted = true;
 		return -1;
 	}
@@ -135,7 +138,7 @@ static bool check_special_dentry(struct erofs_dirent *de,
 	return true;
 }
 
-static int traverse_dirents(erofs_nid_t pnid, erofs_nid_t nid,
+static int traverse_dirents(struct erofs_device devfd, erofs_nid_t pnid, erofs_nid_t nid,
 			    void *dentry_blk, erofs_blk_t block,
 			    unsigned int next_nameoff, unsigned int maxsize)
 {
@@ -209,7 +212,7 @@ static int traverse_dirents(erofs_nid_t pnid, erofs_nid_t nid,
 				goto out;
 			}
 		} else {
-			erofs_check_inode(nid, de->nid);
+			erofs_check_inode(devfd, nid, de->nid);
 		}
 
 		if (fsckcfg.corrupted) {
@@ -232,7 +235,8 @@ out:
 	return ret;
 }
 
-static int verify_uncompressed_inode(struct erofs_inode *inode)
+static int verify_uncompressed_inode(
+	struct erofs_device erofs_dev, struct erofs_inode *inode)
 {
 	struct erofs_map_blocks map = {
 		.index = UINT_MAX,
@@ -243,7 +247,7 @@ static int verify_uncompressed_inode(struct erofs_inode *inode)
 
 	while (ptr < inode->i_size) {
 		map.m_la = ptr;
-		ret = erofs_map_blocks(inode, &map, 0);
+		ret = erofs_map_blocks(erofs_dev, inode, &map, 0);
 		if (ret)
 			return ret;
 
@@ -270,7 +274,7 @@ static int verify_uncompressed_inode(struct erofs_inode *inode)
 	return 0;
 }
 
-static int verify_compressed_inode(struct erofs_inode *inode)
+static int verify_compressed_inode(struct erofs_device erofs_dev, struct erofs_inode *inode)
 {
 	struct erofs_map_blocks map = {
 		.index = UINT_MAX,
@@ -284,7 +288,7 @@ static int verify_compressed_inode(struct erofs_inode *inode)
 	while (end > 0) {
 		map.m_la = end - 1;
 
-		ret = z_erofs_map_blocks_iter(inode, &map, 0);
+		ret = z_erofs_map_blocks_iter(erofs_dev, inode, &map, 0);
 		if (ret)
 			goto out;
 
@@ -317,7 +321,7 @@ static int verify_compressed_inode(struct erofs_inode *inode)
 			BUG_ON(!buffer);
 		}
 
-		ret = dev_read(raw, map.m_pa, map.m_plen);
+		ret = dev_read(erofs_dev, raw, map.m_pa, map.m_plen);
 		if (ret < 0) {
 			erofs_err("failed to read compressed data of m_pa %" PRIu64 ", m_plen %" PRIu64 " @ nid %llu: %d",
 				  map.m_pa, map.m_plen, inode->nid | 0ULL, ret);
@@ -355,7 +359,7 @@ out:
 	return ret < 0 ? ret : 0;
 }
 
-static int erofs_verify_xattr(struct erofs_inode *inode)
+static int erofs_verify_xattr(struct erofs_device erofs_dev, struct erofs_inode *inode)
 {
 	unsigned int xattr_hdr_size = sizeof(struct erofs_xattr_ibody_header);
 	unsigned int xattr_entry_size = sizeof(struct erofs_xattr_entry);
@@ -381,7 +385,7 @@ static int erofs_verify_xattr(struct erofs_inode *inode)
 	}
 
 	addr = iloc(inode->nid) + inode->inode_isize;
-	ret = dev_read(buf, addr, xattr_hdr_size);
+	ret = dev_read(erofs_dev, buf, addr, xattr_hdr_size);
 	if (ret < 0) {
 		erofs_err("failed to read xattr header @ nid %llu: %d",
 			  inode->nid | 0ULL, ret);
@@ -411,7 +415,7 @@ static int erofs_verify_xattr(struct erofs_inode *inode)
 	while (remaining > 0) {
 		unsigned int entry_sz;
 
-		ret = dev_read(buf, addr, xattr_entry_size);
+		ret = dev_read(erofs_dev, buf, addr, xattr_entry_size);
 		if (ret) {
 			erofs_err("failed to read xattr entry @ nid %llu: %d",
 				  inode->nid | 0ULL, ret);
@@ -433,7 +437,7 @@ out:
 	return ret;
 }
 
-static int erofs_verify_inode_data(struct erofs_inode *inode)
+static int erofs_verify_inode_data(struct erofs_device erofs_dev, struct erofs_inode *inode)
 {
 	int ret;
 
@@ -444,11 +448,11 @@ static int erofs_verify_inode_data(struct erofs_inode *inode)
 	case EROFS_INODE_FLAT_PLAIN:
 	case EROFS_INODE_FLAT_INLINE:
 	case EROFS_INODE_CHUNK_BASED:
-		ret = verify_uncompressed_inode(inode);
+		ret = verify_uncompressed_inode(erofs_dev, inode);
 		break;
 	case EROFS_INODE_FLAT_COMPRESSION_LEGACY:
 	case EROFS_INODE_FLAT_COMPRESSION:
-		ret = verify_compressed_inode(inode);
+		ret = verify_compressed_inode(erofs_dev, inode);
 		break;
 	default:
 		ret = -EINVAL;
@@ -462,7 +466,7 @@ static int erofs_verify_inode_data(struct erofs_inode *inode)
 	return ret;
 }
 
-static void erofs_check_inode(erofs_nid_t pnid, erofs_nid_t nid)
+static void erofs_check_inode(struct erofs_device erofs_dev, erofs_nid_t pnid, erofs_nid_t nid)
 {
 	int ret;
 	struct erofs_inode inode;
@@ -472,7 +476,7 @@ static void erofs_check_inode(erofs_nid_t pnid, erofs_nid_t nid)
 	erofs_dbg("check inode: nid(%llu)", nid | 0ULL);
 
 	inode.nid = nid;
-	ret = erofs_read_inode_from_disk(&inode);
+	ret = erofs_read_inode_from_disk(erofs_dev, &inode);
 	if (ret) {
 		if (ret == -EIO)
 			erofs_err("I/O error occurred when reading nid(%llu)",
@@ -481,12 +485,12 @@ static void erofs_check_inode(erofs_nid_t pnid, erofs_nid_t nid)
 	}
 
 	/* verify xattr field */
-	ret = erofs_verify_xattr(&inode);
+	ret = erofs_verify_xattr(erofs_dev,&inode);
 	if (ret)
 		goto out;
 
 	/* verify data chunk layout */
-	ret = erofs_verify_inode_data(&inode);
+	ret = erofs_verify_inode_data(erofs_dev, &inode);
 	if (ret)
 		goto out;
 
@@ -502,7 +506,7 @@ static void erofs_check_inode(erofs_nid_t pnid, erofs_nid_t nid)
 
 		unsigned int nameoff;
 
-		ret = erofs_pread(&inode, buf, maxsize, offset);
+		ret = erofs_pread(erofs_dev, &inode, buf, maxsize, offset);
 		if (ret) {
 			erofs_err("I/O error occurred when reading dirents @ nid %llu, block %u: %d",
 				  nid | 0ULL, block, ret);
@@ -518,7 +522,7 @@ static void erofs_check_inode(erofs_nid_t pnid, erofs_nid_t nid)
 			goto out;
 		}
 
-		ret = traverse_dirents(pnid, nid, buf, block,
+		ret = traverse_dirents(erofs_dev, pnid, nid, buf, block,
 				       nameoff, maxsize);
 		if (ret)
 			goto out;
@@ -533,8 +537,9 @@ out:
 int main(int argc, char **argv)
 {
 	int err;
+	struct erofs_device erofs_dev;
 
-	erofs_init_configure();
+	erofs_init_global_configure();
 
 	fsckcfg.corrupted = false;
 	fsckcfg.print_comp_ratio = false;
@@ -549,24 +554,24 @@ int main(int argc, char **argv)
 		goto exit;
 	}
 
-	err = dev_open_ro(cfg.c_img_path);
+	err = dev_open_ro(cfg.c_img_path, &erofs_dev);
 	if (err) {
 		erofs_err("failed to open image file");
 		goto exit;
 	}
 
-	err = erofs_read_superblock();
+	err = erofs_read_superblock(erofs_dev, &sbi);
 	if (err) {
 		erofs_err("failed to read superblock");
 		goto exit;
 	}
 
-	if (erofs_sb_has_sb_chksum() && erofs_check_sb_chksum()) {
+	if (erofs_sb_has_sb_chksum(&sbi) && erofs_check_sb_chksum(erofs_dev, &sbi)) {
 		erofs_err("failed to verify superblock checksum");
 		goto exit;
 	}
 
-	erofs_check_inode(sbi.root_nid, sbi.root_nid);
+	erofs_check_inode(erofs_dev, sbi.root_nid, sbi.root_nid);
 
 	if (fsckcfg.corrupted) {
 		erofs_err("Found some filesystem corruption");
@@ -583,6 +588,6 @@ int main(int argc, char **argv)
 	}
 
 exit:
-	erofs_exit_configure();
+	erofs_exit_global_configure();
 	return err ? 1 : 0;
 }
diff --git a/fuse/dir.c b/fuse/dir.c
index bc8735b..494c915 100644
--- a/fuse/dir.c
+++ b/fuse/dir.c
@@ -8,6 +8,9 @@
 #include "erofs/internal.h"
 #include "erofs/print.h"
 
+// defined in fuse/main.c
+extern struct erofs_device erofs_dev;
+
 static int erofs_fill_dentries(struct erofs_inode *dir,
 			       fuse_fill_dir_t filler, void *buf,
 			       void *dblk, unsigned int nameoff,
@@ -57,7 +60,7 @@ int erofsfuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
 
 	erofs_dbg("readdir:%s offset=%llu", path, (long long)offset);
 
-	ret = erofs_ilookup(path, &dir);
+	ret = erofs_ilookup(erofs_dev, path, &dir);
 	if (ret)
 		return ret;
 
@@ -76,7 +79,7 @@ int erofsfuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
 
 		maxsize = min_t(unsigned int, EROFS_BLKSIZ,
 				dir.i_size - pos);
-		ret = erofs_pread(&dir, dblk, maxsize, pos);
+		ret = erofs_pread(erofs_dev, &dir, dblk, maxsize, pos);
 		if (ret)
 			return ret;
 
diff --git a/fuse/main.c b/fuse/main.c
index 8137421..b3e1a3d 100644
--- a/fuse/main.c
+++ b/fuse/main.c
@@ -13,6 +13,8 @@
 #include "erofs/print.h"
 #include "erofs/io.h"
 
+struct erofs_device erofs_dev;
+
 int erofsfuse_readdir(const char *path, void *buffer, fuse_fill_dir_t filler,
 		      off_t offset, struct fuse_file_info *fi);
 
@@ -38,7 +40,7 @@ static int erofsfuse_getattr(const char *path, struct stat *stbuf)
 	int ret;
 
 	erofs_dbg("getattr(%s)", path);
-	ret = erofs_ilookup(path, &vi);
+	ret = erofs_ilookup(erofs_dev, path, &vi);
 	if (ret)
 		return -ENOENT;
 
@@ -65,11 +67,11 @@ static int erofsfuse_read(const char *path, char *buffer,
 
 	erofs_dbg("path:%s size=%zd offset=%llu", path, size, (long long)offset);
 
-	ret = erofs_ilookup(path, &vi);
+	ret = erofs_ilookup(erofs_dev, path, &vi);
 	if (ret)
 		return ret;
 
-	ret = erofs_pread(&vi, buffer, size, offset);
+	ret = erofs_pread(erofs_dev, &vi, buffer, size, offset);
 	if (ret)
 		return ret;
 	if (offset >= vi.i_size)
@@ -199,7 +201,7 @@ int main(int argc, char *argv[])
 	int ret;
 	struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
 
-	erofs_init_configure();
+	erofs_init_global_configure();
 	fprintf(stderr, "%s %s\n", basename(argv[0]), cfg.c_version);
 
 #if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE)
@@ -223,13 +225,13 @@ int main(int argc, char *argv[])
 		cfg.c_dbg_lvl = EROFS_DBG;
 
 	erofsfuse_dumpcfg();
-	ret = dev_open_ro(fusecfg.disk);
+	ret = dev_open_ro(fusecfg.disk, &erofs_dev);
 	if (ret) {
 		fprintf(stderr, "failed to open: %s\n", fusecfg.disk);
 		goto err_fuse_free_args;
 	}
 
-	ret = erofs_read_superblock();
+	ret = erofs_read_superblock(erofs_dev, &sbi);
 	if (ret) {
 		fprintf(stderr, "failed to read erofs super block\n");
 		goto err_dev_close;
@@ -237,10 +239,10 @@ int main(int argc, char *argv[])
 
 	ret = fuse_main(args.argc, args.argv, &erofs_ops, NULL);
 err_dev_close:
-	dev_close();
+	dev_close(&erofs_dev);
 err_fuse_free_args:
 	fuse_opt_free_args(&args);
 err:
-	erofs_exit_configure();
+	erofs_exit_global_configure();
 	return ret ? EXIT_FAILURE : EXIT_SUCCESS;
 }
diff --git a/include/erofs/blobchunk.h b/include/erofs/blobchunk.h
index b418227..7f58b17 100644
--- a/include/erofs/blobchunk.h
+++ b/include/erofs/blobchunk.h
@@ -9,9 +9,12 @@
 
 #include "erofs/internal.h"
 
-int erofs_blob_write_chunk_indexes(struct erofs_inode *inode, erofs_off_t off);
+int erofs_blob_write_chunk_indexes(
+	struct erofs_device erofs_dev,
+	struct erofs_inode *inode,
+	erofs_off_t off);
 int erofs_blob_write_chunked_file(struct erofs_inode *inode);
-int erofs_blob_remap(void);
+int erofs_blob_remap(struct erofs_device erofs_dev);
 void erofs_blob_exit(void);
 int erofs_blob_init(void);
 
diff --git a/include/erofs/cache.h b/include/erofs/cache.h
index e324d92..051c696 100644
--- a/include/erofs/cache.h
+++ b/include/erofs/cache.h
@@ -9,6 +9,7 @@
 #define __EROFS_CACHE_H
 
 #include "internal.h"
+#include <stdlib.h>
 
 struct erofs_buffer_head;
 struct erofs_buffer_block;
@@ -21,8 +22,8 @@ struct erofs_buffer_block;
 #define XATTR		3
 
 struct erofs_bhops {
-	bool (*preflush)(struct erofs_buffer_head *bh);
-	bool (*flush)(struct erofs_buffer_head *bh);
+	bool (*preflush)(struct erofs_device erofs_dev, struct erofs_buffer_head *bh);
+	bool (*flush)(struct erofs_device erofs_dev, struct erofs_buffer_head *bh);
 };
 
 struct erofs_buffer_head {
@@ -95,7 +96,7 @@ struct erofs_buffer_head *erofs_battach(struct erofs_buffer_head *bh,
 					int type, unsigned int size);
 
 erofs_blk_t erofs_mapbh(struct erofs_buffer_block *bb);
-bool erofs_bflush(struct erofs_buffer_block *bb);
+bool erofs_bflush(struct erofs_device erofs_dev, struct erofs_buffer_block *bb);
 
 void erofs_bdrop(struct erofs_buffer_head *bh, bool tryrevoke);
 
diff --git a/include/erofs/compress.h b/include/erofs/compress.h
index 4434aaa..73834a7 100644
--- a/include/erofs/compress.h
+++ b/include/erofs/compress.h
@@ -14,9 +14,13 @@
 #define EROFS_CONFIG_COMPR_MAX_SZ           (900  * 1024)
 #define EROFS_CONFIG_COMPR_MIN_SZ           (32   * 1024)
 
-int erofs_write_compressed_file(struct erofs_inode *inode);
+int erofs_write_compressed_file(
+	struct erofs_device erofs_dev,
+	struct erofs_inode *inode);
 
-int z_erofs_compress_init(struct erofs_buffer_head *bh);
+int z_erofs_compress_init(
+	struct erofs_device erofs_dev,
+	struct erofs_buffer_head *bh);
 int z_erofs_compress_exit(void);
 
 const char *z_erofs_list_available_compressors(unsigned int i);
diff --git a/include/erofs/config.h b/include/erofs/config.h
index a18c883..2b0510e 100644
--- a/include/erofs/config.h
+++ b/include/erofs/config.h
@@ -4,10 +4,11 @@
  *             http://www.huawei.com/
  * Created by Li Guifu <bluce.liguifu@huawei.com>
  */
-#ifndef __EROFS_CONFIG_H
-#define __EROFS_CONFIG_H
+#ifndef EROFS_CONFIG_H_
+#define EROFS_CONFIG_H_
 
 #include "defs.h"
+#include "erofs/internal.h"
 #include "err.h"
 
 #ifdef HAVE_LIBSELINUX
@@ -73,20 +74,20 @@ struct erofs_configure {
 
 extern struct erofs_configure cfg;
 
-void erofs_init_configure(void);
+void erofs_init_global_configure(void);
 void erofs_show_config(void);
-void erofs_exit_configure(void);
+void erofs_exit_global_configure(void);
 
 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_global_selabel_open(const char *file_contexts);
 #else
-static inline int erofs_selabel_open(const char *file_contexts)
+static inline int erofs_global_selabel_open(const char *file_contexts)
 {
 	return -EINVAL;
 }
 #endif
 
-#endif
+#endif // EROFS_CONFIG_H_
diff --git a/include/erofs/defs.h b/include/erofs/defs.h
index 96bbb65..2dc9177 100644
--- a/include/erofs/defs.h
+++ b/include/erofs/defs.h
@@ -38,6 +38,27 @@ typedef uint16_t        u16;
 typedef uint32_t        u32;
 typedef uint64_t        u64;
 
+typedef u64 erofs_off_t;
+typedef u64 erofs_nid_t;
+/* data type for filesystem-wide blocks number */
+typedef u32 erofs_blk_t;
+
+#define LOG_BLOCK_SIZE          (12)
+#define EROFS_BLKSIZ            (1U << LOG_BLOCK_SIZE)
+
+#define EROFS_ISLOTBITS		5
+#define EROFS_SLOTSIZE		(1U << EROFS_ISLOTBITS)
+
+
+#define NULL_ADDR	((unsigned int)-1)
+#define NULL_ADDR_UL	((unsigned long)-1)
+
+#define erofs_blknr(addr)       ((addr) / EROFS_BLKSIZ)
+#define erofs_blkoff(addr)      ((addr) % EROFS_BLKSIZ)
+#define blknr_to_addr(nr)       ((erofs_off_t)(nr) * EROFS_BLKSIZ)
+
+#define BLK_ROUND_UP(addr)	DIV_ROUND_UP(addr, EROFS_BLKSIZ)
+
 #ifndef HAVE_LINUX_TYPES_H
 typedef u8	__u8;
 typedef u16	__u16;
diff --git a/include/erofs/inode.h b/include/erofs/inode.h
index a736762..5483d04 100644
--- a/include/erofs/inode.h
+++ b/include/erofs/inode.h
@@ -13,7 +13,9 @@
 void erofs_inode_manager_init(void);
 unsigned int erofs_iput(struct erofs_inode *inode);
 erofs_nid_t erofs_lookupnid(struct erofs_inode *inode);
-struct erofs_inode *erofs_mkfs_build_tree_from_path(struct erofs_inode *parent,
-						    const char *path);
+struct erofs_inode *erofs_mkfs_build_tree_from_path(
+	struct erofs_device erofs_dev,
+	struct erofs_inode *parent,
+	const char *path);
 
 #endif
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index f84e6b4..49a883e 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -16,6 +16,7 @@ typedef unsigned short umode_t;
 
 #include "erofs_fs.h"
 #include <fcntl.h>
+#include "io.h"
 
 #ifndef PATH_MAX
 #define PATH_MAX        4096    /* # chars in a path name including nul */
@@ -38,25 +39,6 @@ typedef unsigned short umode_t;
 #define PAGE_MASK		(~(PAGE_SIZE-1))
 #endif
 
-#define LOG_BLOCK_SIZE          (12)
-#define EROFS_BLKSIZ            (1U << LOG_BLOCK_SIZE)
-
-#define EROFS_ISLOTBITS		5
-#define EROFS_SLOTSIZE		(1U << EROFS_ISLOTBITS)
-
-typedef u64 erofs_off_t;
-typedef u64 erofs_nid_t;
-/* data type for filesystem-wide blocks number */
-typedef u32 erofs_blk_t;
-
-#define NULL_ADDR	((unsigned int)-1)
-#define NULL_ADDR_UL	((unsigned long)-1)
-
-#define erofs_blknr(addr)       ((addr) / EROFS_BLKSIZ)
-#define erofs_blkoff(addr)      ((addr) % EROFS_BLKSIZ)
-#define blknr_to_addr(nr)       ((erofs_off_t)(nr) * EROFS_BLKSIZ)
-
-#define BLK_ROUND_UP(addr)	DIV_ROUND_UP(addr, EROFS_BLKSIZ)
 
 struct erofs_buffer_head;
 
@@ -95,17 +77,17 @@ static inline erofs_off_t iloc(erofs_nid_t nid)
 }
 
 #define EROFS_FEATURE_FUNCS(name, compat, feature) \
-static inline bool erofs_sb_has_##name(void) \
+static inline bool erofs_sb_has_##name(struct erofs_sb_info *sbi) \
 { \
-	return sbi.feature_##compat & EROFS_FEATURE_##feature; \
+	return sbi->feature_##compat & EROFS_FEATURE_##feature; \
 } \
-static inline void erofs_sb_set_##name(void) \
+static inline void erofs_sb_set_##name(struct erofs_sb_info *sbi) \
 { \
-	sbi.feature_##compat |= EROFS_FEATURE_##feature; \
+	sbi->feature_##compat |= EROFS_FEATURE_##feature; \
 } \
-static inline void erofs_sb_clear_##name(void) \
+static inline void erofs_sb_clear_##name(struct erofs_sb_info *sbi) \
 { \
-	sbi.feature_##compat &= ~EROFS_FEATURE_##feature; \
+	sbi->feature_##compat &= ~EROFS_FEATURE_##feature; \
 }
 
 EROFS_FEATURE_FUNCS(lz4_0padding, incompat, INCOMPAT_LZ4_0PADDING)
@@ -268,22 +250,26 @@ struct erofs_map_blocks {
 #define EROFS_GET_BLOCKS_FIEMAP	0x0002
 
 /* super.c */
-int erofs_read_superblock(void);
+int erofs_read_superblock(struct erofs_device devfd, struct erofs_sb_info *sbi);
 
 /* namei.c */
-int erofs_read_inode_from_disk(struct erofs_inode *vi);
-int erofs_ilookup(const char *path, struct erofs_inode *vi);
-int erofs_read_inode_from_disk(struct erofs_inode *vi);
+int erofs_read_inode_from_disk(struct erofs_device fd, struct erofs_inode *vi);
+int erofs_ilookup(struct erofs_device devfd, const char *path, struct erofs_inode *vi);
 
 /* data.c */
-int erofs_pread(struct erofs_inode *inode, char *buf,
+int erofs_pread(struct erofs_device fd, struct erofs_inode *inode, char *buf,
 		erofs_off_t count, erofs_off_t offset);
-int erofs_map_blocks(struct erofs_inode *inode,
+int erofs_map_blocks(
+		struct erofs_device erofs_dev,
+		struct erofs_inode *inode,
 		struct erofs_map_blocks *map, int flags);
 /* zmap.c */
 int z_erofs_fill_inode(struct erofs_inode *vi);
-int z_erofs_map_blocks_iter(struct erofs_inode *vi,
-			    struct erofs_map_blocks *map, int flags);
+int z_erofs_map_blocks_iter(
+	struct erofs_device erofs_dev,
+	struct erofs_inode *vi,
+	struct erofs_map_blocks *map,
+	int flags);
 
 #ifdef EUCLEAN
 #define EFSCORRUPTED	EUCLEAN		/* Filesystem is corrupted */
diff --git a/include/erofs/io.h b/include/erofs/io.h
index 2597c5c..bbdccc4 100644
--- a/include/erofs/io.h
+++ b/include/erofs/io.h
@@ -9,40 +9,52 @@
 
 #define _GNU_SOURCE
 #include <unistd.h>
-#include "internal.h"
+#include "defs.h"
 
 #ifndef O_BINARY
 #define O_BINARY	0
 #endif
 
-int dev_open(const char *devname);
-int dev_open_ro(const char *dev);
-void dev_close(void);
-int dev_write(const void *buf, u64 offset, size_t len);
-int dev_read(void *buf, u64 offset, size_t len);
-int dev_fillzero(u64 offset, size_t len, bool padding);
-int dev_fsync(void);
-int dev_resize(erofs_blk_t nblocks);
-u64 dev_length(void);
+struct erofs_device {
+	const char *erofs_devname;
+	int erofs_devfd;
+	u64 erofs_devsz;
+};
+
+int dev_open(const char *devname, struct erofs_device *erofs_dev);
+int dev_open_ro(const char *dev, struct erofs_device *erofs_dev);
+void dev_close(struct erofs_device *erofs_dev);
+int dev_write(struct erofs_device erofs_dev, const void *buf, u64 offset, size_t len);
+int dev_read(struct erofs_device erofs_dev, void *buf, u64 offset, size_t len);
+int dev_fillzero(struct erofs_device erofs_dev, u64 offset, size_t len, bool padding);
+int dev_fsync(struct erofs_device erofs_dev);
+int dev_resize(struct erofs_device erofs_dev, erofs_blk_t nblocks);
+u64 dev_length(struct erofs_device erofs_dev);
+
 
-extern int erofs_devfd;
 
 int erofs_copy_file_range(int fd_in, erofs_off_t *off_in,
                           int fd_out, erofs_off_t *off_out,
                           size_t length);
 
-static inline int blk_write(const void *buf, erofs_blk_t blkaddr,
-			    u32 nblocks)
+static inline int blk_write(
+	struct erofs_device dev,
+	const void *buf,
+	erofs_blk_t blkaddr,
+	u32 nblocks)
 {
-	return dev_write(buf, blknr_to_addr(blkaddr),
+	return dev_write(dev, buf, blknr_to_addr(blkaddr),
 			 blknr_to_addr(nblocks));
 }
 
-static inline int blk_read(void *buf, erofs_blk_t start,
-			    u32 nblocks)
+static inline int blk_read(
+	struct erofs_device dev,
+	void *buf,
+	erofs_blk_t start,
+	u32 nblocks)
 {
-	return dev_read(buf, blknr_to_addr(start),
+	return dev_read(dev, buf, blknr_to_addr(start),
 			 blknr_to_addr(nblocks));
 }
 
-#endif
+#endif // EROFS_IO_H_
diff --git a/lib/blobchunk.c b/lib/blobchunk.c
index 661c5d0..24904fb 100644
--- a/lib/blobchunk.c
+++ b/lib/blobchunk.c
@@ -97,8 +97,10 @@ static int erofs_blob_hashmap_cmp(const void *a, const void *b,
 		      sizeof(ec1->sha256));
 }
 
-int erofs_blob_write_chunk_indexes(struct erofs_inode *inode,
-				   erofs_off_t off)
+int erofs_blob_write_chunk_indexes(
+	struct erofs_device erofs_dev,
+	struct erofs_inode *inode,
+	erofs_off_t off)
 {
 	struct erofs_inode_chunk_index idx = {0};
 	unsigned int dst, src, unit;
@@ -122,7 +124,7 @@ int erofs_blob_write_chunk_indexes(struct erofs_inode *inode,
 	}
 	off = roundup(off, unit);
 
-	return dev_write(inode->chunkindexes, off, inode->extent_isize);
+	return dev_write(erofs_dev, inode->chunkindexes, off, inode->extent_isize);
 }
 
 int erofs_blob_write_chunked_file(struct erofs_inode *inode)
@@ -174,12 +176,13 @@ err:
 	return ret;
 }
 
-int erofs_blob_remap(void)
+int erofs_blob_remap(struct erofs_device erofs_dev)
 {
 	struct erofs_buffer_head *bh;
 	ssize_t length;
 	erofs_off_t pos_in, pos_out;
 	int ret;
+	const int erofs_devfd = erofs_dev.erofs_devfd;
 
 	fflush(blobfile);
 	length = ftell(blobfile);
diff --git a/lib/cache.c b/lib/cache.c
index 8016e38..bae172c 100644
--- a/lib/cache.c
+++ b/lib/cache.c
@@ -21,7 +21,9 @@ static struct list_head mapped_buckets[META + 1][EROFS_BLKSIZ];
 /* last mapped buffer block to accelerate erofs_mapbh() */
 static struct erofs_buffer_block *last_mapped_block = &blkh;
 
-static bool erofs_bh_flush_drop_directly(struct erofs_buffer_head *bh)
+static bool erofs_bh_flush_drop_directly(
+	struct erofs_device erofs_dev,
+	struct erofs_buffer_head *bh)
 {
 	return erofs_bh_flush_generic_end(bh);
 }
@@ -30,7 +32,9 @@ struct erofs_bhops erofs_drop_directly_bhops = {
 	.flush = erofs_bh_flush_drop_directly,
 };
 
-static bool erofs_bh_flush_skip_write(struct erofs_buffer_head *bh)
+static bool erofs_bh_flush_skip_write(
+	struct erofs_device erofs_dev,
+	struct erofs_buffer_head *bh)
 {
 	return false;
 }
@@ -39,18 +43,20 @@ struct erofs_bhops erofs_skip_write_bhops = {
 	.flush = erofs_bh_flush_skip_write,
 };
 
-int erofs_bh_flush_generic_write(struct erofs_buffer_head *bh, void *buf)
+int erofs_bh_flush_generic_write(struct erofs_device erofs_dev, struct erofs_buffer_head *bh, void *buf)
 {
 	struct erofs_buffer_head *nbh = list_next_entry(bh, list);
 	erofs_off_t offset = erofs_btell(bh, false);
 
 	DBG_BUGON(nbh->off < bh->off);
-	return dev_write(buf, offset, nbh->off - bh->off);
+	return dev_write(erofs_dev, buf, offset, nbh->off - bh->off);
 }
 
-static bool erofs_bh_flush_buf_write(struct erofs_buffer_head *bh)
+static bool erofs_bh_flush_buf_write(
+	struct erofs_device erofs_dev,
+	struct erofs_buffer_head *bh)
 {
-	int err = erofs_bh_flush_generic_write(bh, bh->fsprivate);
+	int err = erofs_bh_flush_generic_write(erofs_dev, bh, bh->fsprivate);
 
 	if (err)
 		return false;
@@ -58,6 +64,7 @@ static bool erofs_bh_flush_buf_write(struct erofs_buffer_head *bh)
 	return erofs_bh_flush_generic_end(bh);
 }
 
+
 struct erofs_bhops erofs_buf_write_bhops = {
 	.flush = erofs_bh_flush_buf_write,
 };
@@ -368,7 +375,7 @@ erofs_blk_t erofs_mapbh(struct erofs_buffer_block *bb)
 	return tail_blkaddr;
 }
 
-bool erofs_bflush(struct erofs_buffer_block *bb)
+bool erofs_bflush(struct erofs_device erofs_dev, struct erofs_buffer_block *bb)
 {
 	struct erofs_buffer_block *p, *n;
 	erofs_blk_t blkaddr;
@@ -383,14 +390,14 @@ bool erofs_bflush(struct erofs_buffer_block *bb)
 
 		/* check if the buffer block can flush */
 		list_for_each_entry(bh, &p->buffers.list, list)
-			if (bh->op->preflush && !bh->op->preflush(bh))
+			if (bh->op->preflush && !bh->op->preflush(erofs_dev, bh))
 				return false;
 
 		blkaddr = __erofs_mapbh(p);
 
 		list_for_each_entry_safe(bh, nbh, &p->buffers.list, list) {
 			/* flush and remove bh */
-			if (!bh->op->flush(bh))
+			if (!bh->op->flush(erofs_dev, bh))
 				skip = true;
 		}
 
@@ -399,7 +406,7 @@ bool erofs_bflush(struct erofs_buffer_block *bb)
 
 		padding = EROFS_BLKSIZ - p->buffers.off % EROFS_BLKSIZ;
 		if (padding != EROFS_BLKSIZ)
-			dev_fillzero(blknr_to_addr(blkaddr) - padding,
+			dev_fillzero(erofs_dev, blknr_to_addr(blkaddr) - padding,
 				     padding, true);
 
 		DBG_BUGON(!list_empty(&p->buffers.list));
diff --git a/lib/compress.c b/lib/compress.c
index 98be7a2..766b75b 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -89,7 +89,7 @@ static void vle_write_indexes(struct z_erofs_vle_compress_ctx *ctx,
 
 	do {
 		/* XXX: big pcluster feature should be per-inode */
-		if (d0 == 1 && erofs_sb_has_big_pcluster()) {
+		if (d0 == 1 && erofs_sb_has_big_pcluster(&sbi)) {
 			type = Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD;
 			di.di_u.delta[0] = cpu_to_le16(ctx->compressedblks |
 					Z_EROFS_VLE_DI_D0_CBLKCNT);
@@ -120,14 +120,16 @@ static void vle_write_indexes(struct z_erofs_vle_compress_ctx *ctx,
 	ctx->clusterofs = clusterofs + count;
 }
 
-static int write_uncompressed_extent(struct z_erofs_vle_compress_ctx *ctx,
+static int write_uncompressed_extent(
+	struct erofs_device erofs_dev,
+	struct z_erofs_vle_compress_ctx *ctx,
 				     unsigned int *len, char *dst)
 {
 	int ret;
 	unsigned int count;
 
 	/* reset clusterofs to 0 if permitted */
-	if (!erofs_sb_has_lz4_0padding() && ctx->clusterofs &&
+	if (!erofs_sb_has_lz4_0padding(&sbi) && ctx->clusterofs &&
 	    ctx->head >= ctx->clusterofs) {
 		ctx->head -= ctx->clusterofs;
 		*len += ctx->clusterofs;
@@ -142,7 +144,7 @@ static int write_uncompressed_extent(struct z_erofs_vle_compress_ctx *ctx,
 
 	erofs_dbg("Writing %u uncompressed data to block %u",
 		  count, ctx->blkaddr);
-	ret = blk_write(dst, ctx->blkaddr, 1);
+	ret = blk_write(erofs_dev, dst, ctx->blkaddr, 1);
 	if (ret)
 		return ret;
 	return count;
@@ -162,9 +164,11 @@ static unsigned int z_erofs_get_max_pclusterblks(struct erofs_inode *inode)
 	return cfg.c_pclusterblks_def;
 }
 
-static int vle_compress_one(struct erofs_inode *inode,
-			    struct z_erofs_vle_compress_ctx *ctx,
-			    bool final)
+static int vle_compress_one(
+		struct erofs_device erofs_dev,
+		struct erofs_inode *inode,
+		struct z_erofs_vle_compress_ctx *ctx,
+		bool final)
 {
 	struct erofs_compress *const h = &compresshandle;
 	unsigned int len = ctx->tail - ctx->head;
@@ -197,7 +201,7 @@ static int vle_compress_one(struct erofs_inode *inode,
 					  erofs_strerror(ret));
 			}
 nocompression:
-			ret = write_uncompressed_extent(ctx, &len, dst);
+			ret = write_uncompressed_extent(erofs_dev, ctx, &len, dst);
 			if (ret < 0)
 				return ret;
 			count = ret;
@@ -206,14 +210,14 @@ nocompression:
 		} else {
 			const unsigned int tailused = ret & (EROFS_BLKSIZ - 1);
 			const unsigned int padding =
-				erofs_sb_has_lz4_0padding() && tailused ?
+				erofs_sb_has_lz4_0padding(&sbi) && tailused ?
 					EROFS_BLKSIZ - tailused : 0;
 
 			ctx->compressedblks = DIV_ROUND_UP(ret, EROFS_BLKSIZ);
 			DBG_BUGON(ctx->compressedblks * EROFS_BLKSIZ >= count);
 
 			/* zero out garbage trailing data for non-0padding */
-			if (!erofs_sb_has_lz4_0padding())
+			if (!erofs_sb_has_lz4_0padding(&sbi))
 				memset(dst + ret, 0,
 				       roundup(ret, EROFS_BLKSIZ) - ret);
 
@@ -221,7 +225,7 @@ nocompression:
 			erofs_dbg("Writing %u compressed data to %u of %u blocks",
 				  count, ctx->blkaddr, ctx->compressedblks);
 
-			ret = blk_write(dst - padding, ctx->blkaddr,
+			ret = blk_write(erofs_dev, dst - padding, ctx->blkaddr,
 					ctx->compressedblks);
 			if (ret)
 				return ret;
@@ -302,7 +306,7 @@ static void *write_compacted_indexes(u8 *out,
 		return ERR_PTR(-EINVAL);
 	encodebits = (vcnt * destsize * 8 - 32) / vcnt;
 	blkaddr = *blkaddr_ret;
-	update_blkaddr = erofs_sb_has_big_pcluster();
+	update_blkaddr = erofs_sb_has_big_pcluster(&sbi);
 
 	pos = 0;
 	for (i = 0; i < vcnt; ++i) {
@@ -398,7 +402,7 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode,
 
 	dummy_head = false;
 	/* prior to bigpcluster, blkaddr was bumped up once coming into HEAD */
-	if (!erofs_sb_has_big_pcluster()) {
+	if (!erofs_sb_has_big_pcluster(&sbi)) {
 		--blkaddr;
 		dummy_head = true;
 	}
@@ -460,7 +464,7 @@ static void z_erofs_write_mapheader(struct erofs_inode *inode,
 	memcpy(compressmeta, &h, sizeof(struct z_erofs_map_header));
 }
 
-int erofs_write_compressed_file(struct erofs_inode *inode)
+int erofs_write_compressed_file(struct erofs_device erofs_dev, struct erofs_inode *inode)
 {
 	struct erofs_buffer_head *bh;
 	struct z_erofs_vle_compress_ctx ctx;
@@ -495,7 +499,7 @@ int erofs_write_compressed_file(struct erofs_inode *inode)
 		inode->datalayout = EROFS_INODE_FLAT_COMPRESSION_LEGACY;
 	}
 
-	if (erofs_sb_has_big_pcluster()) {
+	if (erofs_sb_has_big_pcluster(&sbi)) {
 		inode->z_advise |= Z_EROFS_ADVISE_BIG_PCLUSTER_1;
 		if (inode->datalayout == EROFS_INODE_FLAT_COMPRESSION)
 			inode->z_advise |= Z_EROFS_ADVISE_BIG_PCLUSTER_2;
@@ -526,13 +530,13 @@ int erofs_write_compressed_file(struct erofs_inode *inode)
 		ctx.tail += readcount;
 
 		/* do one compress round */
-		ret = vle_compress_one(inode, &ctx, false);
+		ret = vle_compress_one(erofs_dev, inode, &ctx, false);
 		if (ret)
 			goto err_bdrop;
 	}
 
 	/* do the final round */
-	ret = vle_compress_one(inode, &ctx, true);
+	ret = vle_compress_one(erofs_dev, inode, &ctx, true);
 	if (ret)
 		goto err_bdrop;
 
@@ -593,7 +597,7 @@ static int erofs_get_compress_algorithm_id(const char *name)
 	return -ENOTSUP;
 }
 
-int z_erofs_build_compr_cfgs(struct erofs_buffer_head *sb_bh)
+int z_erofs_build_compr_cfgs(struct erofs_device erofs_dev, struct erofs_buffer_head *sb_bh)
 {
 	struct erofs_buffer_head *bh = sb_bh;
 	int ret = 0;
@@ -617,7 +621,7 @@ int z_erofs_build_compr_cfgs(struct erofs_buffer_head *sb_bh)
 			return PTR_ERR(bh);
 		}
 		erofs_mapbh(bh->block);
-		ret = dev_write(&lz4alg, erofs_btell(bh, false),
+		ret = dev_write(erofs_dev, &lz4alg, erofs_btell(bh, false),
 				sizeof(lz4alg));
 		bh->op = &erofs_drop_directly_bhops;
 	}
@@ -647,7 +651,7 @@ int z_erofs_build_compr_cfgs(struct erofs_buffer_head *sb_bh)
 	return ret;
 }
 
-int z_erofs_compress_init(struct erofs_buffer_head *sb_bh)
+int z_erofs_compress_init(struct erofs_device erofs_dev, struct erofs_buffer_head *sb_bh)
 {
 	/* initialize for primary compression algorithm */
 	int ret = erofs_compressor_init(&compresshandle,
@@ -662,7 +666,7 @@ int z_erofs_compress_init(struct erofs_buffer_head *sb_bh)
 	 */
 	if (!cfg.c_compr_alg_master ||
 	    (cfg.c_legacy_compress && !strcmp(cfg.c_compr_alg_master, "lz4")))
-		erofs_sb_clear_lz4_0padding();
+		erofs_sb_clear_lz4_0padding(&sbi);
 
 	if (!cfg.c_compr_alg_master)
 		return 0;
@@ -690,16 +694,16 @@ int z_erofs_compress_init(struct erofs_buffer_head *sb_bh)
 				  cfg.c_pclusterblks_max);
 			return -EINVAL;
 		}
-		erofs_sb_set_big_pcluster();
+		erofs_sb_set_big_pcluster(&sbi);
 		erofs_warn("EXPERIMENTAL big pcluster feature in use. Use at your own risk!");
 	}
 
 	if (ret != Z_EROFS_COMPRESSION_LZ4)
-		erofs_sb_set_compr_cfgs();
+		erofs_sb_set_compr_cfgs(&sbi);
 
-	if (erofs_sb_has_compr_cfgs()) {
+	if (erofs_sb_has_compr_cfgs(&sbi)) {
 		sbi.available_compr_algs |= 1 << ret;
-		return z_erofs_build_compr_cfgs(sb_bh);
+		return z_erofs_build_compr_cfgs(erofs_dev, sb_bh);
 	}
 	return 0;
 }
diff --git a/lib/compressor_liblzma.c b/lib/compressor_liblzma.c
index 40a05ef..576cdae 100644
--- a/lib/compressor_liblzma.c
+++ b/lib/compressor_liblzma.c
@@ -4,9 +4,9 @@
  *
  * Copyright (C) 2021 Gao Xiang <xiang@kernel.org>
  */
+#ifdef HAVE_LIBLZMA
 #include <stdlib.h>
 #include "config.h"
-#ifdef HAVE_LIBLZMA
 #include <lzma.h>
 #include "erofs/config.h"
 #include "erofs/print.h"
diff --git a/lib/config.c b/lib/config.c
index 363dcc5..7488e08 100644
--- a/lib/config.c
+++ b/lib/config.c
@@ -12,22 +12,26 @@
 struct erofs_configure cfg;
 struct erofs_sb_info sbi;
 
-void erofs_init_configure(void)
+void erofs_init_config(struct erofs_configure *cfg)
 {
-	memset(&cfg, 0, sizeof(cfg));
-
-	cfg.c_dbg_lvl  = EROFS_WARN;
-	cfg.c_version  = PACKAGE_VERSION;
-	cfg.c_dry_run  = false;
-	cfg.c_compr_level_master = -1;
-	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_pclusterblks_max = 1;
-	cfg.c_pclusterblks_def = 1;
-	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_compr_level_master = -1;
+	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_pclusterblks_max = 1;
+	cfg->c_pclusterblks_def = 1;
+	cfg->c_max_decompressed_extent_bytes = -1;
+}
+
+void erofs_init_global_configure() {
+  erofs_init_config(&cfg);
 }
 
 void erofs_show_config(void)
@@ -41,14 +45,18 @@ 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)
 {
 #ifdef HAVE_LIBSELINUX
-	if (cfg.sehnd)
-		selabel_close(cfg.sehnd);
+	if (cfg->sehnd)
+		selabel_close(cfg->sehnd);
 #endif
-	if (cfg.c_img_path)
-		free(cfg.c_img_path);
+	if (cfg->c_img_path)
+		free(cfg->c_img_path);
+}
+
+void erofs_exit_global_configure(void) {
+  erofs_exit_configure(&cfg);
 }
 
 static unsigned int fullpath_prefix;	/* root directory prefix length */
@@ -68,24 +76,31 @@ const char *erofs_fspath(const char *fullpath)
 }
 
 #ifdef HAVE_LIBSELINUX
-int erofs_selabel_open(const char *file_contexts)
+int erofs_selabel_open(struct erofs_configure *cfg_p,const char *file_contexts)
 {
 	struct selinux_opt seopts[] = {
 		{ .type = SELABEL_OPT_PATH, .value = file_contexts }
 	};
 
-	if (cfg.sehnd) {
+	if (cfg_p->sehnd) {
+    struct erofs_configure cfg = *cfg_p;
 		erofs_info("ignore duplicated file contexts \"%s\"",
 			   file_contexts);
 		return -EBUSY;
 	}
 
-	cfg.sehnd = selabel_open(SELABEL_CTX_FILE, seopts, 1);
-	if (!cfg.sehnd) {
+	cfg_p->sehnd = selabel_open(SELABEL_CTX_FILE, seopts, 1);
+	if (!cfg_p->sehnd) {
+    struct erofs_configure cfg = *cfg_p;
 		erofs_err("failed to open file contexts \"%s\"",
 			  file_contexts);
 		return -EINVAL;
 	}
 	return 0;
 }
+
+int erofs_global_selabel_open(const char *file_contexts) {
+  return erofs_selabel_open(&cfg, file_contexts);
+}
+
 #endif
diff --git a/lib/data.c b/lib/data.c
index b5f0196..d9d20ec 100644
--- a/lib/data.c
+++ b/lib/data.c
@@ -61,7 +61,9 @@ err_out:
 	return err;
 }
 
-int erofs_map_blocks(struct erofs_inode *inode,
+int erofs_map_blocks(
+		struct erofs_device erofs_dev,
+		struct erofs_inode *inode,
 		struct erofs_map_blocks *map, int flags)
 {
 	struct erofs_inode *vi = inode;
@@ -91,7 +93,7 @@ int erofs_map_blocks(struct erofs_inode *inode,
 	pos = roundup(iloc(vi->nid) + vi->inode_isize +
 		      vi->xattr_isize, unit) + unit * chunknr;
 
-	err = blk_read(buf, erofs_blknr(pos), 1);
+	err = blk_read(erofs_dev, buf, erofs_blknr(pos), 1);
 	if (err < 0)
 		return -EIO;
 
@@ -135,7 +137,7 @@ out:
 	return err;
 }
 
-static int erofs_read_raw_data(struct erofs_inode *inode, char *buffer,
+static int erofs_read_raw_data(struct erofs_device erofs_dev, struct erofs_inode *inode, char *buffer,
 			       erofs_off_t size, erofs_off_t offset)
 {
 	struct erofs_map_blocks map = {
@@ -149,7 +151,7 @@ static int erofs_read_raw_data(struct erofs_inode *inode, char *buffer,
 		erofs_off_t eend;
 
 		map.m_la = ptr;
-		ret = erofs_map_blocks(inode, &map, 0);
+		ret = erofs_map_blocks(erofs_dev, inode, &map, 0);
 		if (ret)
 			return ret;
 
@@ -176,7 +178,7 @@ static int erofs_read_raw_data(struct erofs_inode *inode, char *buffer,
 			map.m_la = ptr;
 		}
 
-		ret = dev_read(estart, map.m_pa, eend - map.m_la);
+		ret = dev_read(erofs_dev, estart, map.m_pa, eend - map.m_la);
 		if (ret < 0)
 			return -EIO;
 		ptr = eend;
@@ -184,8 +186,12 @@ static int erofs_read_raw_data(struct erofs_inode *inode, char *buffer,
 	return 0;
 }
 
-static int z_erofs_read_data(struct erofs_inode *inode, char *buffer,
-			     erofs_off_t size, erofs_off_t offset)
+static int z_erofs_read_data(
+	struct erofs_device erofs_dev,
+	struct erofs_inode *inode,
+	char *buffer,
+	erofs_off_t size,
+	erofs_off_t offset)
 {
 	erofs_off_t end, length, skip;
 	struct erofs_map_blocks map = {
@@ -201,7 +207,7 @@ static int z_erofs_read_data(struct erofs_inode *inode, char *buffer,
 	while (end > offset) {
 		map.m_la = end - 1;
 
-		ret = z_erofs_map_blocks_iter(inode, &map, 0);
+		ret = z_erofs_map_blocks_iter(erofs_dev, inode, &map, 0);
 		if (ret)
 			break;
 
@@ -240,7 +246,7 @@ static int z_erofs_read_data(struct erofs_inode *inode, char *buffer,
 				break;
 			}
 		}
-		ret = dev_read(raw, map.m_pa, map.m_plen);
+		ret = dev_read(erofs_dev, raw, map.m_pa, map.m_plen);
 		if (ret < 0)
 			break;
 
@@ -266,17 +272,17 @@ static int z_erofs_read_data(struct erofs_inode *inode, char *buffer,
 	return ret < 0 ? ret : 0;
 }
 
-int erofs_pread(struct erofs_inode *inode, char *buf,
+int erofs_pread(struct erofs_device fd, struct erofs_inode *inode, char *buf,
 		erofs_off_t count, erofs_off_t offset)
 {
 	switch (inode->datalayout) {
 	case EROFS_INODE_FLAT_PLAIN:
 	case EROFS_INODE_FLAT_INLINE:
 	case EROFS_INODE_CHUNK_BASED:
-		return erofs_read_raw_data(inode, buf, count, offset);
+		return erofs_read_raw_data(fd, inode, buf, count, offset);
 	case EROFS_INODE_FLAT_COMPRESSION_LEGACY:
 	case EROFS_INODE_FLAT_COMPRESSION:
-		return z_erofs_read_data(inode, buf, count, offset);
+		return z_erofs_read_data(fd, inode, buf, count, offset);
 	default:
 		break;
 	}
diff --git a/lib/decompress.c b/lib/decompress.c
index f313e41..6a60400 100644
--- a/lib/decompress.c
+++ b/lib/decompress.c
@@ -82,7 +82,7 @@ static int z_erofs_decompress_lz4(struct z_erofs_decompress_req *rq)
 	bool support_0padding = false;
 	unsigned int inputmargin = 0;
 
-	if (erofs_sb_has_lz4_0padding()) {
+	if (erofs_sb_has_lz4_0padding(&sbi)) {
 		support_0padding = true;
 
 		while (!src[inputmargin & ~PAGE_MASK])
diff --git a/lib/inode.c b/lib/inode.c
index 6597a26..d1adb49 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -246,16 +246,20 @@ static void fill_dirblock(char *buf, unsigned int size, unsigned int q,
 	memset(buf + q, 0, size - q);
 }
 
-static int write_dirblock(unsigned int q, struct erofs_dentry *head,
-			  struct erofs_dentry *end, erofs_blk_t blkaddr)
+static int write_dirblock(
+	struct erofs_device erofs_dev,
+	unsigned int q, struct erofs_dentry *head,
+	struct erofs_dentry *end, erofs_blk_t blkaddr)
 {
 	char buf[EROFS_BLKSIZ];
 
 	fill_dirblock(buf, EROFS_BLKSIZ, q, head, end);
-	return blk_write(buf, blkaddr, 1);
+	return blk_write(erofs_dev, buf, blkaddr, 1);
 }
 
-static int erofs_write_dir_file(struct erofs_inode *dir)
+static int erofs_write_dir_file(
+	struct erofs_device erofs_dev,
+	struct erofs_inode *dir)
 {
 	struct erofs_dentry *head = list_first_entry(&dir->i_subdirs,
 						     struct erofs_dentry,
@@ -271,7 +275,7 @@ static int erofs_write_dir_file(struct erofs_inode *dir)
 			sizeof(struct erofs_dirent);
 
 		if (used + len > EROFS_BLKSIZ) {
-			ret = write_dirblock(q, head, d,
+			ret = write_dirblock(erofs_dev, q, head, d,
 					     dir->u.i_blkaddr + blkno);
 			if (ret)
 				return ret;
@@ -288,7 +292,7 @@ static int erofs_write_dir_file(struct erofs_inode *dir)
 	if (used == EROFS_BLKSIZ) {
 		DBG_BUGON(dir->i_size % EROFS_BLKSIZ);
 		DBG_BUGON(dir->idata_size);
-		return write_dirblock(q, head, d, dir->u.i_blkaddr + blkno);
+		return write_dirblock(erofs_dev, q, head, d, dir->u.i_blkaddr + blkno);
 	}
 	DBG_BUGON(used != dir->i_size % EROFS_BLKSIZ);
 	if (used) {
@@ -302,7 +306,9 @@ static int erofs_write_dir_file(struct erofs_inode *dir)
 	return 0;
 }
 
-static int erofs_write_file_from_buffer(struct erofs_inode *inode, char *buf)
+static int erofs_write_file_from_buffer(
+	struct erofs_device erofs_dev,
+	struct erofs_inode *inode, char *buf)
 {
 	const unsigned int nblocks = erofs_blknr(inode->i_size);
 	int ret;
@@ -314,7 +320,7 @@ static int erofs_write_file_from_buffer(struct erofs_inode *inode, char *buf)
 		return ret;
 
 	if (nblocks)
-		blk_write(buf, inode->u.i_blkaddr, nblocks);
+		blk_write(erofs_dev, buf, inode->u.i_blkaddr, nblocks);
 	inode->idata_size = inode->i_size % EROFS_BLKSIZ;
 	if (inode->idata_size) {
 		inode->idata = malloc(inode->idata_size);
@@ -334,7 +340,9 @@ static bool erofs_file_is_compressible(struct erofs_inode *inode)
 	return true;
 }
 
-static int write_uncompressed_file_from_fd(struct erofs_inode *inode, int fd)
+static int write_uncompressed_file_from_fd(
+	struct erofs_device erofs_dev,
+	struct erofs_inode *inode, int fd)
 {
 	int ret;
 	unsigned int nblocks, i;
@@ -356,7 +364,7 @@ static int write_uncompressed_file_from_fd(struct erofs_inode *inode, int fd)
 			return -EAGAIN;
 		}
 
-		ret = blk_write(buf, inode->u.i_blkaddr + i, 1);
+		ret = blk_write(erofs_dev, buf, inode->u.i_blkaddr + i, 1);
 		if (ret)
 			return ret;
 	}
@@ -379,7 +387,7 @@ static int write_uncompressed_file_from_fd(struct erofs_inode *inode, int fd)
 	return 0;
 }
 
-int erofs_write_file(struct erofs_inode *inode)
+int erofs_write_file(struct erofs_device erofs_dev, struct erofs_inode *inode)
 {
 	int ret, fd;
 
@@ -395,7 +403,7 @@ int erofs_write_file(struct erofs_inode *inode)
 	}
 
 	if (cfg.c_compr_alg_master && erofs_file_is_compressible(inode)) {
-		ret = erofs_write_compressed_file(inode);
+		ret = erofs_write_compressed_file(erofs_dev, inode);
 
 		if (!ret || ret != -ENOSPC)
 			return ret;
@@ -406,12 +414,14 @@ int erofs_write_file(struct erofs_inode *inode)
 	if (fd < 0)
 		return -errno;
 
-	ret = write_uncompressed_file_from_fd(inode, fd);
+	ret = write_uncompressed_file_from_fd(erofs_dev, inode, fd);
 	close(fd);
 	return ret;
 }
 
-static bool erofs_bh_flush_write_inode(struct erofs_buffer_head *bh)
+static bool erofs_bh_flush_write_inode(
+	struct erofs_device erofs_dev,
+	struct erofs_buffer_head *bh)
 {
 	struct erofs_inode *const inode = bh->fsprivate;
 	const u16 icount = EROFS_INODE_XATTR_ICOUNT(inode->xattr_isize);
@@ -500,7 +510,7 @@ static bool erofs_bh_flush_write_inode(struct erofs_buffer_head *bh)
 		BUG_ON(1);
 	}
 
-	ret = dev_write(&u, off, inode->inode_isize);
+	ret = dev_write(erofs_dev, &u, off, inode->inode_isize);
 	if (ret)
 		return false;
 	off += inode->inode_isize;
@@ -511,7 +521,7 @@ static bool erofs_bh_flush_write_inode(struct erofs_buffer_head *bh)
 		if (IS_ERR(xattrs))
 			return false;
 
-		ret = dev_write(xattrs, off, inode->xattr_isize);
+		ret = dev_write(erofs_dev, xattrs, off, inode->xattr_isize);
 		free(xattrs);
 		if (ret)
 			return false;
@@ -521,13 +531,13 @@ static bool erofs_bh_flush_write_inode(struct erofs_buffer_head *bh)
 
 	if (inode->extent_isize) {
 		if (inode->datalayout == EROFS_INODE_CHUNK_BASED) {
-			ret = erofs_blob_write_chunk_indexes(inode, off);
+			ret = erofs_blob_write_chunk_indexes(erofs_dev, inode, off);
 			if (ret)
 				return false;
 		} else {
 			/* write compression metadata */
 			off = Z_EROFS_VLE_EXTENT_ALIGN(off);
-			ret = dev_write(inode->compressmeta, off,
+			ret = dev_write(erofs_dev, inode->compressmeta, off,
 					inode->extent_isize);
 			if (ret)
 				return false;
@@ -636,13 +646,15 @@ noinline:
 	return 0;
 }
 
-static bool erofs_bh_flush_write_inline(struct erofs_buffer_head *bh)
+static bool erofs_bh_flush_write_inline(
+	struct erofs_device erofs_dev,
+	struct erofs_buffer_head *bh)
 {
 	struct erofs_inode *const inode = bh->fsprivate;
 	const erofs_off_t off = erofs_btell(bh, false);
 	int ret;
 
-	ret = dev_write(inode->idata, off, inode->idata_size);
+	ret = dev_write(erofs_dev, inode->idata, off, inode->idata_size);
 	if (ret)
 		return false;
 
@@ -658,7 +670,7 @@ static struct erofs_bhops erofs_write_inline_bhops = {
 	.flush = erofs_bh_flush_write_inline,
 };
 
-static int erofs_write_tail_end(struct erofs_inode *inode)
+static int erofs_write_tail_end(struct erofs_device erofs_dev, struct erofs_inode *inode)
 {
 	struct erofs_buffer_head *bh, *ibh;
 
@@ -681,11 +693,11 @@ static int erofs_write_tail_end(struct erofs_inode *inode)
 
 		erofs_mapbh(bh->block);
 		pos = erofs_btell(bh, true) - EROFS_BLKSIZ;
-		ret = dev_write(inode->idata, pos, inode->idata_size);
+		ret = dev_write(erofs_dev, inode->idata, pos, inode->idata_size);
 		if (ret)
 			return ret;
 		if (inode->idata_size < EROFS_BLKSIZ) {
-			ret = dev_fillzero(pos + inode->idata_size,
+			ret = dev_fillzero(erofs_dev, pos + inode->idata_size,
 					   EROFS_BLKSIZ - inode->idata_size,
 					   false);
 			if (ret)
@@ -950,7 +962,8 @@ static void erofs_d_invalidate(struct erofs_dentry *d)
 	erofs_iput(inode);
 }
 
-static struct erofs_inode *erofs_mkfs_build_tree(struct erofs_inode *dir)
+static struct erofs_inode *erofs_mkfs_build_tree(
+	struct erofs_device erofs_dev, struct erofs_inode *dir)
 {
 	int ret;
 	DIR *_dir;
@@ -974,18 +987,18 @@ static struct erofs_inode *erofs_mkfs_build_tree(struct erofs_inode *dir)
 				return ERR_PTR(-errno);
 			}
 
-			ret = erofs_write_file_from_buffer(dir, symlink);
+			ret = erofs_write_file_from_buffer(erofs_dev, dir, symlink);
 			free(symlink);
 			if (ret)
 				return ERR_PTR(ret);
 		} else {
-			ret = erofs_write_file(dir);
+			ret = erofs_write_file(erofs_dev, dir);
 			if (ret)
 				return ERR_PTR(ret);
 		}
 
 		erofs_prepare_inode_buffer(dir);
-		erofs_write_tail_end(dir);
+		erofs_write_tail_end(erofs_dev, dir);
 		return dir;
 	}
 
@@ -1060,7 +1073,7 @@ static struct erofs_inode *erofs_mkfs_build_tree(struct erofs_inode *dir)
 			goto fail;
 		}
 
-		d->inode = erofs_mkfs_build_tree_from_path(dir, buf);
+		d->inode = erofs_mkfs_build_tree_from_path(erofs_dev, dir, buf);
 		if (IS_ERR(d->inode)) {
 			ret = PTR_ERR(d->inode);
 fail:
@@ -1078,8 +1091,8 @@ fail:
 			   dir->i_srcpath, d->name, (unsigned long long)d->nid,
 			   d->type);
 	}
-	erofs_write_dir_file(dir);
-	erofs_write_tail_end(dir);
+	erofs_write_dir_file(erofs_dev, dir);
+	erofs_write_tail_end(erofs_dev, dir);
 	return dir;
 
 err_closedir:
@@ -1088,8 +1101,10 @@ err:
 	return ERR_PTR(ret);
 }
 
-struct erofs_inode *erofs_mkfs_build_tree_from_path(struct erofs_inode *parent,
-						    const char *path)
+struct erofs_inode *erofs_mkfs_build_tree_from_path(
+	struct erofs_device erofs_dev,
+	struct erofs_inode *parent,
+	const char *path)
 {
 	struct erofs_inode *const inode = erofs_iget_from_path(path, true);
 
@@ -1108,5 +1123,5 @@ struct erofs_inode *erofs_mkfs_build_tree_from_path(struct erofs_inode *parent,
 	else
 		inode->i_parent = inode;	/* rootdir mark */
 
-	return erofs_mkfs_build_tree(inode);
+	return erofs_mkfs_build_tree(erofs_dev, inode);
 }
diff --git a/lib/io.c b/lib/io.c
index cfc062d..2cb4cb2 100644
--- a/lib/io.c
+++ b/lib/io.c
@@ -23,10 +23,6 @@
 #define EROFS_MODNAME	"erofs_io"
 #include "erofs/print.h"
 
-static const char *erofs_devname;
-int erofs_devfd = -1;
-static u64 erofs_devsz;
-
 int dev_get_blkdev_size(int fd, u64 *bytes)
 {
 	errno = ENOTSUP;
@@ -47,17 +43,18 @@ int dev_get_blkdev_size(int fd, u64 *bytes)
 	return -errno;
 }
 
-void dev_close(void)
+void dev_close(struct erofs_device *erofs_dev)
 {
-	close(erofs_devfd);
-	erofs_devname = NULL;
-	erofs_devfd   = -1;
-	erofs_devsz   = 0;
+	close(erofs_dev->erofs_devfd);
+	erofs_dev->erofs_devname = NULL;
+	erofs_dev->erofs_devfd   = -1;
+	erofs_dev->erofs_devsz   = 0;
 }
 
-int dev_open(const char *dev)
+int dev_open(const char *dev, struct erofs_device *erofs_dev)
 {
 	struct stat st;
+
 	int fd, ret;
 
 	fd = open(dev, O_RDWR | O_CREAT | O_BINARY, 0644);
@@ -75,13 +72,13 @@ int dev_open(const char *dev)
 
 	switch (st.st_mode & S_IFMT) {
 	case S_IFBLK:
-		ret = dev_get_blkdev_size(fd, &erofs_devsz);
+		ret = dev_get_blkdev_size(fd, &erofs_dev->erofs_devsz);
 		if (ret) {
 			erofs_err("failed to get block device size(%s).", dev);
 			close(fd);
 			return ret;
 		}
-		erofs_devsz = round_down(erofs_devsz, EROFS_BLKSIZ);
+		erofs_dev->erofs_devsz = round_down(erofs_dev->erofs_devsz, EROFS_BLKSIZ);
 		break;
 	case S_IFREG:
 		ret = ftruncate(fd, 0);
@@ -91,7 +88,7 @@ int dev_open(const char *dev)
 			return -errno;
 		}
 		/* INT64_MAX is the limit of kernel vfs */
-		erofs_devsz = INT64_MAX;
+		erofs_dev->erofs_devsz = INT64_MAX;
 		break;
 	default:
 		erofs_err("bad file type (%s, %o).", dev, st.st_mode);
@@ -99,15 +96,15 @@ int dev_open(const char *dev)
 		return -EINVAL;
 	}
 
-	erofs_devname = dev;
-	erofs_devfd = fd;
+	erofs_dev->erofs_devname = dev;
+	erofs_dev->erofs_devfd = fd;
 
 	erofs_info("successfully to open %s", dev);
 	return 0;
 }
 
 /* XXX: temporary soluation. Disk I/O implementation needs to be refactored. */
-int dev_open_ro(const char *dev)
+int dev_open_ro(const char *dev, struct erofs_device *erofs_dev)
 {
 	int fd = open(dev, O_RDONLY | O_BINARY);
 
@@ -116,20 +113,23 @@ int dev_open_ro(const char *dev)
 		return -errno;
 	}
 
-	erofs_devfd = fd;
-	erofs_devname = dev;
-	erofs_devsz = INT64_MAX;
+	erofs_dev->erofs_devfd = fd;
+	erofs_dev->erofs_devname = dev;
+	erofs_dev->erofs_devsz = INT64_MAX;
 	return 0;
 }
 
-u64 dev_length(void)
+u64 dev_length(struct erofs_device erofs_dev)
 {
-	return erofs_devsz;
+	return erofs_dev.erofs_devsz;
 }
 
-int dev_write(const void *buf, u64 offset, size_t len)
+int dev_write_fd(const struct erofs_device dev, const void *buf, u64 offset, size_t len)
 {
 	int ret;
+	const int erofs_devfd = dev.erofs_devfd;
+	const u64 erofs_devsz = dev.erofs_devsz;
+	const char *const erofs_devname = dev.erofs_devname;
 
 	if (cfg.c_dry_run)
 		return 0;
@@ -165,7 +165,12 @@ int dev_write(const void *buf, u64 offset, size_t len)
 	return 0;
 }
 
-int dev_fillzero(u64 offset, size_t len, bool padding)
+int dev_write(struct erofs_device erofs_dev, const void *buf, u64 offset, size_t len)
+{
+	return dev_write_fd(erofs_dev, buf, offset, len);
+}
+
+int dev_fillzero(struct erofs_device erofs_dev, u64 offset, size_t len, bool padding)
 {
 	static const char zero[EROFS_BLKSIZ] = {0};
 	int ret;
@@ -174,23 +179,24 @@ int dev_fillzero(u64 offset, size_t len, bool padding)
 		return 0;
 
 #if defined(HAVE_FALLOCATE) && defined(FALLOC_FL_PUNCH_HOLE)
-	if (!padding && fallocate(erofs_devfd, FALLOC_FL_PUNCH_HOLE |
+	if (!padding && fallocate(erofs_dev.erofs_devfd, FALLOC_FL_PUNCH_HOLE |
 				  FALLOC_FL_KEEP_SIZE, offset, len) >= 0)
 		return 0;
 #endif
 	while (len > EROFS_BLKSIZ) {
-		ret = dev_write(zero, offset, EROFS_BLKSIZ);
+		ret = dev_write(erofs_dev, zero, offset, EROFS_BLKSIZ);
 		if (ret)
 			return ret;
 		len -= EROFS_BLKSIZ;
 		offset += EROFS_BLKSIZ;
 	}
-	return dev_write(zero, offset, len);
+	return dev_write(erofs_dev, zero, offset, len);
 }
 
-int dev_fsync(void)
+int dev_fsync(struct erofs_device erofs_dev)
 {
 	int ret;
+	const int erofs_devfd = erofs_dev.erofs_devfd;
 
 	ret = fsync(erofs_devfd);
 	if (ret) {
@@ -200,12 +206,13 @@ int dev_fsync(void)
 	return 0;
 }
 
-int dev_resize(unsigned int blocks)
+int dev_resize(struct erofs_device erofs_dev, unsigned int blocks)
 {
 	int ret;
 	struct stat st;
 	u64 length;
-
+	const int erofs_devfd = erofs_dev.erofs_devfd;
+	const u64 erofs_devsz = erofs_dev.erofs_devsz;
 	if (cfg.c_dry_run || erofs_devsz != INT64_MAX)
 		return 0;
 
@@ -226,12 +233,15 @@ int dev_resize(unsigned int blocks)
 	if (fallocate(erofs_devfd, 0, st.st_size, length) >= 0)
 		return 0;
 #endif
-	return dev_fillzero(st.st_size, length, true);
+	return dev_fillzero(erofs_dev, st.st_size, length, true);
 }
 
-int dev_read(void *buf, u64 offset, size_t len)
+int dev_read(const struct erofs_device dev, void *buf, u64 offset, size_t len)
 {
 	int ret;
+	const int erofs_devfd = dev.erofs_devfd;
+	const u64 erofs_devsz = dev.erofs_devsz;
+	const char * const erofs_devname = dev.erofs_devname;
 
 	if (cfg.c_dry_run)
 		return 0;
@@ -350,6 +360,6 @@ out:
 		*off_out = off64_out;
 		return ret;
 	}
-#endif
+#endif // LIB_IO_H_
 	return __erofs_copy_file_range(fd_in, off_in, fd_out, off_out, length);
 }
diff --git a/lib/namei.c b/lib/namei.c
index 56f199a..57041f5 100644
--- a/lib/namei.c
+++ b/lib/namei.c
@@ -22,7 +22,7 @@ static dev_t erofs_new_decode_dev(u32 dev)
 	return makedev(major, minor);
 }
 
-int erofs_read_inode_from_disk(struct erofs_inode *vi)
+int erofs_read_inode_from_disk(struct erofs_device fd, struct erofs_inode *vi)
 {
 	int ret, ifmt;
 	char buf[sizeof(struct erofs_inode_extended)];
@@ -30,7 +30,7 @@ int erofs_read_inode_from_disk(struct erofs_inode *vi)
 	struct erofs_inode_extended *die;
 	const erofs_off_t inode_loc = iloc(vi->nid);
 
-	ret = dev_read(buf, inode_loc, sizeof(*dic));
+	ret = dev_read(fd, buf, inode_loc, sizeof(*dic));
 	if (ret < 0)
 		return -EIO;
 
@@ -47,7 +47,7 @@ int erofs_read_inode_from_disk(struct erofs_inode *vi)
 	case EROFS_INODE_LAYOUT_EXTENDED:
 		vi->inode_isize = sizeof(struct erofs_inode_extended);
 
-		ret = dev_read(buf + sizeof(*dic), inode_loc + sizeof(*dic),
+		ret = dev_read(fd, buf + sizeof(*dic), inode_loc + sizeof(*dic),
 			       sizeof(*die) - sizeof(*dic));
 		if (ret < 0)
 			return -EIO;
@@ -187,7 +187,7 @@ struct nameidata {
 	unsigned int	ftype;
 };
 
-int erofs_namei(struct nameidata *nd,
+int erofs_namei(struct erofs_device fd, struct nameidata *nd,
 		const char *name, unsigned int len)
 {
 	erofs_nid_t nid = nd->nid;
@@ -196,7 +196,7 @@ int erofs_namei(struct nameidata *nd,
 	struct erofs_inode vi = { .nid = nid };
 	erofs_off_t offset;
 
-	ret = erofs_read_inode_from_disk(&vi);
+	ret = erofs_read_inode_from_disk(fd, &vi);
 	if (ret)
 		return ret;
 
@@ -207,7 +207,7 @@ int erofs_namei(struct nameidata *nd,
 		struct erofs_dirent *de = (void *)buf;
 		unsigned int nameoff;
 
-		ret = erofs_pread(&vi, buf, maxsize, offset);
+		ret = erofs_pread(fd, &vi, buf, maxsize, offset);
 		if (ret)
 			return ret;
 
@@ -233,7 +233,7 @@ int erofs_namei(struct nameidata *nd,
 	return -ENOENT;
 }
 
-static int link_path_walk(const char *name, struct nameidata *nd)
+static int link_path_walk(struct erofs_device devfd, const char *name, struct nameidata *nd)
 {
 	nd->nid = sbi.root_nid;
 
@@ -250,7 +250,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
 		} while (*p != '\0' && *p != '/');
 
 		DBG_BUGON(p <= name);
-		ret = erofs_namei(nd, name, p - name);
+		ret = erofs_namei(devfd, nd, name, p - name);
 		if (ret)
 			return ret;
 
@@ -262,15 +262,15 @@ static int link_path_walk(const char *name, struct nameidata *nd)
 	return 0;
 }
 
-int erofs_ilookup(const char *path, struct erofs_inode *vi)
+int erofs_ilookup(struct erofs_device devfd, const char *path, struct erofs_inode *vi)
 {
 	int ret;
 	struct nameidata nd;
 
-	ret = link_path_walk(path, &nd);
+	ret = link_path_walk(devfd, path, &nd);
 	if (ret)
 		return ret;
 
 	vi->nid = nd.nid;
-	return erofs_read_inode_from_disk(vi);
+	return erofs_read_inode_from_disk(devfd, vi);
 }
diff --git a/lib/super.c b/lib/super.c
index 0c30403..9cb5768 100644
--- a/lib/super.c
+++ b/lib/super.c
@@ -23,14 +23,14 @@ static bool check_layout_compatibility(struct erofs_sb_info *sbi,
 	return true;
 }
 
-int erofs_read_superblock(void)
+int erofs_read_superblock(struct erofs_device devfd, struct erofs_sb_info *sbi)
 {
 	char data[EROFS_BLKSIZ];
 	struct erofs_super_block *dsb;
 	unsigned int blkszbits;
 	int ret;
 
-	ret = blk_read(data, 0, 1);
+	ret = blk_read(devfd, data, 0, 1);
 	if (ret < 0) {
 		erofs_err("cannot read erofs superblock: %d", ret);
 		return -EIO;
@@ -43,7 +43,7 @@ int erofs_read_superblock(void)
 		return ret;
 	}
 
-	sbi.feature_compat = le32_to_cpu(dsb->feature_compat);
+	sbi->feature_compat = le32_to_cpu(dsb->feature_compat);
 
 	blkszbits = dsb->blkszbits;
 	/* 9(512 bytes) + LOG_SECTORS_PER_BLOCK == LOG_BLOCK_SIZE */
@@ -53,20 +53,20 @@ int erofs_read_superblock(void)
 		return ret;
 	}
 
-	if (!check_layout_compatibility(&sbi, dsb))
+	if (!check_layout_compatibility(sbi, dsb))
 		return ret;
 
-	sbi.blocks = le32_to_cpu(dsb->blocks);
-	sbi.meta_blkaddr = le32_to_cpu(dsb->meta_blkaddr);
-	sbi.xattr_blkaddr = le32_to_cpu(dsb->xattr_blkaddr);
-	sbi.islotbits = EROFS_ISLOTBITS;
-	sbi.root_nid = le16_to_cpu(dsb->root_nid);
-	sbi.inos = le64_to_cpu(dsb->inos);
-	sbi.checksum = le32_to_cpu(dsb->checksum);
+	sbi->blocks = le32_to_cpu(dsb->blocks);
+	sbi->meta_blkaddr = le32_to_cpu(dsb->meta_blkaddr);
+	sbi->xattr_blkaddr = le32_to_cpu(dsb->xattr_blkaddr);
+	sbi->islotbits = EROFS_ISLOTBITS;
+	sbi->root_nid = le16_to_cpu(dsb->root_nid);
+	sbi->inos = le64_to_cpu(dsb->inos);
+	sbi->checksum = le32_to_cpu(dsb->checksum);
 
-	sbi.build_time = le64_to_cpu(dsb->build_time);
-	sbi.build_time_nsec = le32_to_cpu(dsb->build_time_nsec);
+	sbi->build_time = le64_to_cpu(dsb->build_time);
+	sbi->build_time_nsec = le32_to_cpu(dsb->build_time_nsec);
 
-	memcpy(&sbi.uuid, dsb->uuid, sizeof(dsb->uuid));
+	memcpy(&sbi->uuid, dsb->uuid, sizeof(dsb->uuid));
 	return 0;
 }
diff --git a/lib/xattr.c b/lib/xattr.c
index 196133a..9f16664 100644
--- a/lib/xattr.c
+++ b/lib/xattr.c
@@ -547,10 +547,12 @@ static void erofs_cleanxattrs(bool sharedxattrs)
 	shared_xattrs_size = shared_xattrs_count = 0;
 }
 
-static bool erofs_bh_flush_write_shared_xattrs(struct erofs_buffer_head *bh)
+static bool erofs_bh_flush_write_shared_xattrs(
+	struct erofs_device erofs_dev,
+	struct erofs_buffer_head *bh)
 {
 	void *buf = bh->fsprivate;
-	int err = dev_write(buf, erofs_btell(bh, false), shared_xattrs_size);
+	int err = dev_write(erofs_dev, buf, erofs_btell(bh, false), shared_xattrs_size);
 
 	if (err)
 		return false;
diff --git a/lib/zmap.c b/lib/zmap.c
index 7dbda87..69fef80 100644
--- a/lib/zmap.c
+++ b/lib/zmap.c
@@ -12,7 +12,7 @@
 
 int z_erofs_fill_inode(struct erofs_inode *vi)
 {
-	if (!erofs_sb_has_big_pcluster() &&
+	if (!erofs_sb_has_big_pcluster(&sbi) &&
 	    vi->datalayout == EROFS_INODE_FLAT_COMPRESSION_LEGACY) {
 		vi->z_advise = 0;
 		vi->z_algorithmtype[0] = 0;
@@ -24,7 +24,7 @@ int z_erofs_fill_inode(struct erofs_inode *vi)
 	return 0;
 }
 
-static int z_erofs_fill_inode_lazy(struct erofs_inode *vi)
+static int z_erofs_fill_inode_lazy(struct erofs_device erofs_dev, struct erofs_inode *vi)
 {
 	int ret;
 	erofs_off_t pos;
@@ -34,11 +34,11 @@ static int z_erofs_fill_inode_lazy(struct erofs_inode *vi)
 	if (vi->flags & EROFS_I_Z_INITED)
 		return 0;
 
-	DBG_BUGON(!erofs_sb_has_big_pcluster() &&
+	DBG_BUGON(!erofs_sb_has_big_pcluster(&sbi) &&
 		  vi->datalayout == EROFS_INODE_FLAT_COMPRESSION_LEGACY);
 	pos = round_up(iloc(vi->nid) + vi->inode_isize + vi->xattr_isize, 8);
 
-	ret = dev_read(buf, pos, sizeof(buf));
+	ret = dev_read(erofs_dev, buf, pos, sizeof(buf));
 	if (ret < 0)
 		return -EIO;
 
@@ -78,7 +78,9 @@ struct z_erofs_maprecorder {
 	erofs_blk_t pblk, compressedlcs;
 };
 
-static int z_erofs_reload_indexes(struct z_erofs_maprecorder *m,
+static int z_erofs_reload_indexes(
+	struct erofs_device erofs_dev,
+	struct z_erofs_maprecorder *m,
 				  erofs_blk_t eblk)
 {
 	int ret;
@@ -88,7 +90,7 @@ static int z_erofs_reload_indexes(struct z_erofs_maprecorder *m,
 	if (map->index == eblk)
 		return 0;
 
-	ret = blk_read(mpage, eblk, 1);
+	ret = blk_read(erofs_dev, mpage, eblk, 1);
 	if (ret < 0)
 		return -EIO;
 
@@ -97,8 +99,10 @@ static int z_erofs_reload_indexes(struct z_erofs_maprecorder *m,
 	return 0;
 }
 
-static int legacy_load_cluster_from_disk(struct z_erofs_maprecorder *m,
-					 unsigned long lcn)
+static int legacy_load_cluster_from_disk(
+	struct erofs_device erofs_dev,
+	struct z_erofs_maprecorder *m,
+	unsigned long lcn)
 {
 	struct erofs_inode *const vi = m->inode;
 	const erofs_off_t ibase = iloc(vi->nid);
@@ -110,7 +114,7 @@ static int legacy_load_cluster_from_disk(struct z_erofs_maprecorder *m,
 	unsigned int advise, type;
 	int err;
 
-	err = z_erofs_reload_indexes(m, erofs_blknr(pos));
+	err = z_erofs_reload_indexes(erofs_dev, m, erofs_blknr(pos));
 	if (err)
 		return err;
 
@@ -289,8 +293,10 @@ static int unpack_compacted_index(struct z_erofs_maprecorder *m,
 	return 0;
 }
 
-static int compacted_load_cluster_from_disk(struct z_erofs_maprecorder *m,
-					    unsigned long lcn, bool lookahead)
+static int compacted_load_cluster_from_disk(
+	struct erofs_device erofs_dev,
+	struct z_erofs_maprecorder *m,
+	unsigned long lcn, bool lookahead)
 {
 	struct erofs_inode *const vi = m->inode;
 	const unsigned int lclusterbits = vi->z_logical_clusterbits;
@@ -337,28 +343,32 @@ static int compacted_load_cluster_from_disk(struct z_erofs_maprecorder *m,
 	amortizedshift = 2;
 out:
 	pos += lcn * (1 << amortizedshift);
-	err = z_erofs_reload_indexes(m, erofs_blknr(pos));
+	err = z_erofs_reload_indexes(erofs_dev, m, erofs_blknr(pos));
 	if (err)
 		return err;
 	return unpack_compacted_index(m, amortizedshift, erofs_blkoff(pos),
 				      lookahead);
 }
 
-static int z_erofs_load_cluster_from_disk(struct z_erofs_maprecorder *m,
+static int z_erofs_load_cluster_from_disk(
+	struct erofs_device erofs_dev,
+	struct z_erofs_maprecorder *m,
 					  unsigned int lcn, bool lookahead)
 {
 	const unsigned int datamode = m->inode->datalayout;
 
 	if (datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY)
-		return legacy_load_cluster_from_disk(m, lcn);
+		return legacy_load_cluster_from_disk(erofs_dev, m, lcn);
 
 	if (datamode == EROFS_INODE_FLAT_COMPRESSION)
-		return compacted_load_cluster_from_disk(m, lcn, lookahead);
+		return compacted_load_cluster_from_disk(erofs_dev, m, lcn, lookahead);
 
 	return -EINVAL;
 }
 
-static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m,
+static int z_erofs_extent_lookback(
+	struct erofs_device erofs_dev,
+	struct z_erofs_maprecorder *m,
 				   unsigned int lookback_distance)
 {
 	struct erofs_inode *const vi = m->inode;
@@ -376,7 +386,7 @@ static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m,
 
 	/* load extent head logical cluster if needed */
 	lcn -= lookback_distance;
-	err = z_erofs_load_cluster_from_disk(m, lcn, false);
+	err = z_erofs_load_cluster_from_disk(erofs_dev, m, lcn, false);
 	if (err)
 		return err;
 
@@ -388,7 +398,7 @@ static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m,
 			DBG_BUGON(1);
 			return -EFSCORRUPTED;
 		}
-		return z_erofs_extent_lookback(m, m->delta[0]);
+		return z_erofs_extent_lookback(erofs_dev, m, m->delta[0]);
 	case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
 		map->m_flags &= ~EROFS_MAP_ZIPPED;
 		/* fallthrough */
@@ -404,8 +414,10 @@ static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m,
 	return 0;
 }
 
-static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m,
-					    unsigned int initial_lcn)
+static int z_erofs_get_extent_compressedlen(
+	struct erofs_device erofs_dev,
+	struct z_erofs_maprecorder *m,
+	unsigned int initial_lcn)
 {
 	struct erofs_inode *const vi = m->inode;
 	struct erofs_map_blocks *const map = m->map;
@@ -425,7 +437,7 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m,
 	if (m->compressedlcs)
 		goto out;
 
-	err = z_erofs_load_cluster_from_disk(m, lcn, false);
+	err = z_erofs_load_cluster_from_disk(erofs_dev, m, lcn, false);
 	if (err)
 		return err;
 
@@ -471,7 +483,9 @@ err_bonus_cblkcnt:
 	return -EFSCORRUPTED;
 }
 
-static int z_erofs_get_extent_decompressedlen(struct z_erofs_maprecorder *m)
+static int z_erofs_get_extent_decompressedlen(
+	struct erofs_device erofs_dev,
+	struct z_erofs_maprecorder *m)
 {
 	struct erofs_inode *const vi = m->inode;
 	struct erofs_map_blocks *map = m->map;
@@ -486,7 +500,7 @@ static int z_erofs_get_extent_decompressedlen(struct z_erofs_maprecorder *m)
 			return 0;
 		}
 
-		err = z_erofs_load_cluster_from_disk(m, lcn, true);
+		err = z_erofs_load_cluster_from_disk(erofs_dev, m, lcn, true);
 		if (err)
 			return err;
 
@@ -513,7 +527,9 @@ static int z_erofs_get_extent_decompressedlen(struct z_erofs_maprecorder *m)
 	return 0;
 }
 
-int z_erofs_map_blocks_iter(struct erofs_inode *vi,
+int z_erofs_map_blocks_iter(
+					struct erofs_device erofs_dev,
+					struct erofs_inode *vi,
 			    struct erofs_map_blocks *map,
 			    int flags)
 {
@@ -535,7 +551,7 @@ int z_erofs_map_blocks_iter(struct erofs_inode *vi,
 		goto out;
 	}
 
-	err = z_erofs_fill_inode_lazy(vi);
+	err = z_erofs_fill_inode_lazy(erofs_dev, vi);
 	if (err)
 		goto out;
 
@@ -544,7 +560,7 @@ int z_erofs_map_blocks_iter(struct erofs_inode *vi,
 	initial_lcn = ofs >> lclusterbits;
 	endoff = ofs & ((1 << lclusterbits) - 1);
 
-	err = z_erofs_load_cluster_from_disk(&m, initial_lcn, false);
+	err = z_erofs_load_cluster_from_disk(erofs_dev, &m, initial_lcn, false);
 	if (err)
 		goto out;
 
@@ -573,7 +589,7 @@ int z_erofs_map_blocks_iter(struct erofs_inode *vi,
 		/* fallthrough */
 	case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
 		/* get the correspoinding first chunk */
-		err = z_erofs_extent_lookback(&m, m.delta[0]);
+		err = z_erofs_extent_lookback(erofs_dev, &m, m.delta[0]);
 		if (err)
 			goto out;
 		break;
@@ -588,12 +604,12 @@ int z_erofs_map_blocks_iter(struct erofs_inode *vi,
 	map->m_pa = blknr_to_addr(m.pblk);
 	map->m_flags |= EROFS_MAP_MAPPED;
 
-	err = z_erofs_get_extent_compressedlen(&m, initial_lcn);
+	err = z_erofs_get_extent_compressedlen(erofs_dev, &m, initial_lcn);
 	if (err)
 		goto out;
 
 	if (flags & EROFS_GET_BLOCKS_FIEMAP) {
-		err = z_erofs_get_extent_decompressedlen(&m);
+		err = z_erofs_get_extent_decompressedlen(erofs_dev, &m);
 		if (!err)
 			map->m_flags |= EROFS_MAP_FULL_MAPPED;
 	}
diff --git a/mkfs/main.c b/mkfs/main.c
index 4ea5467..16f8060 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -164,7 +164,7 @@ static int parse_extended_opts(const char *opts)
 		if (MATCH_EXTENTED_OPT("nosbcrc", token, keylen)) {
 			if (vallen)
 				return -EINVAL;
-			erofs_sb_clear_sb_chksum();
+			erofs_sb_clear_sb_chksum(&sbi);
 		}
 
 		if (MATCH_EXTENTED_OPT("noinline_data", token, keylen)) {
@@ -259,7 +259,7 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
 			break;
 
 		case 4:
-			opt = erofs_selabel_open(optarg);
+			opt = erofs_global_selabel_open(optarg);
 			if (opt && opt != -EBUSY)
 				return opt;
 			break;
@@ -343,7 +343,7 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
 					  optarg);
 				return -EINVAL;
 			}
-			erofs_sb_set_chunked_file();
+			erofs_sb_set_chunked_file(&sbi);
 			break;
 		case 12:
 			quiet = true;
@@ -411,7 +411,7 @@ int erofs_mkfs_update_super_block(struct erofs_buffer_head *bh,
 	sb.root_nid     = cpu_to_le16(root_nid);
 	memcpy(sb.uuid, sbi.uuid, sizeof(sb.uuid));
 
-	if (erofs_sb_has_compr_cfgs())
+	if (erofs_sb_has_compr_cfgs(&sbi))
 		sb.u1.available_compr_algs = sbi.available_compr_algs;
 	else
 		sb.u1.lz4_max_distance = cpu_to_le16(sbi.lz4_max_distance);
@@ -429,14 +429,14 @@ int erofs_mkfs_update_super_block(struct erofs_buffer_head *bh,
 	return 0;
 }
 
-static int erofs_mkfs_superblock_csum_set(void)
+static int erofs_mkfs_superblock_csum_set(struct erofs_device erofs_dev)
 {
 	int ret;
 	u8 buf[EROFS_BLKSIZ];
 	u32 crc;
 	struct erofs_super_block *sb;
 
-	ret = blk_read(buf, 0, 1);
+	ret = blk_read(erofs_dev, buf, 0, 1);
 	if (ret) {
 		erofs_err("failed to read superblock to set checksum: %s",
 			  erofs_strerror(ret));
@@ -462,7 +462,7 @@ static int erofs_mkfs_superblock_csum_set(void)
 	/* set up checksum field to erofs_super_block */
 	sb->checksum = cpu_to_le32(crc);
 
-	ret = blk_write(buf, 0, 1);
+	ret = blk_write(erofs_dev, buf, 0, 1);
 	if (ret) {
 		erofs_err("failed to write checksummed superblock: %s",
 			  erofs_strerror(ret));
@@ -530,8 +530,9 @@ int main(int argc, char **argv)
 	erofs_blk_t nblocks;
 	struct timeval t;
 	char uuid_str[37] = "not available";
+	struct erofs_device erofs_dev;
 
-	erofs_init_configure();
+	erofs_init_global_configure();
 	erofs_mkfs_default_options();
 
 	err = mkfs_parse_options_cfg(argc, argv);
@@ -572,7 +573,7 @@ int main(int argc, char **argv)
 		sbi.build_time_nsec = t.tv_usec;
 	}
 
-	err = dev_open(cfg.c_img_path);
+	err = dev_open(cfg.c_img_path, &erofs_dev);
 	if (err) {
 		usage();
 		return 1;
@@ -591,7 +592,7 @@ int main(int argc, char **argv)
 	}
 #endif
 	erofs_show_config();
-	if (erofs_sb_has_chunked_file())
+	if (erofs_sb_has_chunked_file(&sbi))
 		erofs_warn("EXPERIMENTAL chunked file feature in use. Use at your own risk!");
 	erofs_set_fs_root(cfg.c_src_path);
 #ifndef NDEBUG
@@ -619,7 +620,7 @@ int main(int argc, char **argv)
 		goto exit;
 	}
 
-	err = z_erofs_compress_init(sb_bh);
+	err = z_erofs_compress_init(erofs_dev, sb_bh);
 	if (err) {
 		erofs_err("Failed to initialize compressor: %s",
 			  erofs_strerror(err));
@@ -640,7 +641,7 @@ int main(int argc, char **argv)
 		goto exit;
 	}
 
-	root_inode = erofs_mkfs_build_tree_from_path(NULL, cfg.c_src_path);
+	root_inode = erofs_mkfs_build_tree_from_path(erofs_dev, NULL, cfg.c_src_path);
 	if (IS_ERR(root_inode)) {
 		err = PTR_ERR(root_inode);
 		goto exit;
@@ -651,7 +652,7 @@ int main(int argc, char **argv)
 
 	if (cfg.c_chunkbits) {
 		erofs_info("total metadata: %u blocks", erofs_mapbh(NULL));
-		err = erofs_blob_remap();
+		err = erofs_blob_remap(erofs_dev);
 		if (err)
 			goto exit;
 	}
@@ -661,24 +662,24 @@ int main(int argc, char **argv)
 		goto exit;
 
 	/* flush all remaining buffers */
-	if (!erofs_bflush(NULL))
+	if (!erofs_bflush(erofs_dev, NULL))
 		err = -EIO;
 	else
-		err = dev_resize(nblocks);
+		err = dev_resize(erofs_dev, nblocks);
 
-	if (!err && erofs_sb_has_sb_chksum())
-		err = erofs_mkfs_superblock_csum_set();
+	if (!err && erofs_sb_has_sb_chksum(&sbi))
+		err = erofs_mkfs_superblock_csum_set(erofs_dev);
 exit:
 	z_erofs_compress_exit();
 #ifdef WITH_ANDROID
 	erofs_droid_blocklist_fclose();
 #endif
-	dev_close();
+	dev_close(&erofs_dev);
 	erofs_cleanup_compress_hints();
 	erofs_cleanup_exclude_rules();
 	if (cfg.c_chunkbits)
 		erofs_blob_exit();
-	erofs_exit_configure();
+	erofs_exit_global_configure();
 
 	if (err) {
 		erofs_err("\tCould not format the device : %s\n",
-- 
2.34.0.rc2.393.gf8c9666880-goog


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v1 2/4] Mark certain callback function pointers as const
  2021-11-21  5:39 [PATCH v1 0/3] Make erofs-utils more library friendly Kelvin Zhang via Linux-erofs
  2021-11-21  5:39 ` [PATCH v1 1/4] Make erofs_devfd a parameter for most functions Kelvin Zhang via Linux-erofs
@ 2021-11-21  5:39 ` Kelvin Zhang via Linux-erofs
  2021-11-21  5:39 ` [PATCH v1 3/4] Make super block info struct a paramater instead of globals Kelvin Zhang via Linux-erofs
  2021-11-21 10:31 ` [PATCH v1 0/3] Make erofs-utils more library friendly Gao Xiang
  3 siblings, 0 replies; 8+ messages in thread
From: Kelvin Zhang via Linux-erofs @ 2021-11-21  5:39 UTC (permalink / raw)
  To: linux-erofs mailing list, Li Guifu, Miao Xie, Fang Wei
  Cc: Kelvin Zhang, Chao Yu

Global variables aren't bad, until you start mutating them in multiple
places.

Signed-off-by: Kelvin Zhang <zhangkelvin@google.com>
---
 include/erofs/cache.h    | 8 ++++----
 lib/cache.c              | 6 +++---
 lib/compressor.c         | 2 +-
 lib/compressor.h         | 8 ++++----
 lib/compressor_liblzma.c | 2 +-
 lib/compressor_lz4.c     | 2 +-
 lib/compressor_lz4hc.c   | 2 +-
 7 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/include/erofs/cache.h b/include/erofs/cache.h
index 051c696..fd13614 100644
--- a/include/erofs/cache.h
+++ b/include/erofs/cache.h
@@ -31,7 +31,7 @@ struct erofs_buffer_head {
 	struct erofs_buffer_block *block;
 
 	erofs_off_t off;
-	struct erofs_bhops *op;
+	const struct erofs_bhops *op;
 
 	void *fsprivate;
 };
@@ -64,9 +64,9 @@ static inline const int get_alignsize(int type, int *type_ret)
 	return -EINVAL;
 }
 
-extern struct erofs_bhops erofs_drop_directly_bhops;
-extern struct erofs_bhops erofs_skip_write_bhops;
-extern struct erofs_bhops erofs_buf_write_bhops;
+extern const struct erofs_bhops erofs_drop_directly_bhops;
+extern const struct erofs_bhops erofs_skip_write_bhops;
+extern const struct erofs_bhops erofs_buf_write_bhops;
 
 static inline erofs_off_t erofs_btell(struct erofs_buffer_head *bh, bool end)
 {
diff --git a/lib/cache.c b/lib/cache.c
index bae172c..afb29d0 100644
--- a/lib/cache.c
+++ b/lib/cache.c
@@ -28,7 +28,7 @@ static bool erofs_bh_flush_drop_directly(
 	return erofs_bh_flush_generic_end(bh);
 }
 
-struct erofs_bhops erofs_drop_directly_bhops = {
+const struct erofs_bhops erofs_drop_directly_bhops = {
 	.flush = erofs_bh_flush_drop_directly,
 };
 
@@ -39,7 +39,7 @@ static bool erofs_bh_flush_skip_write(
 	return false;
 }
 
-struct erofs_bhops erofs_skip_write_bhops = {
+const struct erofs_bhops erofs_skip_write_bhops = {
 	.flush = erofs_bh_flush_skip_write,
 };
 
@@ -65,7 +65,7 @@ static bool erofs_bh_flush_buf_write(
 }
 
 
-struct erofs_bhops erofs_buf_write_bhops = {
+const struct erofs_bhops erofs_buf_write_bhops = {
 	.flush = erofs_bh_flush_buf_write,
 };
 
diff --git a/lib/compressor.c b/lib/compressor.c
index ad12cdf..6362825 100644
--- a/lib/compressor.c
+++ b/lib/compressor.c
@@ -10,7 +10,7 @@
 
 #define EROFS_CONFIG_COMPR_DEF_BOUNDARY		(128)
 
-static struct erofs_compressor *compressors[] = {
+static const struct erofs_compressor *compressors[] = {
 #if LZ4_ENABLED
 #if LZ4HC_ENABLED
 		&erofs_compressor_lz4hc,
diff --git a/lib/compressor.h b/lib/compressor.h
index aa85ae0..1ea2724 100644
--- a/lib/compressor.h
+++ b/lib/compressor.h
@@ -27,7 +27,7 @@ struct erofs_compressor {
 };
 
 struct erofs_compress {
-	struct erofs_compressor *alg;
+	const struct erofs_compressor *alg;
 
 	unsigned int compress_threshold;
 	unsigned int compression_level;
@@ -41,9 +41,9 @@ struct erofs_compress {
 };
 
 /* list of compression algorithms */
-extern struct erofs_compressor erofs_compressor_lz4;
-extern struct erofs_compressor erofs_compressor_lz4hc;
-extern struct erofs_compressor erofs_compressor_lzma;
+extern const struct erofs_compressor erofs_compressor_lz4;
+extern const struct erofs_compressor erofs_compressor_lz4hc;
+extern const struct erofs_compressor erofs_compressor_lzma;
 
 int erofs_compress_destsize(struct erofs_compress *c,
 			    void *src, unsigned int *srcsize,
diff --git a/lib/compressor_liblzma.c b/lib/compressor_liblzma.c
index 576cdae..3229841 100644
--- a/lib/compressor_liblzma.c
+++ b/lib/compressor_liblzma.c
@@ -96,7 +96,7 @@ static int erofs_compressor_liblzma_init(struct erofs_compress *c)
 	return 0;
 }
 
-struct erofs_compressor erofs_compressor_lzma = {
+const struct erofs_compressor erofs_compressor_lzma = {
 	.name = "lzma",
 	.default_level = LZMA_PRESET_DEFAULT,
 	.best_level = LZMA_PRESET_EXTREME,
diff --git a/lib/compressor_lz4.c b/lib/compressor_lz4.c
index f6832be..fc8c23c 100644
--- a/lib/compressor_lz4.c
+++ b/lib/compressor_lz4.c
@@ -37,7 +37,7 @@ static int compressor_lz4_init(struct erofs_compress *c)
 	return 0;
 }
 
-struct erofs_compressor erofs_compressor_lz4 = {
+const struct erofs_compressor erofs_compressor_lz4 = {
 	.name = "lz4",
 	.default_level = 0,
 	.best_level = 0,
diff --git a/lib/compressor_lz4hc.c b/lib/compressor_lz4hc.c
index fd801ab..3f68b00 100644
--- a/lib/compressor_lz4hc.c
+++ b/lib/compressor_lz4hc.c
@@ -59,7 +59,7 @@ static int compressor_lz4hc_setlevel(struct erofs_compress *c,
 	return 0;
 }
 
-struct erofs_compressor erofs_compressor_lz4hc = {
+const struct erofs_compressor erofs_compressor_lz4hc = {
 	.name = "lz4hc",
 	.default_level = LZ4HC_CLEVEL_DEFAULT,
 	.best_level = LZ4HC_CLEVEL_MAX,
-- 
2.34.0.rc2.393.gf8c9666880-goog


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v1 3/4] Make super block info struct a paramater instead of globals
  2021-11-21  5:39 [PATCH v1 0/3] Make erofs-utils more library friendly Kelvin Zhang via Linux-erofs
  2021-11-21  5:39 ` [PATCH v1 1/4] Make erofs_devfd a parameter for most functions Kelvin Zhang via Linux-erofs
  2021-11-21  5:39 ` [PATCH v1 2/4] Mark certain callback function pointers as const Kelvin Zhang via Linux-erofs
@ 2021-11-21  5:39 ` Kelvin Zhang via Linux-erofs
  2021-11-23  7:54   ` Gao Xiang
  2021-11-21 10:31 ` [PATCH v1 0/3] Make erofs-utils more library friendly Gao Xiang
  3 siblings, 1 reply; 8+ messages in thread
From: Kelvin Zhang via Linux-erofs @ 2021-11-21  5:39 UTC (permalink / raw)
  To: linux-erofs mailing list, Li Guifu, Miao Xie, Fang Wei
  Cc: Kelvin Zhang, Chao Yu


Test: mkfs.erofs on system.img of
    aosp_cf_x86_64_phone-target_files-7731383.zip
    Make sure output is the same before/after this patch

Signed-off-by: Kelvin Zhang <zhangkelvin@google.com>
---
 dump/main.c                | 67 +++++++++++++++++++------------
 fsck/main.c                | 61 +++++++++++++++++++----------
 fuse/dir.c                 |  5 ++-
 fuse/main.c                |  7 ++--
 include/erofs/compress.h   |  2 +
 include/erofs/decompress.h |  5 ++-
 include/erofs/inode.h      |  3 +-
 include/erofs/internal.h   | 26 ++++++++-----
 include/erofs/xattr.h      |  2 +-
 lib/compress.c             | 80 +++++++++++++++++++++++---------------
 lib/compressor.c           |  7 +++-
 lib/compressor.h           |  5 ++-
 lib/compressor_lz4.c       |  6 ++-
 lib/compressor_lz4hc.c     |  4 +-
 lib/config.c               |  1 -
 lib/data.c                 | 36 ++++++++++-------
 lib/decompress.c           | 12 +++---
 lib/inode.c                | 60 ++++++++++++++++------------
 lib/namei.c                | 40 ++++++++++++-------
 lib/xattr.c                |  4 +-
 lib/zmap.c                 | 46 +++++++++++++---------
 mkfs/main.c                | 63 ++++++++++++++++--------------
 22 files changed, 332 insertions(+), 210 deletions(-)

diff --git a/dump/main.c b/dump/main.c
index 8d0dbd0..0ac97a0 100644
--- a/dump/main.c
+++ b/dump/main.c
@@ -85,7 +85,10 @@ static struct erofsdump_feature feature_lists[] = {
 	{ false, EROFS_FEATURE_INCOMPAT_CHUNKED_FILE, "chunked_file" },
 };
 
-static int erofs_read_dir(struct erofs_device fd, erofs_nid_t nid, erofs_nid_t parent_nid);
+static int erofs_read_dir(
+	struct erofs_device fd,
+	struct erofs_sb_info *sbi,
+	erofs_nid_t nid, erofs_nid_t parent_nid);
 static inline int erofs_checkdirent(struct erofs_dirent *de,
 		struct erofs_dirent *last_de,
 		u32 maxsize, const char *dname);
@@ -258,7 +261,9 @@ static inline int erofs_checkdirent(struct erofs_dirent *de,
 }
 
 static int erofs_read_dirent(
-		struct erofs_device erofs_dev, struct erofs_dirent *de,
+		struct erofs_device erofs_dev,
+		struct erofs_sb_info *sbi,
+		struct erofs_dirent *de,
 		erofs_nid_t nid, erofs_nid_t parent_nid,
 		const char *dname)
 {
@@ -268,7 +273,7 @@ static int erofs_read_dirent(
 
 	stats.files++;
 	stats.file_category_stat[de->file_type]++;
-	err = erofs_read_inode_from_disk(erofs_dev, &inode);
+	err = erofs_read_inode_from_disk(erofs_dev, sbi, &inode);
 	if (err) {
 		erofs_err("read file inode from disk failed!");
 		return err;
@@ -289,7 +294,7 @@ static int erofs_read_dirent(
 
 	if ((de->file_type == EROFS_FT_DIR)
 			&& de->nid != nid && de->nid != parent_nid) {
-		err = erofs_read_dir(erofs_dev, de->nid, nid);
+		err = erofs_read_dir(erofs_dev, sbi, de->nid, nid);
 		if (err) {
 			erofs_err("parse dir nid %llu error occurred\n",
 					de->nid);
@@ -299,14 +304,17 @@ static int erofs_read_dirent(
 	return 0;
 }
 
-static int erofs_read_dir(struct erofs_device fd, erofs_nid_t nid, erofs_nid_t parent_nid)
+static int erofs_read_dir(
+	struct erofs_device fd,
+	struct erofs_sb_info *sbi,
+	erofs_nid_t nid, erofs_nid_t parent_nid)
 {
 	int err;
 	erofs_off_t offset;
 	char buf[EROFS_BLKSIZ];
 	struct erofs_inode vi = { .nid = nid };
 
-	err = erofs_read_inode_from_disk(fd, &vi);
+	err = erofs_read_inode_from_disk(fd, sbi, &vi);
 	if (err)
 		return err;
 
@@ -318,7 +326,7 @@ static int erofs_read_dir(struct erofs_device fd, erofs_nid_t nid, erofs_nid_t p
 		struct erofs_dirent *end;
 		unsigned int nameoff;
 
-		err = erofs_pread(fd, &vi, buf, maxsize, offset);
+		err = erofs_pread(fd, sbi, &vi, buf, maxsize, offset);
 		if (err)
 			return err;
 
@@ -338,7 +346,7 @@ static int erofs_read_dir(struct erofs_device fd, erofs_nid_t nid, erofs_nid_t p
 			ret = erofs_checkdirent(de, end, maxsize, dname);
 			if (ret < 0)
 				return ret;
-			ret = erofs_read_dirent(fd, de, nid, parent_nid, dname);
+			ret = erofs_read_dirent(fd, sbi, de, nid, parent_nid, dname);
 			if (ret < 0)
 				return ret;
 			++de;
@@ -348,7 +356,10 @@ static int erofs_read_dir(struct erofs_device fd, erofs_nid_t nid, erofs_nid_t p
 	return 0;
 }
 
-static int erofs_get_pathname(struct erofs_device fd, erofs_nid_t nid, erofs_nid_t parent_nid,
+static int erofs_get_pathname(
+	struct erofs_device fd,
+	struct erofs_sb_info *sbi,
+	erofs_nid_t nid, erofs_nid_t parent_nid,
 		erofs_nid_t target, char *path, unsigned int pos)
 {
 	int err;
@@ -357,10 +368,10 @@ static int erofs_get_pathname(struct erofs_device fd, erofs_nid_t nid, erofs_nid
 	struct erofs_inode inode = { .nid = nid };
 
 	path[pos++] = '/';
-	if (target == sbi.root_nid)
+	if (target == sbi->root_nid)
 		return 0;
 
-	err = erofs_read_inode_from_disk(fd, &inode);
+	err = erofs_read_inode_from_disk(fd, sbi, &inode);
 	if (err) {
 		erofs_err("read inode failed @ nid %llu", nid | 0ULL);
 		return err;
@@ -374,7 +385,7 @@ static int erofs_get_pathname(struct erofs_device fd, erofs_nid_t nid, erofs_nid
 		struct erofs_dirent *end;
 		unsigned int nameoff;
 
-		err = erofs_pread(fd, &inode, buf, maxsize, offset);
+		err = erofs_pread(fd, sbi, &inode, buf, maxsize, offset);
 		if (err)
 			return err;
 
@@ -400,7 +411,7 @@ static int erofs_get_pathname(struct erofs_device fd, erofs_nid_t nid, erofs_nid
 					de->nid != parent_nid &&
 					de->nid != nid) {
 				memcpy(path + pos, dname, len);
-				err = erofs_get_pathname(fd, de->nid, nid,
+				err = erofs_get_pathname(fd, sbi, de->nid, nid,
 						target, path, pos + len);
 				if (!err)
 					return 0;
@@ -415,16 +426,19 @@ static int erofs_get_pathname(struct erofs_device fd, erofs_nid_t nid, erofs_nid
 
 static int erofsdump_map_blocks(
 	struct erofs_device erofs_dev,
+	struct erofs_sb_info *sbi,
 	struct erofs_inode *inode,
 	struct erofs_map_blocks *map,
 	int flags)
 {
 	if (erofs_inode_is_data_compressed(inode->datalayout))
-		return z_erofs_map_blocks_iter(erofs_dev, inode, map, flags);
-	return erofs_map_blocks(erofs_dev, inode, map, flags);
+		return z_erofs_map_blocks_iter(erofs_dev, sbi, inode, map, flags);
+	return erofs_map_blocks(erofs_dev, sbi, inode, map, flags);
 }
 
-static void erofsdump_show_fileinfo(struct erofs_device fd, bool show_extent)
+static void erofsdump_show_fileinfo(
+	struct erofs_device fd,
+	struct erofs_sb_info *sbi, bool show_extent)
 {
 	int err, i;
 	erofs_off_t size;
@@ -439,7 +453,7 @@ static void erofsdump_show_fileinfo(struct erofs_device fd, bool show_extent)
 		.m_la = 0,
 	};
 
-	err = erofs_read_inode_from_disk(fd, &inode);
+	err = erofs_read_inode_from_disk(fd, sbi, &inode);
 	if (err) {
 		erofs_err("read inode failed @ nid %llu", inode.nid | 0ULL);
 		return;
@@ -451,7 +465,7 @@ static void erofsdump_show_fileinfo(struct erofs_device fd, bool show_extent)
 		return;
 	}
 
-	err = erofs_get_pathname(fd, sbi.root_nid, sbi.root_nid,
+	err = erofs_get_pathname(fd, sbi, sbi->root_nid, sbi->root_nid,
 				 inode.nid, path, 0);
 	if (err < 0) {
 		erofs_err("file path not found @ nid %llu", inode.nid | 0ULL);
@@ -484,7 +498,7 @@ static void erofsdump_show_fileinfo(struct erofs_device fd, bool show_extent)
 
 	fprintf(stdout, "\n Ext:   logical offset   |  length :     physical offset    |  length \n");
 	while (map.m_la < inode.i_size) {
-		err = erofsdump_map_blocks(fd, &inode, &map,
+		err = erofsdump_map_blocks(fd, sbi, &inode, &map,
 				EROFS_GET_BLOCKS_FIEMAP);
 		if (err) {
 			erofs_err("get file blocks range failed");
@@ -584,11 +598,13 @@ static void erofsdump_file_statistic(void)
 			stats.compress_rate);
 }
 
-static void erofsdump_print_statistic(struct erofs_device fd)
+static void erofsdump_print_statistic(
+	struct erofs_device fd,
+	struct erofs_sb_info *sbi)
 {
 	int err;
 
-	err = erofs_read_dir(fd, sbi.root_nid, sbi.root_nid);
+	err = erofs_read_dir(fd, sbi, sbi->root_nid, sbi->root_nid);
 	if (err) {
 		erofs_err("read dir failed");
 		return;
@@ -604,7 +620,7 @@ static void erofsdump_print_statistic(struct erofs_device fd)
 	erofsdump_filetype_distribution(file_types, OTHERFILETYPE);
 }
 
-static void erofsdump_show_superblock(void)
+static void erofsdump_show_superblock(struct erofs_sb_info sbi)
 {
 	time_t time = sbi.build_time;
 	char uuid_str[37] = "not available";
@@ -643,6 +659,7 @@ int main(int argc, char **argv)
 {
 	int err;
 	struct erofs_device erofs_dev;
+	struct erofs_sb_info sbi;
 
 	erofs_init_global_configure();
 	err = erofsdump_parse_options_cfg(argc, argv);
@@ -669,10 +686,10 @@ int main(int argc, char **argv)
 		dumpcfg.totalshow = 1;
 	}
 	if (dumpcfg.show_superblock)
-		erofsdump_show_superblock();
+		erofsdump_show_superblock(sbi);
 
 	if (dumpcfg.show_statistics)
-		erofsdump_print_statistic(erofs_dev);
+		erofsdump_print_statistic(erofs_dev, &sbi);
 
 	if (dumpcfg.show_extent && !dumpcfg.show_inode) {
 		usage();
@@ -680,7 +697,7 @@ int main(int argc, char **argv)
 	}
 
 	if (dumpcfg.show_inode)
-		erofsdump_show_fileinfo(erofs_dev, dumpcfg.show_extent);
+		erofsdump_show_fileinfo(erofs_dev, &sbi, dumpcfg.show_extent);
 
 exit:
 	erofs_exit_global_configure();
diff --git a/fsck/main.c b/fsck/main.c
index b69333b..d6ce1a4 100644
--- a/fsck/main.c
+++ b/fsck/main.c
@@ -11,7 +11,10 @@
 #include "erofs/io.h"
 #include "erofs/decompress.h"
 
-static void erofs_check_inode(struct erofs_device devfd, erofs_nid_t pnid, erofs_nid_t nid);
+static void erofs_check_inode(
+	struct erofs_device devfd,
+	struct erofs_sb_info *sbi,
+	erofs_nid_t pnid, erofs_nid_t nid);
 
 struct erofsfsck_cfg {
 	bool corrupted;
@@ -138,7 +141,10 @@ static bool check_special_dentry(struct erofs_dirent *de,
 	return true;
 }
 
-static int traverse_dirents(struct erofs_device devfd, erofs_nid_t pnid, erofs_nid_t nid,
+static int traverse_dirents(
+	struct erofs_device devfd,
+	struct erofs_sb_info *sbi,
+	erofs_nid_t pnid, erofs_nid_t nid,
 			    void *dentry_blk, erofs_blk_t block,
 			    unsigned int next_nameoff, unsigned int maxsize)
 {
@@ -212,7 +218,7 @@ static int traverse_dirents(struct erofs_device devfd, erofs_nid_t pnid, erofs_n
 				goto out;
 			}
 		} else {
-			erofs_check_inode(devfd, nid, de->nid);
+			erofs_check_inode(devfd, sbi, nid, de->nid);
 		}
 
 		if (fsckcfg.corrupted) {
@@ -236,7 +242,9 @@ out:
 }
 
 static int verify_uncompressed_inode(
-	struct erofs_device erofs_dev, struct erofs_inode *inode)
+	struct erofs_device erofs_dev,
+	struct erofs_sb_info *sbi,
+	struct erofs_inode *inode)
 {
 	struct erofs_map_blocks map = {
 		.index = UINT_MAX,
@@ -247,7 +255,7 @@ static int verify_uncompressed_inode(
 
 	while (ptr < inode->i_size) {
 		map.m_la = ptr;
-		ret = erofs_map_blocks(erofs_dev, inode, &map, 0);
+		ret = erofs_map_blocks(erofs_dev, sbi, inode, &map, 0);
 		if (ret)
 			return ret;
 
@@ -274,7 +282,10 @@ static int verify_uncompressed_inode(
 	return 0;
 }
 
-static int verify_compressed_inode(struct erofs_device erofs_dev, struct erofs_inode *inode)
+static int verify_compressed_inode(
+	struct erofs_device erofs_dev,
+	struct erofs_sb_info *sbi,
+	struct erofs_inode *inode)
 {
 	struct erofs_map_blocks map = {
 		.index = UINT_MAX,
@@ -288,7 +299,7 @@ static int verify_compressed_inode(struct erofs_device erofs_dev, struct erofs_i
 	while (end > 0) {
 		map.m_la = end - 1;
 
-		ret = z_erofs_map_blocks_iter(erofs_dev, inode, &map, 0);
+		ret = z_erofs_map_blocks_iter(erofs_dev, sbi, inode, &map, 0);
 		if (ret)
 			goto out;
 
@@ -336,7 +347,7 @@ static int verify_compressed_inode(struct erofs_device erofs_dev, struct erofs_i
 					.decodedlength = map.m_llen,
 					.alg = algorithmformat,
 					.partial_decoding = 0
-					 });
+					 }, sbi);
 
 		if (ret < 0) {
 			erofs_err("failed to decompress data of m_pa %" PRIu64 ", m_plen %" PRIu64 " @ nid %llu: %d",
@@ -359,7 +370,10 @@ out:
 	return ret < 0 ? ret : 0;
 }
 
-static int erofs_verify_xattr(struct erofs_device erofs_dev, struct erofs_inode *inode)
+static int erofs_verify_xattr(
+	struct erofs_device erofs_dev,
+	struct erofs_sb_info *sbi,
+	struct erofs_inode *inode)
 {
 	unsigned int xattr_hdr_size = sizeof(struct erofs_xattr_ibody_header);
 	unsigned int xattr_entry_size = sizeof(struct erofs_xattr_entry);
@@ -384,7 +398,7 @@ static int erofs_verify_xattr(struct erofs_device erofs_dev, struct erofs_inode
 		}
 	}
 
-	addr = iloc(inode->nid) + inode->inode_isize;
+	addr = iloc(sbi, inode->nid) + inode->inode_isize;
 	ret = dev_read(erofs_dev, buf, addr, xattr_hdr_size);
 	if (ret < 0) {
 		erofs_err("failed to read xattr header @ nid %llu: %d",
@@ -437,7 +451,10 @@ out:
 	return ret;
 }
 
-static int erofs_verify_inode_data(struct erofs_device erofs_dev, struct erofs_inode *inode)
+static int erofs_verify_inode_data(
+	struct erofs_device erofs_dev,
+	struct erofs_sb_info *sbi,
+	struct erofs_inode *inode)
 {
 	int ret;
 
@@ -448,11 +465,11 @@ static int erofs_verify_inode_data(struct erofs_device erofs_dev, struct erofs_i
 	case EROFS_INODE_FLAT_PLAIN:
 	case EROFS_INODE_FLAT_INLINE:
 	case EROFS_INODE_CHUNK_BASED:
-		ret = verify_uncompressed_inode(erofs_dev, inode);
+		ret = verify_uncompressed_inode(erofs_dev, sbi, inode);
 		break;
 	case EROFS_INODE_FLAT_COMPRESSION_LEGACY:
 	case EROFS_INODE_FLAT_COMPRESSION:
-		ret = verify_compressed_inode(erofs_dev, inode);
+		ret = verify_compressed_inode(erofs_dev, sbi, inode);
 		break;
 	default:
 		ret = -EINVAL;
@@ -466,7 +483,10 @@ static int erofs_verify_inode_data(struct erofs_device erofs_dev, struct erofs_i
 	return ret;
 }
 
-static void erofs_check_inode(struct erofs_device erofs_dev, erofs_nid_t pnid, erofs_nid_t nid)
+static void erofs_check_inode(
+	struct erofs_device erofs_dev,
+	struct erofs_sb_info *sbi,
+	erofs_nid_t pnid, erofs_nid_t nid)
 {
 	int ret;
 	struct erofs_inode inode;
@@ -476,7 +496,7 @@ static void erofs_check_inode(struct erofs_device erofs_dev, erofs_nid_t pnid, e
 	erofs_dbg("check inode: nid(%llu)", nid | 0ULL);
 
 	inode.nid = nid;
-	ret = erofs_read_inode_from_disk(erofs_dev, &inode);
+	ret = erofs_read_inode_from_disk(erofs_dev, sbi, &inode);
 	if (ret) {
 		if (ret == -EIO)
 			erofs_err("I/O error occurred when reading nid(%llu)",
@@ -485,12 +505,12 @@ static void erofs_check_inode(struct erofs_device erofs_dev, erofs_nid_t pnid, e
 	}
 
 	/* verify xattr field */
-	ret = erofs_verify_xattr(erofs_dev,&inode);
+	ret = erofs_verify_xattr(erofs_dev, sbi, &inode);
 	if (ret)
 		goto out;
 
 	/* verify data chunk layout */
-	ret = erofs_verify_inode_data(erofs_dev, &inode);
+	ret = erofs_verify_inode_data(erofs_dev, sbi, &inode);
 	if (ret)
 		goto out;
 
@@ -506,7 +526,7 @@ static void erofs_check_inode(struct erofs_device erofs_dev, erofs_nid_t pnid, e
 
 		unsigned int nameoff;
 
-		ret = erofs_pread(erofs_dev, &inode, buf, maxsize, offset);
+		ret = erofs_pread(erofs_dev, sbi, &inode, buf, maxsize, offset);
 		if (ret) {
 			erofs_err("I/O error occurred when reading dirents @ nid %llu, block %u: %d",
 				  nid | 0ULL, block, ret);
@@ -522,7 +542,7 @@ static void erofs_check_inode(struct erofs_device erofs_dev, erofs_nid_t pnid, e
 			goto out;
 		}
 
-		ret = traverse_dirents(erofs_dev, pnid, nid, buf, block,
+		ret = traverse_dirents(erofs_dev, sbi, pnid, nid, buf, block,
 				       nameoff, maxsize);
 		if (ret)
 			goto out;
@@ -538,6 +558,7 @@ int main(int argc, char **argv)
 {
 	int err;
 	struct erofs_device erofs_dev;
+	struct erofs_sb_info sbi;
 
 	erofs_init_global_configure();
 
@@ -571,7 +592,7 @@ int main(int argc, char **argv)
 		goto exit;
 	}
 
-	erofs_check_inode(erofs_dev, sbi.root_nid, sbi.root_nid);
+	erofs_check_inode(erofs_dev, &sbi, sbi.root_nid, sbi.root_nid);
 
 	if (fsckcfg.corrupted) {
 		erofs_err("Found some filesystem corruption");
diff --git a/fuse/dir.c b/fuse/dir.c
index 494c915..b7ff635 100644
--- a/fuse/dir.c
+++ b/fuse/dir.c
@@ -10,6 +10,7 @@
 
 // defined in fuse/main.c
 extern struct erofs_device erofs_dev;
+extern struct erofs_sb_info sbi;
 
 static int erofs_fill_dentries(struct erofs_inode *dir,
 			       fuse_fill_dir_t filler, void *buf,
@@ -60,7 +61,7 @@ int erofsfuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
 
 	erofs_dbg("readdir:%s offset=%llu", path, (long long)offset);
 
-	ret = erofs_ilookup(erofs_dev, path, &dir);
+	ret = erofs_ilookup(erofs_dev, &sbi, path, &dir);
 	if (ret)
 		return ret;
 
@@ -79,7 +80,7 @@ int erofsfuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
 
 		maxsize = min_t(unsigned int, EROFS_BLKSIZ,
 				dir.i_size - pos);
-		ret = erofs_pread(erofs_dev, &dir, dblk, maxsize, pos);
+		ret = erofs_pread(erofs_dev, &sbi, &dir, dblk, maxsize, pos);
 		if (ret)
 			return ret;
 
diff --git a/fuse/main.c b/fuse/main.c
index b3e1a3d..37edf46 100644
--- a/fuse/main.c
+++ b/fuse/main.c
@@ -14,6 +14,7 @@
 #include "erofs/io.h"
 
 struct erofs_device erofs_dev;
+struct erofs_sb_info sbi;
 
 int erofsfuse_readdir(const char *path, void *buffer, fuse_fill_dir_t filler,
 		      off_t offset, struct fuse_file_info *fi);
@@ -40,7 +41,7 @@ static int erofsfuse_getattr(const char *path, struct stat *stbuf)
 	int ret;
 
 	erofs_dbg("getattr(%s)", path);
-	ret = erofs_ilookup(erofs_dev, path, &vi);
+	ret = erofs_ilookup(erofs_dev, &sbi, path, &vi);
 	if (ret)
 		return -ENOENT;
 
@@ -67,11 +68,11 @@ static int erofsfuse_read(const char *path, char *buffer,
 
 	erofs_dbg("path:%s size=%zd offset=%llu", path, size, (long long)offset);
 
-	ret = erofs_ilookup(erofs_dev, path, &vi);
+	ret = erofs_ilookup(erofs_dev, &sbi, path, &vi);
 	if (ret)
 		return ret;
 
-	ret = erofs_pread(erofs_dev, &vi, buffer, size, offset);
+	ret = erofs_pread(erofs_dev, &sbi, &vi, buffer, size, offset);
 	if (ret)
 		return ret;
 	if (offset >= vi.i_size)
diff --git a/include/erofs/compress.h b/include/erofs/compress.h
index 73834a7..813b8e0 100644
--- a/include/erofs/compress.h
+++ b/include/erofs/compress.h
@@ -16,10 +16,12 @@
 
 int erofs_write_compressed_file(
 	struct erofs_device erofs_dev,
+	struct erofs_sb_info *sbi,
 	struct erofs_inode *inode);
 
 int z_erofs_compress_init(
 	struct erofs_device erofs_dev,
+	struct erofs_sb_info *sbi,
 	struct erofs_buffer_head *bh);
 int z_erofs_compress_exit(void);
 
diff --git a/include/erofs/decompress.h b/include/erofs/decompress.h
index 0ba2b08..4880bfd 100644
--- a/include/erofs/decompress.h
+++ b/include/erofs/decompress.h
@@ -28,6 +28,9 @@ struct z_erofs_decompress_req {
 	bool partial_decoding;
 };
 
-int z_erofs_decompress(struct z_erofs_decompress_req *rq);
+int z_erofs_decompress(
+	struct z_erofs_decompress_req *rq,
+	struct erofs_sb_info *sbi
+	);
 
 #endif
diff --git a/include/erofs/inode.h b/include/erofs/inode.h
index 5483d04..3b03482 100644
--- a/include/erofs/inode.h
+++ b/include/erofs/inode.h
@@ -12,9 +12,10 @@
 
 void erofs_inode_manager_init(void);
 unsigned int erofs_iput(struct erofs_inode *inode);
-erofs_nid_t erofs_lookupnid(struct erofs_inode *inode);
+erofs_nid_t erofs_lookupnid(struct erofs_sb_info *sbi, struct erofs_inode *inode);
 struct erofs_inode *erofs_mkfs_build_tree_from_path(
 	struct erofs_device erofs_dev,
+	struct erofs_sb_info *sbi,
 	struct erofs_inode *parent,
 	const char *path);
 
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 49a883e..ff79fe9 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -68,12 +68,9 @@ struct erofs_sb_info {
 	u32 checksum;
 };
 
-/* global sbi */
-extern struct erofs_sb_info sbi;
-
-static inline erofs_off_t iloc(erofs_nid_t nid)
+static inline erofs_off_t iloc(struct erofs_sb_info *sbi, erofs_nid_t nid)
 {
-	return blknr_to_addr(sbi.meta_blkaddr) + (nid << sbi.islotbits);
+	return blknr_to_addr(sbi->meta_blkaddr) + (nid << sbi->islotbits);
 }
 
 #define EROFS_FEATURE_FUNCS(name, compat, feature) \
@@ -253,20 +250,31 @@ struct erofs_map_blocks {
 int erofs_read_superblock(struct erofs_device devfd, struct erofs_sb_info *sbi);
 
 /* namei.c */
-int erofs_read_inode_from_disk(struct erofs_device fd, struct erofs_inode *vi);
-int erofs_ilookup(struct erofs_device devfd, const char *path, struct erofs_inode *vi);
+int erofs_read_inode_from_disk(
+	struct erofs_device fd,
+	struct erofs_sb_info *sbi,
+	struct erofs_inode *vi);
+int erofs_ilookup(
+	struct erofs_device devfd,
+	struct erofs_sb_info *sbi,
+	const char *path, struct erofs_inode *vi);
 
 /* data.c */
-int erofs_pread(struct erofs_device fd, struct erofs_inode *inode, char *buf,
+int erofs_pread(
+	struct erofs_device fd,
+	struct erofs_sb_info *sbi,
+	struct erofs_inode *inode, char *buf,
 		erofs_off_t count, erofs_off_t offset);
 int erofs_map_blocks(
 		struct erofs_device erofs_dev,
+		struct erofs_sb_info *sbi,
 		struct erofs_inode *inode,
 		struct erofs_map_blocks *map, int flags);
 /* zmap.c */
-int z_erofs_fill_inode(struct erofs_inode *vi);
+int z_erofs_fill_inode(struct erofs_inode *vi, struct erofs_sb_info *sbi);
 int z_erofs_map_blocks_iter(
 	struct erofs_device erofs_dev,
+	struct erofs_sb_info *sbi,
 	struct erofs_inode *vi,
 	struct erofs_map_blocks *map,
 	int flags);
diff --git a/include/erofs/xattr.h b/include/erofs/xattr.h
index f0c4c26..c8593e1 100644
--- a/include/erofs/xattr.h
+++ b/include/erofs/xattr.h
@@ -42,6 +42,6 @@
 
 int erofs_prepare_xattr_ibody(struct erofs_inode *inode);
 char *erofs_export_xattr_ibody(struct list_head *ixattrs, unsigned int size);
-int erofs_build_shared_xattrs_from_path(const char *path);
+int erofs_build_shared_xattrs_from_path(const char *path, struct erofs_sb_info *sbi);
 
 #endif
diff --git a/lib/compress.c b/lib/compress.c
index 766b75b..1e1ffde 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -59,8 +59,10 @@ static void vle_write_indexes_final(struct z_erofs_vle_compress_ctx *ctx)
 	ctx->metacur += sizeof(di);
 }
 
-static void vle_write_indexes(struct z_erofs_vle_compress_ctx *ctx,
-			      unsigned int count, bool raw)
+static void vle_write_indexes(
+	struct z_erofs_vle_compress_ctx *ctx,
+	struct erofs_sb_info *sbi,
+	unsigned int count, bool raw)
 {
 	unsigned int clusterofs = ctx->clusterofs;
 	unsigned int d0 = 0, d1 = (clusterofs + count) / EROFS_BLKSIZ;
@@ -89,7 +91,7 @@ static void vle_write_indexes(struct z_erofs_vle_compress_ctx *ctx,
 
 	do {
 		/* XXX: big pcluster feature should be per-inode */
-		if (d0 == 1 && erofs_sb_has_big_pcluster(&sbi)) {
+		if (d0 == 1 && erofs_sb_has_big_pcluster(sbi)) {
 			type = Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD;
 			di.di_u.delta[0] = cpu_to_le16(ctx->compressedblks |
 					Z_EROFS_VLE_DI_D0_CBLKCNT);
@@ -122,6 +124,7 @@ static void vle_write_indexes(struct z_erofs_vle_compress_ctx *ctx,
 
 static int write_uncompressed_extent(
 	struct erofs_device erofs_dev,
+	struct erofs_sb_info *sbi,
 	struct z_erofs_vle_compress_ctx *ctx,
 				     unsigned int *len, char *dst)
 {
@@ -129,7 +132,7 @@ static int write_uncompressed_extent(
 	unsigned int count;
 
 	/* reset clusterofs to 0 if permitted */
-	if (!erofs_sb_has_lz4_0padding(&sbi) && ctx->clusterofs &&
+	if (!erofs_sb_has_lz4_0padding(sbi) && ctx->clusterofs &&
 	    ctx->head >= ctx->clusterofs) {
 		ctx->head -= ctx->clusterofs;
 		*len += ctx->clusterofs;
@@ -166,6 +169,7 @@ static unsigned int z_erofs_get_max_pclusterblks(struct erofs_inode *inode)
 
 static int vle_compress_one(
 		struct erofs_device erofs_dev,
+		struct erofs_sb_info *sbi,
 		struct erofs_inode *inode,
 		struct z_erofs_vle_compress_ctx *ctx,
 		bool final)
@@ -201,7 +205,7 @@ static int vle_compress_one(
 					  erofs_strerror(ret));
 			}
 nocompression:
-			ret = write_uncompressed_extent(erofs_dev, ctx, &len, dst);
+			ret = write_uncompressed_extent(erofs_dev, sbi, ctx, &len, dst);
 			if (ret < 0)
 				return ret;
 			count = ret;
@@ -210,14 +214,14 @@ nocompression:
 		} else {
 			const unsigned int tailused = ret & (EROFS_BLKSIZ - 1);
 			const unsigned int padding =
-				erofs_sb_has_lz4_0padding(&sbi) && tailused ?
+				erofs_sb_has_lz4_0padding(sbi) && tailused ?
 					EROFS_BLKSIZ - tailused : 0;
 
 			ctx->compressedblks = DIV_ROUND_UP(ret, EROFS_BLKSIZ);
 			DBG_BUGON(ctx->compressedblks * EROFS_BLKSIZ >= count);
 
 			/* zero out garbage trailing data for non-0padding */
-			if (!erofs_sb_has_lz4_0padding(&sbi))
+			if (!erofs_sb_has_lz4_0padding(sbi))
 				memset(dst + ret, 0,
 				       roundup(ret, EROFS_BLKSIZ) - ret);
 
@@ -234,7 +238,7 @@ nocompression:
 
 		ctx->head += count;
 		/* write compression indexes for this pcluster */
-		vle_write_indexes(ctx, count, raw);
+		vle_write_indexes(ctx, sbi, count, raw);
 
 		ctx->blkaddr += ctx->compressedblks;
 		len -= count;
@@ -287,7 +291,9 @@ static void *parse_legacy_indexes(struct z_erofs_compressindex_vec *cv,
 	return db + nr;
 }
 
-static void *write_compacted_indexes(u8 *out,
+static void *write_compacted_indexes(
+						 struct erofs_sb_info *sbi,
+						 u8 *out,
 				     struct z_erofs_compressindex_vec *cv,
 				     erofs_blk_t *blkaddr_ret,
 				     unsigned int destsize,
@@ -306,7 +312,7 @@ static void *write_compacted_indexes(u8 *out,
 		return ERR_PTR(-EINVAL);
 	encodebits = (vcnt * destsize * 8 - 32) / vcnt;
 	blkaddr = *blkaddr_ret;
-	update_blkaddr = erofs_sb_has_big_pcluster(&sbi);
+	update_blkaddr = erofs_sb_has_big_pcluster(sbi);
 
 	pos = 0;
 	for (i = 0; i < vcnt; ++i) {
@@ -354,7 +360,9 @@ static void *write_compacted_indexes(u8 *out,
 	return out + destsize * vcnt;
 }
 
-int z_erofs_convert_to_compacted_format(struct erofs_inode *inode,
+int z_erofs_convert_to_compacted_format(
+					struct erofs_sb_info *sbi,
+					struct erofs_inode *inode,
 					erofs_blk_t blkaddr,
 					unsigned int legacymetasize,
 					void *compressmeta)
@@ -402,7 +410,7 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode,
 
 	dummy_head = false;
 	/* prior to bigpcluster, blkaddr was bumped up once coming into HEAD */
-	if (!erofs_sb_has_big_pcluster(&sbi)) {
+	if (!erofs_sb_has_big_pcluster(sbi)) {
 		--blkaddr;
 		dummy_head = true;
 	}
@@ -410,7 +418,7 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode,
 	/* generate compacted_4b_initial */
 	while (compacted_4b_initial) {
 		in = parse_legacy_indexes(cv, 2, in);
-		out = write_compacted_indexes(out, cv, &blkaddr,
+		out = write_compacted_indexes(sbi, out, cv, &blkaddr,
 					      4, logical_clusterbits, false,
 					      &dummy_head);
 		compacted_4b_initial -= 2;
@@ -420,7 +428,7 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode,
 	/* generate compacted_2b */
 	while (compacted_2b) {
 		in = parse_legacy_indexes(cv, 16, in);
-		out = write_compacted_indexes(out, cv, &blkaddr,
+		out = write_compacted_indexes(sbi, out, cv, &blkaddr,
 					      2, logical_clusterbits, false,
 					      &dummy_head);
 		compacted_2b -= 16;
@@ -430,7 +438,7 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode,
 	/* generate compacted_4b_end */
 	while (compacted_4b_end > 1) {
 		in = parse_legacy_indexes(cv, 2, in);
-		out = write_compacted_indexes(out, cv, &blkaddr,
+		out = write_compacted_indexes(sbi, out, cv, &blkaddr,
 					      4, logical_clusterbits, false,
 					      &dummy_head);
 		compacted_4b_end -= 2;
@@ -440,7 +448,7 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode,
 	if (compacted_4b_end) {
 		memset(cv, 0, sizeof(cv));
 		in = parse_legacy_indexes(cv, 1, in);
-		out = write_compacted_indexes(out, cv, &blkaddr,
+		out = write_compacted_indexes(sbi, out, cv, &blkaddr,
 					      4, logical_clusterbits, true,
 					      &dummy_head);
 	}
@@ -464,7 +472,10 @@ static void z_erofs_write_mapheader(struct erofs_inode *inode,
 	memcpy(compressmeta, &h, sizeof(struct z_erofs_map_header));
 }
 
-int erofs_write_compressed_file(struct erofs_device erofs_dev, struct erofs_inode *inode)
+int erofs_write_compressed_file(
+	struct erofs_device erofs_dev,
+	struct erofs_sb_info *sbi,
+	struct erofs_inode *inode)
 {
 	struct erofs_buffer_head *bh;
 	struct z_erofs_vle_compress_ctx ctx;
@@ -499,7 +510,7 @@ int erofs_write_compressed_file(struct erofs_device erofs_dev, struct erofs_inod
 		inode->datalayout = EROFS_INODE_FLAT_COMPRESSION_LEGACY;
 	}
 
-	if (erofs_sb_has_big_pcluster(&sbi)) {
+	if (erofs_sb_has_big_pcluster(sbi)) {
 		inode->z_advise |= Z_EROFS_ADVISE_BIG_PCLUSTER_1;
 		if (inode->datalayout == EROFS_INODE_FLAT_COMPRESSION)
 			inode->z_advise |= Z_EROFS_ADVISE_BIG_PCLUSTER_2;
@@ -530,13 +541,13 @@ int erofs_write_compressed_file(struct erofs_device erofs_dev, struct erofs_inod
 		ctx.tail += readcount;
 
 		/* do one compress round */
-		ret = vle_compress_one(erofs_dev, inode, &ctx, false);
+		ret = vle_compress_one(erofs_dev, sbi, inode, &ctx, false);
 		if (ret)
 			goto err_bdrop;
 	}
 
 	/* do the final round */
-	ret = vle_compress_one(erofs_dev, inode, &ctx, true);
+	ret = vle_compress_one(erofs_dev, sbi, inode, &ctx, true);
 	if (ret)
 		goto err_bdrop;
 
@@ -570,7 +581,7 @@ int erofs_write_compressed_file(struct erofs_device erofs_dev, struct erofs_inod
 	if (inode->datalayout == EROFS_INODE_FLAT_COMPRESSION_LEGACY) {
 		inode->extent_isize = legacymetasize;
 	} else {
-		ret = z_erofs_convert_to_compacted_format(inode, blkaddr,
+		ret = z_erofs_convert_to_compacted_format(sbi, inode, blkaddr,
 							  legacymetasize,
 							  compressmeta);
 		DBG_BUGON(ret);
@@ -597,12 +608,15 @@ static int erofs_get_compress_algorithm_id(const char *name)
 	return -ENOTSUP;
 }
 
-int z_erofs_build_compr_cfgs(struct erofs_device erofs_dev, struct erofs_buffer_head *sb_bh)
+int z_erofs_build_compr_cfgs(
+	struct erofs_device erofs_dev,
+	struct erofs_sb_info *sbi,
+	struct erofs_buffer_head *sb_bh)
 {
 	struct erofs_buffer_head *bh = sb_bh;
 	int ret = 0;
 
-	if (sbi.available_compr_algs & (1 << Z_EROFS_COMPRESSION_LZ4)) {
+	if (sbi->available_compr_algs & (1 << Z_EROFS_COMPRESSION_LZ4)) {
 		struct {
 			__le16 size;
 			struct z_erofs_lz4_cfgs lz4;
@@ -610,7 +624,7 @@ int z_erofs_build_compr_cfgs(struct erofs_device erofs_dev, struct erofs_buffer_
 			.size = cpu_to_le16(sizeof(struct z_erofs_lz4_cfgs)),
 			.lz4 = {
 				.max_distance =
-					cpu_to_le16(sbi.lz4_max_distance),
+					cpu_to_le16(sbi->lz4_max_distance),
 				.max_pclusterblks = cfg.c_pclusterblks_max,
 			}
 		};
@@ -651,10 +665,14 @@ int z_erofs_build_compr_cfgs(struct erofs_device erofs_dev, struct erofs_buffer_
 	return ret;
 }
 
-int z_erofs_compress_init(struct erofs_device erofs_dev, struct erofs_buffer_head *sb_bh)
+int z_erofs_compress_init(
+	struct erofs_device erofs_dev,
+	struct erofs_sb_info *sbi,
+	struct erofs_buffer_head *sb_bh)
 {
 	/* initialize for primary compression algorithm */
 	int ret = erofs_compressor_init(&compresshandle,
+	sbi,
 					cfg.c_compr_alg_master);
 
 	if (ret)
@@ -666,7 +684,7 @@ int z_erofs_compress_init(struct erofs_device erofs_dev, struct erofs_buffer_hea
 	 */
 	if (!cfg.c_compr_alg_master ||
 	    (cfg.c_legacy_compress && !strcmp(cfg.c_compr_alg_master, "lz4")))
-		erofs_sb_clear_lz4_0padding(&sbi);
+		erofs_sb_clear_lz4_0padding(sbi);
 
 	if (!cfg.c_compr_alg_master)
 		return 0;
@@ -694,16 +712,16 @@ int z_erofs_compress_init(struct erofs_device erofs_dev, struct erofs_buffer_hea
 				  cfg.c_pclusterblks_max);
 			return -EINVAL;
 		}
-		erofs_sb_set_big_pcluster(&sbi);
+		erofs_sb_set_big_pcluster(sbi);
 		erofs_warn("EXPERIMENTAL big pcluster feature in use. Use at your own risk!");
 	}
 
 	if (ret != Z_EROFS_COMPRESSION_LZ4)
-		erofs_sb_set_compr_cfgs(&sbi);
+		erofs_sb_set_compr_cfgs(sbi);
 
-	if (erofs_sb_has_compr_cfgs(&sbi)) {
-		sbi.available_compr_algs |= 1 << ret;
-		return z_erofs_build_compr_cfgs(erofs_dev, sb_bh);
+	if (erofs_sb_has_compr_cfgs(sbi)) {
+		sbi->available_compr_algs |= 1 << ret;
+		return z_erofs_build_compr_cfgs(erofs_dev, sbi, sb_bh);
 	}
 	return 0;
 }
diff --git a/lib/compressor.c b/lib/compressor.c
index 6362825..3b8d193 100644
--- a/lib/compressor.c
+++ b/lib/compressor.c
@@ -62,7 +62,10 @@ int erofs_compressor_setlevel(struct erofs_compress *c, int compression_level)
 	return 0;
 }
 
-int erofs_compressor_init(struct erofs_compress *c, char *alg_name)
+int erofs_compressor_init(
+	struct erofs_compress *c,
+	struct erofs_sb_info *sbi,
+	char *alg_name)
 {
 	int ret, i;
 
@@ -84,7 +87,7 @@ int erofs_compressor_init(struct erofs_compress *c, char *alg_name)
 		if (alg_name && strcmp(alg_name, compressors[i]->name))
 			continue;
 
-		ret = compressors[i]->init(c);
+		ret = compressors[i]->init(c, sbi);
 		if (!ret) {
 			DBG_BUGON(!c->alg);
 			return 0;
diff --git a/lib/compressor.h b/lib/compressor.h
index 1ea2724..446c013 100644
--- a/lib/compressor.h
+++ b/lib/compressor.h
@@ -10,6 +10,7 @@
 #include "erofs/defs.h"
 
 struct erofs_compress;
+struct erofs_sb_info;
 
 struct erofs_compressor {
 	const char *name;
@@ -17,7 +18,7 @@ struct erofs_compressor {
 	int default_level;
 	int best_level;
 
-	int (*init)(struct erofs_compress *c);
+	int (*init)(struct erofs_compress *c, struct erofs_sb_info *sbi);
 	int (*exit)(struct erofs_compress *c);
 	int (*setlevel)(struct erofs_compress *c, int compression_level);
 
@@ -50,7 +51,7 @@ int erofs_compress_destsize(struct erofs_compress *c,
 			    void *dst, unsigned int dstsize);
 
 int erofs_compressor_setlevel(struct erofs_compress *c, int compression_level);
-int erofs_compressor_init(struct erofs_compress *c, char *alg_name);
+int erofs_compressor_init(struct erofs_compress *c, struct erofs_sb_info *sbi, char *alg_name);
 int erofs_compressor_exit(struct erofs_compress *c);
 
 #endif
diff --git a/lib/compressor_lz4.c b/lib/compressor_lz4.c
index fc8c23c..ffdbb9f 100644
--- a/lib/compressor_lz4.c
+++ b/lib/compressor_lz4.c
@@ -30,10 +30,12 @@ static int compressor_lz4_exit(struct erofs_compress *c)
 	return 0;
 }
 
-static int compressor_lz4_init(struct erofs_compress *c)
+static int compressor_lz4_init(
+	struct erofs_compress *c,
+	struct erofs_sb_info *sbi)
 {
 	c->alg = &erofs_compressor_lz4;
-	sbi.lz4_max_distance = LZ4_DISTANCE_MAX;
+	sbi->lz4_max_distance = LZ4_DISTANCE_MAX;
 	return 0;
 }
 
diff --git a/lib/compressor_lz4hc.c b/lib/compressor_lz4hc.c
index 3f68b00..f573cd2 100644
--- a/lib/compressor_lz4hc.c
+++ b/lib/compressor_lz4hc.c
@@ -36,7 +36,7 @@ static int compressor_lz4hc_exit(struct erofs_compress *c)
 	return 0;
 }
 
-static int compressor_lz4hc_init(struct erofs_compress *c)
+static int compressor_lz4hc_init(struct erofs_compress *c, struct erofs_sb_info *sbi)
 {
 	c->alg = &erofs_compressor_lz4hc;
 
@@ -44,7 +44,7 @@ static int compressor_lz4hc_init(struct erofs_compress *c)
 	if (!c->private_data)
 		return -ENOMEM;
 
-	sbi.lz4_max_distance = LZ4_DISTANCE_MAX;
+	sbi->lz4_max_distance = LZ4_DISTANCE_MAX;
 	return 0;
 }
 
diff --git a/lib/config.c b/lib/config.c
index 7488e08..7313588 100644
--- a/lib/config.c
+++ b/lib/config.c
@@ -10,7 +10,6 @@
 #include "erofs/internal.h"
 
 struct erofs_configure cfg;
-struct erofs_sb_info sbi;
 
 void erofs_init_config(struct erofs_configure *cfg)
 {
diff --git a/lib/data.c b/lib/data.c
index d9d20ec..e6fe1d6 100644
--- a/lib/data.c
+++ b/lib/data.c
@@ -10,9 +10,11 @@
 #include "erofs/trace.h"
 #include "erofs/decompress.h"
 
-static int erofs_map_blocks_flatmode(struct erofs_inode *inode,
-				     struct erofs_map_blocks *map,
-				     int flags)
+static int erofs_map_blocks_flatmode(
+	struct erofs_sb_info *sbi,
+	struct erofs_inode *inode,
+	struct erofs_map_blocks *map,
+	int flags)
 {
 	int err = 0;
 	erofs_blk_t nblocks, lastblk;
@@ -33,7 +35,7 @@ static int erofs_map_blocks_flatmode(struct erofs_inode *inode,
 		map->m_plen = blknr_to_addr(lastblk) - offset;
 	} else if (tailendpacking) {
 		/* 2 - inode inline B: inode, [xattrs], inline last blk... */
-		map->m_pa = iloc(vi->nid) + vi->inode_isize +
+		map->m_pa = iloc(sbi, vi->nid) + vi->inode_isize +
 			vi->xattr_isize + erofs_blkoff(map->m_la);
 		map->m_plen = inode->i_size - offset;
 
@@ -63,6 +65,7 @@ err_out:
 
 int erofs_map_blocks(
 		struct erofs_device erofs_dev,
+		struct erofs_sb_info *sbi,
 		struct erofs_inode *inode,
 		struct erofs_map_blocks *map, int flags)
 {
@@ -82,7 +85,7 @@ int erofs_map_blocks(
 	}
 
 	if (vi->datalayout != EROFS_INODE_CHUNK_BASED)
-		return erofs_map_blocks_flatmode(inode, map, flags);
+		return erofs_map_blocks_flatmode(sbi, inode, map, flags);
 
 	if (vi->u.chunkformat & EROFS_CHUNK_FORMAT_INDEXES)
 		unit = sizeof(*idx);			/* chunk index */
@@ -90,7 +93,7 @@ int erofs_map_blocks(
 		unit = EROFS_BLOCK_MAP_ENTRY_SIZE;	/* block map */
 
 	chunknr = map->m_la >> vi->u.chunkbits;
-	pos = roundup(iloc(vi->nid) + vi->inode_isize +
+	pos = roundup(iloc(sbi, vi->nid) + vi->inode_isize +
 		      vi->xattr_isize, unit) + unit * chunknr;
 
 	err = blk_read(erofs_dev, buf, erofs_blknr(pos), 1);
@@ -137,7 +140,10 @@ out:
 	return err;
 }
 
-static int erofs_read_raw_data(struct erofs_device erofs_dev, struct erofs_inode *inode, char *buffer,
+static int erofs_read_raw_data(
+	struct erofs_device erofs_dev,
+	struct erofs_sb_info *sbi,
+	struct erofs_inode *inode, char *buffer,
 			       erofs_off_t size, erofs_off_t offset)
 {
 	struct erofs_map_blocks map = {
@@ -151,7 +157,7 @@ static int erofs_read_raw_data(struct erofs_device erofs_dev, struct erofs_inode
 		erofs_off_t eend;
 
 		map.m_la = ptr;
-		ret = erofs_map_blocks(erofs_dev, inode, &map, 0);
+		ret = erofs_map_blocks(erofs_dev, sbi, inode, &map, 0);
 		if (ret)
 			return ret;
 
@@ -188,6 +194,7 @@ static int erofs_read_raw_data(struct erofs_device erofs_dev, struct erofs_inode
 
 static int z_erofs_read_data(
 	struct erofs_device erofs_dev,
+	struct erofs_sb_info *sbi,
 	struct erofs_inode *inode,
 	char *buffer,
 	erofs_off_t size,
@@ -207,7 +214,7 @@ static int z_erofs_read_data(
 	while (end > offset) {
 		map.m_la = end - 1;
 
-		ret = z_erofs_map_blocks_iter(erofs_dev, inode, &map, 0);
+		ret = z_erofs_map_blocks_iter(erofs_dev, sbi, inode, &map, 0);
 		if (ret)
 			break;
 
@@ -263,7 +270,7 @@ static int z_erofs_read_data(
 					.decodedlength = length,
 					.alg = algorithmformat,
 					.partial_decoding = partial
-					 });
+					 }, sbi);
 		if (ret < 0)
 			break;
 	}
@@ -272,17 +279,20 @@ static int z_erofs_read_data(
 	return ret < 0 ? ret : 0;
 }
 
-int erofs_pread(struct erofs_device fd, struct erofs_inode *inode, char *buf,
+int erofs_pread(
+	struct erofs_device fd,
+	struct erofs_sb_info *sbi,
+	struct erofs_inode *inode, char *buf,
 		erofs_off_t count, erofs_off_t offset)
 {
 	switch (inode->datalayout) {
 	case EROFS_INODE_FLAT_PLAIN:
 	case EROFS_INODE_FLAT_INLINE:
 	case EROFS_INODE_CHUNK_BASED:
-		return erofs_read_raw_data(fd, inode, buf, count, offset);
+		return erofs_read_raw_data(fd, sbi, inode, buf, count, offset);
 	case EROFS_INODE_FLAT_COMPRESSION_LEGACY:
 	case EROFS_INODE_FLAT_COMPRESSION:
-		return z_erofs_read_data(fd, inode, buf, count, offset);
+		return z_erofs_read_data(fd, sbi, inode, buf, count, offset);
 	default:
 		break;
 	}
diff --git a/lib/decompress.c b/lib/decompress.c
index 6a60400..483bd52 100644
--- a/lib/decompress.c
+++ b/lib/decompress.c
@@ -12,7 +12,7 @@
 #ifdef HAVE_LIBLZMA
 #include <lzma.h>
 
-static int z_erofs_decompress_lzma(struct z_erofs_decompress_req *rq)
+static int z_erofs_decompress_lzma(struct z_erofs_decompress_req *rq, struct erofs_sb_info *sbi)
 {
 	int ret = 0;
 	u8 *dest = (u8 *)rq->out;
@@ -73,7 +73,7 @@ out:
 #ifdef LZ4_ENABLED
 #include <lz4.h>
 
-static int z_erofs_decompress_lz4(struct z_erofs_decompress_req *rq)
+static int z_erofs_decompress_lz4(struct z_erofs_decompress_req *rq, struct erofs_sb_info *sbi)
 {
 	int ret = 0;
 	char *dest = rq->out;
@@ -82,7 +82,7 @@ static int z_erofs_decompress_lz4(struct z_erofs_decompress_req *rq)
 	bool support_0padding = false;
 	unsigned int inputmargin = 0;
 
-	if (erofs_sb_has_lz4_0padding(&sbi)) {
+	if (erofs_sb_has_lz4_0padding(sbi)) {
 		support_0padding = true;
 
 		while (!src[inputmargin & ~PAGE_MASK])
@@ -126,7 +126,7 @@ out:
 }
 #endif
 
-int z_erofs_decompress(struct z_erofs_decompress_req *rq)
+int z_erofs_decompress(struct z_erofs_decompress_req *rq, struct erofs_sb_info *sbi)
 {
 	if (rq->alg == Z_EROFS_COMPRESSION_SHIFTED) {
 		if (rq->inputsize != EROFS_BLKSIZ)
@@ -142,11 +142,11 @@ int z_erofs_decompress(struct z_erofs_decompress_req *rq)
 
 #ifdef LZ4_ENABLED
 	if (rq->alg == Z_EROFS_COMPRESSION_LZ4)
-		return z_erofs_decompress_lz4(rq);
+		return z_erofs_decompress_lz4(rq, sbi);
 #endif
 #ifdef HAVE_LIBLZMA
 	if (rq->alg == Z_EROFS_COMPRESSION_LZMA)
-		return z_erofs_decompress_lzma(rq);
+		return z_erofs_decompress_lzma(rq, sbi);
 #endif
 	return -EOPNOTSUPP;
 }
diff --git a/lib/inode.c b/lib/inode.c
index d1adb49..70525fa 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -387,7 +387,10 @@ static int write_uncompressed_file_from_fd(
 	return 0;
 }
 
-int erofs_write_file(struct erofs_device erofs_dev, struct erofs_inode *inode)
+int erofs_write_file(
+	struct erofs_device erofs_dev,
+	struct erofs_sb_info *sbi,
+	struct erofs_inode *inode)
 {
 	int ret, fd;
 
@@ -403,7 +406,7 @@ int erofs_write_file(struct erofs_device erofs_dev, struct erofs_inode *inode)
 	}
 
 	if (cfg.c_compr_alg_master && erofs_file_is_compressible(inode)) {
-		ret = erofs_write_compressed_file(erofs_dev, inode);
+		ret = erofs_write_compressed_file(erofs_dev, sbi, inode);
 
 		if (!ret || ret != -ENOSPC)
 			return ret;
@@ -799,7 +802,9 @@ static int erofs_droid_inode_fsconfig(struct erofs_inode *inode,
 }
 #endif
 
-static int erofs_fill_inode(struct erofs_inode *inode,
+static int erofs_fill_inode(
+					struct erofs_inode *inode,
+					struct erofs_sb_info *sbi,
 			    struct stat64 *st,
 			    const char *path)
 {
@@ -815,11 +820,11 @@ static int erofs_fill_inode(struct erofs_inode *inode,
 
 	switch (cfg.c_timeinherit) {
 	case TIMESTAMP_CLAMPING:
-		if (st->st_ctime < sbi.build_time)
+		if (st->st_ctime < sbi->build_time)
 			break;
 	case TIMESTAMP_FIXED:
-		inode->i_ctime = sbi.build_time;
-		inode->i_ctime_nsec = sbi.build_time_nsec;
+		inode->i_ctime = sbi->build_time;
+		inode->i_ctime_nsec = sbi->build_time_nsec;
 	default:
 		break;
 	}
@@ -865,7 +870,7 @@ static int erofs_fill_inode(struct erofs_inode *inode,
 	return 0;
 }
 
-static struct erofs_inode *erofs_new_inode(void)
+static struct erofs_inode *erofs_new_inode(struct erofs_sb_info *sbi)
 {
 	struct erofs_inode *inode;
 
@@ -873,7 +878,7 @@ static struct erofs_inode *erofs_new_inode(void)
 	if (!inode)
 		return ERR_PTR(-ENOMEM);
 
-	inode->i_ino[0] = sbi.inos++;	/* inode serial number */
+	inode->i_ino[0] = sbi->inos++;	/* inode serial number */
 	inode->i_count = 1;
 
 	init_list_head(&inode->i_subdirs);
@@ -882,7 +887,8 @@ static struct erofs_inode *erofs_new_inode(void)
 }
 
 /* get the inode from the (source) path */
-static struct erofs_inode *erofs_iget_from_path(const char *path, bool is_src)
+static struct erofs_inode *erofs_iget_from_path(
+	struct erofs_sb_info *sbi, const char *path, bool is_src)
 {
 	struct stat64 st;
 	struct erofs_inode *inode;
@@ -908,11 +914,11 @@ static struct erofs_inode *erofs_iget_from_path(const char *path, bool is_src)
 	}
 
 	/* cannot find in the inode cache */
-	inode = erofs_new_inode();
+	inode = erofs_new_inode(sbi);
 	if (IS_ERR(inode))
 		return inode;
 
-	ret = erofs_fill_inode(inode, &st, path);
+	ret = erofs_fill_inode(inode, sbi, &st, path);
 	if (ret) {
 		free(inode);
 		return ERR_PTR(ret);
@@ -921,7 +927,7 @@ static struct erofs_inode *erofs_iget_from_path(const char *path, bool is_src)
 	return inode;
 }
 
-static void erofs_fixup_meta_blkaddr(struct erofs_inode *rootdir)
+static void erofs_fixup_meta_blkaddr(struct erofs_sb_info *sbi, struct erofs_inode *rootdir)
 {
 	const erofs_off_t rootnid_maxoffset = 0xffff << EROFS_ISLOTBITS;
 	struct erofs_buffer_head *const bh = rootdir->bh;
@@ -934,11 +940,11 @@ static void erofs_fixup_meta_blkaddr(struct erofs_inode *rootdir)
 		meta_offset = round_up(off - rootnid_maxoffset, EROFS_BLKSIZ);
 	else
 		meta_offset = 0;
-	sbi.meta_blkaddr = erofs_blknr(meta_offset);
+	sbi->meta_blkaddr = erofs_blknr(meta_offset);
 	rootdir->nid = (off - meta_offset) >> EROFS_ISLOTBITS;
 }
 
-erofs_nid_t erofs_lookupnid(struct erofs_inode *inode)
+erofs_nid_t erofs_lookupnid(struct erofs_sb_info *sbi, struct erofs_inode *inode)
 {
 	struct erofs_buffer_head *const bh = inode->bh;
 	erofs_off_t off, meta_offset;
@@ -949,21 +955,24 @@ erofs_nid_t erofs_lookupnid(struct erofs_inode *inode)
 	erofs_mapbh(bh->block);
 	off = erofs_btell(bh, false);
 
-	meta_offset = blknr_to_addr(sbi.meta_blkaddr);
+	meta_offset = blknr_to_addr(sbi->meta_blkaddr);
 	DBG_BUGON(off < meta_offset);
 	return inode->nid = (off - meta_offset) >> EROFS_ISLOTBITS;
 }
 
-static void erofs_d_invalidate(struct erofs_dentry *d)
+static void erofs_d_invalidate(
+	struct erofs_sb_info *sbi, struct erofs_dentry *d)
 {
 	struct erofs_inode *const inode = d->inode;
 
-	d->nid = erofs_lookupnid(inode);
+	d->nid = erofs_lookupnid(sbi, inode);
 	erofs_iput(inode);
 }
 
 static struct erofs_inode *erofs_mkfs_build_tree(
-	struct erofs_device erofs_dev, struct erofs_inode *dir)
+	struct erofs_device erofs_dev,
+	struct erofs_sb_info *sbi,
+	struct erofs_inode *dir)
 {
 	int ret;
 	DIR *_dir;
@@ -992,7 +1001,7 @@ static struct erofs_inode *erofs_mkfs_build_tree(
 			if (ret)
 				return ERR_PTR(ret);
 		} else {
-			ret = erofs_write_file(erofs_dev, dir);
+			ret = erofs_write_file(erofs_dev, sbi, dir);
 			if (ret)
 				return ERR_PTR(ret);
 		}
@@ -1055,14 +1064,14 @@ static struct erofs_inode *erofs_mkfs_build_tree(
 		goto err;
 
 	if (IS_ROOT(dir))
-		erofs_fixup_meta_blkaddr(dir);
+		erofs_fixup_meta_blkaddr(sbi, dir);
 
 	list_for_each_entry(d, &dir->i_subdirs, d_child) {
 		char buf[PATH_MAX];
 		unsigned char ftype;
 
 		if (is_dot_dotdot(d->name)) {
-			erofs_d_invalidate(d);
+			erofs_d_invalidate(sbi, d);
 			continue;
 		}
 
@@ -1073,7 +1082,7 @@ static struct erofs_inode *erofs_mkfs_build_tree(
 			goto fail;
 		}
 
-		d->inode = erofs_mkfs_build_tree_from_path(erofs_dev, dir, buf);
+		d->inode = erofs_mkfs_build_tree_from_path(erofs_dev, sbi, dir, buf);
 		if (IS_ERR(d->inode)) {
 			ret = PTR_ERR(d->inode);
 fail:
@@ -1086,7 +1095,7 @@ fail:
 		DBG_BUGON(ftype == EROFS_FT_DIR && d->type != ftype);
 		d->type = ftype;
 
-		erofs_d_invalidate(d);
+		erofs_d_invalidate(sbi, d);
 		erofs_info("add file %s/%s (nid %llu, type %d)",
 			   dir->i_srcpath, d->name, (unsigned long long)d->nid,
 			   d->type);
@@ -1103,10 +1112,11 @@ err:
 
 struct erofs_inode *erofs_mkfs_build_tree_from_path(
 	struct erofs_device erofs_dev,
+	struct erofs_sb_info *sbi,
 	struct erofs_inode *parent,
 	const char *path)
 {
-	struct erofs_inode *const inode = erofs_iget_from_path(path, true);
+	struct erofs_inode *const inode = erofs_iget_from_path(sbi, path, true);
 
 	if (IS_ERR(inode))
 		return inode;
@@ -1123,5 +1133,5 @@ struct erofs_inode *erofs_mkfs_build_tree_from_path(
 	else
 		inode->i_parent = inode;	/* rootdir mark */
 
-	return erofs_mkfs_build_tree(erofs_dev, inode);
+	return erofs_mkfs_build_tree(erofs_dev, sbi, inode);
 }
diff --git a/lib/namei.c b/lib/namei.c
index 57041f5..ac65425 100644
--- a/lib/namei.c
+++ b/lib/namei.c
@@ -22,13 +22,16 @@ static dev_t erofs_new_decode_dev(u32 dev)
 	return makedev(major, minor);
 }
 
-int erofs_read_inode_from_disk(struct erofs_device fd, struct erofs_inode *vi)
+int erofs_read_inode_from_disk(
+	struct erofs_device fd,
+	struct erofs_sb_info *sbi,
+	struct erofs_inode *vi)
 {
 	int ret, ifmt;
 	char buf[sizeof(struct erofs_inode_extended)];
 	struct erofs_inode_compact *dic;
 	struct erofs_inode_extended *die;
-	const erofs_off_t inode_loc = iloc(vi->nid);
+	const erofs_off_t inode_loc = iloc(sbi, vi->nid);
 
 	ret = dev_read(fd, buf, inode_loc, sizeof(*dic));
 	if (ret < 0)
@@ -114,8 +117,8 @@ int erofs_read_inode_from_disk(struct erofs_device fd, struct erofs_inode *vi)
 		vi->i_gid = le16_to_cpu(dic->i_gid);
 		vi->i_nlink = le16_to_cpu(dic->i_nlink);
 
-		vi->i_ctime = sbi.build_time;
-		vi->i_ctime_nsec = sbi.build_time_nsec;
+		vi->i_ctime = sbi->build_time;
+		vi->i_ctime_nsec = sbi->build_time_nsec;
 
 		vi->i_size = le32_to_cpu(dic->i_size);
 		if (vi->datalayout == EROFS_INODE_CHUNK_BASED)
@@ -137,7 +140,7 @@ int erofs_read_inode_from_disk(struct erofs_device fd, struct erofs_inode *vi)
 		vi->u.chunkbits = LOG_BLOCK_SIZE +
 			(vi->u.chunkformat & EROFS_CHUNK_FORMAT_BLKBITS_MASK);
 	} else if (erofs_inode_is_data_compressed(vi->datalayout))
-		z_erofs_fill_inode(vi);
+		z_erofs_fill_inode(vi, sbi);
 	return 0;
 bogusimode:
 	erofs_err("bogus i_mode (%o) @ nid %llu", vi->i_mode, vi->nid | 0ULL);
@@ -187,7 +190,10 @@ struct nameidata {
 	unsigned int	ftype;
 };
 
-int erofs_namei(struct erofs_device fd, struct nameidata *nd,
+int erofs_namei(
+	struct erofs_device fd,
+	struct erofs_sb_info *sbi,
+	struct nameidata *nd,
 		const char *name, unsigned int len)
 {
 	erofs_nid_t nid = nd->nid;
@@ -196,7 +202,7 @@ int erofs_namei(struct erofs_device fd, struct nameidata *nd,
 	struct erofs_inode vi = { .nid = nid };
 	erofs_off_t offset;
 
-	ret = erofs_read_inode_from_disk(fd, &vi);
+	ret = erofs_read_inode_from_disk(fd, sbi, &vi);
 	if (ret)
 		return ret;
 
@@ -207,7 +213,7 @@ int erofs_namei(struct erofs_device fd, struct nameidata *nd,
 		struct erofs_dirent *de = (void *)buf;
 		unsigned int nameoff;
 
-		ret = erofs_pread(fd, &vi, buf, maxsize, offset);
+		ret = erofs_pread(fd, sbi, &vi, buf, maxsize, offset);
 		if (ret)
 			return ret;
 
@@ -233,9 +239,12 @@ int erofs_namei(struct erofs_device fd, struct nameidata *nd,
 	return -ENOENT;
 }
 
-static int link_path_walk(struct erofs_device devfd, const char *name, struct nameidata *nd)
+static int link_path_walk(
+	struct erofs_device devfd,
+	struct erofs_sb_info *sbi,
+	const char *name, struct nameidata *nd)
 {
-	nd->nid = sbi.root_nid;
+	nd->nid = sbi->root_nid;
 
 	while (*name == '/')
 		name++;
@@ -250,7 +259,7 @@ static int link_path_walk(struct erofs_device devfd, const char *name, struct na
 		} while (*p != '\0' && *p != '/');
 
 		DBG_BUGON(p <= name);
-		ret = erofs_namei(devfd, nd, name, p - name);
+		ret = erofs_namei(devfd, sbi, nd, name, p - name);
 		if (ret)
 			return ret;
 
@@ -262,15 +271,18 @@ static int link_path_walk(struct erofs_device devfd, const char *name, struct na
 	return 0;
 }
 
-int erofs_ilookup(struct erofs_device devfd, const char *path, struct erofs_inode *vi)
+int erofs_ilookup(
+	struct erofs_device devfd,
+	struct erofs_sb_info *sbi,
+	const char *path, struct erofs_inode *vi)
 {
 	int ret;
 	struct nameidata nd;
 
-	ret = link_path_walk(devfd, path, &nd);
+	ret = link_path_walk(devfd, sbi, path, &nd);
 	if (ret)
 		return ret;
 
 	vi->nid = nd.nid;
-	return erofs_read_inode_from_disk(devfd, vi);
+	return erofs_read_inode_from_disk(devfd, sbi, vi);
 }
diff --git a/lib/xattr.c b/lib/xattr.c
index 9f16664..7a1ed9e 100644
--- a/lib/xattr.c
+++ b/lib/xattr.c
@@ -564,7 +564,7 @@ static struct erofs_bhops erofs_write_shared_xattrs_bhops = {
 	.flush = erofs_bh_flush_write_shared_xattrs,
 };
 
-int erofs_build_shared_xattrs_from_path(const char *path)
+int erofs_build_shared_xattrs_from_path(const char *path, struct erofs_sb_info *sbi)
 {
 	int ret;
 	struct erofs_buffer_head *bh;
@@ -604,7 +604,7 @@ int erofs_build_shared_xattrs_from_path(const char *path)
 	erofs_mapbh(bh->block);
 	off = erofs_btell(bh, false);
 
-	sbi.xattr_blkaddr = off / EROFS_BLKSIZ;
+	sbi->xattr_blkaddr = off / EROFS_BLKSIZ;
 	off %= EROFS_BLKSIZ;
 	p = 0;
 
diff --git a/lib/zmap.c b/lib/zmap.c
index 69fef80..e6e9858 100644
--- a/lib/zmap.c
+++ b/lib/zmap.c
@@ -10,9 +10,9 @@
 #include "erofs/io.h"
 #include "erofs/print.h"
 
-int z_erofs_fill_inode(struct erofs_inode *vi)
+int z_erofs_fill_inode(struct erofs_inode *vi, struct erofs_sb_info *sbi)
 {
-	if (!erofs_sb_has_big_pcluster(&sbi) &&
+	if (!erofs_sb_has_big_pcluster(sbi) &&
 	    vi->datalayout == EROFS_INODE_FLAT_COMPRESSION_LEGACY) {
 		vi->z_advise = 0;
 		vi->z_algorithmtype[0] = 0;
@@ -24,7 +24,10 @@ int z_erofs_fill_inode(struct erofs_inode *vi)
 	return 0;
 }
 
-static int z_erofs_fill_inode_lazy(struct erofs_device erofs_dev, struct erofs_inode *vi)
+static int z_erofs_fill_inode_lazy(
+	struct erofs_device erofs_dev,
+	struct erofs_sb_info *sbi,
+	struct erofs_inode *vi)
 {
 	int ret;
 	erofs_off_t pos;
@@ -34,9 +37,9 @@ static int z_erofs_fill_inode_lazy(struct erofs_device erofs_dev, struct erofs_i
 	if (vi->flags & EROFS_I_Z_INITED)
 		return 0;
 
-	DBG_BUGON(!erofs_sb_has_big_pcluster(&sbi) &&
+	DBG_BUGON(!erofs_sb_has_big_pcluster(sbi) &&
 		  vi->datalayout == EROFS_INODE_FLAT_COMPRESSION_LEGACY);
-	pos = round_up(iloc(vi->nid) + vi->inode_isize + vi->xattr_isize, 8);
+	pos = round_up(iloc(sbi, vi->nid) + vi->inode_isize + vi->xattr_isize, 8);
 
 	ret = dev_read(erofs_dev, buf, pos, sizeof(buf));
 	if (ret < 0)
@@ -101,11 +104,12 @@ static int z_erofs_reload_indexes(
 
 static int legacy_load_cluster_from_disk(
 	struct erofs_device erofs_dev,
+	struct erofs_sb_info *sbi,
 	struct z_erofs_maprecorder *m,
 	unsigned long lcn)
 {
 	struct erofs_inode *const vi = m->inode;
-	const erofs_off_t ibase = iloc(vi->nid);
+	const erofs_off_t ibase = iloc(sbi, vi->nid);
 	const erofs_off_t pos =
 		Z_EROFS_VLE_LEGACY_INDEX_ALIGN(ibase + vi->inode_isize +
 					       vi->xattr_isize) +
@@ -295,12 +299,13 @@ static int unpack_compacted_index(struct z_erofs_maprecorder *m,
 
 static int compacted_load_cluster_from_disk(
 	struct erofs_device erofs_dev,
+	struct erofs_sb_info *sbi,
 	struct z_erofs_maprecorder *m,
 	unsigned long lcn, bool lookahead)
 {
 	struct erofs_inode *const vi = m->inode;
 	const unsigned int lclusterbits = vi->z_logical_clusterbits;
-	const erofs_off_t ebase = round_up(iloc(vi->nid) + vi->inode_isize +
+	const erofs_off_t ebase = round_up(iloc(sbi, vi->nid) + vi->inode_isize +
 					   vi->xattr_isize, 8) +
 		sizeof(struct z_erofs_map_header);
 	const unsigned int totalidx = DIV_ROUND_UP(vi->i_size, EROFS_BLKSIZ);
@@ -352,22 +357,24 @@ out:
 
 static int z_erofs_load_cluster_from_disk(
 	struct erofs_device erofs_dev,
+	struct erofs_sb_info *sbi,
 	struct z_erofs_maprecorder *m,
 					  unsigned int lcn, bool lookahead)
 {
 	const unsigned int datamode = m->inode->datalayout;
 
 	if (datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY)
-		return legacy_load_cluster_from_disk(erofs_dev, m, lcn);
+		return legacy_load_cluster_from_disk(erofs_dev, sbi, m, lcn);
 
 	if (datamode == EROFS_INODE_FLAT_COMPRESSION)
-		return compacted_load_cluster_from_disk(erofs_dev, m, lcn, lookahead);
+		return compacted_load_cluster_from_disk(erofs_dev, sbi, m, lcn, lookahead);
 
 	return -EINVAL;
 }
 
 static int z_erofs_extent_lookback(
 	struct erofs_device erofs_dev,
+	struct erofs_sb_info *sbi,
 	struct z_erofs_maprecorder *m,
 				   unsigned int lookback_distance)
 {
@@ -386,7 +393,7 @@ static int z_erofs_extent_lookback(
 
 	/* load extent head logical cluster if needed */
 	lcn -= lookback_distance;
-	err = z_erofs_load_cluster_from_disk(erofs_dev, m, lcn, false);
+	err = z_erofs_load_cluster_from_disk(erofs_dev, sbi, m, lcn, false);
 	if (err)
 		return err;
 
@@ -398,7 +405,7 @@ static int z_erofs_extent_lookback(
 			DBG_BUGON(1);
 			return -EFSCORRUPTED;
 		}
-		return z_erofs_extent_lookback(erofs_dev, m, m->delta[0]);
+		return z_erofs_extent_lookback(erofs_dev, sbi, m, m->delta[0]);
 	case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
 		map->m_flags &= ~EROFS_MAP_ZIPPED;
 		/* fallthrough */
@@ -416,6 +423,7 @@ static int z_erofs_extent_lookback(
 
 static int z_erofs_get_extent_compressedlen(
 	struct erofs_device erofs_dev,
+	struct erofs_sb_info *sbi,
 	struct z_erofs_maprecorder *m,
 	unsigned int initial_lcn)
 {
@@ -437,7 +445,7 @@ static int z_erofs_get_extent_compressedlen(
 	if (m->compressedlcs)
 		goto out;
 
-	err = z_erofs_load_cluster_from_disk(erofs_dev, m, lcn, false);
+	err = z_erofs_load_cluster_from_disk(erofs_dev, sbi, m, lcn, false);
 	if (err)
 		return err;
 
@@ -485,6 +493,7 @@ err_bonus_cblkcnt:
 
 static int z_erofs_get_extent_decompressedlen(
 	struct erofs_device erofs_dev,
+	struct erofs_sb_info *sbi,
 	struct z_erofs_maprecorder *m)
 {
 	struct erofs_inode *const vi = m->inode;
@@ -500,7 +509,7 @@ static int z_erofs_get_extent_decompressedlen(
 			return 0;
 		}
 
-		err = z_erofs_load_cluster_from_disk(erofs_dev, m, lcn, true);
+		err = z_erofs_load_cluster_from_disk(erofs_dev, sbi, m, lcn, true);
 		if (err)
 			return err;
 
@@ -529,6 +538,7 @@ static int z_erofs_get_extent_decompressedlen(
 
 int z_erofs_map_blocks_iter(
 					struct erofs_device erofs_dev,
+					struct erofs_sb_info *sbi,
 					struct erofs_inode *vi,
 			    struct erofs_map_blocks *map,
 			    int flags)
@@ -551,7 +561,7 @@ int z_erofs_map_blocks_iter(
 		goto out;
 	}
 
-	err = z_erofs_fill_inode_lazy(erofs_dev, vi);
+	err = z_erofs_fill_inode_lazy(erofs_dev, sbi, vi);
 	if (err)
 		goto out;
 
@@ -560,7 +570,7 @@ int z_erofs_map_blocks_iter(
 	initial_lcn = ofs >> lclusterbits;
 	endoff = ofs & ((1 << lclusterbits) - 1);
 
-	err = z_erofs_load_cluster_from_disk(erofs_dev, &m, initial_lcn, false);
+	err = z_erofs_load_cluster_from_disk(erofs_dev, sbi, &m, initial_lcn, false);
 	if (err)
 		goto out;
 
@@ -589,7 +599,7 @@ int z_erofs_map_blocks_iter(
 		/* fallthrough */
 	case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
 		/* get the correspoinding first chunk */
-		err = z_erofs_extent_lookback(erofs_dev, &m, m.delta[0]);
+		err = z_erofs_extent_lookback(erofs_dev, sbi, &m, m.delta[0]);
 		if (err)
 			goto out;
 		break;
@@ -604,12 +614,12 @@ int z_erofs_map_blocks_iter(
 	map->m_pa = blknr_to_addr(m.pblk);
 	map->m_flags |= EROFS_MAP_MAPPED;
 
-	err = z_erofs_get_extent_compressedlen(erofs_dev, &m, initial_lcn);
+	err = z_erofs_get_extent_compressedlen(erofs_dev, sbi, &m, initial_lcn);
 	if (err)
 		goto out;
 
 	if (flags & EROFS_GET_BLOCKS_FIEMAP) {
-		err = z_erofs_get_extent_decompressedlen(erofs_dev, &m);
+		err = z_erofs_get_extent_decompressedlen(erofs_dev, sbi, &m);
 		if (!err)
 			map->m_flags |= EROFS_MAP_FULL_MAPPED;
 	}
diff --git a/mkfs/main.c b/mkfs/main.c
index 16f8060..f7b432e 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -109,7 +109,7 @@ static void usage(void)
 	print_available_compressors(stderr, ", ");
 }
 
-static int parse_extended_opts(const char *opts)
+static int parse_extended_opts(struct erofs_sb_info *sbi, const char *opts)
 {
 #define MATCH_EXTENTED_OPT(opt, token, keylen) \
 	(keylen == sizeof(opt) - 1 && !memcmp(token, opt, sizeof(opt) - 1))
@@ -164,7 +164,7 @@ static int parse_extended_opts(const char *opts)
 		if (MATCH_EXTENTED_OPT("nosbcrc", token, keylen)) {
 			if (vallen)
 				return -EINVAL;
-			erofs_sb_clear_sb_chksum(&sbi);
+			erofs_sb_clear_sb_chksum(sbi);
 		}
 
 		if (MATCH_EXTENTED_OPT("noinline_data", token, keylen)) {
@@ -176,7 +176,7 @@ static int parse_extended_opts(const char *opts)
 	return 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;
@@ -221,7 +221,7 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
 			break;
 
 		case 'E':
-			opt = parse_extended_opts(optarg);
+			opt = parse_extended_opts(sbi, optarg);
 			if (opt)
 				return opt;
 			break;
@@ -235,7 +235,7 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
 			break;
 #ifdef HAVE_LIBUUID
 		case 'U':
-			if (uuid_parse(optarg, sbi.uuid)) {
+			if (uuid_parse(optarg, sbi->uuid)) {
 				erofs_err("invalid UUID %s", optarg);
 				return -EINVAL;
 			}
@@ -343,7 +343,7 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
 					  optarg);
 				return -EINVAL;
 			}
-			erofs_sb_set_chunked_file(&sbi);
+			erofs_sb_set_chunked_file(sbi);
 			break;
 		case 12:
 			quiet = true;
@@ -385,21 +385,23 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
 	return 0;
 }
 
-int erofs_mkfs_update_super_block(struct erofs_buffer_head *bh,
+int erofs_mkfs_update_super_block(
+					struct erofs_sb_info *sbi,
+					struct erofs_buffer_head *bh,
 				  erofs_nid_t root_nid,
 				  erofs_blk_t *blocks)
 {
 	struct erofs_super_block sb = {
 		.magic     = cpu_to_le32(EROFS_SUPER_MAGIC_V1),
 		.blkszbits = LOG_BLOCK_SIZE,
-		.inos   = cpu_to_le64(sbi.inos),
-		.build_time = cpu_to_le64(sbi.build_time),
-		.build_time_nsec = cpu_to_le32(sbi.build_time_nsec),
+		.inos   = cpu_to_le64(sbi->inos),
+		.build_time = cpu_to_le64(sbi->build_time),
+		.build_time_nsec = cpu_to_le32(sbi->build_time_nsec),
 		.blocks = 0,
-		.meta_blkaddr  = sbi.meta_blkaddr,
-		.xattr_blkaddr = sbi.xattr_blkaddr,
-		.feature_incompat = cpu_to_le32(sbi.feature_incompat),
-		.feature_compat = cpu_to_le32(sbi.feature_compat &
+		.meta_blkaddr  = sbi->meta_blkaddr,
+		.xattr_blkaddr = sbi->xattr_blkaddr,
+		.feature_incompat = cpu_to_le32(sbi->feature_incompat),
+		.feature_compat = cpu_to_le32(sbi->feature_compat &
 					      ~EROFS_FEATURE_COMPAT_SB_CHKSUM),
 	};
 	const unsigned int sb_blksize =
@@ -409,12 +411,12 @@ int erofs_mkfs_update_super_block(struct erofs_buffer_head *bh,
 	*blocks         = erofs_mapbh(NULL);
 	sb.blocks       = cpu_to_le32(*blocks);
 	sb.root_nid     = cpu_to_le16(root_nid);
-	memcpy(sb.uuid, sbi.uuid, sizeof(sb.uuid));
+	memcpy(sb.uuid, sbi->uuid, sizeof(sb.uuid));
 
-	if (erofs_sb_has_compr_cfgs(&sbi))
-		sb.u1.available_compr_algs = sbi.available_compr_algs;
+	if (erofs_sb_has_compr_cfgs(sbi))
+		sb.u1.available_compr_algs = sbi->available_compr_algs;
 	else
-		sb.u1.lz4_max_distance = cpu_to_le16(sbi.lz4_max_distance);
+		sb.u1.lz4_max_distance = cpu_to_le16(sbi->lz4_max_distance);
 
 	buf = calloc(sb_blksize, 1);
 	if (!buf) {
@@ -473,17 +475,17 @@ static int erofs_mkfs_superblock_csum_set(struct erofs_device erofs_dev)
 	return 0;
 }
 
-static void erofs_mkfs_default_options(void)
+static void erofs_mkfs_default_options(struct erofs_sb_info *sbi)
 {
 	cfg.c_legacy_compress = false;
-	sbi.feature_incompat = EROFS_FEATURE_INCOMPAT_LZ4_0PADDING;
-	sbi.feature_compat = EROFS_FEATURE_COMPAT_SB_CHKSUM;
+	sbi->feature_incompat = EROFS_FEATURE_INCOMPAT_LZ4_0PADDING;
+	sbi->feature_compat = EROFS_FEATURE_COMPAT_SB_CHKSUM;
 
 	/* generate a default uuid first */
 #ifdef HAVE_LIBUUID
 	do {
-		uuid_generate(sbi.uuid);
-	} while (uuid_is_null(sbi.uuid));
+		uuid_generate(sbi->uuid);
+	} while (uuid_is_null(sbi->uuid));
 #endif
 }
 
@@ -531,11 +533,12 @@ int main(int argc, char **argv)
 	struct timeval t;
 	char uuid_str[37] = "not available";
 	struct erofs_device erofs_dev;
+	struct erofs_sb_info sbi;
 
 	erofs_init_global_configure();
-	erofs_mkfs_default_options();
+	erofs_mkfs_default_options(&sbi);
 
-	err = mkfs_parse_options_cfg(argc, argv);
+	err = mkfs_parse_options_cfg(&sbi, argc, argv);
 	erofs_show_progs(argc, argv);
 	if (err) {
 		if (err == -EINVAL)
@@ -620,7 +623,7 @@ int main(int argc, char **argv)
 		goto exit;
 	}
 
-	err = z_erofs_compress_init(erofs_dev, sb_bh);
+	err = z_erofs_compress_init(erofs_dev, &sbi, sb_bh);
 	if (err) {
 		erofs_err("Failed to initialize compressor: %s",
 			  erofs_strerror(err));
@@ -634,20 +637,20 @@ int main(int argc, char **argv)
 
 	erofs_inode_manager_init();
 
-	err = erofs_build_shared_xattrs_from_path(cfg.c_src_path);
+	err = erofs_build_shared_xattrs_from_path(cfg.c_src_path, &sbi);
 	if (err) {
 		erofs_err("Failed to build shared xattrs: %s",
 			  erofs_strerror(err));
 		goto exit;
 	}
 
-	root_inode = erofs_mkfs_build_tree_from_path(erofs_dev, NULL, cfg.c_src_path);
+	root_inode = erofs_mkfs_build_tree_from_path(erofs_dev, &sbi, NULL, cfg.c_src_path);
 	if (IS_ERR(root_inode)) {
 		err = PTR_ERR(root_inode);
 		goto exit;
 	}
 
-	root_nid = erofs_lookupnid(root_inode);
+	root_nid = erofs_lookupnid(&sbi, root_inode);
 	erofs_iput(root_inode);
 
 	if (cfg.c_chunkbits) {
@@ -657,7 +660,7 @@ int main(int argc, char **argv)
 			goto exit;
 	}
 
-	err = erofs_mkfs_update_super_block(sb_bh, root_nid, &nblocks);
+	err = erofs_mkfs_update_super_block(&sbi, sb_bh, root_nid, &nblocks);
 	if (err)
 		goto exit;
 
-- 
2.34.0.rc2.393.gf8c9666880-goog


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v1 0/3] Make erofs-utils more library friendly
  2021-11-21  5:39 [PATCH v1 0/3] Make erofs-utils more library friendly Kelvin Zhang via Linux-erofs
                   ` (2 preceding siblings ...)
  2021-11-21  5:39 ` [PATCH v1 3/4] Make super block info struct a paramater instead of globals Kelvin Zhang via Linux-erofs
@ 2021-11-21 10:31 ` Gao Xiang
  2021-11-23  7:39   ` Kelvin Zhang via Linux-erofs
  3 siblings, 1 reply; 8+ messages in thread
From: Gao Xiang @ 2021-11-21 10:31 UTC (permalink / raw)
  To: Kelvin Zhang; +Cc: linux-erofs mailing list, Chao Yu, Li Guifu, Miao Xie

Hi Kelvin,

On Sat, Nov 20, 2021 at 09:39:17PM -0800, Kelvin Zhang wrote:
> EROFS-utils contains several usage of global variables, namely
> 
> 1. int erofs_devfd, stores the file descriptor to open'ed block devices.
> This is referened in many places.
> 2. struct erofs_sb_info sbi; Stores parsed super block.
> 
> These global variables make embedding erofs library diffcult. To make
> library usage easier, a series of 3 patches are drafted to refactor away
> the global variables. Each patch has been built and tested by calling
> mkfs.erofs and ensure the same output is generated.

Agreed, that is mainly due to fast iterative development. If we consider
to export liberofs as a real library, these all needs to be resolved in
advance, and it'd be better to stablize all liberofs APIs as well.

However, let's postpone this work until 1.4 is out, I have to admit I'm
a bit delay of releasing v1.4 due to my busy work.
Now I'm working on pre-releasing..

Thanks,
Gao Xiang

> 
> Kelvin Zhang (3):
>   Make erofs_devfd a parameter for most functions
>   Mark certain callback function pointers as const
>   Make super block info struct a paramater instead of globals
> 
>  Android.bp                 |  44 +++++++-
>  dump/main.c                |  84 ++++++++------
>  fsck/main.c                |  90 +++++++++------
>  fuse/dir.c                 |   8 +-
>  fuse/main.c                |  19 ++--
>  include/erofs/blobchunk.h  |   7 +-
>  include/erofs/cache.h      |  15 +--
>  include/erofs/compress.h   |  10 +-
>  include/erofs/config.h     |  15 +--
>  include/erofs/decompress.h |   5 +-
>  include/erofs/defs.h       |  21 ++++
>  include/erofs/inode.h      |   9 +-
>  include/erofs/internal.h   |  72 ++++++------
>  include/erofs/io.h         |  48 +++++---
>  include/erofs/iterate.h    |  35 ++++++
>  include/erofs/xattr.h      |   2 +-
>  iterate/main.c             |  51 +++++++++
>  lib/blobchunk.c            |  11 +-
>  lib/cache.c                |  33 +++---
>  lib/compress.c             | 104 ++++++++++-------
>  lib/compressor.c           |   9 +-
>  lib/compressor.h           |  13 ++-
>  lib/compressor_liblzma.c   |   4 +-
>  lib/compressor_lz4.c       |   8 +-
>  lib/compressor_lz4hc.c     |   6 +-
>  lib/config.c               |  64 ++++++-----
>  lib/data.c                 |  54 +++++----
>  lib/decompress.c           |  12 +-
>  lib/inode.c                | 129 ++++++++++++---------
>  lib/io.c                   |  74 ++++++------
>  lib/iterate.c              | 223 +++++++++++++++++++++++++++++++++++++
>  lib/namei.c                |  44 +++++---
>  lib/super.c                |  28 ++---
>  lib/xattr.c                |  10 +-
>  lib/zmap.c                 |  92 +++++++++------
>  mkfs/main.c                |  92 +++++++--------
>  36 files changed, 1069 insertions(+), 476 deletions(-)
>  create mode 100644 include/erofs/iterate.h
>  create mode 100644 iterate/main.c
>  create mode 100644 lib/iterate.c
> 
> -- 
> 2.34.0.rc2.393.gf8c9666880-goog

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v1 0/3] Make erofs-utils more library friendly
  2021-11-21 10:31 ` [PATCH v1 0/3] Make erofs-utils more library friendly Gao Xiang
@ 2021-11-23  7:39   ` Kelvin Zhang via Linux-erofs
  0 siblings, 0 replies; 8+ messages in thread
From: Kelvin Zhang via Linux-erofs @ 2021-11-23  7:39 UTC (permalink / raw)
  To: Gao Xiang; +Cc: linux-erofs mailing list, Chao Yu, Li Guifu, Miao Xie

[-- Attachment #1: Type: text/plain, Size: 3355 bytes --]

Sounds good, now that v1.4 is available on kernel.lorg, shall we start
working on the refactoring commits?

On Sun, Nov 21, 2021 at 2:31 AM Gao Xiang <hsiangkao@linux.alibaba.com>
wrote:

> Hi Kelvin,
>
> On Sat, Nov 20, 2021 at 09:39:17PM -0800, Kelvin Zhang wrote:
> > EROFS-utils contains several usage of global variables, namely
> >
> > 1. int erofs_devfd, stores the file descriptor to open'ed block devices.
> > This is referened in many places.
> > 2. struct erofs_sb_info sbi; Stores parsed super block.
> >
> > These global variables make embedding erofs library diffcult. To make
> > library usage easier, a series of 3 patches are drafted to refactor away
> > the global variables. Each patch has been built and tested by calling
> > mkfs.erofs and ensure the same output is generated.
>
> Agreed, that is mainly due to fast iterative development. If we consider
> to export liberofs as a real library, these all needs to be resolved in
> advance, and it'd be better to stablize all liberofs APIs as well.
>
> However, let's postpone this work until 1.4 is out, I have to admit I'm
> a bit delay of releasing v1.4 due to my busy work.
> Now I'm working on pre-releasing..
>
> Thanks,
> Gao Xiang
>
> >
> > Kelvin Zhang (3):
> >   Make erofs_devfd a parameter for most functions
> >   Mark certain callback function pointers as const
> >   Make super block info struct a paramater instead of globals
> >
> >  Android.bp                 |  44 +++++++-
> >  dump/main.c                |  84 ++++++++------
> >  fsck/main.c                |  90 +++++++++------
> >  fuse/dir.c                 |   8 +-
> >  fuse/main.c                |  19 ++--
> >  include/erofs/blobchunk.h  |   7 +-
> >  include/erofs/cache.h      |  15 +--
> >  include/erofs/compress.h   |  10 +-
> >  include/erofs/config.h     |  15 +--
> >  include/erofs/decompress.h |   5 +-
> >  include/erofs/defs.h       |  21 ++++
> >  include/erofs/inode.h      |   9 +-
> >  include/erofs/internal.h   |  72 ++++++------
> >  include/erofs/io.h         |  48 +++++---
> >  include/erofs/iterate.h    |  35 ++++++
> >  include/erofs/xattr.h      |   2 +-
> >  iterate/main.c             |  51 +++++++++
> >  lib/blobchunk.c            |  11 +-
> >  lib/cache.c                |  33 +++---
> >  lib/compress.c             | 104 ++++++++++-------
> >  lib/compressor.c           |   9 +-
> >  lib/compressor.h           |  13 ++-
> >  lib/compressor_liblzma.c   |   4 +-
> >  lib/compressor_lz4.c       |   8 +-
> >  lib/compressor_lz4hc.c     |   6 +-
> >  lib/config.c               |  64 ++++++-----
> >  lib/data.c                 |  54 +++++----
> >  lib/decompress.c           |  12 +-
> >  lib/inode.c                | 129 ++++++++++++---------
> >  lib/io.c                   |  74 ++++++------
> >  lib/iterate.c              | 223 +++++++++++++++++++++++++++++++++++++
> >  lib/namei.c                |  44 +++++---
> >  lib/super.c                |  28 ++---
> >  lib/xattr.c                |  10 +-
> >  lib/zmap.c                 |  92 +++++++++------
> >  mkfs/main.c                |  92 +++++++--------
> >  36 files changed, 1069 insertions(+), 476 deletions(-)
> >  create mode 100644 include/erofs/iterate.h
> >  create mode 100644 iterate/main.c
> >  create mode 100644 lib/iterate.c
> >
> > --
> > 2.34.0.rc2.393.gf8c9666880-goog
>


-- 
Sincerely,

Kelvin Zhang

[-- Attachment #2: Type: text/html, Size: 4487 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v1 1/4] Make erofs_devfd a parameter for most functions
  2021-11-21  5:39 ` [PATCH v1 1/4] Make erofs_devfd a parameter for most functions Kelvin Zhang via Linux-erofs
@ 2021-11-23  7:49   ` Gao Xiang
  0 siblings, 0 replies; 8+ messages in thread
From: Gao Xiang @ 2021-11-23  7:49 UTC (permalink / raw)
  To: Kelvin Zhang; +Cc: linux-erofs mailing list, Chao Yu, Li Guifu, Miao Xie

Hi Kelvin,

On Sat, Nov 20, 2021 at 09:39:18PM -0800, Kelvin Zhang wrote:
> Test: extract system.img from
> aosp_cf_x86_64_phone-target_files-7731383.zip , mount it, mkfs.erofs to
> generate an EROFS image. Make sure the content is the same before/after
> this patch. (Except super block, which has an UUID)
> 
> target_files.zip can be downloaded from
> https://ci.android.com/builds/branches/aosp-master/grid?head=7934850&tail=7934850
> 
> Signed-off-by: Kelvin Zhang <zhangkelvin@google.com>

Thanks for your effort!

Just a quick glance, I'm not sure if we have to expose erofs_device to
most of the functions... Also it breaks some common functions argument
lists which was porting from the kernel side.

How about integrating struct erofs_device to struct erofs_sb_info? and
make inode->sb_info->dev chain workable?

Also it would be better to leave a descriptive commit message ;) it
would be helpful!

Thanks,
Gao Xiang

> ---
>  dump/main.c               | 61 +++++++++++++++--------------
>  fsck/main.c               | 65 ++++++++++++++++---------------
>  fuse/dir.c                |  7 +++-
>  fuse/main.c               | 18 +++++----
>  include/erofs/blobchunk.h |  7 +++-
>  include/erofs/cache.h     |  7 ++--
>  include/erofs/compress.h  |  8 +++-
>  include/erofs/config.h    | 15 ++++----
>  include/erofs/defs.h      | 21 ++++++++++
>  include/erofs/inode.h     |  6 ++-
>  include/erofs/internal.h  | 52 +++++++++----------------
>  include/erofs/io.h        | 48 ++++++++++++++---------
>  lib/blobchunk.c           | 11 ++++--
>  lib/cache.c               | 27 ++++++++-----
>  lib/compress.c            | 54 ++++++++++++++------------
>  lib/compressor_liblzma.c  |  2 +-
>  lib/config.c              | 63 ++++++++++++++++++------------
>  lib/data.c                | 30 +++++++++------
>  lib/decompress.c          |  2 +-
>  lib/inode.c               | 81 +++++++++++++++++++++++----------------
>  lib/io.c                  | 74 +++++++++++++++++++----------------
>  lib/namei.c               | 22 +++++------
>  lib/super.c               | 28 +++++++-------
>  lib/xattr.c               |  6 ++-
>  lib/zmap.c                | 74 +++++++++++++++++++++--------------
>  mkfs/main.c               | 39 ++++++++++---------
>  26 files changed, 476 insertions(+), 352 deletions(-)
>
 

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v1 3/4] Make super block info struct a paramater instead of globals
  2021-11-21  5:39 ` [PATCH v1 3/4] Make super block info struct a paramater instead of globals Kelvin Zhang via Linux-erofs
@ 2021-11-23  7:54   ` Gao Xiang
  0 siblings, 0 replies; 8+ messages in thread
From: Gao Xiang @ 2021-11-23  7:54 UTC (permalink / raw)
  To: Kelvin Zhang; +Cc: linux-erofs mailing list, Chao Yu, Li Guifu, Miao Xie

On Sat, Nov 20, 2021 at 09:39:20PM -0800, Kelvin Zhang wrote:
> 
> Test: mkfs.erofs on system.img of
>     aosp_cf_x86_64_phone-target_files-7731383.zip
>     Make sure output is the same before/after this patch
> 
> Signed-off-by: Kelvin Zhang <zhangkelvin@google.com>

Yeah, it'd be helpful if we have multiple sb instances.

Yet same as I suggested in [PATCH 1/4], it would be better to
make

struct erofs_inode {
..
	struct erofs_sb_info *sbi;
...
};

So most functions don't need to pass in sbi... And inode -> sbi
can help multiple instance runtime as well.

Thanks,
Gao Xiang


> ---
>  dump/main.c                | 67 +++++++++++++++++++------------
>  fsck/main.c                | 61 +++++++++++++++++++----------
>  fuse/dir.c                 |  5 ++-
>  fuse/main.c                |  7 ++--
>  include/erofs/compress.h   |  2 +
>  include/erofs/decompress.h |  5 ++-
>  include/erofs/inode.h      |  3 +-
>  include/erofs/internal.h   | 26 ++++++++-----
>  include/erofs/xattr.h      |  2 +-
>  lib/compress.c             | 80 +++++++++++++++++++++++---------------
>  lib/compressor.c           |  7 +++-
>  lib/compressor.h           |  5 ++-
>  lib/compressor_lz4.c       |  6 ++-
>  lib/compressor_lz4hc.c     |  4 +-
>  lib/config.c               |  1 -
>  lib/data.c                 | 36 ++++++++++-------
>  lib/decompress.c           | 12 +++---
>  lib/inode.c                | 60 ++++++++++++++++------------
>  lib/namei.c                | 40 ++++++++++++-------
>  lib/xattr.c                |  4 +-
>  lib/zmap.c                 | 46 +++++++++++++---------
>  mkfs/main.c                | 63 ++++++++++++++++--------------
>  22 files changed, 332 insertions(+), 210 deletions(-)
> 
> diff --git a/dump/main.c b/dump/main.c
> index 8d0dbd0..0ac97a0 100644
> --- a/dump/main.c
> +++ b/dump/main.c
> @@ -85,7 +85,10 @@ static struct erofsdump_feature feature_lists[] = {
>  	{ false, EROFS_FEATURE_INCOMPAT_CHUNKED_FILE, "chunked_file" },
>  };
>  
> -static int erofs_read_dir(struct erofs_device fd, erofs_nid_t nid, erofs_nid_t parent_nid);
> +static int erofs_read_dir(
> +	struct erofs_device fd,
> +	struct erofs_sb_info *sbi,
> +	erofs_nid_t nid, erofs_nid_t parent_nid);
>  static inline int erofs_checkdirent(struct erofs_dirent *de,
>  		struct erofs_dirent *last_de,
>  		u32 maxsize, const char *dname);
> @@ -258,7 +261,9 @@ static inline int erofs_checkdirent(struct erofs_dirent *de,
>  }
>  
>  static int erofs_read_dirent(
> -		struct erofs_device erofs_dev, struct erofs_dirent *de,
> +		struct erofs_device erofs_dev,
> +		struct erofs_sb_info *sbi,
> +		struct erofs_dirent *de,
>  		erofs_nid_t nid, erofs_nid_t parent_nid,
>  		const char *dname)
>  {
> @@ -268,7 +273,7 @@ static int erofs_read_dirent(
>  
>  	stats.files++;
>  	stats.file_category_stat[de->file_type]++;
> -	err = erofs_read_inode_from_disk(erofs_dev, &inode);
> +	err = erofs_read_inode_from_disk(erofs_dev, sbi, &inode);
>  	if (err) {
>  		erofs_err("read file inode from disk failed!");
>  		return err;
> @@ -289,7 +294,7 @@ static int erofs_read_dirent(
>  
>  	if ((de->file_type == EROFS_FT_DIR)
>  			&& de->nid != nid && de->nid != parent_nid) {
> -		err = erofs_read_dir(erofs_dev, de->nid, nid);
> +		err = erofs_read_dir(erofs_dev, sbi, de->nid, nid);
>  		if (err) {
>  			erofs_err("parse dir nid %llu error occurred\n",
>  					de->nid);
> @@ -299,14 +304,17 @@ static int erofs_read_dirent(
>  	return 0;
>  }
>  
> -static int erofs_read_dir(struct erofs_device fd, erofs_nid_t nid, erofs_nid_t parent_nid)
> +static int erofs_read_dir(
> +	struct erofs_device fd,
> +	struct erofs_sb_info *sbi,
> +	erofs_nid_t nid, erofs_nid_t parent_nid)
>  {
>  	int err;
>  	erofs_off_t offset;
>  	char buf[EROFS_BLKSIZ];
>  	struct erofs_inode vi = { .nid = nid };
>  
> -	err = erofs_read_inode_from_disk(fd, &vi);
> +	err = erofs_read_inode_from_disk(fd, sbi, &vi);
>  	if (err)
>  		return err;
>  
> @@ -318,7 +326,7 @@ static int erofs_read_dir(struct erofs_device fd, erofs_nid_t nid, erofs_nid_t p
>  		struct erofs_dirent *end;
>  		unsigned int nameoff;
>  
> -		err = erofs_pread(fd, &vi, buf, maxsize, offset);
> +		err = erofs_pread(fd, sbi, &vi, buf, maxsize, offset);
>  		if (err)
>  			return err;
>  
> @@ -338,7 +346,7 @@ static int erofs_read_dir(struct erofs_device fd, erofs_nid_t nid, erofs_nid_t p
>  			ret = erofs_checkdirent(de, end, maxsize, dname);
>  			if (ret < 0)
>  				return ret;
> -			ret = erofs_read_dirent(fd, de, nid, parent_nid, dname);
> +			ret = erofs_read_dirent(fd, sbi, de, nid, parent_nid, dname);
>  			if (ret < 0)
>  				return ret;
>  			++de;
> @@ -348,7 +356,10 @@ static int erofs_read_dir(struct erofs_device fd, erofs_nid_t nid, erofs_nid_t p
>  	return 0;
>  }
>  
> -static int erofs_get_pathname(struct erofs_device fd, erofs_nid_t nid, erofs_nid_t parent_nid,
> +static int erofs_get_pathname(
> +	struct erofs_device fd,
> +	struct erofs_sb_info *sbi,
> +	erofs_nid_t nid, erofs_nid_t parent_nid,
>  		erofs_nid_t target, char *path, unsigned int pos)
>  {
>  	int err;
> @@ -357,10 +368,10 @@ static int erofs_get_pathname(struct erofs_device fd, erofs_nid_t nid, erofs_nid
>  	struct erofs_inode inode = { .nid = nid };
>  
>  	path[pos++] = '/';
> -	if (target == sbi.root_nid)
> +	if (target == sbi->root_nid)
>  		return 0;
>  
> -	err = erofs_read_inode_from_disk(fd, &inode);
> +	err = erofs_read_inode_from_disk(fd, sbi, &inode);
>  	if (err) {
>  		erofs_err("read inode failed @ nid %llu", nid | 0ULL);
>  		return err;
> @@ -374,7 +385,7 @@ static int erofs_get_pathname(struct erofs_device fd, erofs_nid_t nid, erofs_nid
>  		struct erofs_dirent *end;
>  		unsigned int nameoff;
>  
> -		err = erofs_pread(fd, &inode, buf, maxsize, offset);
> +		err = erofs_pread(fd, sbi, &inode, buf, maxsize, offset);
>  		if (err)
>  			return err;
>  
> @@ -400,7 +411,7 @@ static int erofs_get_pathname(struct erofs_device fd, erofs_nid_t nid, erofs_nid
>  					de->nid != parent_nid &&
>  					de->nid != nid) {
>  				memcpy(path + pos, dname, len);
> -				err = erofs_get_pathname(fd, de->nid, nid,
> +				err = erofs_get_pathname(fd, sbi, de->nid, nid,
>  						target, path, pos + len);
>  				if (!err)
>  					return 0;
> @@ -415,16 +426,19 @@ static int erofs_get_pathname(struct erofs_device fd, erofs_nid_t nid, erofs_nid
>  
>  static int erofsdump_map_blocks(
>  	struct erofs_device erofs_dev,
> +	struct erofs_sb_info *sbi,
>  	struct erofs_inode *inode,
>  	struct erofs_map_blocks *map,
>  	int flags)
>  {
>  	if (erofs_inode_is_data_compressed(inode->datalayout))
> -		return z_erofs_map_blocks_iter(erofs_dev, inode, map, flags);
> -	return erofs_map_blocks(erofs_dev, inode, map, flags);
> +		return z_erofs_map_blocks_iter(erofs_dev, sbi, inode, map, flags);
> +	return erofs_map_blocks(erofs_dev, sbi, inode, map, flags);
>  }
>  
> -static void erofsdump_show_fileinfo(struct erofs_device fd, bool show_extent)
> +static void erofsdump_show_fileinfo(
> +	struct erofs_device fd,
> +	struct erofs_sb_info *sbi, bool show_extent)
>  {
>  	int err, i;
>  	erofs_off_t size;
> @@ -439,7 +453,7 @@ static void erofsdump_show_fileinfo(struct erofs_device fd, bool show_extent)
>  		.m_la = 0,
>  	};
>  
> -	err = erofs_read_inode_from_disk(fd, &inode);
> +	err = erofs_read_inode_from_disk(fd, sbi, &inode);
>  	if (err) {
>  		erofs_err("read inode failed @ nid %llu", inode.nid | 0ULL);
>  		return;
> @@ -451,7 +465,7 @@ static void erofsdump_show_fileinfo(struct erofs_device fd, bool show_extent)
>  		return;
>  	}
>  
> -	err = erofs_get_pathname(fd, sbi.root_nid, sbi.root_nid,
> +	err = erofs_get_pathname(fd, sbi, sbi->root_nid, sbi->root_nid,
>  				 inode.nid, path, 0);
>  	if (err < 0) {
>  		erofs_err("file path not found @ nid %llu", inode.nid | 0ULL);
> @@ -484,7 +498,7 @@ static void erofsdump_show_fileinfo(struct erofs_device fd, bool show_extent)
>  
>  	fprintf(stdout, "\n Ext:   logical offset   |  length :     physical offset    |  length \n");
>  	while (map.m_la < inode.i_size) {
> -		err = erofsdump_map_blocks(fd, &inode, &map,
> +		err = erofsdump_map_blocks(fd, sbi, &inode, &map,
>  				EROFS_GET_BLOCKS_FIEMAP);
>  		if (err) {
>  			erofs_err("get file blocks range failed");
> @@ -584,11 +598,13 @@ static void erofsdump_file_statistic(void)
>  			stats.compress_rate);
>  }
>  
> -static void erofsdump_print_statistic(struct erofs_device fd)
> +static void erofsdump_print_statistic(
> +	struct erofs_device fd,
> +	struct erofs_sb_info *sbi)
>  {
>  	int err;
>  
> -	err = erofs_read_dir(fd, sbi.root_nid, sbi.root_nid);
> +	err = erofs_read_dir(fd, sbi, sbi->root_nid, sbi->root_nid);
>  	if (err) {
>  		erofs_err("read dir failed");
>  		return;
> @@ -604,7 +620,7 @@ static void erofsdump_print_statistic(struct erofs_device fd)
>  	erofsdump_filetype_distribution(file_types, OTHERFILETYPE);
>  }
>  
> -static void erofsdump_show_superblock(void)
> +static void erofsdump_show_superblock(struct erofs_sb_info sbi)
>  {
>  	time_t time = sbi.build_time;
>  	char uuid_str[37] = "not available";
> @@ -643,6 +659,7 @@ int main(int argc, char **argv)
>  {
>  	int err;
>  	struct erofs_device erofs_dev;
> +	struct erofs_sb_info sbi;
>  
>  	erofs_init_global_configure();
>  	err = erofsdump_parse_options_cfg(argc, argv);
> @@ -669,10 +686,10 @@ int main(int argc, char **argv)
>  		dumpcfg.totalshow = 1;
>  	}
>  	if (dumpcfg.show_superblock)
> -		erofsdump_show_superblock();
> +		erofsdump_show_superblock(sbi);
>  
>  	if (dumpcfg.show_statistics)
> -		erofsdump_print_statistic(erofs_dev);
> +		erofsdump_print_statistic(erofs_dev, &sbi);
>  
>  	if (dumpcfg.show_extent && !dumpcfg.show_inode) {
>  		usage();
> @@ -680,7 +697,7 @@ int main(int argc, char **argv)
>  	}
>  
>  	if (dumpcfg.show_inode)
> -		erofsdump_show_fileinfo(erofs_dev, dumpcfg.show_extent);
> +		erofsdump_show_fileinfo(erofs_dev, &sbi, dumpcfg.show_extent);
>  
>  exit:
>  	erofs_exit_global_configure();
> diff --git a/fsck/main.c b/fsck/main.c
> index b69333b..d6ce1a4 100644
> --- a/fsck/main.c
> +++ b/fsck/main.c
> @@ -11,7 +11,10 @@
>  #include "erofs/io.h"
>  #include "erofs/decompress.h"
>  
> -static void erofs_check_inode(struct erofs_device devfd, erofs_nid_t pnid, erofs_nid_t nid);
> +static void erofs_check_inode(
> +	struct erofs_device devfd,
> +	struct erofs_sb_info *sbi,
> +	erofs_nid_t pnid, erofs_nid_t nid);
>  
>  struct erofsfsck_cfg {
>  	bool corrupted;
> @@ -138,7 +141,10 @@ static bool check_special_dentry(struct erofs_dirent *de,
>  	return true;
>  }
>  
> -static int traverse_dirents(struct erofs_device devfd, erofs_nid_t pnid, erofs_nid_t nid,
> +static int traverse_dirents(
> +	struct erofs_device devfd,
> +	struct erofs_sb_info *sbi,
> +	erofs_nid_t pnid, erofs_nid_t nid,
>  			    void *dentry_blk, erofs_blk_t block,
>  			    unsigned int next_nameoff, unsigned int maxsize)
>  {
> @@ -212,7 +218,7 @@ static int traverse_dirents(struct erofs_device devfd, erofs_nid_t pnid, erofs_n
>  				goto out;
>  			}
>  		} else {
> -			erofs_check_inode(devfd, nid, de->nid);
> +			erofs_check_inode(devfd, sbi, nid, de->nid);
>  		}
>  
>  		if (fsckcfg.corrupted) {
> @@ -236,7 +242,9 @@ out:
>  }
>  
>  static int verify_uncompressed_inode(
> -	struct erofs_device erofs_dev, struct erofs_inode *inode)
> +	struct erofs_device erofs_dev,
> +	struct erofs_sb_info *sbi,
> +	struct erofs_inode *inode)
>  {
>  	struct erofs_map_blocks map = {
>  		.index = UINT_MAX,
> @@ -247,7 +255,7 @@ static int verify_uncompressed_inode(
>  
>  	while (ptr < inode->i_size) {
>  		map.m_la = ptr;
> -		ret = erofs_map_blocks(erofs_dev, inode, &map, 0);
> +		ret = erofs_map_blocks(erofs_dev, sbi, inode, &map, 0);
>  		if (ret)
>  			return ret;
>  
> @@ -274,7 +282,10 @@ static int verify_uncompressed_inode(
>  	return 0;
>  }
>  
> -static int verify_compressed_inode(struct erofs_device erofs_dev, struct erofs_inode *inode)
> +static int verify_compressed_inode(
> +	struct erofs_device erofs_dev,
> +	struct erofs_sb_info *sbi,
> +	struct erofs_inode *inode)
>  {
>  	struct erofs_map_blocks map = {
>  		.index = UINT_MAX,
> @@ -288,7 +299,7 @@ static int verify_compressed_inode(struct erofs_device erofs_dev, struct erofs_i
>  	while (end > 0) {
>  		map.m_la = end - 1;
>  
> -		ret = z_erofs_map_blocks_iter(erofs_dev, inode, &map, 0);
> +		ret = z_erofs_map_blocks_iter(erofs_dev, sbi, inode, &map, 0);
>  		if (ret)
>  			goto out;
>  
> @@ -336,7 +347,7 @@ static int verify_compressed_inode(struct erofs_device erofs_dev, struct erofs_i
>  					.decodedlength = map.m_llen,
>  					.alg = algorithmformat,
>  					.partial_decoding = 0
> -					 });
> +					 }, sbi);
>  
>  		if (ret < 0) {
>  			erofs_err("failed to decompress data of m_pa %" PRIu64 ", m_plen %" PRIu64 " @ nid %llu: %d",
> @@ -359,7 +370,10 @@ out:
>  	return ret < 0 ? ret : 0;
>  }
>  
> -static int erofs_verify_xattr(struct erofs_device erofs_dev, struct erofs_inode *inode)
> +static int erofs_verify_xattr(
> +	struct erofs_device erofs_dev,
> +	struct erofs_sb_info *sbi,
> +	struct erofs_inode *inode)
>  {
>  	unsigned int xattr_hdr_size = sizeof(struct erofs_xattr_ibody_header);
>  	unsigned int xattr_entry_size = sizeof(struct erofs_xattr_entry);
> @@ -384,7 +398,7 @@ static int erofs_verify_xattr(struct erofs_device erofs_dev, struct erofs_inode
>  		}
>  	}
>  
> -	addr = iloc(inode->nid) + inode->inode_isize;
> +	addr = iloc(sbi, inode->nid) + inode->inode_isize;
>  	ret = dev_read(erofs_dev, buf, addr, xattr_hdr_size);
>  	if (ret < 0) {
>  		erofs_err("failed to read xattr header @ nid %llu: %d",
> @@ -437,7 +451,10 @@ out:
>  	return ret;
>  }
>  
> -static int erofs_verify_inode_data(struct erofs_device erofs_dev, struct erofs_inode *inode)
> +static int erofs_verify_inode_data(
> +	struct erofs_device erofs_dev,
> +	struct erofs_sb_info *sbi,
> +	struct erofs_inode *inode)
>  {
>  	int ret;
>  
> @@ -448,11 +465,11 @@ static int erofs_verify_inode_data(struct erofs_device erofs_dev, struct erofs_i
>  	case EROFS_INODE_FLAT_PLAIN:
>  	case EROFS_INODE_FLAT_INLINE:
>  	case EROFS_INODE_CHUNK_BASED:
> -		ret = verify_uncompressed_inode(erofs_dev, inode);
> +		ret = verify_uncompressed_inode(erofs_dev, sbi, inode);
>  		break;
>  	case EROFS_INODE_FLAT_COMPRESSION_LEGACY:
>  	case EROFS_INODE_FLAT_COMPRESSION:
> -		ret = verify_compressed_inode(erofs_dev, inode);
> +		ret = verify_compressed_inode(erofs_dev, sbi, inode);
>  		break;
>  	default:
>  		ret = -EINVAL;
> @@ -466,7 +483,10 @@ static int erofs_verify_inode_data(struct erofs_device erofs_dev, struct erofs_i
>  	return ret;
>  }
>  
> -static void erofs_check_inode(struct erofs_device erofs_dev, erofs_nid_t pnid, erofs_nid_t nid)
> +static void erofs_check_inode(
> +	struct erofs_device erofs_dev,
> +	struct erofs_sb_info *sbi,
> +	erofs_nid_t pnid, erofs_nid_t nid)
>  {
>  	int ret;
>  	struct erofs_inode inode;
> @@ -476,7 +496,7 @@ static void erofs_check_inode(struct erofs_device erofs_dev, erofs_nid_t pnid, e
>  	erofs_dbg("check inode: nid(%llu)", nid | 0ULL);
>  
>  	inode.nid = nid;
> -	ret = erofs_read_inode_from_disk(erofs_dev, &inode);
> +	ret = erofs_read_inode_from_disk(erofs_dev, sbi, &inode);
>  	if (ret) {
>  		if (ret == -EIO)
>  			erofs_err("I/O error occurred when reading nid(%llu)",
> @@ -485,12 +505,12 @@ static void erofs_check_inode(struct erofs_device erofs_dev, erofs_nid_t pnid, e
>  	}
>  
>  	/* verify xattr field */
> -	ret = erofs_verify_xattr(erofs_dev,&inode);
> +	ret = erofs_verify_xattr(erofs_dev, sbi, &inode);
>  	if (ret)
>  		goto out;
>  
>  	/* verify data chunk layout */
> -	ret = erofs_verify_inode_data(erofs_dev, &inode);
> +	ret = erofs_verify_inode_data(erofs_dev, sbi, &inode);
>  	if (ret)
>  		goto out;
>  
> @@ -506,7 +526,7 @@ static void erofs_check_inode(struct erofs_device erofs_dev, erofs_nid_t pnid, e
>  
>  		unsigned int nameoff;
>  
> -		ret = erofs_pread(erofs_dev, &inode, buf, maxsize, offset);
> +		ret = erofs_pread(erofs_dev, sbi, &inode, buf, maxsize, offset);
>  		if (ret) {
>  			erofs_err("I/O error occurred when reading dirents @ nid %llu, block %u: %d",
>  				  nid | 0ULL, block, ret);
> @@ -522,7 +542,7 @@ static void erofs_check_inode(struct erofs_device erofs_dev, erofs_nid_t pnid, e
>  			goto out;
>  		}
>  
> -		ret = traverse_dirents(erofs_dev, pnid, nid, buf, block,
> +		ret = traverse_dirents(erofs_dev, sbi, pnid, nid, buf, block,
>  				       nameoff, maxsize);
>  		if (ret)
>  			goto out;
> @@ -538,6 +558,7 @@ int main(int argc, char **argv)
>  {
>  	int err;
>  	struct erofs_device erofs_dev;
> +	struct erofs_sb_info sbi;
>  
>  	erofs_init_global_configure();
>  
> @@ -571,7 +592,7 @@ int main(int argc, char **argv)
>  		goto exit;
>  	}
>  
> -	erofs_check_inode(erofs_dev, sbi.root_nid, sbi.root_nid);
> +	erofs_check_inode(erofs_dev, &sbi, sbi.root_nid, sbi.root_nid);
>  
>  	if (fsckcfg.corrupted) {
>  		erofs_err("Found some filesystem corruption");
> diff --git a/fuse/dir.c b/fuse/dir.c
> index 494c915..b7ff635 100644
> --- a/fuse/dir.c
> +++ b/fuse/dir.c
> @@ -10,6 +10,7 @@
>  
>  // defined in fuse/main.c
>  extern struct erofs_device erofs_dev;
> +extern struct erofs_sb_info sbi;
>  
>  static int erofs_fill_dentries(struct erofs_inode *dir,
>  			       fuse_fill_dir_t filler, void *buf,
> @@ -60,7 +61,7 @@ int erofsfuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
>  
>  	erofs_dbg("readdir:%s offset=%llu", path, (long long)offset);
>  
> -	ret = erofs_ilookup(erofs_dev, path, &dir);
> +	ret = erofs_ilookup(erofs_dev, &sbi, path, &dir);
>  	if (ret)
>  		return ret;
>  
> @@ -79,7 +80,7 @@ int erofsfuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
>  
>  		maxsize = min_t(unsigned int, EROFS_BLKSIZ,
>  				dir.i_size - pos);
> -		ret = erofs_pread(erofs_dev, &dir, dblk, maxsize, pos);
> +		ret = erofs_pread(erofs_dev, &sbi, &dir, dblk, maxsize, pos);
>  		if (ret)
>  			return ret;
>  
> diff --git a/fuse/main.c b/fuse/main.c
> index b3e1a3d..37edf46 100644
> --- a/fuse/main.c
> +++ b/fuse/main.c
> @@ -14,6 +14,7 @@
>  #include "erofs/io.h"
>  
>  struct erofs_device erofs_dev;
> +struct erofs_sb_info sbi;
>  
>  int erofsfuse_readdir(const char *path, void *buffer, fuse_fill_dir_t filler,
>  		      off_t offset, struct fuse_file_info *fi);
> @@ -40,7 +41,7 @@ static int erofsfuse_getattr(const char *path, struct stat *stbuf)
>  	int ret;
>  
>  	erofs_dbg("getattr(%s)", path);
> -	ret = erofs_ilookup(erofs_dev, path, &vi);
> +	ret = erofs_ilookup(erofs_dev, &sbi, path, &vi);
>  	if (ret)
>  		return -ENOENT;
>  
> @@ -67,11 +68,11 @@ static int erofsfuse_read(const char *path, char *buffer,
>  
>  	erofs_dbg("path:%s size=%zd offset=%llu", path, size, (long long)offset);
>  
> -	ret = erofs_ilookup(erofs_dev, path, &vi);
> +	ret = erofs_ilookup(erofs_dev, &sbi, path, &vi);
>  	if (ret)
>  		return ret;
>  
> -	ret = erofs_pread(erofs_dev, &vi, buffer, size, offset);
> +	ret = erofs_pread(erofs_dev, &sbi, &vi, buffer, size, offset);
>  	if (ret)
>  		return ret;
>  	if (offset >= vi.i_size)
> diff --git a/include/erofs/compress.h b/include/erofs/compress.h
> index 73834a7..813b8e0 100644
> --- a/include/erofs/compress.h
> +++ b/include/erofs/compress.h
> @@ -16,10 +16,12 @@
>  
>  int erofs_write_compressed_file(
>  	struct erofs_device erofs_dev,
> +	struct erofs_sb_info *sbi,
>  	struct erofs_inode *inode);
>  
>  int z_erofs_compress_init(
>  	struct erofs_device erofs_dev,
> +	struct erofs_sb_info *sbi,
>  	struct erofs_buffer_head *bh);
>  int z_erofs_compress_exit(void);
>  
> diff --git a/include/erofs/decompress.h b/include/erofs/decompress.h
> index 0ba2b08..4880bfd 100644
> --- a/include/erofs/decompress.h
> +++ b/include/erofs/decompress.h
> @@ -28,6 +28,9 @@ struct z_erofs_decompress_req {
>  	bool partial_decoding;
>  };
>  
> -int z_erofs_decompress(struct z_erofs_decompress_req *rq);
> +int z_erofs_decompress(
> +	struct z_erofs_decompress_req *rq,
> +	struct erofs_sb_info *sbi
> +	);
>  
>  #endif
> diff --git a/include/erofs/inode.h b/include/erofs/inode.h
> index 5483d04..3b03482 100644
> --- a/include/erofs/inode.h
> +++ b/include/erofs/inode.h
> @@ -12,9 +12,10 @@
>  
>  void erofs_inode_manager_init(void);
>  unsigned int erofs_iput(struct erofs_inode *inode);
> -erofs_nid_t erofs_lookupnid(struct erofs_inode *inode);
> +erofs_nid_t erofs_lookupnid(struct erofs_sb_info *sbi, struct erofs_inode *inode);
>  struct erofs_inode *erofs_mkfs_build_tree_from_path(
>  	struct erofs_device erofs_dev,
> +	struct erofs_sb_info *sbi,
>  	struct erofs_inode *parent,
>  	const char *path);
>  
> diff --git a/include/erofs/internal.h b/include/erofs/internal.h
> index 49a883e..ff79fe9 100644
> --- a/include/erofs/internal.h
> +++ b/include/erofs/internal.h
> @@ -68,12 +68,9 @@ struct erofs_sb_info {
>  	u32 checksum;
>  };
>  
> -/* global sbi */
> -extern struct erofs_sb_info sbi;
> -
> -static inline erofs_off_t iloc(erofs_nid_t nid)
> +static inline erofs_off_t iloc(struct erofs_sb_info *sbi, erofs_nid_t nid)
>  {
> -	return blknr_to_addr(sbi.meta_blkaddr) + (nid << sbi.islotbits);
> +	return blknr_to_addr(sbi->meta_blkaddr) + (nid << sbi->islotbits);
>  }
>  
>  #define EROFS_FEATURE_FUNCS(name, compat, feature) \
> @@ -253,20 +250,31 @@ struct erofs_map_blocks {
>  int erofs_read_superblock(struct erofs_device devfd, struct erofs_sb_info *sbi);
>  
>  /* namei.c */
> -int erofs_read_inode_from_disk(struct erofs_device fd, struct erofs_inode *vi);
> -int erofs_ilookup(struct erofs_device devfd, const char *path, struct erofs_inode *vi);
> +int erofs_read_inode_from_disk(
> +	struct erofs_device fd,
> +	struct erofs_sb_info *sbi,
> +	struct erofs_inode *vi);
> +int erofs_ilookup(
> +	struct erofs_device devfd,
> +	struct erofs_sb_info *sbi,
> +	const char *path, struct erofs_inode *vi);
>  
>  /* data.c */
> -int erofs_pread(struct erofs_device fd, struct erofs_inode *inode, char *buf,
> +int erofs_pread(
> +	struct erofs_device fd,
> +	struct erofs_sb_info *sbi,
> +	struct erofs_inode *inode, char *buf,
>  		erofs_off_t count, erofs_off_t offset);
>  int erofs_map_blocks(
>  		struct erofs_device erofs_dev,
> +		struct erofs_sb_info *sbi,
>  		struct erofs_inode *inode,
>  		struct erofs_map_blocks *map, int flags);
>  /* zmap.c */
> -int z_erofs_fill_inode(struct erofs_inode *vi);
> +int z_erofs_fill_inode(struct erofs_inode *vi, struct erofs_sb_info *sbi);
>  int z_erofs_map_blocks_iter(
>  	struct erofs_device erofs_dev,
> +	struct erofs_sb_info *sbi,
>  	struct erofs_inode *vi,
>  	struct erofs_map_blocks *map,
>  	int flags);
> diff --git a/include/erofs/xattr.h b/include/erofs/xattr.h
> index f0c4c26..c8593e1 100644
> --- a/include/erofs/xattr.h
> +++ b/include/erofs/xattr.h
> @@ -42,6 +42,6 @@
>  
>  int erofs_prepare_xattr_ibody(struct erofs_inode *inode);
>  char *erofs_export_xattr_ibody(struct list_head *ixattrs, unsigned int size);
> -int erofs_build_shared_xattrs_from_path(const char *path);
> +int erofs_build_shared_xattrs_from_path(const char *path, struct erofs_sb_info *sbi);
>  
>  #endif
> diff --git a/lib/compress.c b/lib/compress.c
> index 766b75b..1e1ffde 100644
> --- a/lib/compress.c
> +++ b/lib/compress.c
> @@ -59,8 +59,10 @@ static void vle_write_indexes_final(struct z_erofs_vle_compress_ctx *ctx)
>  	ctx->metacur += sizeof(di);
>  }
>  
> -static void vle_write_indexes(struct z_erofs_vle_compress_ctx *ctx,
> -			      unsigned int count, bool raw)
> +static void vle_write_indexes(
> +	struct z_erofs_vle_compress_ctx *ctx,
> +	struct erofs_sb_info *sbi,
> +	unsigned int count, bool raw)
>  {
>  	unsigned int clusterofs = ctx->clusterofs;
>  	unsigned int d0 = 0, d1 = (clusterofs + count) / EROFS_BLKSIZ;
> @@ -89,7 +91,7 @@ static void vle_write_indexes(struct z_erofs_vle_compress_ctx *ctx,
>  
>  	do {
>  		/* XXX: big pcluster feature should be per-inode */
> -		if (d0 == 1 && erofs_sb_has_big_pcluster(&sbi)) {
> +		if (d0 == 1 && erofs_sb_has_big_pcluster(sbi)) {
>  			type = Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD;
>  			di.di_u.delta[0] = cpu_to_le16(ctx->compressedblks |
>  					Z_EROFS_VLE_DI_D0_CBLKCNT);
> @@ -122,6 +124,7 @@ static void vle_write_indexes(struct z_erofs_vle_compress_ctx *ctx,
>  
>  static int write_uncompressed_extent(
>  	struct erofs_device erofs_dev,
> +	struct erofs_sb_info *sbi,
>  	struct z_erofs_vle_compress_ctx *ctx,
>  				     unsigned int *len, char *dst)
>  {
> @@ -129,7 +132,7 @@ static int write_uncompressed_extent(
>  	unsigned int count;
>  
>  	/* reset clusterofs to 0 if permitted */
> -	if (!erofs_sb_has_lz4_0padding(&sbi) && ctx->clusterofs &&
> +	if (!erofs_sb_has_lz4_0padding(sbi) && ctx->clusterofs &&
>  	    ctx->head >= ctx->clusterofs) {
>  		ctx->head -= ctx->clusterofs;
>  		*len += ctx->clusterofs;
> @@ -166,6 +169,7 @@ static unsigned int z_erofs_get_max_pclusterblks(struct erofs_inode *inode)
>  
>  static int vle_compress_one(
>  		struct erofs_device erofs_dev,
> +		struct erofs_sb_info *sbi,
>  		struct erofs_inode *inode,
>  		struct z_erofs_vle_compress_ctx *ctx,
>  		bool final)
> @@ -201,7 +205,7 @@ static int vle_compress_one(
>  					  erofs_strerror(ret));
>  			}
>  nocompression:
> -			ret = write_uncompressed_extent(erofs_dev, ctx, &len, dst);
> +			ret = write_uncompressed_extent(erofs_dev, sbi, ctx, &len, dst);
>  			if (ret < 0)
>  				return ret;
>  			count = ret;
> @@ -210,14 +214,14 @@ nocompression:
>  		} else {
>  			const unsigned int tailused = ret & (EROFS_BLKSIZ - 1);
>  			const unsigned int padding =
> -				erofs_sb_has_lz4_0padding(&sbi) && tailused ?
> +				erofs_sb_has_lz4_0padding(sbi) && tailused ?
>  					EROFS_BLKSIZ - tailused : 0;
>  
>  			ctx->compressedblks = DIV_ROUND_UP(ret, EROFS_BLKSIZ);
>  			DBG_BUGON(ctx->compressedblks * EROFS_BLKSIZ >= count);
>  
>  			/* zero out garbage trailing data for non-0padding */
> -			if (!erofs_sb_has_lz4_0padding(&sbi))
> +			if (!erofs_sb_has_lz4_0padding(sbi))
>  				memset(dst + ret, 0,
>  				       roundup(ret, EROFS_BLKSIZ) - ret);
>  
> @@ -234,7 +238,7 @@ nocompression:
>  
>  		ctx->head += count;
>  		/* write compression indexes for this pcluster */
> -		vle_write_indexes(ctx, count, raw);
> +		vle_write_indexes(ctx, sbi, count, raw);
>  
>  		ctx->blkaddr += ctx->compressedblks;
>  		len -= count;
> @@ -287,7 +291,9 @@ static void *parse_legacy_indexes(struct z_erofs_compressindex_vec *cv,
>  	return db + nr;
>  }
>  
> -static void *write_compacted_indexes(u8 *out,
> +static void *write_compacted_indexes(
> +						 struct erofs_sb_info *sbi,
> +						 u8 *out,
>  				     struct z_erofs_compressindex_vec *cv,
>  				     erofs_blk_t *blkaddr_ret,
>  				     unsigned int destsize,
> @@ -306,7 +312,7 @@ static void *write_compacted_indexes(u8 *out,
>  		return ERR_PTR(-EINVAL);
>  	encodebits = (vcnt * destsize * 8 - 32) / vcnt;
>  	blkaddr = *blkaddr_ret;
> -	update_blkaddr = erofs_sb_has_big_pcluster(&sbi);
> +	update_blkaddr = erofs_sb_has_big_pcluster(sbi);
>  
>  	pos = 0;
>  	for (i = 0; i < vcnt; ++i) {
> @@ -354,7 +360,9 @@ static void *write_compacted_indexes(u8 *out,
>  	return out + destsize * vcnt;
>  }
>  
> -int z_erofs_convert_to_compacted_format(struct erofs_inode *inode,
> +int z_erofs_convert_to_compacted_format(
> +					struct erofs_sb_info *sbi,
> +					struct erofs_inode *inode,
>  					erofs_blk_t blkaddr,
>  					unsigned int legacymetasize,
>  					void *compressmeta)
> @@ -402,7 +410,7 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode,
>  
>  	dummy_head = false;
>  	/* prior to bigpcluster, blkaddr was bumped up once coming into HEAD */
> -	if (!erofs_sb_has_big_pcluster(&sbi)) {
> +	if (!erofs_sb_has_big_pcluster(sbi)) {
>  		--blkaddr;
>  		dummy_head = true;
>  	}
> @@ -410,7 +418,7 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode,
>  	/* generate compacted_4b_initial */
>  	while (compacted_4b_initial) {
>  		in = parse_legacy_indexes(cv, 2, in);
> -		out = write_compacted_indexes(out, cv, &blkaddr,
> +		out = write_compacted_indexes(sbi, out, cv, &blkaddr,
>  					      4, logical_clusterbits, false,
>  					      &dummy_head);
>  		compacted_4b_initial -= 2;
> @@ -420,7 +428,7 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode,
>  	/* generate compacted_2b */
>  	while (compacted_2b) {
>  		in = parse_legacy_indexes(cv, 16, in);
> -		out = write_compacted_indexes(out, cv, &blkaddr,
> +		out = write_compacted_indexes(sbi, out, cv, &blkaddr,
>  					      2, logical_clusterbits, false,
>  					      &dummy_head);
>  		compacted_2b -= 16;
> @@ -430,7 +438,7 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode,
>  	/* generate compacted_4b_end */
>  	while (compacted_4b_end > 1) {
>  		in = parse_legacy_indexes(cv, 2, in);
> -		out = write_compacted_indexes(out, cv, &blkaddr,
> +		out = write_compacted_indexes(sbi, out, cv, &blkaddr,
>  					      4, logical_clusterbits, false,
>  					      &dummy_head);
>  		compacted_4b_end -= 2;
> @@ -440,7 +448,7 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode,
>  	if (compacted_4b_end) {
>  		memset(cv, 0, sizeof(cv));
>  		in = parse_legacy_indexes(cv, 1, in);
> -		out = write_compacted_indexes(out, cv, &blkaddr,
> +		out = write_compacted_indexes(sbi, out, cv, &blkaddr,
>  					      4, logical_clusterbits, true,
>  					      &dummy_head);
>  	}
> @@ -464,7 +472,10 @@ static void z_erofs_write_mapheader(struct erofs_inode *inode,
>  	memcpy(compressmeta, &h, sizeof(struct z_erofs_map_header));
>  }
>  
> -int erofs_write_compressed_file(struct erofs_device erofs_dev, struct erofs_inode *inode)
> +int erofs_write_compressed_file(
> +	struct erofs_device erofs_dev,
> +	struct erofs_sb_info *sbi,
> +	struct erofs_inode *inode)
>  {
>  	struct erofs_buffer_head *bh;
>  	struct z_erofs_vle_compress_ctx ctx;
> @@ -499,7 +510,7 @@ int erofs_write_compressed_file(struct erofs_device erofs_dev, struct erofs_inod
>  		inode->datalayout = EROFS_INODE_FLAT_COMPRESSION_LEGACY;
>  	}
>  
> -	if (erofs_sb_has_big_pcluster(&sbi)) {
> +	if (erofs_sb_has_big_pcluster(sbi)) {
>  		inode->z_advise |= Z_EROFS_ADVISE_BIG_PCLUSTER_1;
>  		if (inode->datalayout == EROFS_INODE_FLAT_COMPRESSION)
>  			inode->z_advise |= Z_EROFS_ADVISE_BIG_PCLUSTER_2;
> @@ -530,13 +541,13 @@ int erofs_write_compressed_file(struct erofs_device erofs_dev, struct erofs_inod
>  		ctx.tail += readcount;
>  
>  		/* do one compress round */
> -		ret = vle_compress_one(erofs_dev, inode, &ctx, false);
> +		ret = vle_compress_one(erofs_dev, sbi, inode, &ctx, false);
>  		if (ret)
>  			goto err_bdrop;
>  	}
>  
>  	/* do the final round */
> -	ret = vle_compress_one(erofs_dev, inode, &ctx, true);
> +	ret = vle_compress_one(erofs_dev, sbi, inode, &ctx, true);
>  	if (ret)
>  		goto err_bdrop;
>  
> @@ -570,7 +581,7 @@ int erofs_write_compressed_file(struct erofs_device erofs_dev, struct erofs_inod
>  	if (inode->datalayout == EROFS_INODE_FLAT_COMPRESSION_LEGACY) {
>  		inode->extent_isize = legacymetasize;
>  	} else {
> -		ret = z_erofs_convert_to_compacted_format(inode, blkaddr,
> +		ret = z_erofs_convert_to_compacted_format(sbi, inode, blkaddr,
>  							  legacymetasize,
>  							  compressmeta);
>  		DBG_BUGON(ret);
> @@ -597,12 +608,15 @@ static int erofs_get_compress_algorithm_id(const char *name)
>  	return -ENOTSUP;
>  }
>  
> -int z_erofs_build_compr_cfgs(struct erofs_device erofs_dev, struct erofs_buffer_head *sb_bh)
> +int z_erofs_build_compr_cfgs(
> +	struct erofs_device erofs_dev,
> +	struct erofs_sb_info *sbi,
> +	struct erofs_buffer_head *sb_bh)
>  {
>  	struct erofs_buffer_head *bh = sb_bh;
>  	int ret = 0;
>  
> -	if (sbi.available_compr_algs & (1 << Z_EROFS_COMPRESSION_LZ4)) {
> +	if (sbi->available_compr_algs & (1 << Z_EROFS_COMPRESSION_LZ4)) {
>  		struct {
>  			__le16 size;
>  			struct z_erofs_lz4_cfgs lz4;
> @@ -610,7 +624,7 @@ int z_erofs_build_compr_cfgs(struct erofs_device erofs_dev, struct erofs_buffer_
>  			.size = cpu_to_le16(sizeof(struct z_erofs_lz4_cfgs)),
>  			.lz4 = {
>  				.max_distance =
> -					cpu_to_le16(sbi.lz4_max_distance),
> +					cpu_to_le16(sbi->lz4_max_distance),
>  				.max_pclusterblks = cfg.c_pclusterblks_max,
>  			}
>  		};
> @@ -651,10 +665,14 @@ int z_erofs_build_compr_cfgs(struct erofs_device erofs_dev, struct erofs_buffer_
>  	return ret;
>  }
>  
> -int z_erofs_compress_init(struct erofs_device erofs_dev, struct erofs_buffer_head *sb_bh)
> +int z_erofs_compress_init(
> +	struct erofs_device erofs_dev,
> +	struct erofs_sb_info *sbi,
> +	struct erofs_buffer_head *sb_bh)
>  {
>  	/* initialize for primary compression algorithm */
>  	int ret = erofs_compressor_init(&compresshandle,
> +	sbi,
>  					cfg.c_compr_alg_master);
>  
>  	if (ret)
> @@ -666,7 +684,7 @@ int z_erofs_compress_init(struct erofs_device erofs_dev, struct erofs_buffer_hea
>  	 */
>  	if (!cfg.c_compr_alg_master ||
>  	    (cfg.c_legacy_compress && !strcmp(cfg.c_compr_alg_master, "lz4")))
> -		erofs_sb_clear_lz4_0padding(&sbi);
> +		erofs_sb_clear_lz4_0padding(sbi);
>  
>  	if (!cfg.c_compr_alg_master)
>  		return 0;
> @@ -694,16 +712,16 @@ int z_erofs_compress_init(struct erofs_device erofs_dev, struct erofs_buffer_hea
>  				  cfg.c_pclusterblks_max);
>  			return -EINVAL;
>  		}
> -		erofs_sb_set_big_pcluster(&sbi);
> +		erofs_sb_set_big_pcluster(sbi);
>  		erofs_warn("EXPERIMENTAL big pcluster feature in use. Use at your own risk!");
>  	}
>  
>  	if (ret != Z_EROFS_COMPRESSION_LZ4)
> -		erofs_sb_set_compr_cfgs(&sbi);
> +		erofs_sb_set_compr_cfgs(sbi);
>  
> -	if (erofs_sb_has_compr_cfgs(&sbi)) {
> -		sbi.available_compr_algs |= 1 << ret;
> -		return z_erofs_build_compr_cfgs(erofs_dev, sb_bh);
> +	if (erofs_sb_has_compr_cfgs(sbi)) {
> +		sbi->available_compr_algs |= 1 << ret;
> +		return z_erofs_build_compr_cfgs(erofs_dev, sbi, sb_bh);
>  	}
>  	return 0;
>  }
> diff --git a/lib/compressor.c b/lib/compressor.c
> index 6362825..3b8d193 100644
> --- a/lib/compressor.c
> +++ b/lib/compressor.c
> @@ -62,7 +62,10 @@ int erofs_compressor_setlevel(struct erofs_compress *c, int compression_level)
>  	return 0;
>  }
>  
> -int erofs_compressor_init(struct erofs_compress *c, char *alg_name)
> +int erofs_compressor_init(
> +	struct erofs_compress *c,
> +	struct erofs_sb_info *sbi,
> +	char *alg_name)
>  {
>  	int ret, i;
>  
> @@ -84,7 +87,7 @@ int erofs_compressor_init(struct erofs_compress *c, char *alg_name)
>  		if (alg_name && strcmp(alg_name, compressors[i]->name))
>  			continue;
>  
> -		ret = compressors[i]->init(c);
> +		ret = compressors[i]->init(c, sbi);
>  		if (!ret) {
>  			DBG_BUGON(!c->alg);
>  			return 0;
> diff --git a/lib/compressor.h b/lib/compressor.h
> index 1ea2724..446c013 100644
> --- a/lib/compressor.h
> +++ b/lib/compressor.h
> @@ -10,6 +10,7 @@
>  #include "erofs/defs.h"
>  
>  struct erofs_compress;
> +struct erofs_sb_info;
>  
>  struct erofs_compressor {
>  	const char *name;
> @@ -17,7 +18,7 @@ struct erofs_compressor {
>  	int default_level;
>  	int best_level;
>  
> -	int (*init)(struct erofs_compress *c);
> +	int (*init)(struct erofs_compress *c, struct erofs_sb_info *sbi);
>  	int (*exit)(struct erofs_compress *c);
>  	int (*setlevel)(struct erofs_compress *c, int compression_level);
>  
> @@ -50,7 +51,7 @@ int erofs_compress_destsize(struct erofs_compress *c,
>  			    void *dst, unsigned int dstsize);
>  
>  int erofs_compressor_setlevel(struct erofs_compress *c, int compression_level);
> -int erofs_compressor_init(struct erofs_compress *c, char *alg_name);
> +int erofs_compressor_init(struct erofs_compress *c, struct erofs_sb_info *sbi, char *alg_name);
>  int erofs_compressor_exit(struct erofs_compress *c);
>  
>  #endif
> diff --git a/lib/compressor_lz4.c b/lib/compressor_lz4.c
> index fc8c23c..ffdbb9f 100644
> --- a/lib/compressor_lz4.c
> +++ b/lib/compressor_lz4.c
> @@ -30,10 +30,12 @@ static int compressor_lz4_exit(struct erofs_compress *c)
>  	return 0;
>  }
>  
> -static int compressor_lz4_init(struct erofs_compress *c)
> +static int compressor_lz4_init(
> +	struct erofs_compress *c,
> +	struct erofs_sb_info *sbi)
>  {
>  	c->alg = &erofs_compressor_lz4;
> -	sbi.lz4_max_distance = LZ4_DISTANCE_MAX;
> +	sbi->lz4_max_distance = LZ4_DISTANCE_MAX;
>  	return 0;
>  }
>  
> diff --git a/lib/compressor_lz4hc.c b/lib/compressor_lz4hc.c
> index 3f68b00..f573cd2 100644
> --- a/lib/compressor_lz4hc.c
> +++ b/lib/compressor_lz4hc.c
> @@ -36,7 +36,7 @@ static int compressor_lz4hc_exit(struct erofs_compress *c)
>  	return 0;
>  }
>  
> -static int compressor_lz4hc_init(struct erofs_compress *c)
> +static int compressor_lz4hc_init(struct erofs_compress *c, struct erofs_sb_info *sbi)
>  {
>  	c->alg = &erofs_compressor_lz4hc;
>  
> @@ -44,7 +44,7 @@ static int compressor_lz4hc_init(struct erofs_compress *c)
>  	if (!c->private_data)
>  		return -ENOMEM;
>  
> -	sbi.lz4_max_distance = LZ4_DISTANCE_MAX;
> +	sbi->lz4_max_distance = LZ4_DISTANCE_MAX;
>  	return 0;
>  }
>  
> diff --git a/lib/config.c b/lib/config.c
> index 7488e08..7313588 100644
> --- a/lib/config.c
> +++ b/lib/config.c
> @@ -10,7 +10,6 @@
>  #include "erofs/internal.h"
>  
>  struct erofs_configure cfg;
> -struct erofs_sb_info sbi;
>  
>  void erofs_init_config(struct erofs_configure *cfg)
>  {
> diff --git a/lib/data.c b/lib/data.c
> index d9d20ec..e6fe1d6 100644
> --- a/lib/data.c
> +++ b/lib/data.c
> @@ -10,9 +10,11 @@
>  #include "erofs/trace.h"
>  #include "erofs/decompress.h"
>  
> -static int erofs_map_blocks_flatmode(struct erofs_inode *inode,
> -				     struct erofs_map_blocks *map,
> -				     int flags)
> +static int erofs_map_blocks_flatmode(
> +	struct erofs_sb_info *sbi,
> +	struct erofs_inode *inode,
> +	struct erofs_map_blocks *map,
> +	int flags)
>  {
>  	int err = 0;
>  	erofs_blk_t nblocks, lastblk;
> @@ -33,7 +35,7 @@ static int erofs_map_blocks_flatmode(struct erofs_inode *inode,
>  		map->m_plen = blknr_to_addr(lastblk) - offset;
>  	} else if (tailendpacking) {
>  		/* 2 - inode inline B: inode, [xattrs], inline last blk... */
> -		map->m_pa = iloc(vi->nid) + vi->inode_isize +
> +		map->m_pa = iloc(sbi, vi->nid) + vi->inode_isize +
>  			vi->xattr_isize + erofs_blkoff(map->m_la);
>  		map->m_plen = inode->i_size - offset;
>  
> @@ -63,6 +65,7 @@ err_out:
>  
>  int erofs_map_blocks(
>  		struct erofs_device erofs_dev,
> +		struct erofs_sb_info *sbi,
>  		struct erofs_inode *inode,
>  		struct erofs_map_blocks *map, int flags)
>  {
> @@ -82,7 +85,7 @@ int erofs_map_blocks(
>  	}
>  
>  	if (vi->datalayout != EROFS_INODE_CHUNK_BASED)
> -		return erofs_map_blocks_flatmode(inode, map, flags);
> +		return erofs_map_blocks_flatmode(sbi, inode, map, flags);
>  
>  	if (vi->u.chunkformat & EROFS_CHUNK_FORMAT_INDEXES)
>  		unit = sizeof(*idx);			/* chunk index */
> @@ -90,7 +93,7 @@ int erofs_map_blocks(
>  		unit = EROFS_BLOCK_MAP_ENTRY_SIZE;	/* block map */
>  
>  	chunknr = map->m_la >> vi->u.chunkbits;
> -	pos = roundup(iloc(vi->nid) + vi->inode_isize +
> +	pos = roundup(iloc(sbi, vi->nid) + vi->inode_isize +
>  		      vi->xattr_isize, unit) + unit * chunknr;
>  
>  	err = blk_read(erofs_dev, buf, erofs_blknr(pos), 1);
> @@ -137,7 +140,10 @@ out:
>  	return err;
>  }
>  
> -static int erofs_read_raw_data(struct erofs_device erofs_dev, struct erofs_inode *inode, char *buffer,
> +static int erofs_read_raw_data(
> +	struct erofs_device erofs_dev,
> +	struct erofs_sb_info *sbi,
> +	struct erofs_inode *inode, char *buffer,
>  			       erofs_off_t size, erofs_off_t offset)
>  {
>  	struct erofs_map_blocks map = {
> @@ -151,7 +157,7 @@ static int erofs_read_raw_data(struct erofs_device erofs_dev, struct erofs_inode
>  		erofs_off_t eend;
>  
>  		map.m_la = ptr;
> -		ret = erofs_map_blocks(erofs_dev, inode, &map, 0);
> +		ret = erofs_map_blocks(erofs_dev, sbi, inode, &map, 0);
>  		if (ret)
>  			return ret;
>  
> @@ -188,6 +194,7 @@ static int erofs_read_raw_data(struct erofs_device erofs_dev, struct erofs_inode
>  
>  static int z_erofs_read_data(
>  	struct erofs_device erofs_dev,
> +	struct erofs_sb_info *sbi,
>  	struct erofs_inode *inode,
>  	char *buffer,
>  	erofs_off_t size,
> @@ -207,7 +214,7 @@ static int z_erofs_read_data(
>  	while (end > offset) {
>  		map.m_la = end - 1;
>  
> -		ret = z_erofs_map_blocks_iter(erofs_dev, inode, &map, 0);
> +		ret = z_erofs_map_blocks_iter(erofs_dev, sbi, inode, &map, 0);
>  		if (ret)
>  			break;
>  
> @@ -263,7 +270,7 @@ static int z_erofs_read_data(
>  					.decodedlength = length,
>  					.alg = algorithmformat,
>  					.partial_decoding = partial
> -					 });
> +					 }, sbi);
>  		if (ret < 0)
>  			break;
>  	}
> @@ -272,17 +279,20 @@ static int z_erofs_read_data(
>  	return ret < 0 ? ret : 0;
>  }
>  
> -int erofs_pread(struct erofs_device fd, struct erofs_inode *inode, char *buf,
> +int erofs_pread(
> +	struct erofs_device fd,
> +	struct erofs_sb_info *sbi,
> +	struct erofs_inode *inode, char *buf,
>  		erofs_off_t count, erofs_off_t offset)
>  {
>  	switch (inode->datalayout) {
>  	case EROFS_INODE_FLAT_PLAIN:
>  	case EROFS_INODE_FLAT_INLINE:
>  	case EROFS_INODE_CHUNK_BASED:
> -		return erofs_read_raw_data(fd, inode, buf, count, offset);
> +		return erofs_read_raw_data(fd, sbi, inode, buf, count, offset);
>  	case EROFS_INODE_FLAT_COMPRESSION_LEGACY:
>  	case EROFS_INODE_FLAT_COMPRESSION:
> -		return z_erofs_read_data(fd, inode, buf, count, offset);
> +		return z_erofs_read_data(fd, sbi, inode, buf, count, offset);
>  	default:
>  		break;
>  	}
> diff --git a/lib/decompress.c b/lib/decompress.c
> index 6a60400..483bd52 100644
> --- a/lib/decompress.c
> +++ b/lib/decompress.c
> @@ -12,7 +12,7 @@
>  #ifdef HAVE_LIBLZMA
>  #include <lzma.h>
>  
> -static int z_erofs_decompress_lzma(struct z_erofs_decompress_req *rq)
> +static int z_erofs_decompress_lzma(struct z_erofs_decompress_req *rq, struct erofs_sb_info *sbi)
>  {
>  	int ret = 0;
>  	u8 *dest = (u8 *)rq->out;
> @@ -73,7 +73,7 @@ out:
>  #ifdef LZ4_ENABLED
>  #include <lz4.h>
>  
> -static int z_erofs_decompress_lz4(struct z_erofs_decompress_req *rq)
> +static int z_erofs_decompress_lz4(struct z_erofs_decompress_req *rq, struct erofs_sb_info *sbi)
>  {
>  	int ret = 0;
>  	char *dest = rq->out;
> @@ -82,7 +82,7 @@ static int z_erofs_decompress_lz4(struct z_erofs_decompress_req *rq)
>  	bool support_0padding = false;
>  	unsigned int inputmargin = 0;
>  
> -	if (erofs_sb_has_lz4_0padding(&sbi)) {
> +	if (erofs_sb_has_lz4_0padding(sbi)) {
>  		support_0padding = true;
>  
>  		while (!src[inputmargin & ~PAGE_MASK])
> @@ -126,7 +126,7 @@ out:
>  }
>  #endif
>  
> -int z_erofs_decompress(struct z_erofs_decompress_req *rq)
> +int z_erofs_decompress(struct z_erofs_decompress_req *rq, struct erofs_sb_info *sbi)
>  {
>  	if (rq->alg == Z_EROFS_COMPRESSION_SHIFTED) {
>  		if (rq->inputsize != EROFS_BLKSIZ)
> @@ -142,11 +142,11 @@ int z_erofs_decompress(struct z_erofs_decompress_req *rq)
>  
>  #ifdef LZ4_ENABLED
>  	if (rq->alg == Z_EROFS_COMPRESSION_LZ4)
> -		return z_erofs_decompress_lz4(rq);
> +		return z_erofs_decompress_lz4(rq, sbi);
>  #endif
>  #ifdef HAVE_LIBLZMA
>  	if (rq->alg == Z_EROFS_COMPRESSION_LZMA)
> -		return z_erofs_decompress_lzma(rq);
> +		return z_erofs_decompress_lzma(rq, sbi);
>  #endif
>  	return -EOPNOTSUPP;
>  }
> diff --git a/lib/inode.c b/lib/inode.c
> index d1adb49..70525fa 100644
> --- a/lib/inode.c
> +++ b/lib/inode.c
> @@ -387,7 +387,10 @@ static int write_uncompressed_file_from_fd(
>  	return 0;
>  }
>  
> -int erofs_write_file(struct erofs_device erofs_dev, struct erofs_inode *inode)
> +int erofs_write_file(
> +	struct erofs_device erofs_dev,
> +	struct erofs_sb_info *sbi,
> +	struct erofs_inode *inode)
>  {
>  	int ret, fd;
>  
> @@ -403,7 +406,7 @@ int erofs_write_file(struct erofs_device erofs_dev, struct erofs_inode *inode)
>  	}
>  
>  	if (cfg.c_compr_alg_master && erofs_file_is_compressible(inode)) {
> -		ret = erofs_write_compressed_file(erofs_dev, inode);
> +		ret = erofs_write_compressed_file(erofs_dev, sbi, inode);
>  
>  		if (!ret || ret != -ENOSPC)
>  			return ret;
> @@ -799,7 +802,9 @@ static int erofs_droid_inode_fsconfig(struct erofs_inode *inode,
>  }
>  #endif
>  
> -static int erofs_fill_inode(struct erofs_inode *inode,
> +static int erofs_fill_inode(
> +					struct erofs_inode *inode,
> +					struct erofs_sb_info *sbi,
>  			    struct stat64 *st,
>  			    const char *path)
>  {
> @@ -815,11 +820,11 @@ static int erofs_fill_inode(struct erofs_inode *inode,
>  
>  	switch (cfg.c_timeinherit) {
>  	case TIMESTAMP_CLAMPING:
> -		if (st->st_ctime < sbi.build_time)
> +		if (st->st_ctime < sbi->build_time)
>  			break;
>  	case TIMESTAMP_FIXED:
> -		inode->i_ctime = sbi.build_time;
> -		inode->i_ctime_nsec = sbi.build_time_nsec;
> +		inode->i_ctime = sbi->build_time;
> +		inode->i_ctime_nsec = sbi->build_time_nsec;
>  	default:
>  		break;
>  	}
> @@ -865,7 +870,7 @@ static int erofs_fill_inode(struct erofs_inode *inode,
>  	return 0;
>  }
>  
> -static struct erofs_inode *erofs_new_inode(void)
> +static struct erofs_inode *erofs_new_inode(struct erofs_sb_info *sbi)
>  {
>  	struct erofs_inode *inode;
>  
> @@ -873,7 +878,7 @@ static struct erofs_inode *erofs_new_inode(void)
>  	if (!inode)
>  		return ERR_PTR(-ENOMEM);
>  
> -	inode->i_ino[0] = sbi.inos++;	/* inode serial number */
> +	inode->i_ino[0] = sbi->inos++;	/* inode serial number */
>  	inode->i_count = 1;
>  
>  	init_list_head(&inode->i_subdirs);
> @@ -882,7 +887,8 @@ static struct erofs_inode *erofs_new_inode(void)
>  }
>  
>  /* get the inode from the (source) path */
> -static struct erofs_inode *erofs_iget_from_path(const char *path, bool is_src)
> +static struct erofs_inode *erofs_iget_from_path(
> +	struct erofs_sb_info *sbi, const char *path, bool is_src)
>  {
>  	struct stat64 st;
>  	struct erofs_inode *inode;
> @@ -908,11 +914,11 @@ static struct erofs_inode *erofs_iget_from_path(const char *path, bool is_src)
>  	}
>  
>  	/* cannot find in the inode cache */
> -	inode = erofs_new_inode();
> +	inode = erofs_new_inode(sbi);
>  	if (IS_ERR(inode))
>  		return inode;
>  
> -	ret = erofs_fill_inode(inode, &st, path);
> +	ret = erofs_fill_inode(inode, sbi, &st, path);
>  	if (ret) {
>  		free(inode);
>  		return ERR_PTR(ret);
> @@ -921,7 +927,7 @@ static struct erofs_inode *erofs_iget_from_path(const char *path, bool is_src)
>  	return inode;
>  }
>  
> -static void erofs_fixup_meta_blkaddr(struct erofs_inode *rootdir)
> +static void erofs_fixup_meta_blkaddr(struct erofs_sb_info *sbi, struct erofs_inode *rootdir)
>  {
>  	const erofs_off_t rootnid_maxoffset = 0xffff << EROFS_ISLOTBITS;
>  	struct erofs_buffer_head *const bh = rootdir->bh;
> @@ -934,11 +940,11 @@ static void erofs_fixup_meta_blkaddr(struct erofs_inode *rootdir)
>  		meta_offset = round_up(off - rootnid_maxoffset, EROFS_BLKSIZ);
>  	else
>  		meta_offset = 0;
> -	sbi.meta_blkaddr = erofs_blknr(meta_offset);
> +	sbi->meta_blkaddr = erofs_blknr(meta_offset);
>  	rootdir->nid = (off - meta_offset) >> EROFS_ISLOTBITS;
>  }
>  
> -erofs_nid_t erofs_lookupnid(struct erofs_inode *inode)
> +erofs_nid_t erofs_lookupnid(struct erofs_sb_info *sbi, struct erofs_inode *inode)
>  {
>  	struct erofs_buffer_head *const bh = inode->bh;
>  	erofs_off_t off, meta_offset;
> @@ -949,21 +955,24 @@ erofs_nid_t erofs_lookupnid(struct erofs_inode *inode)
>  	erofs_mapbh(bh->block);
>  	off = erofs_btell(bh, false);
>  
> -	meta_offset = blknr_to_addr(sbi.meta_blkaddr);
> +	meta_offset = blknr_to_addr(sbi->meta_blkaddr);
>  	DBG_BUGON(off < meta_offset);
>  	return inode->nid = (off - meta_offset) >> EROFS_ISLOTBITS;
>  }
>  
> -static void erofs_d_invalidate(struct erofs_dentry *d)
> +static void erofs_d_invalidate(
> +	struct erofs_sb_info *sbi, struct erofs_dentry *d)
>  {
>  	struct erofs_inode *const inode = d->inode;
>  
> -	d->nid = erofs_lookupnid(inode);
> +	d->nid = erofs_lookupnid(sbi, inode);
>  	erofs_iput(inode);
>  }
>  
>  static struct erofs_inode *erofs_mkfs_build_tree(
> -	struct erofs_device erofs_dev, struct erofs_inode *dir)
> +	struct erofs_device erofs_dev,
> +	struct erofs_sb_info *sbi,
> +	struct erofs_inode *dir)
>  {
>  	int ret;
>  	DIR *_dir;
> @@ -992,7 +1001,7 @@ static struct erofs_inode *erofs_mkfs_build_tree(
>  			if (ret)
>  				return ERR_PTR(ret);
>  		} else {
> -			ret = erofs_write_file(erofs_dev, dir);
> +			ret = erofs_write_file(erofs_dev, sbi, dir);
>  			if (ret)
>  				return ERR_PTR(ret);
>  		}
> @@ -1055,14 +1064,14 @@ static struct erofs_inode *erofs_mkfs_build_tree(
>  		goto err;
>  
>  	if (IS_ROOT(dir))
> -		erofs_fixup_meta_blkaddr(dir);
> +		erofs_fixup_meta_blkaddr(sbi, dir);
>  
>  	list_for_each_entry(d, &dir->i_subdirs, d_child) {
>  		char buf[PATH_MAX];
>  		unsigned char ftype;
>  
>  		if (is_dot_dotdot(d->name)) {
> -			erofs_d_invalidate(d);
> +			erofs_d_invalidate(sbi, d);
>  			continue;
>  		}
>  
> @@ -1073,7 +1082,7 @@ static struct erofs_inode *erofs_mkfs_build_tree(
>  			goto fail;
>  		}
>  
> -		d->inode = erofs_mkfs_build_tree_from_path(erofs_dev, dir, buf);
> +		d->inode = erofs_mkfs_build_tree_from_path(erofs_dev, sbi, dir, buf);
>  		if (IS_ERR(d->inode)) {
>  			ret = PTR_ERR(d->inode);
>  fail:
> @@ -1086,7 +1095,7 @@ fail:
>  		DBG_BUGON(ftype == EROFS_FT_DIR && d->type != ftype);
>  		d->type = ftype;
>  
> -		erofs_d_invalidate(d);
> +		erofs_d_invalidate(sbi, d);
>  		erofs_info("add file %s/%s (nid %llu, type %d)",
>  			   dir->i_srcpath, d->name, (unsigned long long)d->nid,
>  			   d->type);
> @@ -1103,10 +1112,11 @@ err:
>  
>  struct erofs_inode *erofs_mkfs_build_tree_from_path(
>  	struct erofs_device erofs_dev,
> +	struct erofs_sb_info *sbi,
>  	struct erofs_inode *parent,
>  	const char *path)
>  {
> -	struct erofs_inode *const inode = erofs_iget_from_path(path, true);
> +	struct erofs_inode *const inode = erofs_iget_from_path(sbi, path, true);
>  
>  	if (IS_ERR(inode))
>  		return inode;
> @@ -1123,5 +1133,5 @@ struct erofs_inode *erofs_mkfs_build_tree_from_path(
>  	else
>  		inode->i_parent = inode;	/* rootdir mark */
>  
> -	return erofs_mkfs_build_tree(erofs_dev, inode);
> +	return erofs_mkfs_build_tree(erofs_dev, sbi, inode);
>  }
> diff --git a/lib/namei.c b/lib/namei.c
> index 57041f5..ac65425 100644
> --- a/lib/namei.c
> +++ b/lib/namei.c
> @@ -22,13 +22,16 @@ static dev_t erofs_new_decode_dev(u32 dev)
>  	return makedev(major, minor);
>  }
>  
> -int erofs_read_inode_from_disk(struct erofs_device fd, struct erofs_inode *vi)
> +int erofs_read_inode_from_disk(
> +	struct erofs_device fd,
> +	struct erofs_sb_info *sbi,
> +	struct erofs_inode *vi)
>  {
>  	int ret, ifmt;
>  	char buf[sizeof(struct erofs_inode_extended)];
>  	struct erofs_inode_compact *dic;
>  	struct erofs_inode_extended *die;
> -	const erofs_off_t inode_loc = iloc(vi->nid);
> +	const erofs_off_t inode_loc = iloc(sbi, vi->nid);
>  
>  	ret = dev_read(fd, buf, inode_loc, sizeof(*dic));
>  	if (ret < 0)
> @@ -114,8 +117,8 @@ int erofs_read_inode_from_disk(struct erofs_device fd, struct erofs_inode *vi)
>  		vi->i_gid = le16_to_cpu(dic->i_gid);
>  		vi->i_nlink = le16_to_cpu(dic->i_nlink);
>  
> -		vi->i_ctime = sbi.build_time;
> -		vi->i_ctime_nsec = sbi.build_time_nsec;
> +		vi->i_ctime = sbi->build_time;
> +		vi->i_ctime_nsec = sbi->build_time_nsec;
>  
>  		vi->i_size = le32_to_cpu(dic->i_size);
>  		if (vi->datalayout == EROFS_INODE_CHUNK_BASED)
> @@ -137,7 +140,7 @@ int erofs_read_inode_from_disk(struct erofs_device fd, struct erofs_inode *vi)
>  		vi->u.chunkbits = LOG_BLOCK_SIZE +
>  			(vi->u.chunkformat & EROFS_CHUNK_FORMAT_BLKBITS_MASK);
>  	} else if (erofs_inode_is_data_compressed(vi->datalayout))
> -		z_erofs_fill_inode(vi);
> +		z_erofs_fill_inode(vi, sbi);
>  	return 0;
>  bogusimode:
>  	erofs_err("bogus i_mode (%o) @ nid %llu", vi->i_mode, vi->nid | 0ULL);
> @@ -187,7 +190,10 @@ struct nameidata {
>  	unsigned int	ftype;
>  };
>  
> -int erofs_namei(struct erofs_device fd, struct nameidata *nd,
> +int erofs_namei(
> +	struct erofs_device fd,
> +	struct erofs_sb_info *sbi,
> +	struct nameidata *nd,
>  		const char *name, unsigned int len)
>  {
>  	erofs_nid_t nid = nd->nid;
> @@ -196,7 +202,7 @@ int erofs_namei(struct erofs_device fd, struct nameidata *nd,
>  	struct erofs_inode vi = { .nid = nid };
>  	erofs_off_t offset;
>  
> -	ret = erofs_read_inode_from_disk(fd, &vi);
> +	ret = erofs_read_inode_from_disk(fd, sbi, &vi);
>  	if (ret)
>  		return ret;
>  
> @@ -207,7 +213,7 @@ int erofs_namei(struct erofs_device fd, struct nameidata *nd,
>  		struct erofs_dirent *de = (void *)buf;
>  		unsigned int nameoff;
>  
> -		ret = erofs_pread(fd, &vi, buf, maxsize, offset);
> +		ret = erofs_pread(fd, sbi, &vi, buf, maxsize, offset);
>  		if (ret)
>  			return ret;
>  
> @@ -233,9 +239,12 @@ int erofs_namei(struct erofs_device fd, struct nameidata *nd,
>  	return -ENOENT;
>  }
>  
> -static int link_path_walk(struct erofs_device devfd, const char *name, struct nameidata *nd)
> +static int link_path_walk(
> +	struct erofs_device devfd,
> +	struct erofs_sb_info *sbi,
> +	const char *name, struct nameidata *nd)
>  {
> -	nd->nid = sbi.root_nid;
> +	nd->nid = sbi->root_nid;
>  
>  	while (*name == '/')
>  		name++;
> @@ -250,7 +259,7 @@ static int link_path_walk(struct erofs_device devfd, const char *name, struct na
>  		} while (*p != '\0' && *p != '/');
>  
>  		DBG_BUGON(p <= name);
> -		ret = erofs_namei(devfd, nd, name, p - name);
> +		ret = erofs_namei(devfd, sbi, nd, name, p - name);
>  		if (ret)
>  			return ret;
>  
> @@ -262,15 +271,18 @@ static int link_path_walk(struct erofs_device devfd, const char *name, struct na
>  	return 0;
>  }
>  
> -int erofs_ilookup(struct erofs_device devfd, const char *path, struct erofs_inode *vi)
> +int erofs_ilookup(
> +	struct erofs_device devfd,
> +	struct erofs_sb_info *sbi,
> +	const char *path, struct erofs_inode *vi)
>  {
>  	int ret;
>  	struct nameidata nd;
>  
> -	ret = link_path_walk(devfd, path, &nd);
> +	ret = link_path_walk(devfd, sbi, path, &nd);
>  	if (ret)
>  		return ret;
>  
>  	vi->nid = nd.nid;
> -	return erofs_read_inode_from_disk(devfd, vi);
> +	return erofs_read_inode_from_disk(devfd, sbi, vi);
>  }
> diff --git a/lib/xattr.c b/lib/xattr.c
> index 9f16664..7a1ed9e 100644
> --- a/lib/xattr.c
> +++ b/lib/xattr.c
> @@ -564,7 +564,7 @@ static struct erofs_bhops erofs_write_shared_xattrs_bhops = {
>  	.flush = erofs_bh_flush_write_shared_xattrs,
>  };
>  
> -int erofs_build_shared_xattrs_from_path(const char *path)
> +int erofs_build_shared_xattrs_from_path(const char *path, struct erofs_sb_info *sbi)
>  {
>  	int ret;
>  	struct erofs_buffer_head *bh;
> @@ -604,7 +604,7 @@ int erofs_build_shared_xattrs_from_path(const char *path)
>  	erofs_mapbh(bh->block);
>  	off = erofs_btell(bh, false);
>  
> -	sbi.xattr_blkaddr = off / EROFS_BLKSIZ;
> +	sbi->xattr_blkaddr = off / EROFS_BLKSIZ;
>  	off %= EROFS_BLKSIZ;
>  	p = 0;
>  
> diff --git a/lib/zmap.c b/lib/zmap.c
> index 69fef80..e6e9858 100644
> --- a/lib/zmap.c
> +++ b/lib/zmap.c
> @@ -10,9 +10,9 @@
>  #include "erofs/io.h"
>  #include "erofs/print.h"
>  
> -int z_erofs_fill_inode(struct erofs_inode *vi)
> +int z_erofs_fill_inode(struct erofs_inode *vi, struct erofs_sb_info *sbi)
>  {
> -	if (!erofs_sb_has_big_pcluster(&sbi) &&
> +	if (!erofs_sb_has_big_pcluster(sbi) &&
>  	    vi->datalayout == EROFS_INODE_FLAT_COMPRESSION_LEGACY) {
>  		vi->z_advise = 0;
>  		vi->z_algorithmtype[0] = 0;
> @@ -24,7 +24,10 @@ int z_erofs_fill_inode(struct erofs_inode *vi)
>  	return 0;
>  }
>  
> -static int z_erofs_fill_inode_lazy(struct erofs_device erofs_dev, struct erofs_inode *vi)
> +static int z_erofs_fill_inode_lazy(
> +	struct erofs_device erofs_dev,
> +	struct erofs_sb_info *sbi,
> +	struct erofs_inode *vi)
>  {
>  	int ret;
>  	erofs_off_t pos;
> @@ -34,9 +37,9 @@ static int z_erofs_fill_inode_lazy(struct erofs_device erofs_dev, struct erofs_i
>  	if (vi->flags & EROFS_I_Z_INITED)
>  		return 0;
>  
> -	DBG_BUGON(!erofs_sb_has_big_pcluster(&sbi) &&
> +	DBG_BUGON(!erofs_sb_has_big_pcluster(sbi) &&
>  		  vi->datalayout == EROFS_INODE_FLAT_COMPRESSION_LEGACY);
> -	pos = round_up(iloc(vi->nid) + vi->inode_isize + vi->xattr_isize, 8);
> +	pos = round_up(iloc(sbi, vi->nid) + vi->inode_isize + vi->xattr_isize, 8);
>  
>  	ret = dev_read(erofs_dev, buf, pos, sizeof(buf));
>  	if (ret < 0)
> @@ -101,11 +104,12 @@ static int z_erofs_reload_indexes(
>  
>  static int legacy_load_cluster_from_disk(
>  	struct erofs_device erofs_dev,
> +	struct erofs_sb_info *sbi,
>  	struct z_erofs_maprecorder *m,
>  	unsigned long lcn)
>  {
>  	struct erofs_inode *const vi = m->inode;
> -	const erofs_off_t ibase = iloc(vi->nid);
> +	const erofs_off_t ibase = iloc(sbi, vi->nid);
>  	const erofs_off_t pos =
>  		Z_EROFS_VLE_LEGACY_INDEX_ALIGN(ibase + vi->inode_isize +
>  					       vi->xattr_isize) +
> @@ -295,12 +299,13 @@ static int unpack_compacted_index(struct z_erofs_maprecorder *m,
>  
>  static int compacted_load_cluster_from_disk(
>  	struct erofs_device erofs_dev,
> +	struct erofs_sb_info *sbi,
>  	struct z_erofs_maprecorder *m,
>  	unsigned long lcn, bool lookahead)
>  {
>  	struct erofs_inode *const vi = m->inode;
>  	const unsigned int lclusterbits = vi->z_logical_clusterbits;
> -	const erofs_off_t ebase = round_up(iloc(vi->nid) + vi->inode_isize +
> +	const erofs_off_t ebase = round_up(iloc(sbi, vi->nid) + vi->inode_isize +
>  					   vi->xattr_isize, 8) +
>  		sizeof(struct z_erofs_map_header);
>  	const unsigned int totalidx = DIV_ROUND_UP(vi->i_size, EROFS_BLKSIZ);
> @@ -352,22 +357,24 @@ out:
>  
>  static int z_erofs_load_cluster_from_disk(
>  	struct erofs_device erofs_dev,
> +	struct erofs_sb_info *sbi,
>  	struct z_erofs_maprecorder *m,
>  					  unsigned int lcn, bool lookahead)
>  {
>  	const unsigned int datamode = m->inode->datalayout;
>  
>  	if (datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY)
> -		return legacy_load_cluster_from_disk(erofs_dev, m, lcn);
> +		return legacy_load_cluster_from_disk(erofs_dev, sbi, m, lcn);
>  
>  	if (datamode == EROFS_INODE_FLAT_COMPRESSION)
> -		return compacted_load_cluster_from_disk(erofs_dev, m, lcn, lookahead);
> +		return compacted_load_cluster_from_disk(erofs_dev, sbi, m, lcn, lookahead);
>  
>  	return -EINVAL;
>  }
>  
>  static int z_erofs_extent_lookback(
>  	struct erofs_device erofs_dev,
> +	struct erofs_sb_info *sbi,
>  	struct z_erofs_maprecorder *m,
>  				   unsigned int lookback_distance)
>  {
> @@ -386,7 +393,7 @@ static int z_erofs_extent_lookback(
>  
>  	/* load extent head logical cluster if needed */
>  	lcn -= lookback_distance;
> -	err = z_erofs_load_cluster_from_disk(erofs_dev, m, lcn, false);
> +	err = z_erofs_load_cluster_from_disk(erofs_dev, sbi, m, lcn, false);
>  	if (err)
>  		return err;
>  
> @@ -398,7 +405,7 @@ static int z_erofs_extent_lookback(
>  			DBG_BUGON(1);
>  			return -EFSCORRUPTED;
>  		}
> -		return z_erofs_extent_lookback(erofs_dev, m, m->delta[0]);
> +		return z_erofs_extent_lookback(erofs_dev, sbi, m, m->delta[0]);
>  	case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
>  		map->m_flags &= ~EROFS_MAP_ZIPPED;
>  		/* fallthrough */
> @@ -416,6 +423,7 @@ static int z_erofs_extent_lookback(
>  
>  static int z_erofs_get_extent_compressedlen(
>  	struct erofs_device erofs_dev,
> +	struct erofs_sb_info *sbi,
>  	struct z_erofs_maprecorder *m,
>  	unsigned int initial_lcn)
>  {
> @@ -437,7 +445,7 @@ static int z_erofs_get_extent_compressedlen(
>  	if (m->compressedlcs)
>  		goto out;
>  
> -	err = z_erofs_load_cluster_from_disk(erofs_dev, m, lcn, false);
> +	err = z_erofs_load_cluster_from_disk(erofs_dev, sbi, m, lcn, false);
>  	if (err)
>  		return err;
>  
> @@ -485,6 +493,7 @@ err_bonus_cblkcnt:
>  
>  static int z_erofs_get_extent_decompressedlen(
>  	struct erofs_device erofs_dev,
> +	struct erofs_sb_info *sbi,
>  	struct z_erofs_maprecorder *m)
>  {
>  	struct erofs_inode *const vi = m->inode;
> @@ -500,7 +509,7 @@ static int z_erofs_get_extent_decompressedlen(
>  			return 0;
>  		}
>  
> -		err = z_erofs_load_cluster_from_disk(erofs_dev, m, lcn, true);
> +		err = z_erofs_load_cluster_from_disk(erofs_dev, sbi, m, lcn, true);
>  		if (err)
>  			return err;
>  
> @@ -529,6 +538,7 @@ static int z_erofs_get_extent_decompressedlen(
>  
>  int z_erofs_map_blocks_iter(
>  					struct erofs_device erofs_dev,
> +					struct erofs_sb_info *sbi,
>  					struct erofs_inode *vi,
>  			    struct erofs_map_blocks *map,
>  			    int flags)
> @@ -551,7 +561,7 @@ int z_erofs_map_blocks_iter(
>  		goto out;
>  	}
>  
> -	err = z_erofs_fill_inode_lazy(erofs_dev, vi);
> +	err = z_erofs_fill_inode_lazy(erofs_dev, sbi, vi);
>  	if (err)
>  		goto out;
>  
> @@ -560,7 +570,7 @@ int z_erofs_map_blocks_iter(
>  	initial_lcn = ofs >> lclusterbits;
>  	endoff = ofs & ((1 << lclusterbits) - 1);
>  
> -	err = z_erofs_load_cluster_from_disk(erofs_dev, &m, initial_lcn, false);
> +	err = z_erofs_load_cluster_from_disk(erofs_dev, sbi, &m, initial_lcn, false);
>  	if (err)
>  		goto out;
>  
> @@ -589,7 +599,7 @@ int z_erofs_map_blocks_iter(
>  		/* fallthrough */
>  	case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
>  		/* get the correspoinding first chunk */
> -		err = z_erofs_extent_lookback(erofs_dev, &m, m.delta[0]);
> +		err = z_erofs_extent_lookback(erofs_dev, sbi, &m, m.delta[0]);
>  		if (err)
>  			goto out;
>  		break;
> @@ -604,12 +614,12 @@ int z_erofs_map_blocks_iter(
>  	map->m_pa = blknr_to_addr(m.pblk);
>  	map->m_flags |= EROFS_MAP_MAPPED;
>  
> -	err = z_erofs_get_extent_compressedlen(erofs_dev, &m, initial_lcn);
> +	err = z_erofs_get_extent_compressedlen(erofs_dev, sbi, &m, initial_lcn);
>  	if (err)
>  		goto out;
>  
>  	if (flags & EROFS_GET_BLOCKS_FIEMAP) {
> -		err = z_erofs_get_extent_decompressedlen(erofs_dev, &m);
> +		err = z_erofs_get_extent_decompressedlen(erofs_dev, sbi, &m);
>  		if (!err)
>  			map->m_flags |= EROFS_MAP_FULL_MAPPED;
>  	}
> diff --git a/mkfs/main.c b/mkfs/main.c
> index 16f8060..f7b432e 100644
> --- a/mkfs/main.c
> +++ b/mkfs/main.c
> @@ -109,7 +109,7 @@ static void usage(void)
>  	print_available_compressors(stderr, ", ");
>  }
>  
> -static int parse_extended_opts(const char *opts)
> +static int parse_extended_opts(struct erofs_sb_info *sbi, const char *opts)
>  {
>  #define MATCH_EXTENTED_OPT(opt, token, keylen) \
>  	(keylen == sizeof(opt) - 1 && !memcmp(token, opt, sizeof(opt) - 1))
> @@ -164,7 +164,7 @@ static int parse_extended_opts(const char *opts)
>  		if (MATCH_EXTENTED_OPT("nosbcrc", token, keylen)) {
>  			if (vallen)
>  				return -EINVAL;
> -			erofs_sb_clear_sb_chksum(&sbi);
> +			erofs_sb_clear_sb_chksum(sbi);
>  		}
>  
>  		if (MATCH_EXTENTED_OPT("noinline_data", token, keylen)) {
> @@ -176,7 +176,7 @@ static int parse_extended_opts(const char *opts)
>  	return 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;
> @@ -221,7 +221,7 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
>  			break;
>  
>  		case 'E':
> -			opt = parse_extended_opts(optarg);
> +			opt = parse_extended_opts(sbi, optarg);
>  			if (opt)
>  				return opt;
>  			break;
> @@ -235,7 +235,7 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
>  			break;
>  #ifdef HAVE_LIBUUID
>  		case 'U':
> -			if (uuid_parse(optarg, sbi.uuid)) {
> +			if (uuid_parse(optarg, sbi->uuid)) {
>  				erofs_err("invalid UUID %s", optarg);
>  				return -EINVAL;
>  			}
> @@ -343,7 +343,7 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
>  					  optarg);
>  				return -EINVAL;
>  			}
> -			erofs_sb_set_chunked_file(&sbi);
> +			erofs_sb_set_chunked_file(sbi);
>  			break;
>  		case 12:
>  			quiet = true;
> @@ -385,21 +385,23 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
>  	return 0;
>  }
>  
> -int erofs_mkfs_update_super_block(struct erofs_buffer_head *bh,
> +int erofs_mkfs_update_super_block(
> +					struct erofs_sb_info *sbi,
> +					struct erofs_buffer_head *bh,
>  				  erofs_nid_t root_nid,
>  				  erofs_blk_t *blocks)
>  {
>  	struct erofs_super_block sb = {
>  		.magic     = cpu_to_le32(EROFS_SUPER_MAGIC_V1),
>  		.blkszbits = LOG_BLOCK_SIZE,
> -		.inos   = cpu_to_le64(sbi.inos),
> -		.build_time = cpu_to_le64(sbi.build_time),
> -		.build_time_nsec = cpu_to_le32(sbi.build_time_nsec),
> +		.inos   = cpu_to_le64(sbi->inos),
> +		.build_time = cpu_to_le64(sbi->build_time),
> +		.build_time_nsec = cpu_to_le32(sbi->build_time_nsec),
>  		.blocks = 0,
> -		.meta_blkaddr  = sbi.meta_blkaddr,
> -		.xattr_blkaddr = sbi.xattr_blkaddr,
> -		.feature_incompat = cpu_to_le32(sbi.feature_incompat),
> -		.feature_compat = cpu_to_le32(sbi.feature_compat &
> +		.meta_blkaddr  = sbi->meta_blkaddr,
> +		.xattr_blkaddr = sbi->xattr_blkaddr,
> +		.feature_incompat = cpu_to_le32(sbi->feature_incompat),
> +		.feature_compat = cpu_to_le32(sbi->feature_compat &
>  					      ~EROFS_FEATURE_COMPAT_SB_CHKSUM),
>  	};
>  	const unsigned int sb_blksize =
> @@ -409,12 +411,12 @@ int erofs_mkfs_update_super_block(struct erofs_buffer_head *bh,
>  	*blocks         = erofs_mapbh(NULL);
>  	sb.blocks       = cpu_to_le32(*blocks);
>  	sb.root_nid     = cpu_to_le16(root_nid);
> -	memcpy(sb.uuid, sbi.uuid, sizeof(sb.uuid));
> +	memcpy(sb.uuid, sbi->uuid, sizeof(sb.uuid));
>  
> -	if (erofs_sb_has_compr_cfgs(&sbi))
> -		sb.u1.available_compr_algs = sbi.available_compr_algs;
> +	if (erofs_sb_has_compr_cfgs(sbi))
> +		sb.u1.available_compr_algs = sbi->available_compr_algs;
>  	else
> -		sb.u1.lz4_max_distance = cpu_to_le16(sbi.lz4_max_distance);
> +		sb.u1.lz4_max_distance = cpu_to_le16(sbi->lz4_max_distance);
>  
>  	buf = calloc(sb_blksize, 1);
>  	if (!buf) {
> @@ -473,17 +475,17 @@ static int erofs_mkfs_superblock_csum_set(struct erofs_device erofs_dev)
>  	return 0;
>  }
>  
> -static void erofs_mkfs_default_options(void)
> +static void erofs_mkfs_default_options(struct erofs_sb_info *sbi)
>  {
>  	cfg.c_legacy_compress = false;
> -	sbi.feature_incompat = EROFS_FEATURE_INCOMPAT_LZ4_0PADDING;
> -	sbi.feature_compat = EROFS_FEATURE_COMPAT_SB_CHKSUM;
> +	sbi->feature_incompat = EROFS_FEATURE_INCOMPAT_LZ4_0PADDING;
> +	sbi->feature_compat = EROFS_FEATURE_COMPAT_SB_CHKSUM;
>  
>  	/* generate a default uuid first */
>  #ifdef HAVE_LIBUUID
>  	do {
> -		uuid_generate(sbi.uuid);
> -	} while (uuid_is_null(sbi.uuid));
> +		uuid_generate(sbi->uuid);
> +	} while (uuid_is_null(sbi->uuid));
>  #endif
>  }
>  
> @@ -531,11 +533,12 @@ int main(int argc, char **argv)
>  	struct timeval t;
>  	char uuid_str[37] = "not available";
>  	struct erofs_device erofs_dev;
> +	struct erofs_sb_info sbi;
>  
>  	erofs_init_global_configure();
> -	erofs_mkfs_default_options();
> +	erofs_mkfs_default_options(&sbi);
>  
> -	err = mkfs_parse_options_cfg(argc, argv);
> +	err = mkfs_parse_options_cfg(&sbi, argc, argv);
>  	erofs_show_progs(argc, argv);
>  	if (err) {
>  		if (err == -EINVAL)
> @@ -620,7 +623,7 @@ int main(int argc, char **argv)
>  		goto exit;
>  	}
>  
> -	err = z_erofs_compress_init(erofs_dev, sb_bh);
> +	err = z_erofs_compress_init(erofs_dev, &sbi, sb_bh);
>  	if (err) {
>  		erofs_err("Failed to initialize compressor: %s",
>  			  erofs_strerror(err));
> @@ -634,20 +637,20 @@ int main(int argc, char **argv)
>  
>  	erofs_inode_manager_init();
>  
> -	err = erofs_build_shared_xattrs_from_path(cfg.c_src_path);
> +	err = erofs_build_shared_xattrs_from_path(cfg.c_src_path, &sbi);
>  	if (err) {
>  		erofs_err("Failed to build shared xattrs: %s",
>  			  erofs_strerror(err));
>  		goto exit;
>  	}
>  
> -	root_inode = erofs_mkfs_build_tree_from_path(erofs_dev, NULL, cfg.c_src_path);
> +	root_inode = erofs_mkfs_build_tree_from_path(erofs_dev, &sbi, NULL, cfg.c_src_path);
>  	if (IS_ERR(root_inode)) {
>  		err = PTR_ERR(root_inode);
>  		goto exit;
>  	}
>  
> -	root_nid = erofs_lookupnid(root_inode);
> +	root_nid = erofs_lookupnid(&sbi, root_inode);
>  	erofs_iput(root_inode);
>  
>  	if (cfg.c_chunkbits) {
> @@ -657,7 +660,7 @@ int main(int argc, char **argv)
>  			goto exit;
>  	}
>  
> -	err = erofs_mkfs_update_super_block(sb_bh, root_nid, &nblocks);
> +	err = erofs_mkfs_update_super_block(&sbi, sb_bh, root_nid, &nblocks);
>  	if (err)
>  		goto exit;
>  
> -- 
> 2.34.0.rc2.393.gf8c9666880-goog
> 

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2021-11-23  7:54 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-21  5:39 [PATCH v1 0/3] Make erofs-utils more library friendly Kelvin Zhang via Linux-erofs
2021-11-21  5:39 ` [PATCH v1 1/4] Make erofs_devfd a parameter for most functions Kelvin Zhang via Linux-erofs
2021-11-23  7:49   ` Gao Xiang
2021-11-21  5:39 ` [PATCH v1 2/4] Mark certain callback function pointers as const Kelvin Zhang via Linux-erofs
2021-11-21  5:39 ` [PATCH v1 3/4] Make super block info struct a paramater instead of globals Kelvin Zhang via Linux-erofs
2021-11-23  7:54   ` Gao Xiang
2021-11-21 10:31 ` [PATCH v1 0/3] Make erofs-utils more library friendly Gao Xiang
2021-11-23  7:39   ` Kelvin Zhang via Linux-erofs

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.