Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

erofs: handle 48-bit blocks/uniaddr for extra devices

erofs_init_device() only reads blocks_lo and uniaddr_lo from the
on-disk device slot, ignoring blocks_hi and uniaddr_hi that were
introduced alongside the 48-bit block addressing feature.

For the primary device (dif0), erofs_read_superblock() already handles
this correctly by combining blocks_lo with blocks_hi when 48-bit
layout is enabled. But the same logic was not applied to extra
devices.

With a 48-bit EROFS image using extra devices whose uniaddr or blocks
exceed 32-bit range, the truncated values cause erofs_map_dev() to
compute wrong physical addresses, leading to silent data corruption.

Fix this by reading blocks_hi and uniaddr_hi in erofs_init_device()
when 48-bit layout is enabled, consistent with the primary device
handling. Also fix the erofs_deviceslot on-disk definition where
blocks_hi was incorrectly declared as __le32 instead of __le16.

Fixes: 61ba89b57905 ("erofs: add 48-bit block addressing on-disk support")
Suggested-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Signed-off-by: Zhan Xusheng <zhanxusheng@xiaomi.com>
Reviewed-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>

authored by

Zhan Xusheng and committed by
Gao Xiang
63c2f061 d6250d49

+8 -4
+2 -2
fs/erofs/erofs_fs.h
··· 44 44 u8 tag[64]; /* digest(sha256), etc. */ 45 45 __le32 blocks_lo; /* total blocks count of this device */ 46 46 __le32 uniaddr_lo; /* unified starting block of this device */ 47 - __le32 blocks_hi; /* total blocks count MSB */ 47 + __le16 blocks_hi; /* total blocks count MSB */ 48 48 __le16 uniaddr_hi; /* unified starting block MSB */ 49 - u8 reserved[50]; 49 + u8 reserved[52]; 50 50 }; 51 51 #define EROFS_DEVT_SLOT_SIZE sizeof(struct erofs_deviceslot) 52 52
+6 -2
fs/erofs/super.c
··· 129 129 struct erofs_fscache *fscache; 130 130 struct erofs_deviceslot *dis; 131 131 struct file *file; 132 + bool _48bit; 132 133 133 134 dis = erofs_read_metabuf(buf, sb, *pos, false); 134 135 if (IS_ERR(dis)) ··· 176 175 dif->file = file; 177 176 } 178 177 179 - dif->blocks = le32_to_cpu(dis->blocks_lo); 180 - dif->uniaddr = le32_to_cpu(dis->uniaddr_lo); 178 + _48bit = erofs_sb_has_48bit(sbi); 179 + dif->blocks = le32_to_cpu(dis->blocks_lo) | 180 + (_48bit ? (u64)le16_to_cpu(dis->blocks_hi) << 32 : 0); 181 + dif->uniaddr = le32_to_cpu(dis->uniaddr_lo) | 182 + (_48bit ? (u64)le16_to_cpu(dis->uniaddr_hi) << 32 : 0); 181 183 sbi->total_blocks += dif->blocks; 182 184 *pos += EROFS_DEVT_SLOT_SIZE; 183 185 return 0;