[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