[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