[PATCH 09/11] erofs-utils: formalize erofs_pread()

Gao Xiang hsiangkao at linux.alibaba.com
Fri Jul 18 16:54:17 AEST 2025


Now erofs_pread() is simply a wrapper around erofs_io_pread(), and
erofs_iopen() is used to obtain a virtual file for erofs_pread().

Signed-off-by: Gao Xiang <hsiangkao at linux.alibaba.com>
---
 dump/main.c              | 10 +++++++--
 fsck/main.c              |  7 +++++-
 fuse/main.c              | 23 ++++++++++++++-----
 include/erofs/internal.h |  3 +--
 include/erofs/io.h       | 11 +++++++++
 lib/data.c               | 48 ++++++++++++++++++++++------------------
 lib/dir.c                | 12 ++++++----
 lib/fragments.c          | 20 +++++++++++++----
 lib/inode.c              |  7 +++++-
 lib/namei.c              |  7 +++++-
 lib/rebuild.c            | 10 +++++++--
 lib/super.c              |  3 ++-
 12 files changed, 116 insertions(+), 45 deletions(-)

diff --git a/dump/main.c b/dump/main.c
index 632075a2..f0dab02e 100644
--- a/dump/main.c
+++ b/dump/main.c
@@ -679,6 +679,7 @@ static void erofsdump_show_file_content(void)
 	erofs_off_t pending_size;
 	erofs_off_t read_offset;
 	erofs_off_t read_size;
+	struct erofs_vfile vf;
 
 	if (dumpcfg.inode_path) {
 		err = erofs_ilookup(dumpcfg.inode_path, &inode);
@@ -694,6 +695,10 @@ static void erofsdump_show_file_content(void)
 		}
 	}
 
+	err = erofs_iopen(&vf, &inode);
+	if (err)
+		return;
+
 	buffer_size = erofs_blksiz(inode.sbi);
 	buffer_ptr = malloc(buffer_size);
 	if (!buffer_ptr) {
@@ -704,8 +709,9 @@ static void erofsdump_show_file_content(void)
 	pending_size = inode.i_size;
 	read_offset = 0;
 	while (pending_size > 0) {
-		read_size = pending_size > buffer_size? buffer_size: pending_size;
-		err = erofs_pread(&inode, buffer_ptr, read_size, read_offset);
+		read_size = pending_size > buffer_size ?
+			buffer_size : pending_size;
+		err = erofs_pread(&vf, buffer_ptr, read_size, read_offset);
 		if (err) {
 			erofs_err("read file failed @ nid %llu", inode.nid | 0ULL);
 			goto out;
diff --git a/fsck/main.c b/fsck/main.c
index 96096a91..44719b95 100644
--- a/fsck/main.c
+++ b/fsck/main.c
@@ -775,6 +775,7 @@ again:
 
 static inline int erofs_extract_symlink(struct erofs_inode *inode)
 {
+	struct erofs_vfile vf;
 	bool tryagain = true;
 	int ret;
 	char *buf = NULL;
@@ -792,7 +793,11 @@ static inline int erofs_extract_symlink(struct erofs_inode *inode)
 		goto out;
 	}
 
-	ret = erofs_pread(inode, buf, inode->i_size, 0);
+	ret = erofs_iopen(&vf, inode);
+	if (ret)
+		goto out;
+
+	ret = erofs_pread(&vf, buf, inode->i_size, 0);
 	if (ret) {
 		erofs_err("I/O error occurred when reading symlink @ nid %llu: %d",
 			  inode->nid | 0ULL, ret);
diff --git a/fuse/main.c b/fuse/main.c
index db4f3236..001d1fde 100644
--- a/fuse/main.c
+++ b/fuse/main.c
@@ -366,11 +366,15 @@ out:
 static void erofsfuse_read(fuse_req_t req, fuse_ino_t ino, size_t size,
 			   off_t off, struct fuse_file_info *fi)
 {
-	int ret;
-	char *buf = NULL;
 	struct erofs_inode *vi = (struct erofs_inode *)fi->fh;
+	struct erofs_vfile vf;
+	char *buf = NULL;
+	int ret;
 
 	erofs_dbg("read(%llu): size = %zu, off = %lu", ino | 0ULL, size, off);
+	ret = erofs_iopen(&vf, vi);
+	if (ret)
+		return ret;
 
 	buf = malloc(size);
 	if (!buf) {
@@ -378,7 +382,7 @@ static void erofsfuse_read(fuse_req_t req, fuse_ino_t ino, size_t size,
 		return;
 	}
 
-	ret = erofs_pread(vi, buf, size, off);
+	ret = erofs_pread(&vf, buf, size, off);
 	if (ret) {
 		fuse_reply_err(req, -ret);
 		goto out;
@@ -398,9 +402,10 @@ out:
 
 static void erofsfuse_readlink(fuse_req_t req, fuse_ino_t ino)
 {
-	int ret;
-	char *buf = NULL;
 	struct erofs_inode vi = { .sbi = &g_sbi, .nid = erofsfuse_to_nid(ino) };
+	struct erofs_vfile vf;
+	char *buf = NULL;
+	int ret;
 
 	ret = erofs_read_inode_from_disk(&vi);
 	if (ret < 0) {
@@ -408,13 +413,19 @@ static void erofsfuse_readlink(fuse_req_t req, fuse_ino_t ino)
 		return;
 	}
 
+	ret = erofs_iopen(&vf, &vi);
+	if (ret) {
+		fuse_reply_err(req, -ret);
+		return;
+	}
+
 	buf = malloc(vi.i_size + 1);
 	if (!buf) {
 		fuse_reply_err(req, ENOMEM);
 		return;
 	}
 
-	ret = erofs_pread(&vi, buf, vi.i_size, 0);
+	ret = erofs_pread(&vf, buf, vi.i_size, 0);
 	if (ret < 0) {
 		fuse_reply_err(req, -ret);
 		goto out;
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 0a49394d..3439a183 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -440,8 +440,7 @@ void *erofs_bread(struct erofs_buf *buf, erofs_off_t offset, bool need_kmap);
 void erofs_init_metabuf(struct erofs_buf *buf, struct erofs_sb_info *sbi);
 void *erofs_read_metabuf(struct erofs_buf *buf, struct erofs_sb_info *sbi,
 			 erofs_off_t offset);
-int erofs_pread(struct erofs_inode *inode, char *buf,
-		erofs_off_t count, erofs_off_t offset);
+int erofs_iopen(struct erofs_vfile *vf, struct erofs_inode *inode);
 int erofs_map_blocks(struct erofs_inode *inode,
 		struct erofs_map_blocks *map, int flags);
 int erofs_map_dev(struct erofs_sb_info *sbi, struct erofs_map_dev *map);
diff --git a/include/erofs/io.h b/include/erofs/io.h
index 01a7ff44..cc7a3cd2 100644
--- a/include/erofs/io.h
+++ b/include/erofs/io.h
@@ -70,6 +70,17 @@ ssize_t erofs_copy_file_range(int fd_in, u64 *off_in, int fd_out, u64 *off_out,
 int erofs_io_xcopy(struct erofs_vfile *vout, off_t pos,
 		   struct erofs_vfile *vin, unsigned int len, bool noseek);
 
+static inline int erofs_pread(struct erofs_vfile *vf, void *buf,
+			      size_t len, u64 offset)
+{
+	ssize_t read;
+
+	read = erofs_io_pread(vf, buf, len, offset);
+	if (read < 0)
+		return read;
+	return read != len ? -EIO : 0;
+}
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/data.c b/lib/data.c
index 83cc5d5d..87ced24f 100644
--- a/lib/data.c
+++ b/lib/data.c
@@ -22,12 +22,10 @@ void *erofs_bread(struct erofs_buf *buf, erofs_off_t offset, bool need_kmap)
 	blknr = erofs_blknr(sbi, offset);
 	if (blknr != buf->blocknr) {
 		buf->blocknr = ~0ULL;
-		err = erofs_io_pread(buf->vf, buf->base, blksiz,
-				     round_down(offset, blksiz));
-		if (err < 0)
+		err = erofs_pread(buf->vf, buf->base, blksiz,
+				  round_down(offset, blksiz));
+		if (err)
 			return ERR_PTR(err);
-		if (err != blksiz)
-			return ERR_PTR(-EIO);
 		buf->blocknr = blknr;
 	}
 	return buf->base + erofs_blkoff(sbi, offset);
@@ -364,27 +362,31 @@ 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,
-		erofs_off_t count, erofs_off_t offset)
+ssize_t erofs_preadi(struct erofs_vfile *vf, void *buf, size_t len, u64 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);
-	case EROFS_INODE_COMPRESSED_FULL:
-	case EROFS_INODE_COMPRESSED_COMPACT:
-		return z_erofs_read_data(inode, buf, count, offset);
-	default:
-		break;
-	}
-	return -EINVAL;
+	struct erofs_inode *inode = *(struct erofs_inode **)vf->payload;
+
+	if (erofs_inode_is_data_compressed(inode->datalayout))
+		return z_erofs_read_data(inode, buf, len, offset) ?: len;
+	return erofs_read_raw_data(inode, buf, len, offset) ?: len;
+}
+
+int erofs_iopen(struct erofs_vfile *vf, struct erofs_inode *inode)
+{
+	static struct erofs_vfops ops = {
+		.pread = erofs_preadi,
+	};
+
+	vf->ops = &ops;
+	*(struct erofs_inode **)vf->payload = inode;
+	return 0;
 }
 
 static void *erofs_read_metadata_nid(struct erofs_sb_info *sbi, erofs_nid_t nid,
 				     erofs_off_t *offset, int *lengthp)
 {
 	struct erofs_inode vi = { .sbi = sbi, .nid = nid };
+	struct erofs_vfile vf;
 	__le16 __len;
 	int ret, len;
 	char *buffer;
@@ -393,8 +395,12 @@ static void *erofs_read_metadata_nid(struct erofs_sb_info *sbi, erofs_nid_t nid,
 	if (ret)
 		return ERR_PTR(ret);
 
+	ret = erofs_iopen(&vf, &vi);
+	if (ret)
+		return ERR_PTR(ret);
+
 	*offset = round_up(*offset, 4);
-	ret = erofs_pread(&vi, (void *)&__len, sizeof(__le16), *offset);
+	ret = erofs_pread(&vf, (void *)&__len, sizeof(__le16), *offset);
 	if (ret)
 		return ERR_PTR(ret);
 
@@ -408,7 +414,7 @@ static void *erofs_read_metadata_nid(struct erofs_sb_info *sbi, erofs_nid_t nid,
 	*offset += sizeof(__le16);
 	*lengthp = len;
 
-	ret = erofs_pread(&vi, buffer, len, *offset);
+	ret = erofs_pread(&vf, buffer, len, *offset);
 	if (ret) {
 		free(buffer);
 		return ERR_PTR(ret);
diff --git a/lib/dir.c b/lib/dir.c
index 9c6849d8..98edb8e1 100644
--- a/lib/dir.c
+++ b/lib/dir.c
@@ -142,9 +142,10 @@ int erofs_iterate_dir(struct erofs_dir_context *ctx, bool fsck)
 {
 	struct erofs_inode *dir = ctx->dir;
 	struct erofs_sb_info *sbi = dir->sbi;
-	int err = 0;
+	struct erofs_vfile vf;
 	erofs_off_t pos;
 	char buf[EROFS_MAX_BLOCK_SIZE];
+	int err = 0;
 
 	if (!S_ISDIR(dir->i_mode))
 		return -ENOTDIR;
@@ -152,15 +153,18 @@ int erofs_iterate_dir(struct erofs_dir_context *ctx, bool fsck)
 	ctx->flags &= ~EROFS_READDIR_ALL_SPECIAL_FOUND;
 	if (dir->dot_omitted)
 		ctx->flags |= EROFS_READDIR_DOT_FOUND;
-	pos = 0;
-	while (pos < dir->i_size) {
+	err = erofs_iopen(&vf, dir);
+	if (err)
+		return err;
+
+	for (pos = 0; pos < dir->i_size; ) {
 		erofs_blk_t lblk = erofs_blknr(sbi, pos);
 		erofs_off_t maxsize = min_t(erofs_off_t,
 					dir->i_size - pos, erofs_blksiz(sbi));
 		const struct erofs_dirent *de = (const void *)buf;
 		unsigned int nameoff;
 
-		err = erofs_pread(dir, buf, maxsize, pos);
+		err = erofs_pread(&vf, buf, maxsize, pos);
 		if (err) {
 			erofs_err("I/O error when reading dirents @ nid %llu, lblk %llu: %s",
 				  dir->nid | 0ULL, lblk | 0ULL,
diff --git a/lib/fragments.c b/lib/fragments.c
index 887c2530..0221a538 100644
--- a/lib/fragments.c
+++ b/lib/fragments.c
@@ -510,6 +510,7 @@ static void *erofs_packedfile_preload(struct erofs_inode *pi,
 	struct erofs_sb_info *sbi = pi->sbi;
 	struct erofs_packed_inode *epi = sbi->packedinode;
 	unsigned int bsz = erofs_blksiz(sbi);
+	struct erofs_vfile vf;
 	char *buffer;
 	erofs_off_t pos, end;
 	ssize_t err;
@@ -529,13 +530,17 @@ static void *erofs_packedfile_preload(struct erofs_inode *pi,
 	else
 		DBG_BUGON(map->m_la > pos);
 
+	err = erofs_iopen(&vf, pi);
+	if (err)
+		return ERR_PTR(err);
+
 	map->m_llen = end - map->m_la;
 	DBG_BUGON(!map->m_llen);
 	buffer = malloc(map->m_llen);
 	if (!buffer)
 		return ERR_PTR(-ENOMEM);
 
-	err = erofs_pread(pi, buffer, map->m_llen, map->m_la);
+	err = erofs_pread(&vf, buffer, map->m_llen, map->m_la);
 	if (err)
 		goto err_out;
 
@@ -572,13 +577,17 @@ int erofs_packedfile_read(struct erofs_sb_info *sbi,
 	struct erofs_map_blocks map = { .buf = __EROFS_BUF_INITIALIZER };
 	unsigned int bsz = erofs_blksiz(sbi);
 	erofs_off_t end = pos + len;
+	struct erofs_vfile vf;
 	char *buffer = NULL;
 	int err;
 
 	if (!epi) {
 		err = erofs_load_packedinode_from_disk(&pi);
-		if (!err)
-			err = erofs_pread(&pi, buf, len, pos);
+		if (!err) {
+			err = erofs_iopen(&vf, &pi);
+			if (!err)
+				err = erofs_pread(&vf, buf, len, pos);
+		}
 		return err;
 	}
 
@@ -632,8 +641,11 @@ int erofs_packedfile_read(struct erofs_sb_info *sbi,
 			} else {
 fallback:
 				err = erofs_load_packedinode_from_disk(&pi);
+				if (err)
+					break;
+				err = erofs_iopen(&vf, &pi);
 				if (!err)
-					err = erofs_pread(&pi, buf, len, pos);
+					err = erofs_pread(&vf, buf, len, pos);
 				if (err)
 					break;
 			}
diff --git a/lib/inode.c b/lib/inode.c
index f7c6b87f..5f50c09f 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -371,6 +371,7 @@ static int erofs_rebuild_inode_fix_pnid(struct erofs_inode *parent,
 	};
 	unsigned int bsz = erofs_blksiz(dir.sbi);
 	unsigned int err, isz;
+	struct erofs_vfile vf;
 	erofs_off_t boff, off;
 	erofs_nid_t pnid;
 	bool fixed = false;
@@ -386,6 +387,10 @@ static int erofs_rebuild_inode_fix_pnid(struct erofs_inode *parent,
 	    dir.datalayout != EROFS_INODE_FLAT_PLAIN)
 		return -EOPNOTSUPP;
 
+	err = erofs_iopen(&vf, &dir);
+	if (err)
+		return err;
+
 	pnid = erofs_lookupnid(parent);
 	isz = dir.inode_isize + dir.xattr_isize;
 	boff = erofs_pos(dir.sbi, dir.u.i_blkaddr);
@@ -395,7 +400,7 @@ static int erofs_rebuild_inode_fix_pnid(struct erofs_inode *parent,
 		unsigned int nameoff, count, de_nameoff;
 
 		count = min_t(erofs_off_t, bsz, dir.i_size - off);
-		err = erofs_pread(&dir, buf, count, off);
+		err = erofs_pread(&vf, buf, count, off);
 		if (err)
 			return err;
 
diff --git a/lib/namei.c b/lib/namei.c
index c3ddd590..8de0a908 100644
--- a/lib/namei.c
+++ b/lib/namei.c
@@ -224,12 +224,17 @@ int erofs_namei(struct nameidata *nd, const char *name, unsigned int len)
 	char buf[EROFS_MAX_BLOCK_SIZE];
 	struct erofs_sb_info *sbi = nd->sbi;
 	struct erofs_inode vi = { .sbi = sbi, .nid = nid };
+	struct erofs_vfile vf;
 	erofs_off_t offset;
 
 	ret = erofs_read_inode_from_disk(&vi);
 	if (ret)
 		return ret;
 
+	ret = erofs_iopen(&vf, &vi);
+	if (ret)
+		return ret;
+
 	offset = 0;
 	while (offset < vi.i_size) {
 		erofs_off_t maxsize = min_t(erofs_off_t,
@@ -237,7 +242,7 @@ int erofs_namei(struct nameidata *nd, const char *name, unsigned int len)
 		struct erofs_dirent *de = (void *)buf;
 		unsigned int nameoff;
 
-		ret = erofs_pread(&vi, buf, maxsize, offset);
+		ret = erofs_pread(&vf, buf, maxsize, offset);
 		if (ret)
 			return ret;
 
diff --git a/lib/rebuild.c b/lib/rebuild.c
index 33857fd6..7ad0658a 100644
--- a/lib/rebuild.c
+++ b/lib/rebuild.c
@@ -243,13 +243,19 @@ static int erofs_rebuild_update_inode(struct erofs_sb_info *dst_sb,
 	case S_IFDIR:
 		err = erofs_init_empty_dir(inode);
 		break;
-	case S_IFLNK:
+	case S_IFLNK: {
+		struct erofs_vfile vf;
+
 		inode->i_link = malloc(inode->i_size + 1);
 		if (!inode->i_link)
 			return -ENOMEM;
-		err = erofs_pread(inode, inode->i_link, inode->i_size, 0);
+		err = erofs_iopen(&vf, inode);
+		if (err)
+			return err;
+		err = erofs_pread(&vf, inode->i_link, inode->i_size, 0);
 		erofs_dbg("\tsymlink: %s -> %s", inode->i_srcpath, inode->i_link);
 		break;
+	}
 	case S_IFREG:
 		if (!inode->i_size) {
 			inode->u.i_blkaddr = EROFS_NULL_ADDR;
diff --git a/lib/super.c b/lib/super.c
index 8c0abafd..1d13e6e3 100644
--- a/lib/super.c
+++ b/lib/super.c
@@ -81,7 +81,8 @@ int erofs_read_superblock(struct erofs_sb_info *sbi)
 	read = erofs_io_pread(&sbi->bdev, data, EROFS_MAX_BLOCK_SIZE, 0);
 	if (read < EROFS_SUPER_END) {
 		ret = read < 0 ? read : -EIO;
-		erofs_err("cannot read erofs superblock: %d", ret);
+		erofs_err("cannot read erofs superblock: %s",
+			  erofs_strerror(ret));
 		return ret;
 	}
 	dsb = (struct erofs_super_block *)(data + EROFS_SUPER_OFFSET);
-- 
2.43.5



More information about the Linux-erofs mailing list