mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] ext4: do not accept rec_len 0 for block sizes below 64k
@ 2026-10-06 11:15 hengyul
  2026-10-06 16:16 ` Jan Kara
  2026-10-08  2:38 ` Baokun Li
  0 siblings, 2 replies; 4+ messages in thread
From: hengyul @ 2026-10-06 11:15 UTC (permalink / raw)
  To: tytso, linux-ext4
  Cc: adilger.kernel, libaokun, jack, ojaswin, ritesh.list, yi.zhang,
	linux-kernel, Hengyu Liang, stable

From: Hengyu Liang <hengyul@cs.unc.edu>

Commit afa6d5a16bf2 ("ext4: remove PAGE_SIZE checks for rec_len
conversion") made ext4_rec_len_from_disk() read a rec_len of 0 as "this
entry covers the whole block" for every block size.

However, this special value only exists for block sizes of 64k and
more. With smaller blocks, a rec_len of 0 means that the directory
block is corrupted. As of now, a directory block that has been
overwritten with zeroes is treated as an empty block. The kernel no
longer reports the corruption and can store new entries in that block,
while e2fsck still reports the block as corrupted.

The issue can be reproduced on a file system without metadata_csum:

    mke2fs -q -t ext4 -b 1024 -O ^metadata_csum,^dir_index img 8M
    mount -o loop img /mnt
    mkdir /mnt/d
    for i in $(seq 100); do touch /mnt/d/file_with_a_long_name_$i; done
    umount /mnt
    dd if=/dev/zero of=img bs=1024 count=1 conv=notrunc \
        seek=$(debugfs -R "bmap d 1" img)
    mount -o loop img /mnt
    touch /mnt/d/new

Before commit afa6d5a16bf2 ("ext4: remove PAGE_SIZE checks for rec_len
conversion"), the last command fails with "Structure needs cleaning".
After that commit, it succeeds.

This patch makes ext4_rec_len_from_disk() return the on-disk value
unchanged when the block size is below 64k, as e2fsprogs does.

Fixes: afa6d5a16bf2 ("ext4: remove PAGE_SIZE checks for rec_len conversion")
Cc: stable@vger.kernel.org
Signed-off-by: Hengyu Liang <hengyul@cs.unc.edu>
---
 fs/ext4/ext4.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 724a27e8be61..ab716a5ad6da 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -2611,6 +2611,13 @@ ext4_rec_len_from_disk(__le16 dlen, unsigned blocksize)
 {
 	unsigned len = le16_to_cpu(dlen);
 
+	/*
+	 * Only blocks of 64k and more need the special encoding of rec_len.
+	 * For smaller blocks 0 and EXT4_MAX_REC_LEN are not valid lengths
+	 * and must not be taken for an entry that spans the whole block.
+	 */
+	if (blocksize < 65536)
+		return len;
 	if (len == EXT4_MAX_REC_LEN || len == 0)
 		return blocksize;
 	return (len & 65532) | ((len & 3) << 16);
-- 
2.53.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] ext4: do not accept rec_len 0 for block sizes below 64k
  2026-10-06 11:15 [PATCH] ext4: do not accept rec_len 0 for block sizes below 64k hengyul
@ 2026-10-06 16:16 ` Jan Kara
  2026-10-07  7:43   ` Andreas Dilger
  2026-10-08  2:38 ` Baokun Li
  1 sibling, 1 reply; 4+ messages in thread
From: Jan Kara @ 2026-10-06 16:16 UTC (permalink / raw)
  To: hengyul
  Cc: tytso, linux-ext4, adilger.kernel, libaokun, jack, ojaswin,
	ritesh.list, yi.zhang, linux-kernel, stable

On Tue 06-10-26 07:15:46, hengyul@cs.unc.edu wrote:
> From: Hengyu Liang <hengyul@cs.unc.edu>
> 
> Commit afa6d5a16bf2 ("ext4: remove PAGE_SIZE checks for rec_len
> conversion") made ext4_rec_len_from_disk() read a rec_len of 0 as "this
> entry covers the whole block" for every block size.
> 
> However, this special value only exists for block sizes of 64k and
> more. With smaller blocks, a rec_len of 0 means that the directory
> block is corrupted. As of now, a directory block that has been
> overwritten with zeroes is treated as an empty block. The kernel no
> longer reports the corruption and can store new entries in that block,
> while e2fsck still reports the block as corrupted.
> 
> The issue can be reproduced on a file system without metadata_csum:
> 
>     mke2fs -q -t ext4 -b 1024 -O ^metadata_csum,^dir_index img 8M
>     mount -o loop img /mnt
>     mkdir /mnt/d
>     for i in $(seq 100); do touch /mnt/d/file_with_a_long_name_$i; done
>     umount /mnt
>     dd if=/dev/zero of=img bs=1024 count=1 conv=notrunc \
>         seek=$(debugfs -R "bmap d 1" img)
>     mount -o loop img /mnt
>     touch /mnt/d/new
> 
> Before commit afa6d5a16bf2 ("ext4: remove PAGE_SIZE checks for rec_len
> conversion"), the last command fails with "Structure needs cleaning".
> After that commit, it succeeds.
> 
> This patch makes ext4_rec_len_from_disk() return the on-disk value
> unchanged when the block size is below 64k, as e2fsprogs does.
> 
> Fixes: afa6d5a16bf2 ("ext4: remove PAGE_SIZE checks for rec_len conversion")
> Cc: stable@vger.kernel.org
> Signed-off-by: Hengyu Liang <hengyul@cs.unc.edu>

Makes sense. Feel free to add:

Reviewed-by: Jan Kara <jack@suse.cz>

BTW, the kernel never allowed larger than 64k block size so I'm kind of at
loss why we have that strange code trying to accommodate upto 256k
blocksize here. I'd just delete that code (not really related to your
chnage). Ted?

								Honza

> ---
>  fs/ext4/ext4.h | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
> index 724a27e8be61..ab716a5ad6da 100644
> --- a/fs/ext4/ext4.h
> +++ b/fs/ext4/ext4.h
> @@ -2611,6 +2611,13 @@ ext4_rec_len_from_disk(__le16 dlen, unsigned blocksize)
>  {
>  	unsigned len = le16_to_cpu(dlen);
>  
> +	/*
> +	 * Only blocks of 64k and more need the special encoding of rec_len.
> +	 * For smaller blocks 0 and EXT4_MAX_REC_LEN are not valid lengths
> +	 * and must not be taken for an entry that spans the whole block.
> +	 */
> +	if (blocksize < 65536)
> +		return len;
>  	if (len == EXT4_MAX_REC_LEN || len == 0)
>  		return blocksize;
>  	return (len & 65532) | ((len & 3) << 16);
> -- 
> 2.53.0
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] ext4: do not accept rec_len 0 for block sizes below 64k
  2026-10-06 16:16 ` Jan Kara
@ 2026-10-07  7:43   ` Andreas Dilger
  0 siblings, 0 replies; 4+ messages in thread
From: Andreas Dilger @ 2026-10-07  7:43 UTC (permalink / raw)
  To: Jan Kara
  Cc: hengyul, tytso, linux-ext4, libaokun, ojaswin, ritesh.list,
	yi.zhang, linux-kernel, stable

On Oct 6, 2026, at 10:16, Jan Kara <jack@suse.cz> wrote:
> 
> On Tue 06-10-26 07:15:46, hengyul@cs.unc.edu wrote:
>> From: Hengyu Liang <hengyul@cs.unc.edu>
>> 
>> Commit afa6d5a16bf2 ("ext4: remove PAGE_SIZE checks for rec_len
>> conversion") made ext4_rec_len_from_disk() read a rec_len of 0 as "this
>> entry covers the whole block" for every block size.
>> 
>> However, this special value only exists for block sizes of 64k and
>> more. With smaller blocks, a rec_len of 0 means that the directory
>> block is corrupted. As of now, a directory block that has been
>> overwritten with zeroes is treated as an empty block. The kernel no
>> longer reports the corruption and can store new entries in that block,
>> while e2fsck still reports the block as corrupted.
>> 
>> The issue can be reproduced on a file system without metadata_csum:
>> 
>>    mke2fs -q -t ext4 -b 1024 -O ^metadata_csum,^dir_index img 8M
>>    mount -o loop img /mnt
>>    mkdir /mnt/d
>>    for i in $(seq 100); do touch /mnt/d/file_with_a_long_name_$i; done
>>    umount /mnt
>>    dd if=/dev/zero of=img bs=1024 count=1 conv=notrunc \
>>        seek=$(debugfs -R "bmap d 1" img)
>>    mount -o loop img /mnt
>>    touch /mnt/d/new
>> 
>> Before commit afa6d5a16bf2 ("ext4: remove PAGE_SIZE checks for rec_len
>> conversion"), the last command fails with "Structure needs cleaning".
>> After that commit, it succeeds.
>> 
>> This patch makes ext4_rec_len_from_disk() return the on-disk value
>> unchanged when the block size is below 64k, as e2fsprogs does.
>> 
>> Fixes: afa6d5a16bf2 ("ext4: remove PAGE_SIZE checks for rec_len conversion")
>> Cc: stable@vger.kernel.org
>> Signed-off-by: Hengyu Liang <hengyul@cs.unc.edu>
> 
> Makes sense. Feel free to add:
> 
> Reviewed-by: Jan Kara <jack@suse.cz>
> 
> BTW, the kernel never allowed larger than 64k block size so I'm kind of at
> loss why we have that strange code trying to accommodate upto 256k
> blocksize here. I'd just delete that code (not really related to your
> chnage). Ted?
> 
> Honza
> -- 
> Jan Kara <jack@suse.com>
> SUSE Labs, CR

I think Fujitsu was using 256KiB blocksize on SPARC servers?  Something
like that, but I never saw any patches for it.

Cheers, Andreas






^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] ext4: do not accept rec_len 0 for block sizes below 64k
  2026-10-06 11:15 [PATCH] ext4: do not accept rec_len 0 for block sizes below 64k hengyul
  2026-10-06 16:16 ` Jan Kara
@ 2026-10-08  2:38 ` Baokun Li
  1 sibling, 0 replies; 4+ messages in thread
From: Baokun Li @ 2026-10-08  2:38 UTC (permalink / raw)
  To: hengyul
  Cc: linux-ext4, tytso, adilger.kernel, jack, ojaswin, ritesh.list,
	yi.zhang, linux-kernel, stable

On 2026/10/6 19:15, hengyul@cs.unc.edu wrote:
> From: Hengyu Liang <hengyul@cs.unc.edu>
>
> Commit afa6d5a16bf2 ("ext4: remove PAGE_SIZE checks for rec_len
> conversion") made ext4_rec_len_from_disk() read a rec_len of 0 as "this
> entry covers the whole block" for every block size.
>
> However, this special value only exists for block sizes of 64k and
> more. With smaller blocks, a rec_len of 0 means that the directory
> block is corrupted. As of now, a directory block that has been
> overwritten with zeroes is treated as an empty block. The kernel no
> longer reports the corruption and can store new entries in that block,
> while e2fsck still reports the block as corrupted.
>
> The issue can be reproduced on a file system without metadata_csum:
>
>     mke2fs -q -t ext4 -b 1024 -O ^metadata_csum,^dir_index img 8M
>     mount -o loop img /mnt
>     mkdir /mnt/d
>     for i in $(seq 100); do touch /mnt/d/file_with_a_long_name_$i; done
>     umount /mnt
>     dd if=/dev/zero of=img bs=1024 count=1 conv=notrunc \
>         seek=$(debugfs -R "bmap d 1" img)
>     mount -o loop img /mnt
>     touch /mnt/d/new
>
> Before commit afa6d5a16bf2 ("ext4: remove PAGE_SIZE checks for rec_len
> conversion"), the last command fails with "Structure needs cleaning".
> After that commit, it succeeds.
>
> This patch makes ext4_rec_len_from_disk() return the on-disk value
> unchanged when the block size is below 64k, as e2fsprogs does.
>
> Fixes: afa6d5a16bf2 ("ext4: remove PAGE_SIZE checks for rec_len conversion")
> Cc: stable@vger.kernel.org
> Signed-off-by: Hengyu Liang <hengyul@cs.unc.edu>

Looks good, thanks for the fix!

The extended rec_len encoding is only needed for block sizes >= 64k,
so this matches what e2fsprogs does: ext2fs_get_rec_len() has had the
same "blocksize < 65536" check since commit a4fdf09414e0 ("libext2fs:
Don't use the extended rec_len encoding for standard file systems").

Reviewed-by: Baokun Li <libaokun@linux.alibaba.com>


> ---
>  fs/ext4/ext4.h | 7 +++++++
>  1 file changed, 7 insertions(+)
>
> diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
> index 724a27e8be61..ab716a5ad6da 100644
> --- a/fs/ext4/ext4.h
> +++ b/fs/ext4/ext4.h
> @@ -2611,6 +2611,13 @@ ext4_rec_len_from_disk(__le16 dlen, unsigned blocksize)
>  {
>  	unsigned len = le16_to_cpu(dlen);
>  
> +	/*
> +	 * Only blocks of 64k and more need the special encoding of rec_len.
> +	 * For smaller blocks 0 and EXT4_MAX_REC_LEN are not valid lengths
> +	 * and must not be taken for an entry that spans the whole block.
> +	 */
> +	if (blocksize < 65536)
> +		return len;
>  	if (len == EXT4_MAX_REC_LEN || len == 0)
>  		return blocksize;
>  	return (len & 65532) | ((len & 3) << 16);



^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-10-08  2:43 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-06 11:15 [PATCH] ext4: do not accept rec_len 0 for block sizes below 64k hengyul
2026-10-06 16:16 ` Jan Kara
2026-10-07  7:43   ` Andreas Dilger
2026-10-08  2:38 ` Baokun Li

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®