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

Zhan Xusheng <[email protected]>
Newsgroups org.ozlabs.lists.linux-erofs
Message-ID <[email protected]>
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 <[email protected]>
---
 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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.