* Re: [PATCH 41/61] pinctrl: Prefer IS_ERR_OR_NULL over manual NULL check
From: Linus Walleij @ 2026-03-11 9:32 UTC (permalink / raw)
To: Philipp Hahn
Cc: amd-gfx, apparmor, bpf, ceph-devel, cocci, dm-devel, dri-devel,
gfs2, intel-gfx, intel-wired-lan, iommu, kvm, linux-arm-kernel,
linux-block, linux-bluetooth, linux-btrfs, linux-cifs, linux-clk,
linux-erofs, linux-ext4, linux-fsdevel, linux-gpio, linux-hyperv,
linux-input, linux-kernel, linux-leds, linux-media, linux-mips,
linux-mm, linux-modules, linux-mtd, linux-nfs, linux-omap,
linux-phy, linux-pm, linux-rockchip, linux-s390, linux-scsi,
linux-sctp, linux-security-module, linux-sh, linux-sound,
linux-stm32, linux-trace-kernel, linux-usb, linux-wireless,
netdev, ntfs3, samba-technical, sched-ext, target-devel,
tipc-discussion, v9fs
In-Reply-To: <20260310-b4-is_err_or_null-v1-41-bd63b656022d@avm.de>
On Tue, Mar 10, 2026 at 12:55 PM Philipp Hahn <phahn-oss@avm.de> wrote:
> Prefer using IS_ERR_OR_NULL() over using IS_ERR() and a manual NULL
> check.
>
> Change generated with coccinelle.
>
> To: Linus Walleij <linusw@kernel.org>
> Cc: linux-gpio@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org
> Signed-off-by: Philipp Hahn <phahn-oss@avm.de>
Patch applied to the pinctrl tree as obviously correct.
Yours,
Linus Walleij
^ permalink raw reply
* Re: [PATCH v4 17/25] xfs: use read ioend for fsverity data verification
From: Andrey Albershteyn @ 2026-03-11 11:40 UTC (permalink / raw)
To: Darrick J. Wong
Cc: Andrey Albershteyn, linux-xfs, fsverity, linux-fsdevel, ebiggers,
hch, linux-ext4, linux-f2fs-devel, linux-btrfs
In-Reply-To: <20260310012105.GE1105363@frogsfrogsfrogs>
On 2026-03-09 18:21:05, Darrick J. Wong wrote:
> >
> > spin_lock_irqsave(&ip->i_ioend_lock, flags);
> > - if (list_empty(&ip->i_ioend_list))
> > - WARN_ON_ONCE(!queue_work(mp->m_unwritten_workqueue,
> > + if (list_empty(&ip->i_ioend_list)) {
> > + if (IS_ENABLED(CONFIG_FS_VERITY) && ioend->io_vi &&
> > + ioend->io_offset < xfs_fsverity_metadata_offset(ip))
> > + fsverity_enqueue_verify_work(&ip->i_ioend_work);
>
> I think the fsverity metadata (merkle tree & descriptor) don't need any
> (read) ioend completion work since all we're doing is reading that into
> the pagecache and eventually fsverity will go look at those contents
> when it wants to verify some actual file data, right?
Yes, metadata don't need any verification. We skip it here and
enqueue only data (this check):
+ ioend->io_offset < xfs_fsverity_metadata_offset(ip))
The metadata goes through normal read path ioend completion.
--
- Andrey
^ permalink raw reply
* Re: [PATCH v4 01/25] fsverity: report validation errors through fserror to fsnotify
From: Andrey Albershteyn @ 2026-03-11 11:47 UTC (permalink / raw)
To: Darrick J. Wong
Cc: Andrey Albershteyn, linux-xfs, fsverity, linux-fsdevel, ebiggers,
hch, linux-ext4, linux-f2fs-devel, linux-btrfs
In-Reply-To: <20260310004627.GV6033@frogsfrogsfrogs>
On 2026-03-09 17:46:27, Darrick J. Wong wrote:
> On Mon, Mar 09, 2026 at 08:23:16PM +0100, Andrey Albershteyn wrote:
> > Reported verification errors to fsnotify through recently added fserror
> > interface.
> >
> > Signed-off-by: Andrey Albershteyn <aalbersh@kernel.org>
> > ---
> > fs/verity/verify.c | 2 ++
> > 1 file changed, 2 insertions(+)
> >
> > diff --git a/fs/verity/verify.c b/fs/verity/verify.c
> > index 4004a1d42875..99276053d3bb 100644
> > --- a/fs/verity/verify.c
> > +++ b/fs/verity/verify.c
> > @@ -9,6 +9,7 @@
> >
> > #include <linux/bio.h>
> > #include <linux/export.h>
> > +#include <linux/fserror.h>
> >
> > #define FS_VERITY_MAX_PENDING_BLOCKS 2
> >
> > @@ -312,6 +313,7 @@ static bool verify_data_block(struct fsverity_info *vi,
> > data_pos, level - 1, params->hash_alg->name, hsize, want_hash,
> > params->hash_alg->name, hsize,
> > level == 0 ? dblock->real_hash : real_hash);
> > + fserror_report_data_lost(inode, data_pos, params->block_size, GFP_NOFS);
>
> Don't we also need to cover the "if (unlikely(data_pos >= inode->i_size))"
> around line 199 in verify_data_block?
make sense, will add it there too
--
- Andrey
^ permalink raw reply
* Re: [PATCH 36/61] arch/sh: Prefer IS_ERR_OR_NULL over manual NULL check
From: Geert Uytterhoeven @ 2026-03-11 13:15 UTC (permalink / raw)
To: Philipp Hahn
Cc: amd-gfx, apparmor, bpf, ceph-devel, cocci, dm-devel, dri-devel,
gfs2, intel-gfx, intel-wired-lan, iommu, kvm, linux-arm-kernel,
linux-block, linux-bluetooth, linux-btrfs, linux-cifs, linux-clk,
linux-erofs, linux-ext4, linux-fsdevel, linux-gpio, linux-hyperv,
linux-input, linux-kernel, linux-leds, linux-media, linux-mips,
linux-mm, linux-modules, linux-mtd, linux-nfs, linux-omap,
linux-phy, linux-pm, linux-rockchip, linux-s390, linux-scsi,
linux-sctp, linux-security-module, linux-sh, linux-sound,
linux-stm32, linux-trace-kernel, linux-usb, linux-wireless,
netdev, ntfs3, samba-technical, sched-ext, target-devel,
tipc-discussion, v9fs, Yoshinori Sato, Rich Felker,
John Paul Adrian Glaubitz
In-Reply-To: <20260310-b4-is_err_or_null-v1-36-bd63b656022d@avm.de>
On Tue, 10 Mar 2026 at 12:56, Philipp Hahn <phahn-oss@avm.de> wrote:
> Prefer using IS_ERR_OR_NULL() over using IS_ERR() and a manual NULL
> check.
>
> Change generated with coccinelle.
>
> To: Yoshinori Sato <ysato@users.sourceforge.jp>
> To: Rich Felker <dalias@libc.org>
> To: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
> Cc: linux-sh@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org
> Signed-off-by: Philipp Hahn <phahn-oss@avm.de>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH 15/61] trace: Prefer IS_ERR_OR_NULL over manual NULL check
From: Steven Rostedt @ 2026-03-11 14:03 UTC (permalink / raw)
To: Masami Hiramatsu (Google)
Cc: Philipp Hahn, amd-gfx, apparmor, bpf, ceph-devel, cocci, dm-devel,
dri-devel, gfs2, intel-gfx, intel-wired-lan, iommu, kvm,
linux-arm-kernel, linux-block, linux-bluetooth, linux-btrfs,
linux-cifs, linux-clk, linux-erofs, linux-ext4, linux-fsdevel,
linux-gpio, linux-hyperv, linux-input, linux-kernel, linux-leds,
linux-media, linux-mips, linux-mm, linux-modules, linux-mtd,
linux-nfs, linux-omap, linux-phy, linux-pm, linux-rockchip,
linux-s390, linux-scsi, linux-sctp, linux-security-module,
linux-sh, linux-sound, linux-stm32, linux-trace-kernel, linux-usb,
linux-wireless, netdev, ntfs3, samba-technical, sched-ext,
target-devel, tipc-discussion, v9fs, Mathieu Desnoyers
In-Reply-To: <20260311141332.b611237d36b61b2409e66cb3@kernel.org>
On Wed, 11 Mar 2026 14:13:32 +0900
Masami Hiramatsu (Google) <mhiramat@kernel.org> wrote:
> Hmm, now IS_ERR_OR_NULL() is an inline function, so it is safe.
> But if you want to use IS_ERR_OR_NULL() here, it will be better something like
>
> node = rhashtable_walk_next(&iter);
> while (!IS_ERR_OR_NULL(node)) {
> fprobe_remove_node_in_module(mod, node, &alist);
> node = rhashtable_walk_next(&iter);
> }
But now you need to have a duplicate code in order to acquire "node"
I think the patch just makes the code worse.
-- Steve
^ permalink raw reply
* [PATCH] Fix default orphan file size calculations
From: Theodore Ts'o @ 2026-03-11 14:11 UTC (permalink / raw)
To: Ext4 Developers List; +Cc: Baokun Li, Theodore Ts'o
Due to missing parenthesis around the #defines for
EXT4_{MAX,DEFAULT}_ORPHAN_FILE_SIZE, the default number of blocks
assigned to the orphan file was calculated as 2 when the file system
has more than 2**21 blocks:
% mke2fs -t ext4 -Fq /tmp/foo.img 8191M
/tmp/foo.img contains a ext4 file system
created on Wed Mar 11 09:54:04 2026
% debugfs -R "extents <12>" /tmp/foo.img
debugfs 1.47.4 (6-Mar-2025)
Level Entries Logical Physical Length Flags
0/ 0 1/ 1 0 - 510 9255 - 9765 511
% mke2fs -t ext4 -Fq /tmp/foo.img 8192M
/tmp/foo.img contains a ext4 file system
created on Wed Mar 11 09:54:11 2026
% debugfs -R "extents <12>" /tmp/foo.img
debugfs 1.47.4 (6-Mar-2025)
Level Entries Logical Physical Length Flags
0/ 0 1/ 1 0 - 1 9255 - 9256 2 <======
In addition, looking at how the defaults was calculated, there were
some unit mismatches where number of blocks was compared with number
of bytes, and number of blocks divided by the blocksize. As a result,
the number of blocks was much larger than before when the file system
blocksize was 1k, and much smaller than when the file system was 64k,
which was a bit surprising.
This caused a libblockdev regression test to fail when it created an
ext4 file system using a 1k blocksize and had a size of 138240k.
Before e2fsprogs 1.47.4, the size of the orphan file was 33k; but in
e2fsprogs 1.47.4, the size of the orphan file became 135k. This
pushed the overhead just over 10%, which triggered the test failure.
So simplify the calculation so that default of the orphan file ranges
from 32 file system blocks and EXT4_DEFAULT_ORPHAN_SIZE, and avoids
the use of the file system blocksize.
Fixes: 6f03c698ef53 ("libext2fs: fix orphan file size > kernel limit with large blocksize")
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
---
lib/ext2fs/ext2fs.h | 4 ++--
lib/ext2fs/orphan.c | 12 ++++++------
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index d9df007c4..92da4d140 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -1819,8 +1819,8 @@ errcode_t ext2fs_set_data_io(ext2_filsys fs, io_channel new_io);
errcode_t ext2fs_rewrite_to_io(ext2_filsys fs, io_channel new_io);
/* orphan.c */
-#define EXT4_MAX_ORPHAN_FILE_SIZE 8 << 20
-#define EXT4_DEFAULT_ORPHAN_FILE_SIZE 2 << 20
+#define EXT4_MAX_ORPHAN_FILE_SIZE (8 << 20)
+#define EXT4_DEFAULT_ORPHAN_FILE_SIZE (2 << 20)
extern errcode_t ext2fs_create_orphan_file(ext2_filsys fs, blk_t num_blocks);
extern errcode_t ext2fs_truncate_orphan_file(ext2_filsys fs);
extern e2_blkcnt_t ext2fs_default_orphan_file_blocks(ext2_filsys fs);
diff --git a/lib/ext2fs/orphan.c b/lib/ext2fs/orphan.c
index 40b1c5c72..b894f2468 100644
--- a/lib/ext2fs/orphan.c
+++ b/lib/ext2fs/orphan.c
@@ -218,18 +218,18 @@ out:
/*
* Find reasonable size for orphan file. We choose orphan file size to be
- * between 32 filesystem blocks and EXT4_DEFAULT_ORPHAN_FILE_SIZE, and not
- * more than 1/fs->blocksize of the filesystem unless it is really small.
+ * between 32 filesystem blocks and EXT4_DEFAULT_ORPHAN_FILE_SIZE.
*/
e2_blkcnt_t ext2fs_default_orphan_file_blocks(ext2_filsys fs)
{
__u64 num_blocks = ext2fs_blocks_count(fs->super);
- e2_blkcnt_t blks = EXT4_DEFAULT_ORPHAN_FILE_SIZE / fs->blocksize;
+ e2_blkcnt_t blks = num_blocks / 4096;
+ e2_blkcnt_t max_blks = EXT4_DEFAULT_ORPHAN_FILE_SIZE / fs->blocksize;
- if (num_blocks < 128 * 1024)
+ if (blks < 32)
blks = 32;
- else if (num_blocks < EXT4_DEFAULT_ORPHAN_FILE_SIZE)
- blks = num_blocks / fs->blocksize;
+ if (blks > max_blks)
+ blks = max_blks;
return (blks + EXT2FS_CLUSTER_MASK(fs)) & ~EXT2FS_CLUSTER_MASK(fs);
}
--
2.51.0
^ permalink raw reply related
* Re: [PATCH 15/61] trace: Prefer IS_ERR_OR_NULL over manual NULL check
From: Geert Uytterhoeven @ 2026-03-11 14:06 UTC (permalink / raw)
To: Steven Rostedt
Cc: Masami Hiramatsu (Google), Philipp Hahn, amd-gfx, apparmor, bpf,
ceph-devel, cocci, dm-devel, dri-devel, gfs2, intel-gfx,
intel-wired-lan, iommu, kvm, linux-arm-kernel, linux-block,
linux-bluetooth, linux-btrfs, linux-cifs, linux-clk, linux-erofs,
linux-ext4, linux-fsdevel, linux-gpio, linux-hyperv, linux-input,
linux-kernel, linux-leds, linux-media, linux-mips, linux-mm,
linux-modules, linux-mtd, linux-nfs, linux-omap, linux-phy,
linux-pm, linux-rockchip, linux-s390, linux-scsi, linux-sctp,
linux-security-module, linux-sh, linux-sound, linux-stm32,
linux-trace-kernel, linux-usb, linux-wireless, netdev, ntfs3,
samba-technical, sched-ext, target-devel, tipc-discussion, v9fs,
Mathieu Desnoyers
In-Reply-To: <20260311100332.6a2ce4b1@gandalf.local.home>
Hi Steven,
On Wed, 11 Mar 2026 at 15:03, Steven Rostedt <rostedt@goodmis.org> wrote:
> On Wed, 11 Mar 2026 14:13:32 +0900
> Masami Hiramatsu (Google) <mhiramat@kernel.org> wrote:
>
> > Hmm, now IS_ERR_OR_NULL() is an inline function, so it is safe.
> > But if you want to use IS_ERR_OR_NULL() here, it will be better something like
> >
> > node = rhashtable_walk_next(&iter);
> > while (!IS_ERR_OR_NULL(node)) {
> > fprobe_remove_node_in_module(mod, node, &alist);
> > node = rhashtable_walk_next(&iter);
> > }
>
> But now you need to have a duplicate code in order to acquire "node"
>
> I think the patch just makes the code worse.
Obviously we need a new for_each_*() helper hiding all the gory internals?
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: BUG: KCSAN: data-race in _copy_to_iter / ext4_generic_delete_entry
From: Theodore Tso @ 2026-03-11 14:40 UTC (permalink / raw)
To: Jianzhou Zhao; +Cc: adilger.kernel, linux-ext4, linux-kernel
In-Reply-To: <6c4b2013.6d16.19cdbecff3e.Coremail.luckd0g@163.com>
On Wed, Mar 11, 2026 at 04:04:28PM +0800, Jianzhou Zhao wrote:
> Subject: [BUG] ext4: KCSAN: data-race in _copy_to_iter / ext4_generic_delete_entry
>
> Dear Maintainers,
>
> We are writing to report a KCSAN-detected data race vulnerability
> within `ext4` and the block device layer. This bug was found by our
> custom fuzzing tool, RacePilot. The race occurs when
> `ext4_generic_delete_entry` modifies the `rec_len` of a previous
> directory entry (via a 2-byte write) during a path unlink operation,
> while a concurrent thread directly accesses the raw block device of
> the mounted filesystem (via `read()`), executing `_copy_to_iter()`
> which blindly bulk-reads the buffer underlying the filesystem page
> cache. We observed this bug on the Linux kernel version
> 6.18.0-08691-g2061f18ad76e-dirty.
Any attempts to read from a block device while it is mounted is
subject to arbitrary race conditions; there is no guarantee that the
file system contents accessed by userspace is going to be consistent.
In fact, it's practically guaranteed that it will not be consistent.
So this is considered NOTABUG.
- Ted
^ permalink raw reply
* Re: [PATCH] Fix default orphan file size calculations
From: Andreas Dilger @ 2026-03-11 15:01 UTC (permalink / raw)
To: Theodore Ts'o; +Cc: Ext4 Developers List, Baokun Li
In-Reply-To: <20260311141150.120724-1-tytso@mit.edu>
On Mar 11, 2026, at 08:11, Theodore Ts'o <tytso@mit.edu> wrote:
>
> Due to missing parenthesis around the #defines for
> EXT4_{MAX,DEFAULT}_ORPHAN_FILE_SIZE, the default number of blocks
> assigned to the orphan file was calculated as 2 when the file system
> has more than 2**21 blocks:
>
> % mke2fs -t ext4 -Fq /tmp/foo.img 8191M
> /tmp/foo.img contains a ext4 file system
> created on Wed Mar 11 09:54:04 2026
> % debugfs -R "extents <12>" /tmp/foo.img
> debugfs 1.47.4 (6-Mar-2025)
> Level Entries Logical Physical Length Flags
> 0/ 0 1/ 1 0 - 510 9255 - 9765 511
>
> % mke2fs -t ext4 -Fq /tmp/foo.img 8192M
> /tmp/foo.img contains a ext4 file system
> created on Wed Mar 11 09:54:11 2026
> % debugfs -R "extents <12>" /tmp/foo.img
> debugfs 1.47.4 (6-Mar-2025)
> Level Entries Logical Physical Length Flags
> 0/ 0 1/ 1 0 - 1 9255 - 9256 2 <======
>
> In addition, looking at how the defaults was calculated, there were
> some unit mismatches where number of blocks was compared with number
> of bytes, and number of blocks divided by the blocksize. As a result,
> the number of blocks was much larger than before when the file system
> blocksize was 1k, and much smaller than when the file system was 64k,
> which was a bit surprising.
>
> This caused a libblockdev regression test to fail when it created an
> ext4 file system using a 1k blocksize and had a size of 138240k.
> Before e2fsprogs 1.47.4, the size of the orphan file was 33k; but in
> e2fsprogs 1.47.4, the size of the orphan file became 135k. This
> pushed the overhead just over 10%, which triggered the test failure.
>
> So simplify the calculation so that default of the orphan file ranges
> from 32 file system blocks and EXT4_DEFAULT_ORPHAN_SIZE, and avoids
> the use of the file system blocksize.
>
> Fixes: 6f03c698ef53 ("libext2fs: fix orphan file size > kernel limit with large blocksize")
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> ---
> lib/ext2fs/ext2fs.h | 4 ++--
> lib/ext2fs/orphan.c | 12 ++++++------
> 2 files changed, 8 insertions(+), 8 deletions(-)
>
> diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
> index d9df007c4..92da4d140 100644
> --- a/lib/ext2fs/ext2fs.h
> +++ b/lib/ext2fs/ext2fs.h
> @@ -1819,8 +1819,8 @@ errcode_t ext2fs_set_data_io(ext2_filsys fs, io_channel new_io);
> errcode_t ext2fs_rewrite_to_io(ext2_filsys fs, io_channel new_io);
>
> /* orphan.c */
> -#define EXT4_MAX_ORPHAN_FILE_SIZE 8 << 20
> -#define EXT4_DEFAULT_ORPHAN_FILE_SIZE 2 << 20
> +#define EXT4_MAX_ORPHAN_FILE_SIZE (8 << 20)
> +#define EXT4_DEFAULT_ORPHAN_FILE_SIZE (2 << 20)
Some of the issues here would be avoided with better variable naming,
like "EXT4_MAX_ORPHAN_FILE_BYTES" and "EXT4_DEFAULT_ORPHAN_FILE_BYTES"
rather than "size", which is a bit ambiguous.
Cheers, Andreas
^ permalink raw reply
* Re: [PATCH 01/61] Coccinelle: Prefer IS_ERR_OR_NULL over manual NULL check
From: Markus Elfring @ 2026-03-11 15:12 UTC (permalink / raw)
To: Philipp Hahn, cocci, Julia Lawall, Nicolas Palix
Cc: amd-gfx, apparmor, bpf, ceph-devel, dm-devel, dri-devel, gfs2,
intel-gfx, intel-wired-lan, iommu, kvm, linux-arm-kernel,
linux-block, linux-bluetooth, linux-btrfs, linux-cifs, linux-clk,
linux-erofs, linux-ext4, linux-fsdevel, linux-gpio, linux-hyperv,
linux-input, linux-leds, linux-media, linux-mips, linux-mm,
linux-modules, linux-mtd, linux-nfs, linux-omap, linux-phy,
linux-pm, linux-rockchip, linux-s390, linux-scsi, linux-sctp,
linux-security-module, linux-sh, linux-sound, linux-stm32,
linux-trace-kernel, linux-usb, linux-wireless, netdev, ntfs3,
samba-technical, sched-ext, target-devel, tipc-discussion, v9fs,
LKML
In-Reply-To: <20260310-b4-is_err_or_null-v1-1-bd63b656022d@avm.de>
…
> +// Confidence: High
Some contributors presented discerning comments for this change approach.
Thus I became also curious how much they can eventually be taken better into account
by the means of the semantic patch language (Coccinelle software).
…
+@p1 depends on patch@
+expression E;
+@@
+(
> +- E != NULL && !IS_ERR(E)
> ++ !IS_ERR_OR_NULL(E)
> +|
> +- E == NULL || IS_ERR(E)
> ++ IS_ERR_OR_NULL(E)
> +|
> +- !IS_ERR(E) && E != NULL
> ++ !IS_ERR_OR_NULL(E)
> +|
> +- IS_ERR(E) || E == NULL
> ++ IS_ERR_OR_NULL(E)
> +)
Several detected expressions should refer to return values from function calls.
https://en.wikipedia.org/wiki/Return_statement
* Do any development challenges hinder still the determination of corresponding
failure predicates?
* How will interests evolve to improve data processing any further for such
use cases?
Regards,
Markus
^ permalink raw reply
* Re: [PATCH] Fix default orphan file size calculations
From: Baokun Li @ 2026-03-11 16:27 UTC (permalink / raw)
To: Theodore Ts'o; +Cc: Ext4 Developers List, libaokun
In-Reply-To: <20260311141150.120724-1-tytso@mit.edu>
On 3/11/26 10:11 PM, Theodore Ts'o wrote:
> Due to missing parenthesis around the #defines for
> EXT4_{MAX,DEFAULT}_ORPHAN_FILE_SIZE, the default number of blocks
> assigned to the orphan file was calculated as 2 when the file system
> has more than 2**21 blocks:
>
> % mke2fs -t ext4 -Fq /tmp/foo.img 8191M
> /tmp/foo.img contains a ext4 file system
> created on Wed Mar 11 09:54:04 2026
> % debugfs -R "extents <12>" /tmp/foo.img
> debugfs 1.47.4 (6-Mar-2025)
> Level Entries Logical Physical Length Flags
> 0/ 0 1/ 1 0 - 510 9255 - 9765 511
>
> % mke2fs -t ext4 -Fq /tmp/foo.img 8192M
> /tmp/foo.img contains a ext4 file system
> created on Wed Mar 11 09:54:11 2026
> % debugfs -R "extents <12>" /tmp/foo.img
> debugfs 1.47.4 (6-Mar-2025)
> Level Entries Logical Physical Length Flags
> 0/ 0 1/ 1 0 - 1 9255 - 9256 2 <======
>
> In addition, looking at how the defaults was calculated, there were
> some unit mismatches where number of blocks was compared with number
> of bytes, and number of blocks divided by the blocksize. As a result,
> the number of blocks was much larger than before when the file system
> blocksize was 1k, and much smaller than when the file system was 64k,
> which was a bit surprising.
>
> This caused a libblockdev regression test to fail when it created an
> ext4 file system using a 1k blocksize and had a size of 138240k.
> Before e2fsprogs 1.47.4, the size of the orphan file was 33k; but in
> e2fsprogs 1.47.4, the size of the orphan file became 135k. This
> pushed the overhead just over 10%, which triggered the test failure.
>
> So simplify the calculation so that default of the orphan file ranges
> from 32 file system blocks and EXT4_DEFAULT_ORPHAN_SIZE, and avoids
> the use of the file system blocksize.
>
> Fixes: 6f03c698ef53 ("libext2fs: fix orphan file size > kernel limit with large blocksize")
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> ---
Hi Ted,
I’m very sorry for introducing this issue.
In fact, the patch that introduced it was not the latest version —
there was a later v3 that is consistent with the upstream kernel:
https://lore.kernel.org/linux-ext4/20251120135514.3013973-1-libaokun@huaweicloud.com/
I noticed the wrong version had been applied and sent you a private email
at the time, but it seems that message fell through the cracks. I then got
caught up with other things and unfortunately lost track of this as well.
My apologies.
Would it be possible to revert the patch that introduced the issue and
apply the v3 version instead? Alternatively, I can send a new patch that
includes both the revert and the v3 changes.
Thanks,
Baokun
> lib/ext2fs/ext2fs.h | 4 ++--
> lib/ext2fs/orphan.c | 12 ++++++------
> 2 files changed, 8 insertions(+), 8 deletions(-)
>
> diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
> index d9df007c4..92da4d140 100644
> --- a/lib/ext2fs/ext2fs.h
> +++ b/lib/ext2fs/ext2fs.h
> @@ -1819,8 +1819,8 @@ errcode_t ext2fs_set_data_io(ext2_filsys fs, io_channel new_io);
> errcode_t ext2fs_rewrite_to_io(ext2_filsys fs, io_channel new_io);
>
> /* orphan.c */
> -#define EXT4_MAX_ORPHAN_FILE_SIZE 8 << 20
> -#define EXT4_DEFAULT_ORPHAN_FILE_SIZE 2 << 20
> +#define EXT4_MAX_ORPHAN_FILE_SIZE (8 << 20)
> +#define EXT4_DEFAULT_ORPHAN_FILE_SIZE (2 << 20)
> extern errcode_t ext2fs_create_orphan_file(ext2_filsys fs, blk_t num_blocks);
> extern errcode_t ext2fs_truncate_orphan_file(ext2_filsys fs);
> extern e2_blkcnt_t ext2fs_default_orphan_file_blocks(ext2_filsys fs);
> diff --git a/lib/ext2fs/orphan.c b/lib/ext2fs/orphan.c
> index 40b1c5c72..b894f2468 100644
> --- a/lib/ext2fs/orphan.c
> +++ b/lib/ext2fs/orphan.c
> @@ -218,18 +218,18 @@ out:
>
> /*
> * Find reasonable size for orphan file. We choose orphan file size to be
> - * between 32 filesystem blocks and EXT4_DEFAULT_ORPHAN_FILE_SIZE, and not
> - * more than 1/fs->blocksize of the filesystem unless it is really small.
> + * between 32 filesystem blocks and EXT4_DEFAULT_ORPHAN_FILE_SIZE.
> */
> e2_blkcnt_t ext2fs_default_orphan_file_blocks(ext2_filsys fs)
> {
> __u64 num_blocks = ext2fs_blocks_count(fs->super);
> - e2_blkcnt_t blks = EXT4_DEFAULT_ORPHAN_FILE_SIZE / fs->blocksize;
> + e2_blkcnt_t blks = num_blocks / 4096;
> + e2_blkcnt_t max_blks = EXT4_DEFAULT_ORPHAN_FILE_SIZE / fs->blocksize;
>
> - if (num_blocks < 128 * 1024)
> + if (blks < 32)
> blks = 32;
> - else if (num_blocks < EXT4_DEFAULT_ORPHAN_FILE_SIZE)
> - blks = num_blocks / fs->blocksize;
> + if (blks > max_blks)
> + blks = max_blks;
> return (blks + EXT2FS_CLUSTER_MASK(fs)) & ~EXT2FS_CLUSTER_MASK(fs);
> }
>
^ permalink raw reply
* Re: [PATCH] Fix default orphan file size calculations
From: Theodore Tso @ 2026-03-11 17:27 UTC (permalink / raw)
To: Baokun Li; +Cc: Ext4 Developers List
In-Reply-To: <d4d64000-6b55-449e-83bb-be438aaa5146@linux.alibaba.com>
On Thu, Mar 12, 2026 at 12:27:07AM +0800, Baokun Li wrote:
>
> In fact, the patch that introduced it was not the latest version —
> there was a later v3 that is consistent with the upstream kernel:
Hmm, I wonder why b4 didn't pick up the newer version of the patch.
Maybe I screwed up and missed the -c option to "b4 am -c".
The main difference between my proposed fix and your v3 patch is that
if the user doesn't specify an explicit orphan file size, with the v3
patch, it might max out to 8MB when the block size is 64k. With my
fix, it will max out to 2MB in those situations. The user can
explicitly specify a orphan file size as 8MB, but it makes the default
to be 2MB.
In retrospect, I think we went wrong when we capped the orphan file in
terms of bytes instead of blocks in the kernel. When the block size
is 64k, 8MB is only 32 blocks. When the block size is 4k, the orphan
file size can be up to 512 blocks. And the scalability is really a
function of the number of blocks, not the number of bytes, since with
the orphan file, we use a hash that maps the cpu number to a logical
block number in orphan size.
Now, most of the time, I suspect 32 blocks is plenty most of the time,
since it's unlikely we'll have that many running processes trying to
truncate files or something else that requires adding the inode to the
oprhan file.
So I thought about just using a default orphan inode size of 32 file
system blocks. I also thought about changing the kernel to allow size
of the orphan file to be say, up to 256 blocks. And also maybe
allowing mke2fs and tune2fs to accept an extended options
orphan_file_blocks which takes an argument denominated in blocks.
Ultimately, though, *most* of the time, consuming 512MB on the orphan
file inode if the file system is say, 2TB. So I decided it wasn't
worth the effort to change how things worked. But if we were starting
from scratch, I think we would have been better of doing things in
terms of blocks, instead of bytes.
But maybe we should go and make that change. What do folks think?
- Ted
^ permalink raw reply
* Re: [PATCH 49/61] media: Prefer IS_ERR_OR_NULL over manual NULL check
From: Kieran Bingham @ 2026-03-11 23:03 UTC (permalink / raw)
To: Philipp Hahn, amd-gfx, apparmor, bpf, ceph-devel, cocci, dm-devel,
dri-devel, gfs2, intel-gfx, intel-wired-lan, iommu, kvm,
linux-arm-kernel, linux-block, linux-bluetooth, linux-btrfs,
linux-cifs, linux-clk, linux-erofs, linux-ext4, linux-fsdevel,
linux-gpio, linux-hyperv, linux-input, linux-kernel, linux-leds,
linux-media, linux-mips, linux-mm, linux-modules, linux-mtd,
linux-nfs, linux-omap, linux-phy, lin
Cc: Shuah Khan, Mauro Carvalho Chehab
In-Reply-To: <20260310-b4-is_err_or_null-v1-49-bd63b656022d@avm.de>
Quoting Philipp Hahn (2026-03-10 11:49:15)
> Prefer using IS_ERR_OR_NULL() over using IS_ERR() and a manual NULL
> check.
>
> Change generated with coccinelle.
>
> To: Shuah Khan <skhan@linuxfoundation.org>
> To: Kieran Bingham <kieran.bingham@ideasonboard.com>
> To: Mauro Carvalho Chehab <mchehab@kernel.org>
> Cc: linux-media@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org
> Signed-off-by: Philipp Hahn <phahn-oss@avm.de>
> ---
> drivers/media/test-drivers/vimc/vimc-streamer.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/media/test-drivers/vimc/vimc-streamer.c b/drivers/media/test-drivers/vimc/vimc-streamer.c
> index 15d863f97cbf96b7ca7fbf3d7b6b6ec39fcc8ae3..da5aca50bcb4990c06f28e5a883eb398606991e9 100644
> --- a/drivers/media/test-drivers/vimc/vimc-streamer.c
> +++ b/drivers/media/test-drivers/vimc/vimc-streamer.c
> @@ -167,7 +167,7 @@ static int vimc_streamer_thread(void *data)
> for (i = stream->pipe_size - 1; i >= 0; i--) {
> frame = stream->ved_pipeline[i]->process_frame(
> stream->ved_pipeline[i], frame);
> - if (!frame || IS_ERR(frame))
> + if (IS_ERR_OR_NULL(frame))
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> break;
> }
> //wait for 60hz
>
> --
> 2.43.0
>
^ permalink raw reply
* Re: [PATCH] Fix default orphan file size calculations
From: Baokun Li @ 2026-03-12 4:58 UTC (permalink / raw)
To: Theodore Tso; +Cc: Ext4 Developers List, libaokun
In-Reply-To: <20260311172755.GA74864@macsyma-wired.lan>
Hi Ted,
On 3/12/26 1:27 AM, Theodore Tso wrote:
> On Thu, Mar 12, 2026 at 12:27:07AM +0800, Baokun Li wrote:
>> In fact, the patch that introduced it was not the latest version —
>> there was a later v3 that is consistent with the upstream kernel:
> Hmm, I wonder why b4 didn't pick up the newer version of the patch.
> Maybe I screwed up and missed the -c option to "b4 am -c".
>
> The main difference between my proposed fix and your v3 patch is that
> if the user doesn't specify an explicit orphan file size, with the v3
> patch, it might max out to 8MB when the block size is 64k. With my
> fix, it will max out to 2MB in those situations. The user can
> explicitly specify a orphan file size as 8MB, but it makes the default
> to be 2MB.
Yes, but if we cap the maximum size at 8 MB, then the maximum orphan file
created with the previous default settings would be 512 blocks. On 64 KB
page-size systems, older mkfs versions could create a 64 KB-block ext4 fs
with a 32 MB orphan file, so that would break forward compatibility.
This is also why kernel commit 7c11c56eb32e ("ext4: align max orphan file
size with e2fsprogs limit") changed the limit to 512 blocks instead.
That at least preserves compatibility for filesystems created with the
default mkfs options.
>
> In retrospect, I think we went wrong when we capped the orphan file in
> terms of bytes instead of blocks in the kernel. When the block size
> is 64k, 8MB is only 32 blocks. When the block size is 4k, the orphan
> file size can be up to 512 blocks. And the scalability is really a
> function of the number of blocks, not the number of bytes, since with
> the orphan file, we use a hash that maps the cpu number to a logical
> block number in orphan size.
Yes, limiting it by the number of blocks is simpler, and that is exactly
what kernel commit 7c11c56eb32e does.
>
> Now, most of the time, I suspect 32 blocks is plenty most of the time,
> since it's unlikely we'll have that many running processes trying to
> truncate files or something else that requires adding the inode to the
> oprhan file.
>
> So I thought about just using a default orphan inode size of 32 file
> system blocks. I also thought about changing the kernel to allow size
> of the orphan file to be say, up to 256 blocks. And also maybe
> allowing mke2fs and tune2fs to accept an extended options
> orphan_file_blocks which takes an argument denominated in blocks.
>
> Ultimately, though, *most* of the time, consuming 512MB on the orphan
> file inode if the file system is say, 2TB. So I decided it wasn't
> worth the effort to change how things worked. But if we were starting
> from scratch, I think we would have been better of doing things in
> terms of blocks, instead of bytes.
>
> But maybe we should go and make that change. What do folks think?
>
I’d prefer reverting e2fsprogs commit 6f03c698ef53 and taking v3 instead.
It looks like the simplest fix for now, and it should still preserve some
compatibility.
Regards,
Baokun
^ permalink raw reply
* Re: [PATCH e2fsprogs] lib/quota: fix checksum mismatch on uninitialized PRJQUOTA inode
From: Baokun Li @ 2026-03-12 6:26 UTC (permalink / raw)
To: tytso; +Cc: adilger.kernel, jack, linux-ext4, libaokun
In-Reply-To: <20251210081558.2714709-1-libaokun@huaweicloud.com>
A gentle ping...
On 12/10/25 4:15 PM, libaokun@huaweicloud.com wrote:
> From: Baokun Li <libaokun1@huawei.com>
>
> In quota_inode_init_new(), we attempt to read and truncate an existing
> quota inode before proceeding with its initialization.
>
> This read operation verifies the inode's checksum. This works fine for
> USRQUOTA and GRPQUOTA inodes because write_reserved_inodes() is always
> called during ext4 image creation to set appropriate checksums for these
> reserved inodes.
>
> However, the PRJQUOTA inode is not reserved, and its corresponding inode
> table block may not have been zeroed, potentially containing stale data.
> Consequently, reading this inode can fail due to a checksum mismatch.
>
> This can be reproduced by running the following sequence:
>
> dd if=/dev/random of=$DISK bs=1M count=128
> mkfs.ext4 -F -q -b 1024 $DISK 5G
> tune2fs -O quota,project $DISK
>
> Which results in the following error output:
>
> tune2fs 1.47.3 (8-Jul-2025)
> [ERROR] quotaio.c:279:quota_inode_init_new: ex2fs_read_inode failed
> [ERROR] quotaio.c:341:quota_file_create: init_new_quota_inode failed
> tune2fs: Inode checksum does not match inode while writing quota file (2)
>
> While running `kvm-xfstests -c ext4/1k -C 1 generic/383`, the test itself
> does not fail, but checksum verification failures are reported even
> without fault injection, which led to discovering this issue.
>
> To fix this, we stop attempting to read the quota inode that is about
> to be initialized inside quota_inode_init_new(). Instead, the logic
> to attempt truncation of an existing quota inode is moved to be handled
> inside quota_file_create().
>
> Fixes: 080e09b4 ("Add project quota support")
> Signed-off-by: Baokun Li <libaokun1@huawei.com>
> ---
> lib/support/quotaio.c | 30 +++++++++++++-----------------
> 1 file changed, 13 insertions(+), 17 deletions(-)
>
> diff --git a/lib/support/quotaio.c b/lib/support/quotaio.c
> index f5f2c7f7..827df85b 100644
> --- a/lib/support/quotaio.c
> +++ b/lib/support/quotaio.c
> @@ -274,18 +274,6 @@ static errcode_t quota_inode_init_new(ext2_filsys fs, ext2_ino_t ino)
> errcode_t err = 0;
> time_t now;
>
> - err = ext2fs_read_inode(fs, ino, &inode);
> - if (err) {
> - log_err("ex2fs_read_inode failed");
> - return err;
> - }
> -
> - if (EXT2_I_SIZE(&inode)) {
> - err = quota_inode_truncate(fs, ino);
> - if (err)
> - return err;
> - }
> -
> memset(&inode, 0, sizeof(struct ext2_inode));
> ext2fs_iblk_set(fs, &inode, 0);
> now = fs->now ? fs->now : time(0);
> @@ -319,6 +307,10 @@ errcode_t quota_file_create(struct quota_handle *h, ext2_filsys fs,
> if (fmt == -1)
> fmt = QFMT_VFS_V1;
>
> + err = ext2fs_read_bitmaps(fs);
> + if (err)
> + goto out_err;
> +
> h->qh_qf.fs = fs;
> qf_inum = quota_type2inum(qtype, fs->super);
> if (qf_inum == 0 && qtype == PRJQUOTA) {
> @@ -330,15 +322,19 @@ errcode_t quota_file_create(struct quota_handle *h, ext2_filsys fs,
> ext2fs_mark_ib_dirty(fs);
> } else if (qf_inum == 0) {
> return EXT2_ET_BAD_INODE_NUM;
> + } else {
> + err = quota_inode_truncate(fs, qf_inum);
> + if (err) {
> + log_err("quota_inode_truncate failed, ino=%u, type=%d",
> + qf_inum, qtype);
> + return err;
> + }
> }
>
> - err = ext2fs_read_bitmaps(fs);
> - if (err)
> - goto out_err;
> -
> err = quota_inode_init_new(fs, qf_inum);
> if (err) {
> - log_err("init_new_quota_inode failed");
> + log_err("init_new_quota_inode failed, ino=%u, type=%d",
> + qf_inum, qtype);
> goto out_err;
> }
> h->qh_qf.ino = qf_inum;
^ permalink raw reply
* Re: [PATCH 00/61] treewide: Use IS_ERR_OR_NULL over manual NULL check - refactor
From: Jason Gunthorpe @ 2026-03-12 12:57 UTC (permalink / raw)
To: Kuan-Wei Chiu
Cc: Philipp Hahn, amd-gfx, apparmor, bpf, ceph-devel, cocci, dm-devel,
dri-devel, gfs2, intel-gfx, intel-wired-lan, iommu, kvm,
linux-arm-kernel, linux-block, linux-bluetooth, linux-btrfs,
linux-cifs, linux-clk, linux-erofs, linux-ext4, linux-fsdevel,
linux-gpio, linux-hyperv, linux-input, linux-kernel, linux-leds,
linux-media, linux-mips, linux-mm, linux-modules, linux-mtd,
linux-nfs, linux-omap, linux-phy, linux-pm, linux-rockchip,
linux-s390, linux-scsi, linux-sctp, linux-security-module,
linux-sh, linux-sound, linux-stm32, linux-trace-kernel, linux-usb,
linux-wireless, netdev, ntfs3, samba-technical, sched-ext,
target-devel, tipc-discussion, v9fs
In-Reply-To: <abBlpGKO842B3yl9@google.com>
On Wed, Mar 11, 2026 at 02:40:36AM +0800, Kuan-Wei Chiu wrote:
> IMHO, the necessity of IS_ERR_OR_NULL() often highlights a confusing or
> flawed API design. It usually implies that the caller is unsure whether
> a failure results in an error pointer or a NULL pointer.
+1
IS_ERR_OR_NULL() should always be looked on with suspicion. Very
little should be returning some tri-state 'ERR' 'NULL' 'SUCCESS'
pointer. What does the middle condition even mean? IS_ERR_OR_NULL()
implies ERR and NULL are semanticly the same, so fix the things to
always use ERR.
If you want to improve things work to get rid of the NULL checks this
script identifies. Remove ERR or NULL because only one can ever
happen, or fix the source to consistently return ERR.
Jason
^ permalink raw reply
* [PATCH v2 7/8] ext4: fix possible null-ptr-deref in extents_kunit_exit()
From: Ye Bin @ 2026-03-12 13:12 UTC (permalink / raw)
To: tytso, adilger.kernel, linux-ext4; +Cc: jack
In-Reply-To: <20260312131253.366296-1-yebin@huaweicloud.com>
From: Ye Bin <yebin10@huawei.com>
There's issue as follows:
KASAN: null-ptr-deref in range [0x00000000000002c0-0x00000000000002c7]
Tainted: [E]=UNSIGNED_MODULE, [N]=TEST
RIP: 0010:extents_kunit_exit+0x2e/0xc0 [ext4_test]
Call Trace:
<TASK>
kunit_try_run_case_cleanup+0xbc/0x100 [kunit]
kunit_generic_run_threadfn_adapter+0x89/0x100 [kunit]
kthread+0x408/0x540
ret_from_fork+0xa76/0xdf0
ret_from_fork_asm+0x1a/0x30
Above issue happens as extents_kunit_init() init testcase failed.
So test if testcase is inited success.
Fixes: cb1e0c1d1fad ("ext4: kunit tests for extent splitting and conversion")
Signed-off-by: Ye Bin <yebin10@huawei.com>
---
fs/ext4/extents-test.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/fs/ext4/extents-test.c b/fs/ext4/extents-test.c
index 7e2796f72d45..b1ea37e74f12 100644
--- a/fs/ext4/extents-test.c
+++ b/fs/ext4/extents-test.c
@@ -142,8 +142,12 @@ static struct file_system_type ext_fs_type = {
static void extents_kunit_exit(struct kunit *test)
{
- struct ext4_sb_info *sbi = k_ctx.k_ei->vfs_inode.i_sb->s_fs_info;
+ struct ext4_sb_info *sbi;
+ if (!k_ctx.k_ei)
+ return;
+
+ sbi = k_ctx.k_ei->vfs_inode.i_sb->s_fs_info;
deactivate_super(sbi->s_sb);
kfree(k_ctx.k_ei);
kfree(k_ctx.k_data);
--
2.34.1
^ permalink raw reply related
* [PATCH v2 3/8] ext4: fix extents-test.c is not compiled when EXT4_KUNIT_TESTS=M
From: Ye Bin @ 2026-03-12 13:12 UTC (permalink / raw)
To: tytso, adilger.kernel, linux-ext4; +Cc: jack
In-Reply-To: <20260312131253.366296-1-yebin@huaweicloud.com>
From: Ye Bin <yebin10@huawei.com>
Now, only EXT4_KUNIT_TESTS=Y testcase will be compiled in 'extents.c'.
To solve this issue, the ext4 test code needs to be decoupled. The
'extents-test' module is compiled into 'ext4-test' module.
Fixes: cb1e0c1d1fad ("ext4: kunit tests for extent splitting and conversion")
Signed-off-by: Ye Bin <yebin10@huawei.com>
---
fs/ext4/Makefile | 3 ++-
fs/ext4/ext4_extents.h | 12 ++++++++++++
fs/ext4/extents-test.c | 8 ++++----
fs/ext4/extents.c | 38 ++++++++++++++++++++++++++++++++------
4 files changed, 50 insertions(+), 11 deletions(-)
diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile
index d836c3fe311b..3baee4e7c1cf 100644
--- a/fs/ext4/Makefile
+++ b/fs/ext4/Makefile
@@ -14,7 +14,8 @@ ext4-y := balloc.o bitmap.o block_validity.o dir.o ext4_jbd2.o extents.o \
ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o
ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o
-ext4-test-objs += inode-test.o mballoc-test.o
+ext4-test-objs += inode-test.o mballoc-test.o \
+ extents-test.o
obj-$(CONFIG_EXT4_KUNIT_TESTS) += ext4-test.o
ext4-$(CONFIG_FS_VERITY) += verity.o
ext4-$(CONFIG_FS_ENCRYPTION) += crypto.o
diff --git a/fs/ext4/ext4_extents.h b/fs/ext4/ext4_extents.h
index c484125d963f..ebaf7cc42430 100644
--- a/fs/ext4/ext4_extents.h
+++ b/fs/ext4/ext4_extents.h
@@ -264,5 +264,17 @@ static inline void ext4_idx_store_pblock(struct ext4_extent_idx *ix,
0xffff);
}
+extern int __ext4_ext_dirty(const char *where, unsigned int line,
+ handle_t *handle, struct inode *inode,
+ struct ext4_ext_path *path);
+extern int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex);
+#if IS_ENABLED(CONFIG_EXT4_KUNIT_TESTS)
+extern int ext4_ext_space_root_idx_test(struct inode *inode, int check);
+extern struct ext4_ext_path *ext4_split_convert_extents_test(
+ handle_t *handle, struct inode *inode,
+ struct ext4_map_blocks *map,
+ struct ext4_ext_path *path,
+ int flags, unsigned int *allocated);
+#endif
#endif /* _EXT4_EXTENTS */
diff --git a/fs/ext4/extents-test.c b/fs/ext4/extents-test.c
index 7c4690eb7dad..9e055f399167 100644
--- a/fs/ext4/extents-test.c
+++ b/fs/ext4/extents-test.c
@@ -280,8 +280,8 @@ static int extents_kunit_init(struct kunit *test)
eh->eh_depth = 0;
eh->eh_entries = cpu_to_le16(1);
eh->eh_magic = EXT4_EXT_MAGIC;
- eh->eh_max =
- cpu_to_le16(ext4_ext_space_root_idx(&k_ctx.k_ei->vfs_inode, 0));
+ eh->eh_max = cpu_to_le16(ext4_ext_space_root_idx_test(
+ &k_ctx.k_ei->vfs_inode, 0));
eh->eh_generation = 0;
/*
@@ -384,8 +384,8 @@ static void test_split_convert(struct kunit *test)
switch (param->type) {
case TEST_SPLIT_CONVERT:
- path = ext4_split_convert_extents(NULL, inode, &map, path,
- param->split_flags, NULL);
+ path = ext4_split_convert_extents_test(NULL, inode, &map,
+ path, param->split_flags, NULL);
break;
case TEST_CREATE_BLOCKS:
ext4_map_create_blocks_helper(test, inode, &map, param->split_flags);
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index ae3804f36535..0942d2ed4603 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -184,9 +184,9 @@ static int ext4_ext_get_access(handle_t *handle, struct inode *inode,
* - ENOMEM
* - EIO
*/
-static int __ext4_ext_dirty(const char *where, unsigned int line,
- handle_t *handle, struct inode *inode,
- struct ext4_ext_path *path)
+int __ext4_ext_dirty(const char *where, unsigned int line,
+ handle_t *handle, struct inode *inode,
+ struct ext4_ext_path *path)
{
int err;
@@ -3144,7 +3144,7 @@ static void ext4_zeroout_es(struct inode *inode, struct ext4_extent *ex)
}
/* FIXME!! we need to try to merge to left or right after zero-out */
-static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex)
+int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex)
{
ext4_fsblk_t ee_pblock;
unsigned int ee_len;
@@ -6238,6 +6238,32 @@ int ext4_ext_clear_bb(struct inode *inode)
return 0;
}
-#ifdef CONFIG_EXT4_KUNIT_TESTS
-#include "extents-test.c"
+#if IS_ENABLED(CONFIG_EXT4_KUNIT_TESTS)
+int ext4_ext_space_root_idx_test(struct inode *inode, int check)
+{
+ return ext4_ext_space_root_idx(inode, check);
+}
+EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_ext_space_root_idx_test);
+
+struct ext4_ext_path *ext4_split_convert_extents_test(handle_t *handle,
+ struct inode *inode, struct ext4_map_blocks *map,
+ struct ext4_ext_path *path, int flags,
+ unsigned int *allocated)
+{
+ return ext4_split_convert_extents(handle, inode, map, path,
+ flags, allocated);
+}
+EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_split_convert_extents_test);
+
+EXPORT_SYMBOL_FOR_EXT4_TEST(__ext4_ext_dirty);
+EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_ext_zeroout);
+EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_es_register_shrinker);
+EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_map_create_blocks);
+EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_es_init_tree);
+EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_es_lookup_extent);
+EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_es_insert_extent);
+EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_ext_insert_extent);
+EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_find_extent);
+EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_issue_zeroout);
+EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_map_query_blocks);
#endif
--
2.34.1
^ permalink raw reply related
* [PATCH v2 6/8] ext4: fix the error handling process in extents_kunit_init).
From: Ye Bin @ 2026-03-12 13:12 UTC (permalink / raw)
To: tytso, adilger.kernel, linux-ext4; +Cc: jack
In-Reply-To: <20260312131253.366296-1-yebin@huaweicloud.com>
From: Ye Bin <yebin10@huawei.com>
The error processing in extents_kunit_init() is improper, causing
resource leakage.
Reconstruct the error handling process to prevent potential resource
leaks
Fixes: cb1e0c1d1fad ("ext4: kunit tests for extent splitting and conversion")
Signed-off-by: Ye Bin <yebin10@huawei.com>
---
fs/ext4/extents-test.c | 41 +++++++++++++++++++++++++++++------------
1 file changed, 29 insertions(+), 12 deletions(-)
diff --git a/fs/ext4/extents-test.c b/fs/ext4/extents-test.c
index 70d84c0a18e2..7e2796f72d45 100644
--- a/fs/ext4/extents-test.c
+++ b/fs/ext4/extents-test.c
@@ -222,33 +222,37 @@ static int extents_kunit_init(struct kunit *test)
(struct kunit_ext_test_param *)(test->param_value);
int err;
- sb = sget(&ext_fs_type, NULL, ext_set, 0, NULL);
- if (IS_ERR(sb))
- return PTR_ERR(sb);
-
- sb->s_blocksize = 4096;
- sb->s_blocksize_bits = 12;
-
sbi = kzalloc_obj(struct ext4_sb_info);
if (sbi == NULL)
return -ENOMEM;
+ sb = sget(&ext_fs_type, NULL, ext_set, 0, NULL);
+ if (IS_ERR(sb)) {
+ kfree(sbi);
+ return PTR_ERR(sb);
+ }
+
sbi->s_sb = sb;
sb->s_fs_info = sbi;
+ sb->s_blocksize = 4096;
+ sb->s_blocksize_bits = 12;
+
if (!param || !param->disable_zeroout)
sbi->s_extent_max_zeroout_kb = 32;
/* setup the mock inode */
k_ctx.k_ei = kzalloc_obj(struct ext4_inode_info);
- if (k_ctx.k_ei == NULL)
- return -ENOMEM;
+ if (k_ctx.k_ei == NULL) {
+ err = -ENOMEM;
+ goto out_deactivate;
+ }
ei = k_ctx.k_ei;
inode = &ei->vfs_inode;
err = ext4_es_register_shrinker(sbi);
if (err)
- return err;
+ goto out_deactivate;
ext4_es_init_tree(&ei->i_es_tree);
rwlock_init(&ei->i_es_lock);
@@ -264,8 +268,10 @@ static int extents_kunit_init(struct kunit *test)
inode->i_sb = sb;
k_ctx.k_data = kzalloc(EXT_DATA_LEN * 4096, GFP_KERNEL);
- if (k_ctx.k_data == NULL)
- return -ENOMEM;
+ if (k_ctx.k_data == NULL) {
+ err = -ENOMEM;
+ goto out_deactivate;
+ }
/*
* set the data area to a junk value
@@ -310,6 +316,17 @@ static int extents_kunit_init(struct kunit *test)
up_write(&sb->s_umount);
return 0;
+
+out_deactivate:
+ kfree(k_ctx.k_ei);
+ k_ctx.k_ei = NULL;
+
+ kfree(k_ctx.k_data);
+ k_ctx.k_data = NULL;
+
+ deactivate_locked_super(sb);
+
+ return err;
}
/*
--
2.34.1
^ permalink raw reply related
* [PATCH v2 0/8] Fix some issues about ext4-test
From: Ye Bin @ 2026-03-12 13:12 UTC (permalink / raw)
To: tytso, adilger.kernel, linux-ext4; +Cc: jack
From: Ye Bin <yebin10@huawei.com>
Diff v2 vs v1:
1. Fix compile warning when disable EXT4_KUNIT_TESTS for patch[1][3];
2. Remove reviewed-by tag for patch[1];
Patch [1]-[2]:
Decoupled mballoc-test and extents-test from ext4. Patch [1] does not
have any changes compared to the previously released version, so the
reviewed-by is added.
Patch [3-7]:
Bugfix for extents-test.c.
Patch [8]:
Bugfix for mballoc-test.c.
Ye Bin (8):
ext4: fix mballoc-test.c is not compiled when EXT4_KUNIT_TESTS=M
ext4: introduce EXPORT_SYMBOL_FOR_EXT4_TEST() helper
ext4: fix extents-test.c is not compiled when EXT4_KUNIT_TESTS=M
ext4: fix miss unlock 'sb->s_umount' in extents_kunit_init()
ext4: fix miss free super_block in extents_kunit_exit()
ext4: fix the error handling process in extents_kunit_init).
ext4: fix possible null-ptr-deref in extents_kunit_exit()
ext4: fix possible null-ptr-deref in mbt_kunit_exit()
fs/ext4/Makefile | 5 +-
fs/ext4/ext4.h | 5 ++
fs/ext4/ext4_extents.h | 12 +++++
fs/ext4/extents-test.c | 59 ++++++++++++++++--------
fs/ext4/extents.c | 38 ++++++++++++---
fs/ext4/mballoc-test.c | 87 ++++++++++++++++++-----------------
fs/ext4/mballoc.c | 102 +++++++++++++++++++++++++++++++++++++++--
fs/ext4/mballoc.h | 30 ++++++++++++
8 files changed, 268 insertions(+), 70 deletions(-)
--
2.34.1
^ permalink raw reply
* [PATCH v2 1/8] ext4: fix mballoc-test.c is not compiled when EXT4_KUNIT_TESTS=M
From: Ye Bin @ 2026-03-12 13:12 UTC (permalink / raw)
To: tytso, adilger.kernel, linux-ext4; +Cc: jack
In-Reply-To: <20260312131253.366296-1-yebin@huaweicloud.com>
From: Ye Bin <yebin10@huawei.com>
Now, only EXT4_KUNIT_TESTS=Y testcase will be compiled in 'mballoc.c'.
To solve this issue, the ext4 test code needs to be decoupled. The ext4
test module is compiled into a separate module.
Reported-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Closes: https://patchwork.kernel.org/project/cifs-client/patch/20260118091313.1988168-2-chenxiaosong.chenxiaosong@linux.dev/
Fixes: 7c9fa399a369 ("ext4: add first unit test for ext4_mb_new_blocks_simple in mballoc")
Signed-off-by: Ye Bin <yebin10@huawei.com>
---
fs/ext4/Makefile | 4 +-
fs/ext4/mballoc-test.c | 81 +++++++++++++++----------------
fs/ext4/mballoc.c | 105 +++++++++++++++++++++++++++++++++++++++--
fs/ext4/mballoc.h | 30 ++++++++++++
4 files changed, 175 insertions(+), 45 deletions(-)
diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile
index 72206a292676..d836c3fe311b 100644
--- a/fs/ext4/Makefile
+++ b/fs/ext4/Makefile
@@ -14,7 +14,7 @@ ext4-y := balloc.o bitmap.o block_validity.o dir.o ext4_jbd2.o extents.o \
ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o
ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o
-ext4-inode-test-objs += inode-test.o
-obj-$(CONFIG_EXT4_KUNIT_TESTS) += ext4-inode-test.o
+ext4-test-objs += inode-test.o mballoc-test.o
+obj-$(CONFIG_EXT4_KUNIT_TESTS) += ext4-test.o
ext4-$(CONFIG_FS_VERITY) += verity.o
ext4-$(CONFIG_FS_ENCRYPTION) += crypto.o
diff --git a/fs/ext4/mballoc-test.c b/fs/ext4/mballoc-test.c
index b9f22e3a8d5c..c75b91ae0cf0 100644
--- a/fs/ext4/mballoc-test.c
+++ b/fs/ext4/mballoc-test.c
@@ -8,6 +8,7 @@
#include <linux/random.h>
#include "ext4.h"
+#include "mballoc.h"
struct mbt_grp_ctx {
struct buffer_head bitmap_bh;
@@ -336,7 +337,7 @@ ext4_mb_mark_context_stub(handle_t *handle, struct super_block *sb, bool state,
if (state)
mb_set_bits(bitmap_bh->b_data, blkoff, len);
else
- mb_clear_bits(bitmap_bh->b_data, blkoff, len);
+ mb_clear_bits_test(bitmap_bh->b_data, blkoff, len);
return 0;
}
@@ -413,14 +414,14 @@ static void test_new_blocks_simple(struct kunit *test)
/* get block at goal */
ar.goal = ext4_group_first_block_no(sb, goal_group);
- found = ext4_mb_new_blocks_simple(&ar, &err);
+ found = ext4_mb_new_blocks_simple_test(&ar, &err);
KUNIT_ASSERT_EQ_MSG(test, ar.goal, found,
"failed to alloc block at goal, expected %llu found %llu",
ar.goal, found);
/* get block after goal in goal group */
ar.goal = ext4_group_first_block_no(sb, goal_group);
- found = ext4_mb_new_blocks_simple(&ar, &err);
+ found = ext4_mb_new_blocks_simple_test(&ar, &err);
KUNIT_ASSERT_EQ_MSG(test, ar.goal + EXT4_C2B(sbi, 1), found,
"failed to alloc block after goal in goal group, expected %llu found %llu",
ar.goal + 1, found);
@@ -428,7 +429,7 @@ static void test_new_blocks_simple(struct kunit *test)
/* get block after goal group */
mbt_ctx_mark_used(sb, goal_group, 0, EXT4_CLUSTERS_PER_GROUP(sb));
ar.goal = ext4_group_first_block_no(sb, goal_group);
- found = ext4_mb_new_blocks_simple(&ar, &err);
+ found = ext4_mb_new_blocks_simple_test(&ar, &err);
KUNIT_ASSERT_EQ_MSG(test,
ext4_group_first_block_no(sb, goal_group + 1), found,
"failed to alloc block after goal group, expected %llu found %llu",
@@ -438,7 +439,7 @@ static void test_new_blocks_simple(struct kunit *test)
for (i = goal_group; i < ext4_get_groups_count(sb); i++)
mbt_ctx_mark_used(sb, i, 0, EXT4_CLUSTERS_PER_GROUP(sb));
ar.goal = ext4_group_first_block_no(sb, goal_group);
- found = ext4_mb_new_blocks_simple(&ar, &err);
+ found = ext4_mb_new_blocks_simple_test(&ar, &err);
KUNIT_ASSERT_EQ_MSG(test,
ext4_group_first_block_no(sb, 0) + EXT4_C2B(sbi, 1), found,
"failed to alloc block before goal group, expected %llu found %llu",
@@ -448,7 +449,7 @@ static void test_new_blocks_simple(struct kunit *test)
for (i = 0; i < ext4_get_groups_count(sb); i++)
mbt_ctx_mark_used(sb, i, 0, EXT4_CLUSTERS_PER_GROUP(sb));
ar.goal = ext4_group_first_block_no(sb, goal_group);
- found = ext4_mb_new_blocks_simple(&ar, &err);
+ found = ext4_mb_new_blocks_simple_test(&ar, &err);
KUNIT_ASSERT_NE_MSG(test, err, 0,
"unexpectedly get block when no block is available");
}
@@ -492,16 +493,16 @@ validate_free_blocks_simple(struct kunit *test, struct super_block *sb,
continue;
bitmap = mbt_ctx_bitmap(sb, i);
- bit = mb_find_next_zero_bit(bitmap, max, 0);
+ bit = mb_find_next_zero_bit_test(bitmap, max, 0);
KUNIT_ASSERT_EQ_MSG(test, bit, max,
"free block on unexpected group %d", i);
}
bitmap = mbt_ctx_bitmap(sb, goal_group);
- bit = mb_find_next_zero_bit(bitmap, max, 0);
+ bit = mb_find_next_zero_bit_test(bitmap, max, 0);
KUNIT_ASSERT_EQ(test, bit, start);
- bit = mb_find_next_bit(bitmap, max, bit + 1);
+ bit = mb_find_next_bit_test(bitmap, max, bit + 1);
KUNIT_ASSERT_EQ(test, bit, start + len);
}
@@ -524,7 +525,7 @@ test_free_blocks_simple_range(struct kunit *test, ext4_group_t goal_group,
block = ext4_group_first_block_no(sb, goal_group) +
EXT4_C2B(sbi, start);
- ext4_free_blocks_simple(inode, block, len);
+ ext4_free_blocks_simple_test(inode, block, len);
validate_free_blocks_simple(test, sb, goal_group, start, len);
mbt_ctx_mark_used(sb, goal_group, 0, EXT4_CLUSTERS_PER_GROUP(sb));
}
@@ -566,15 +567,15 @@ test_mark_diskspace_used_range(struct kunit *test,
bitmap = mbt_ctx_bitmap(sb, TEST_GOAL_GROUP);
memset(bitmap, 0, sb->s_blocksize);
- ret = ext4_mb_mark_diskspace_used(ac, NULL);
+ ret = ext4_mb_mark_diskspace_used_test(ac, NULL);
KUNIT_ASSERT_EQ(test, ret, 0);
max = EXT4_CLUSTERS_PER_GROUP(sb);
- i = mb_find_next_bit(bitmap, max, 0);
+ i = mb_find_next_bit_test(bitmap, max, 0);
KUNIT_ASSERT_EQ(test, i, start);
- i = mb_find_next_zero_bit(bitmap, max, i + 1);
+ i = mb_find_next_zero_bit_test(bitmap, max, i + 1);
KUNIT_ASSERT_EQ(test, i, start + len);
- i = mb_find_next_bit(bitmap, max, i + 1);
+ i = mb_find_next_bit_test(bitmap, max, i + 1);
KUNIT_ASSERT_EQ(test, max, i);
}
@@ -617,54 +618,54 @@ static void mbt_generate_buddy(struct super_block *sb, void *buddy,
max = EXT4_CLUSTERS_PER_GROUP(sb);
bb_h = buddy + sbi->s_mb_offsets[1];
- off = mb_find_next_zero_bit(bb, max, 0);
+ off = mb_find_next_zero_bit_test(bb, max, 0);
grp->bb_first_free = off;
while (off < max) {
grp->bb_counters[0]++;
grp->bb_free++;
- if (!(off & 1) && !mb_test_bit(off + 1, bb)) {
+ if (!(off & 1) && !mb_test_bit_test(off + 1, bb)) {
grp->bb_free++;
grp->bb_counters[0]--;
- mb_clear_bit(off >> 1, bb_h);
+ mb_clear_bit_test(off >> 1, bb_h);
grp->bb_counters[1]++;
grp->bb_largest_free_order = 1;
off++;
}
- off = mb_find_next_zero_bit(bb, max, off + 1);
+ off = mb_find_next_zero_bit_test(bb, max, off + 1);
}
for (order = 1; order < MB_NUM_ORDERS(sb) - 1; order++) {
bb = buddy + sbi->s_mb_offsets[order];
bb_h = buddy + sbi->s_mb_offsets[order + 1];
max = max >> 1;
- off = mb_find_next_zero_bit(bb, max, 0);
+ off = mb_find_next_zero_bit_test(bb, max, 0);
while (off < max) {
- if (!(off & 1) && !mb_test_bit(off + 1, bb)) {
+ if (!(off & 1) && !mb_test_bit_test(off + 1, bb)) {
mb_set_bits(bb, off, 2);
grp->bb_counters[order] -= 2;
- mb_clear_bit(off >> 1, bb_h);
+ mb_clear_bit_test(off >> 1, bb_h);
grp->bb_counters[order + 1]++;
grp->bb_largest_free_order = order + 1;
off++;
}
- off = mb_find_next_zero_bit(bb, max, off + 1);
+ off = mb_find_next_zero_bit_test(bb, max, off + 1);
}
}
max = EXT4_CLUSTERS_PER_GROUP(sb);
- off = mb_find_next_zero_bit(bitmap, max, 0);
+ off = mb_find_next_zero_bit_test(bitmap, max, 0);
while (off < max) {
grp->bb_fragments++;
- off = mb_find_next_bit(bitmap, max, off + 1);
+ off = mb_find_next_bit_test(bitmap, max, off + 1);
if (off + 1 >= max)
break;
- off = mb_find_next_zero_bit(bitmap, max, off + 1);
+ off = mb_find_next_zero_bit_test(bitmap, max, off + 1);
}
}
@@ -706,7 +707,7 @@ do_test_generate_buddy(struct kunit *test, struct super_block *sb, void *bitmap,
/* needed by validation in ext4_mb_generate_buddy */
ext4_grp->bb_free = mbt_grp->bb_free;
memset(ext4_buddy, 0xff, sb->s_blocksize);
- ext4_mb_generate_buddy(sb, ext4_buddy, bitmap, TEST_GOAL_GROUP,
+ ext4_mb_generate_buddy_test(sb, ext4_buddy, bitmap, TEST_GOAL_GROUP,
ext4_grp);
KUNIT_ASSERT_EQ(test, memcmp(mbt_buddy, ext4_buddy, sb->s_blocksize),
@@ -760,7 +761,7 @@ test_mb_mark_used_range(struct kunit *test, struct ext4_buddy *e4b,
ex.fe_group = TEST_GOAL_GROUP;
ext4_lock_group(sb, TEST_GOAL_GROUP);
- mb_mark_used(e4b, &ex);
+ mb_mark_used_test(e4b, &ex);
ext4_unlock_group(sb, TEST_GOAL_GROUP);
mb_set_bits(bitmap, start, len);
@@ -769,7 +770,7 @@ test_mb_mark_used_range(struct kunit *test, struct ext4_buddy *e4b,
memset(buddy, 0xff, sb->s_blocksize);
for (i = 0; i < MB_NUM_ORDERS(sb); i++)
grp->bb_counters[i] = 0;
- ext4_mb_generate_buddy(sb, buddy, bitmap, 0, grp);
+ ext4_mb_generate_buddy_test(sb, buddy, bitmap, 0, grp);
KUNIT_ASSERT_EQ(test, memcmp(buddy, e4b->bd_buddy, sb->s_blocksize),
0);
@@ -798,7 +799,7 @@ static void test_mb_mark_used(struct kunit *test)
bb_counters[MB_NUM_ORDERS(sb)]), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, grp);
- ret = ext4_mb_load_buddy(sb, TEST_GOAL_GROUP, &e4b);
+ ret = ext4_mb_load_buddy_test(sb, TEST_GOAL_GROUP, &e4b);
KUNIT_ASSERT_EQ(test, ret, 0);
grp->bb_free = EXT4_CLUSTERS_PER_GROUP(sb);
@@ -809,7 +810,7 @@ static void test_mb_mark_used(struct kunit *test)
test_mb_mark_used_range(test, &e4b, ranges[i].start,
ranges[i].len, bitmap, buddy, grp);
- ext4_mb_unload_buddy(&e4b);
+ ext4_mb_unload_buddy_test(&e4b);
}
static void
@@ -825,16 +826,16 @@ test_mb_free_blocks_range(struct kunit *test, struct ext4_buddy *e4b,
return;
ext4_lock_group(sb, e4b->bd_group);
- mb_free_blocks(NULL, e4b, start, len);
+ mb_free_blocks_test(NULL, e4b, start, len);
ext4_unlock_group(sb, e4b->bd_group);
- mb_clear_bits(bitmap, start, len);
+ mb_clear_bits_test(bitmap, start, len);
/* bypass bb_free validatoin in ext4_mb_generate_buddy */
grp->bb_free += len;
memset(buddy, 0xff, sb->s_blocksize);
for (i = 0; i < MB_NUM_ORDERS(sb); i++)
grp->bb_counters[i] = 0;
- ext4_mb_generate_buddy(sb, buddy, bitmap, 0, grp);
+ ext4_mb_generate_buddy_test(sb, buddy, bitmap, 0, grp);
KUNIT_ASSERT_EQ(test, memcmp(buddy, e4b->bd_buddy, sb->s_blocksize),
0);
@@ -865,7 +866,7 @@ static void test_mb_free_blocks(struct kunit *test)
bb_counters[MB_NUM_ORDERS(sb)]), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, grp);
- ret = ext4_mb_load_buddy(sb, TEST_GOAL_GROUP, &e4b);
+ ret = ext4_mb_load_buddy_test(sb, TEST_GOAL_GROUP, &e4b);
KUNIT_ASSERT_EQ(test, ret, 0);
ex.fe_start = 0;
@@ -873,7 +874,7 @@ static void test_mb_free_blocks(struct kunit *test)
ex.fe_group = TEST_GOAL_GROUP;
ext4_lock_group(sb, TEST_GOAL_GROUP);
- mb_mark_used(&e4b, &ex);
+ mb_mark_used_test(&e4b, &ex);
ext4_unlock_group(sb, TEST_GOAL_GROUP);
grp->bb_free = 0;
@@ -886,7 +887,7 @@ static void test_mb_free_blocks(struct kunit *test)
test_mb_free_blocks_range(test, &e4b, ranges[i].start,
ranges[i].len, bitmap, buddy, grp);
- ext4_mb_unload_buddy(&e4b);
+ ext4_mb_unload_buddy_test(&e4b);
}
#define COUNT_FOR_ESTIMATE 100000
@@ -904,7 +905,7 @@ static void test_mb_mark_used_cost(struct kunit *test)
if (sb->s_blocksize > PAGE_SIZE)
kunit_skip(test, "blocksize exceeds pagesize");
- ret = ext4_mb_load_buddy(sb, TEST_GOAL_GROUP, &e4b);
+ ret = ext4_mb_load_buddy_test(sb, TEST_GOAL_GROUP, &e4b);
KUNIT_ASSERT_EQ(test, ret, 0);
ex.fe_group = TEST_GOAL_GROUP;
@@ -918,7 +919,7 @@ static void test_mb_mark_used_cost(struct kunit *test)
ex.fe_start = ranges[i].start;
ex.fe_len = ranges[i].len;
ext4_lock_group(sb, TEST_GOAL_GROUP);
- mb_mark_used(&e4b, &ex);
+ mb_mark_used_test(&e4b, &ex);
ext4_unlock_group(sb, TEST_GOAL_GROUP);
}
end = jiffies;
@@ -929,14 +930,14 @@ static void test_mb_mark_used_cost(struct kunit *test)
continue;
ext4_lock_group(sb, TEST_GOAL_GROUP);
- mb_free_blocks(NULL, &e4b, ranges[i].start,
+ mb_free_blocks_test(NULL, &e4b, ranges[i].start,
ranges[i].len);
ext4_unlock_group(sb, TEST_GOAL_GROUP);
}
}
kunit_info(test, "costed jiffies %lu\n", all);
- ext4_mb_unload_buddy(&e4b);
+ ext4_mb_unload_buddy_test(&e4b);
}
static const struct mbt_ext4_block_layout mbt_test_layouts[] = {
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index fcc55d2a00a1..842a604ae5db 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -4088,7 +4088,7 @@ void ext4_exit_mballoc(void)
#define EXT4_MB_BITMAP_MARKED_CHECK 0x0001
#define EXT4_MB_SYNC_UPDATE 0x0002
-static int
+int
ext4_mb_mark_context(handle_t *handle, struct super_block *sb, bool state,
ext4_group_t group, ext4_grpblk_t blkoff,
ext4_grpblk_t len, int flags, ext4_grpblk_t *ret_changed)
@@ -7192,6 +7192,105 @@ ext4_mballoc_query_range(
return error;
}
-#ifdef CONFIG_EXT4_KUNIT_TESTS
-#include "mballoc-test.c"
+#if IS_ENABLED(CONFIG_EXT4_KUNIT_TESTS)
+#define EXPORT_SYMBOL_FOR_EXT4_TEST(sym) \
+ EXPORT_SYMBOL_FOR_MODULES(sym, "ext4-test")
+
+void mb_clear_bits_test(void *bm, int cur, int len)
+{
+ mb_clear_bits(bm, cur, len);
+}
+EXPORT_SYMBOL_FOR_EXT4_TEST(mb_clear_bits_test);
+
+ext4_fsblk_t
+ext4_mb_new_blocks_simple_test(struct ext4_allocation_request *ar,
+ int *errp)
+{
+ return ext4_mb_new_blocks_simple(ar, errp);
+}
+EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_new_blocks_simple_test);
+
+int mb_find_next_zero_bit_test(void *addr, int max, int start)
+{
+ return mb_find_next_zero_bit(addr, max, start);
+}
+EXPORT_SYMBOL_FOR_EXT4_TEST(mb_find_next_zero_bit_test);
+
+int mb_find_next_bit_test(void *addr, int max, int start)
+{
+ return mb_find_next_bit(addr, max, start);
+}
+EXPORT_SYMBOL_FOR_EXT4_TEST(mb_find_next_bit_test);
+
+void mb_clear_bit_test(int bit, void *addr)
+{
+ mb_clear_bit(bit, addr);
+}
+EXPORT_SYMBOL_FOR_EXT4_TEST(mb_clear_bit_test);
+
+int mb_test_bit_test(int bit, void *addr)
+{
+ return mb_test_bit(bit, addr);
+}
+EXPORT_SYMBOL_FOR_EXT4_TEST(mb_test_bit_test);
+
+int ext4_mb_mark_diskspace_used_test(struct ext4_allocation_context *ac,
+ handle_t *handle)
+{
+ return ext4_mb_mark_diskspace_used(ac, handle);
+}
+EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_mark_diskspace_used_test);
+
+int mb_mark_used_test(struct ext4_buddy *e4b, struct ext4_free_extent *ex)
+{
+ return mb_mark_used(e4b, ex);
+}
+EXPORT_SYMBOL_FOR_EXT4_TEST(mb_mark_used_test);
+
+void ext4_mb_generate_buddy_test(struct super_block *sb, void *buddy,
+ void *bitmap, ext4_group_t group,
+ struct ext4_group_info *grp)
+{
+ ext4_mb_generate_buddy(sb, buddy, bitmap, group, grp);
+}
+EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_generate_buddy_test);
+
+int ext4_mb_load_buddy_test(struct super_block *sb, ext4_group_t group,
+ struct ext4_buddy *e4b)
+{
+ return ext4_mb_load_buddy(sb, group, e4b);
+}
+EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_load_buddy_test);
+
+void ext4_mb_unload_buddy_test(struct ext4_buddy *e4b)
+{
+ ext4_mb_unload_buddy(e4b);
+}
+EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_unload_buddy_test);
+
+void mb_free_blocks_test(struct inode *inode, struct ext4_buddy *e4b,
+ int first, int count)
+{
+ mb_free_blocks(inode, e4b, first, count);
+}
+EXPORT_SYMBOL_FOR_EXT4_TEST(mb_free_blocks_test);
+
+void ext4_free_blocks_simple_test(struct inode *inode, ext4_fsblk_t block,
+ unsigned long count)
+{
+ return ext4_free_blocks_simple(inode, block, count);
+}
+EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_free_blocks_simple_test);
+
+EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_wait_block_bitmap);
+EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_init);
+EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_get_group_desc);
+EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_count_free_clusters);
+EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_get_group_info);
+EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_free_group_clusters_set);
+EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_release);
+EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_read_block_bitmap_nowait);
+EXPORT_SYMBOL_FOR_EXT4_TEST(mb_set_bits);
+EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_fc_init_inode);
+EXPORT_SYMBOL_FOR_EXT4_TEST(ext4_mb_mark_context);
#endif
diff --git a/fs/ext4/mballoc.h b/fs/ext4/mballoc.h
index 15a049f05d04..39333ce72cbd 100644
--- a/fs/ext4/mballoc.h
+++ b/fs/ext4/mballoc.h
@@ -270,4 +270,34 @@ ext4_mballoc_query_range(
ext4_mballoc_query_range_fn formatter,
void *priv);
+extern int ext4_mb_mark_context(handle_t *handle,
+ struct super_block *sb, bool state,
+ ext4_group_t group, ext4_grpblk_t blkoff,
+ ext4_grpblk_t len, int flags,
+ ext4_grpblk_t *ret_changed);
+#if IS_ENABLED(CONFIG_EXT4_KUNIT_TESTS)
+extern void mb_clear_bits_test(void *bm, int cur, int len);
+extern ext4_fsblk_t
+ext4_mb_new_blocks_simple_test(struct ext4_allocation_request *ar,
+ int *errp);
+extern int mb_find_next_zero_bit_test(void *addr, int max, int start);
+extern int mb_find_next_bit_test(void *addr, int max, int start);
+extern void mb_clear_bit_test(int bit, void *addr);
+extern int mb_test_bit_test(int bit, void *addr);
+extern int
+ext4_mb_mark_diskspace_used_test(struct ext4_allocation_context *ac,
+ handle_t *handle);
+extern int mb_mark_used_test(struct ext4_buddy *e4b,
+ struct ext4_free_extent *ex);
+extern void ext4_mb_generate_buddy_test(struct super_block *sb,
+ void *buddy, void *bitmap, ext4_group_t group,
+ struct ext4_group_info *grp);
+extern int ext4_mb_load_buddy_test(struct super_block *sb,
+ ext4_group_t group, struct ext4_buddy *e4b);
+extern void ext4_mb_unload_buddy_test(struct ext4_buddy *e4b);
+extern void mb_free_blocks_test(struct inode *inode,
+ struct ext4_buddy *e4b, int first, int count);
+extern void ext4_free_blocks_simple_test(struct inode *inode,
+ ext4_fsblk_t block, unsigned long count);
+#endif
#endif
--
2.34.1
^ permalink raw reply related
* [PATCH v2 8/8] ext4: fix possible null-ptr-deref in mbt_kunit_exit()
From: Ye Bin @ 2026-03-12 13:12 UTC (permalink / raw)
To: tytso, adilger.kernel, linux-ext4; +Cc: jack
In-Reply-To: <20260312131253.366296-1-yebin@huaweicloud.com>
From: Ye Bin <yebin10@huawei.com>
There's issue as follows:
# test_new_blocks_simple: failed to initialize: -12
KASAN: null-ptr-deref in range [0x0000000000000638-0x000000000000063f]
Tainted: [E]=UNSIGNED_MODULE, [N]=TEST
RIP: 0010:mbt_kunit_exit+0x5e/0x3e0 [ext4_test]
Call Trace:
<TASK>
kunit_try_run_case_cleanup+0xbc/0x100 [kunit]
kunit_generic_run_threadfn_adapter+0x89/0x100 [kunit]
kthread+0x408/0x540
ret_from_fork+0xa76/0xdf0
ret_from_fork_asm+0x1a/0x30
If mbt_kunit_init() init testcase failed will lead to null-ptr-deref.
So add test if 'sb' is inited success in mbt_kunit_exit().
Fixes: 7c9fa399a369 ("ext4: add first unit test for ext4_mb_new_blocks_simple in mballoc")
Signed-off-by: Ye Bin <yebin10@huawei.com>
---
fs/ext4/mballoc-test.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/fs/ext4/mballoc-test.c b/fs/ext4/mballoc-test.c
index c75b91ae0cf0..90ed505fa4b1 100644
--- a/fs/ext4/mballoc-test.c
+++ b/fs/ext4/mballoc-test.c
@@ -362,7 +362,6 @@ static int mbt_kunit_init(struct kunit *test)
return ret;
}
- test->priv = sb;
kunit_activate_static_stub(test,
ext4_read_block_bitmap_nowait,
ext4_read_block_bitmap_nowait_stub);
@@ -383,6 +382,8 @@ static int mbt_kunit_init(struct kunit *test)
return -ENOMEM;
}
+ test->priv = sb;
+
return 0;
}
@@ -390,6 +391,9 @@ static void mbt_kunit_exit(struct kunit *test)
{
struct super_block *sb = (struct super_block *)test->priv;
+ if (!sb)
+ return;
+
mbt_mb_release(sb);
mbt_ctx_release(sb);
mbt_ext4_free_super_block(sb);
--
2.34.1
^ permalink raw reply related
* [PATCH v2 2/8] ext4: introduce EXPORT_SYMBOL_FOR_EXT4_TEST() helper
From: Ye Bin @ 2026-03-12 13:12 UTC (permalink / raw)
To: tytso, adilger.kernel, linux-ext4; +Cc: jack
In-Reply-To: <20260312131253.366296-1-yebin@huaweicloud.com>
From: Ye Bin <yebin10@huawei.com>
Introduce EXPORT_SYMBOL_FOR_EXT4_TEST() helper for kuint test.
Signed-off-by: Ye Bin <yebin10@huawei.com>
---
fs/ext4/ext4.h | 5 +++++
fs/ext4/mballoc.c | 3 ---
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 4cb2345339ba..8bf2a2ac4787 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -3945,6 +3945,11 @@ static inline bool ext4_inode_can_atomic_write(struct inode *inode)
extern int ext4_block_write_begin(handle_t *handle, struct folio *folio,
loff_t pos, unsigned len,
get_block_t *get_block);
+
+#if IS_ENABLED(CONFIG_EXT4_KUNIT_TESTS)
+#define EXPORT_SYMBOL_FOR_EXT4_TEST(sym) \
+ EXPORT_SYMBOL_FOR_MODULES(sym, "ext4-test")
+#endif
#endif /* __KERNEL__ */
#endif /* _EXT4_H */
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index 842a604ae5db..97b3f0e4c80b 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -7193,9 +7193,6 @@ ext4_mballoc_query_range(
}
#if IS_ENABLED(CONFIG_EXT4_KUNIT_TESTS)
-#define EXPORT_SYMBOL_FOR_EXT4_TEST(sym) \
- EXPORT_SYMBOL_FOR_MODULES(sym, "ext4-test")
-
void mb_clear_bits_test(void *bm, int cur, int len)
{
mb_clear_bits(bm, cur, len);
--
2.34.1
^ permalink raw reply related
* [PATCH v2 5/8] ext4: fix miss free super_block in extents_kunit_exit()
From: Ye Bin @ 2026-03-12 13:12 UTC (permalink / raw)
To: tytso, adilger.kernel, linux-ext4; +Cc: jack
In-Reply-To: <20260312131253.366296-1-yebin@huaweicloud.com>
From: Ye Bin <yebin10@huawei.com>
There's issue as follows:
ODEBUG: free active (active state 0) object: ffff88812f2d68a0 object type: percpu_counter hint: 0x0
<TASK>
debug_check_no_obj_freed+0x3d9/0x4d0
kfree+0x2bb/0x6c0
extents_kunit_exit+0x65/0x90 [ext4_test]
kunit_try_run_case_cleanup+0xbc/0x100 [kunit]
kunit_generic_run_threadfn_adapter+0x89/0x100 [kunit]
kthread+0x408/0x540
ret_from_fork+0xa76/0xdf0
ret_from_fork_asm+0x1a/0x30
The above issue was caused because the super_block cleanup process
was not properly performed.
Therefore, deactivate_super() is called in extents_kunit_exit() to
cleanup the super_block.
Fixes: cb1e0c1d1fad ("ext4: kunit tests for extent splitting and conversion")
Signed-off-by: Ye Bin <yebin10@huawei.com>
---
fs/ext4/extents-test.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/ext4/extents-test.c b/fs/ext4/extents-test.c
index 5a5016ea1ecc..70d84c0a18e2 100644
--- a/fs/ext4/extents-test.c
+++ b/fs/ext4/extents-test.c
@@ -144,7 +144,7 @@ static void extents_kunit_exit(struct kunit *test)
{
struct ext4_sb_info *sbi = k_ctx.k_ei->vfs_inode.i_sb->s_fs_info;
- kfree(sbi);
+ deactivate_super(sbi->s_sb);
kfree(k_ctx.k_ei);
kfree(k_ctx.k_data);
}
--
2.34.1
^ permalink raw reply related
* [PATCH v2 4/8] ext4: fix miss unlock 'sb->s_umount' in extents_kunit_init()
From: Ye Bin @ 2026-03-12 13:12 UTC (permalink / raw)
To: tytso, adilger.kernel, linux-ext4; +Cc: jack
In-Reply-To: <20260312131253.366296-1-yebin@huaweicloud.com>
From: Ye Bin <yebin10@huawei.com>
There's warning as follows when do ext4 kunit test:
WARNING: kunit_try_catch/15923 still has locks held!
7.0.0-rc3-next-20260309-00028-g73f965a1bbb1-dirty #281 Tainted: G E N
1 lock held by kunit_try_catch/15923:
#0: ffff888139f860e0 (&type->s_umount_key#70/1){+.+.}-{4:4}, at: alloc_super.constprop.0+0x172/0xa90
Call Trace:
<TASK>
dump_stack_lvl+0x180/0x1b0
debug_check_no_locks_held+0xc8/0xd0
do_exit+0x1502/0x2b20
kthread+0x3a9/0x540
ret_from_fork+0xa76/0xdf0
ret_from_fork_asm+0x1a/0x30
As sget() will return 'sb' which holds 's->s_umount' lock. However,
"extents-test" miss unlock this lock.
So unlock 's->s_umount' in the end of extents_kunit_init().
Fixes: cb1e0c1d1fad ("ext4: kunit tests for extent splitting and conversion")
Signed-off-by: Ye Bin <yebin10@huawei.com>
---
fs/ext4/extents-test.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/fs/ext4/extents-test.c b/fs/ext4/extents-test.c
index 9e055f399167..5a5016ea1ecc 100644
--- a/fs/ext4/extents-test.c
+++ b/fs/ext4/extents-test.c
@@ -307,6 +307,8 @@ static int extents_kunit_init(struct kunit *test)
kunit_activate_static_stub(test, ext4_ext_zeroout, ext4_ext_zeroout_stub);
kunit_activate_static_stub(test, ext4_issue_zeroout,
ext4_issue_zeroout_stub);
+ up_write(&sb->s_umount);
+
return 0;
}
--
2.34.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox