Re: [PATCH] erofs: handle 48-bit blocks/uniaddr for extra devices

Gao Xiang <[email protected]>
Newsgroups org.ozlabs.lists.linux-erofs,org.kernel.vger.linux-kernel
Message-ID <[email protected]>

On 2026/4/3 11:34, Zhan Xusheng wrote:
> 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.
> 
> Fixes: 61ba89b57905 ("erofs: add 48-bit block addressing on-disk support")
> Signed-off-by: Zhan Xusheng <[email protected]>

Yeah, it seems that part was never implemented,

but could you fix

__le32 blocks_hi; in `struct erofs_deviceslot` to `__le16` as well?

`blocks_hi` shouldn't be `__le32`.

> ---
> Note: erofs-utils also needs corresponding fixes for the write path
> (erofs_mkfs_format_devices) and a swapped hi/lo read in
> erofs_read_superblock, which will be sent separately.
> ---
>   fs/erofs/super.c | 4 ++++
>   1 file changed, 4 insertions(+)
> 
> diff --git a/fs/erofs/super.c b/fs/erofs/super.c
> index 972a0c82198d..a04e70ef4fcc 100644
> --- a/fs/erofs/super.c
> +++ b/fs/erofs/super.c
> @@ -177,6 +177,10 @@ static int erofs_init_device(struct erofs_buf *buf, struct super_block *sb,
>   
>   	dif->blocks = le32_to_cpu(dis->blocks_lo);
>   	dif->uniaddr = le32_to_cpu(dis->uniaddr_lo);
> +	if (erofs_sb_has_48bit(sbi)) {
> +		dif->blocks |= (u64)le32_to_cpu(dis->blocks_hi) << 32;
> +		dif->uniaddr |= (u64)le16_to_cpu(dis->uniaddr_hi) << 32;
> +	}

Maybe just

	bool _48bit = erofs_sb_has_48bit(sbi);

	..

	dif->blocks = le32_to_cpu(dis->blocks_lo) |
		(_48bit ? (u64)le16_to_cpu(dis->blocks_hi) << 32 : 0);
	dif->uniaddr = le32_to_cpu(dis->uniaddr_lo) |
		(_48bit ? (u64)le16_to_cpu(dis->uniaddr_hi) << 32 : 0);

Thanks,
Gao Xiang
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.