[PATCH erofs-utils v2 2/2] erofs-utils: handle 48-bit blocks/uniaddr for extra devices

Zhan Xusheng zhanxusheng1024 at gmail.com
Sat Apr 4 00:05:46 AEDT 2026


erofs_write_device_table() only writes blocks_lo and uniaddr_lo to
the on-disk device slot, but does not write blocks_hi or uniaddr_hi.
Similarly, erofs_init_devices() only reads the _lo fields for extra
devices.

For extra devices whose blocks or uniaddr exceed 32 bits in a 48-bit
EROFS image, the upper bits are silently lost in both read and write
paths.  This is inconsistent with the primary device handling, which
correctly writes blocks_hi (super.c:231) and reads it (super.c:125).

Also sync the erofs_deviceslot on-disk definition with the kernel:
blocks_hi should be __le16 (not __le32), matching the 48-bit design
where all block address high parts are 16-bit.

A corresponding kernel fix has been applied:
  ("erofs: handle 48-bit blocks/uniaddr for extra devices")

Signed-off-by: Zhan Xusheng <zhanxusheng at xiaomi.com>
---
 include/erofs_fs.h |  4 ++--
 lib/super.c        | 10 ++++++++--
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/include/erofs_fs.h b/include/erofs_fs.h
index ff8ac78..5d12049 100644
--- a/include/erofs_fs.h
+++ b/include/erofs_fs.h
@@ -45,9 +45,9 @@ struct erofs_deviceslot {
 	u8 tag[64];		/* digest(sha256), etc. */
 	__le32 blocks_lo;	/* total blocks count of this device */
 	__le32 uniaddr_lo;	/* unified starting block of this device */
-	__le32 blocks_hi;	/* total blocks count MSB */
+	__le16 blocks_hi;	/* total blocks count MSB */
 	__le16 uniaddr_hi;	/* unified starting block MSB */
-	u8 reserved[50];
+	u8 reserved[52];
 };
 #define EROFS_DEVT_SLOT_SIZE	sizeof(struct erofs_deviceslot)
 
diff --git a/lib/super.c b/lib/super.c
index 86d50a1..fd7972c 100644
--- a/lib/super.c
+++ b/lib/super.c
@@ -54,6 +54,8 @@ static int erofs_init_devices(struct erofs_sb_info *sbi,
 	if (!sbi->devs)
 		return -ENOMEM;
 	pos = le16_to_cpu(dsb->devt_slotoff) * EROFS_DEVT_SLOT_SIZE;
+	bool _48bit = erofs_sb_has_48bit(sbi);
+
 	for (i = 0; i < ondisk_extradevs; ++i) {
 		struct erofs_deviceslot dis;
 		int ret;
@@ -65,8 +67,10 @@ static int erofs_init_devices(struct erofs_sb_info *sbi,
 			return ret;
 		}
 
-		sbi->devs[i].uniaddr = le32_to_cpu(dis.uniaddr_lo);
-		sbi->devs[i].blocks = le32_to_cpu(dis.blocks_lo);
+		sbi->devs[i].blocks = le32_to_cpu(dis.blocks_lo) |
+			(_48bit ? (u64)le16_to_cpu(dis.blocks_hi) << 32 : 0);
+		sbi->devs[i].uniaddr = le32_to_cpu(dis.uniaddr_lo) |
+			(_48bit ? (u64)le16_to_cpu(dis.uniaddr_hi) << 32 : 0);
 		memcpy(sbi->devs[i].tag, dis.tag, sizeof(dis.tag));
 		sbi->total_blocks += sbi->devs[i].blocks;
 		pos += EROFS_DEVT_SLOT_SIZE;
@@ -423,6 +427,8 @@ int erofs_write_device_table(struct erofs_sb_info *sbi)
 		struct erofs_deviceslot dis = {
 			.uniaddr_lo = cpu_to_le32(nblocks),
 			.blocks_lo = cpu_to_le32(sbi->devs[i].blocks),
+			.blocks_hi = cpu_to_le16(sbi->devs[i].blocks >> 32),
+			.uniaddr_hi = cpu_to_le16(nblocks >> 32),
 		};
 
 		memcpy(dis.tag, sbi->devs[i].tag, sizeof(dis.tag));
-- 
2.43.0



More information about the Linux-erofs mailing list