[PATCH 06/11] erofs-utils: lib: use meta buffers for inode operations

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


Source kernel commit: c521e3ad6cc980df6f3bdd2616808ecb973af880

Signed-off-by: Gao Xiang <hsiangkao at linux.alibaba.com>
---
 lib/namei.c | 78 ++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 56 insertions(+), 22 deletions(-)

diff --git a/lib/namei.c b/lib/namei.c
index d6013e5c..c3ddd590 100644
--- a/lib/namei.c
+++ b/lib/namei.c
@@ -24,39 +24,67 @@ static dev_t erofs_new_decode_dev(u32 dev)
 
 int erofs_read_inode_from_disk(struct erofs_inode *vi)
 {
-	int ret, ifmt;
-	char buf[sizeof(struct erofs_inode_extended)];
-	erofs_off_t inode_loc = erofs_iloc(vi);
 	struct erofs_sb_info *sbi = vi->sbi;
+	erofs_blk_t blkaddr = erofs_blknr(sbi, erofs_iloc(vi));
+	unsigned int ofs = erofs_blkoff(sbi, erofs_iloc(vi));
+	struct erofs_buf buf = __EROFS_BUF_INITIALIZER;
 	erofs_blk_t addrmask = BIT_ULL(48) - 1;
 	struct erofs_inode_extended *die, copied;
 	struct erofs_inode_compact *dic;
+	unsigned int ifmt;
+	void *ptr;
+	int err = 0;
+
+	ptr = erofs_read_metabuf(&buf, sbi, erofs_pos(sbi, blkaddr));
+	if (IS_ERR(ptr)) {
+		err = PTR_ERR(ptr);
+		erofs_err("failed to get inode (nid: %llu) page, err %d",
+			  vi->nid, err);
+		goto err_out;
+	}
 
-	DBG_BUGON(!sbi);
-	ret = erofs_dev_read(sbi, 0, buf, inode_loc, sizeof(*dic));
-	if (ret < 0)
-		return -EIO;
-
-	dic = (struct erofs_inode_compact *)buf;
+	dic = ptr + ofs;
 	ifmt = le16_to_cpu(dic->i_format);
+	if (ifmt & ~EROFS_I_ALL) {
+		erofs_err("unsupported i_format %u of nid %llu",
+			  ifmt, vi->nid);
+		err = -EOPNOTSUPP;
+		goto err_out;
+	}
 
 	vi->datalayout = erofs_inode_datalayout(ifmt);
 	if (vi->datalayout >= EROFS_INODE_DATALAYOUT_MAX) {
 		erofs_err("unsupported datalayout %u of nid %llu",
 			  vi->datalayout, vi->nid | 0ULL);
-		return -EOPNOTSUPP;
+		err = -EOPNOTSUPP;
+		goto err_out;
 	}
+
 	switch (erofs_inode_version(ifmt)) {
 	case EROFS_INODE_LAYOUT_EXTENDED:
 		vi->inode_isize = sizeof(struct erofs_inode_extended);
-
-		ret = erofs_dev_read(sbi, 0, buf + sizeof(*dic),
-			       inode_loc + sizeof(*dic),
-			       sizeof(*die) - sizeof(*dic));
-		if (ret < 0)
-			return -EIO;
-
-		die = (struct erofs_inode_extended *)buf;
+		/* check if the extended inode acrosses block boundary */
+		if (ofs + vi->inode_isize <= erofs_blksiz(sbi)) {
+			ofs += vi->inode_isize;
+			die = (struct erofs_inode_extended *)dic;
+			copied.i_u = die->i_u;
+			copied.i_nb = die->i_nb;
+		} else {
+			const unsigned int gotten = erofs_blksiz(sbi) - ofs;
+
+			memcpy(&copied, dic, gotten);
+			ptr = erofs_read_metabuf(&buf, sbi,
+					erofs_pos(sbi, blkaddr + 1));
+			if (IS_ERR(ptr)) {
+				err = PTR_ERR(ptr);
+				erofs_err("failed to get inode payload block (nid: %llu), err %d",
+					  vi->nid, err);
+				goto err_out;
+			}
+			ofs = vi->inode_isize - gotten;
+			memcpy((u8 *)&copied + gotten, ptr, ofs);
+			die = &copied;
+		}
 		vi->xattr_isize = erofs_xattr_ibody_size(die->i_xattr_icount);
 		vi->i_mode = le16_to_cpu(die->i_mode);
 		vi->i_ino[0] = le32_to_cpu(die->i_ino);
@@ -72,6 +100,7 @@ int erofs_read_inode_from_disk(struct erofs_inode *vi)
 		break;
 	case EROFS_INODE_LAYOUT_COMPACT:
 		vi->inode_isize = sizeof(struct erofs_inode_compact);
+		ofs += vi->inode_isize;
 		vi->xattr_isize = erofs_xattr_ibody_size(dic->i_xattr_icount);
 		vi->i_mode = le16_to_cpu(dic->i_mode);
 		vi->i_ino[0] = le32_to_cpu(dic->i_ino);
@@ -96,7 +125,8 @@ int erofs_read_inode_from_disk(struct erofs_inode *vi)
 	default:
 		erofs_err("unsupported on-disk inode version %u of nid %llu",
 			  erofs_inode_version(ifmt), vi->nid | 0ULL);
-		return -EOPNOTSUPP;
+		err = -EOPNOTSUPP;
+		goto err_out;
 	}
 
 	switch (vi->i_mode & S_IFMT) {
@@ -122,7 +152,8 @@ int erofs_read_inode_from_disk(struct erofs_inode *vi)
 	default:
 		erofs_err("bogus i_mode (%o) @ nid %llu", vi->i_mode,
 			  vi->nid | 0ULL);
-		return -EFSCORRUPTED;
+		err = -EFSCORRUPTED;
+		goto err_out;
 	}
 
 	vi->flags = 0;
@@ -132,12 +163,15 @@ int erofs_read_inode_from_disk(struct erofs_inode *vi)
 		if (vi->u.chunkformat & ~EROFS_CHUNK_FORMAT_ALL) {
 			erofs_err("unsupported chunk format %x of nid %llu",
 				  vi->u.chunkformat, vi->nid | 0ULL);
-			return -EOPNOTSUPP;
+			err = -EOPNOTSUPP;
+			goto err_out;
 		}
 		vi->u.chunkbits = sbi->blkszbits +
 			(vi->u.chunkformat & EROFS_CHUNK_FORMAT_BLKBITS_MASK);
 	}
-	return 0;
+err_out:
+	erofs_put_metabuf(&buf);
+	return err;
 }
 
 struct erofs_dirent *find_target_dirent(erofs_nid_t pnid,
-- 
2.43.5



More information about the Linux-erofs mailing list