Linux EXT4 FS development
 help / color / mirror / Atom feed
* [PATCH] ext4: convert pa_count from atomic_t to refcount_t
@ 2026-07-20  3:44 rafad900
  2026-07-20  7:25 ` [syzbot ci] " syzbot ci
  0 siblings, 1 reply; 2+ messages in thread
From: rafad900 @ 2026-07-20  3:44 UTC (permalink / raw)
  To: tytso, adilger.kernel, libaokun, jack; +Cc: linux-ext4, linux-kernel, rafad900

The pa_count field in struct ext4_prealloc_space is
reference counter for preallocation descriptors.
Converting it from atomic_t to refcount_t provides
underflow and overflow protection.

This was found using Coccinelle script
atomic_as_refcounter.cocci

Testing was done on a QEMU x86 VM revealing a
pre-existing race condition leading to a
use-after-free.

Signed-off-by: rafad900 <rafad900@gmail.com>
---
 fs/ext4/mballoc.c | 22 +++++++++++-----------
 fs/ext4/mballoc.h |  2 +-
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index ed1bd00e11cd..59b3d4abaab0 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -4823,7 +4823,7 @@ ext4_mb_check_group_pa(ext4_fsblk_t goal_block,
 	ext4_fsblk_t cur_distance, new_distance;
 
 	if (cpa == NULL) {
-		atomic_inc(&pa->pa_count);
+		refcount_inc(&pa->pa_count);
 		return pa;
 	}
 	cur_distance = abs(goal_block - cpa->pa_pstart);
@@ -4833,8 +4833,8 @@ ext4_mb_check_group_pa(ext4_fsblk_t goal_block,
 		return cpa;
 
 	/* drop the previous reference */
-	atomic_dec(&cpa->pa_count);
-	atomic_inc(&pa->pa_count);
+	refcount_dec(&cpa->pa_count);
+	refcount_inc(&pa->pa_count);
 	return pa;
 }
 
@@ -4993,7 +4993,7 @@ ext4_mb_use_preallocated(struct ext4_allocation_context *ac)
 	}
 
 	if (tmp_pa->pa_free && likely(ext4_mb_pa_goal_check(ac, tmp_pa))) {
-		atomic_inc(&tmp_pa->pa_count);
+		refcount_inc(&tmp_pa->pa_count);
 		ext4_mb_use_inode_pa(ac, tmp_pa);
 		spin_unlock(&tmp_pa->pa_lock);
 		read_unlock(&ei->i_prealloc_lock);
@@ -5139,7 +5139,7 @@ static void ext4_mb_mark_pa_deleted(struct super_block *sb,
 static inline void ext4_mb_pa_free(struct ext4_prealloc_space *pa)
 {
 	BUG_ON(!pa);
-	BUG_ON(atomic_read(&pa->pa_count));
+	BUG_ON(refcount_read(&pa->pa_count));
 	BUG_ON(pa->pa_deleted == 0);
 	kmem_cache_free(ext4_pspace_cachep, pa);
 }
@@ -5165,7 +5165,7 @@ static void ext4_mb_put_pa(struct ext4_allocation_context *ac,
 
 	/* in this short window concurrent discard can set pa_deleted */
 	spin_lock(&pa->pa_lock);
-	if (!atomic_dec_and_test(&pa->pa_count) || pa->pa_free != 0) {
+	if (!refcount_dec_and_test(&pa->pa_count) || pa->pa_free != 0) {
 		spin_unlock(&pa->pa_lock);
 		return;
 	}
@@ -5535,7 +5535,7 @@ ext4_mb_discard_group_preallocations(struct super_block *sb,
 	list_for_each_entry_safe(pa, tmp,
 				&grp->bb_prealloc_list, pa_group_list) {
 		spin_lock(&pa->pa_lock);
-		if (atomic_read(&pa->pa_count)) {
+		if (refcount_read(&pa->pa_count)) {
 			spin_unlock(&pa->pa_lock);
 			*busy = 1;
 			continue;
@@ -5637,7 +5637,7 @@ void ext4_discard_preallocations(struct inode *inode)
 		BUG_ON(pa->pa_node_lock.inode_lock != &ei->i_prealloc_lock);
 
 		spin_lock(&pa->pa_lock);
-		if (atomic_read(&pa->pa_count)) {
+		if (refcount_read(&pa->pa_count)) {
 			/* this shouldn't happen often - nobody should
 			 * use preallocation while we're discarding it */
 			spin_unlock(&pa->pa_lock);
@@ -5720,7 +5720,7 @@ static int ext4_mb_pa_alloc(struct ext4_allocation_context *ac)
 	pa = kmem_cache_zalloc(ext4_pspace_cachep, GFP_NOFS);
 	if (!pa)
 		return -ENOMEM;
-	atomic_set(&pa->pa_count, 1);
+	refcount_set(&pa->pa_count, 1);
 	ac->ac_pa = pa;
 	return 0;
 }
@@ -5731,7 +5731,7 @@ static void ext4_mb_pa_put_free(struct ext4_allocation_context *ac)
 
 	BUG_ON(!pa);
 	ac->ac_pa = NULL;
-	WARN_ON(!atomic_dec_and_test(&pa->pa_count));
+	WARN_ON(!refcount_dec_and_test(&pa->pa_count));
 	/*
 	 * current function is only called due to an error or due to
 	 * len of found blocks < len of requested blocks hence the PA has not
@@ -5948,7 +5948,7 @@ ext4_mb_discard_lg_preallocations(struct super_block *sb,
 				pa_node.lg_list,
 				lockdep_is_held(&lg->lg_prealloc_lock)) {
 		spin_lock(&pa->pa_lock);
-		if (atomic_read(&pa->pa_count)) {
+		if (refcount_read(&pa->pa_count)) {
 			/*
 			 * This is the pa that we just used
 			 * for block allocation. So don't
diff --git a/fs/ext4/mballoc.h b/fs/ext4/mballoc.h
index 39333ce72cbd..f708d303228e 100644
--- a/fs/ext4/mballoc.h
+++ b/fs/ext4/mballoc.h
@@ -126,7 +126,7 @@ struct ext4_prealloc_space {
 		struct rcu_head	pa_rcu;
 	} u;
 	spinlock_t		pa_lock;
-	atomic_t		pa_count;
+	refcount_t		pa_count;
 	unsigned		pa_deleted;
 	ext4_fsblk_t		pa_pstart;	/* phys. block */
 	ext4_lblk_t		pa_lstart;	/* log. block */
-- 
2.43.0


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

* [syzbot ci] Re: ext4: convert pa_count from atomic_t to refcount_t
  2026-07-20  3:44 [PATCH] ext4: convert pa_count from atomic_t to refcount_t rafad900
@ 2026-07-20  7:25 ` syzbot ci
  0 siblings, 0 replies; 2+ messages in thread
From: syzbot ci @ 2026-07-20  7:25 UTC (permalink / raw)
  To: adilger.kernel, jack, libaokun, linux-ext4, linux-kernel,
	rafad900, tytso
  Cc: syzbot, syzkaller-bugs

syzbot ci has tested the following series

[v1] ext4: convert pa_count from atomic_t to refcount_t
https://lore.kernel.org/all/20260720034441.3900050-1-rafad900@gmail.com
* [PATCH] ext4: convert pa_count from atomic_t to refcount_t

and found the following issue:
WARNING: refcount bug in ext4_mb_use_preallocated

Full report is available here:
https://ci.syzbot.org/series/34fda797-e979-409c-bc2d-7af3e163df14

***

WARNING: refcount bug in ext4_mb_use_preallocated

tree:      torvalds
URL:       https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux
base:      1590cf0329716306e948a8fc29f1d3ee87d3989f
arch:      amd64
compiler:  Debian clang version 22.1.6 (++20260514074242+fc4aad7b5db3-1~exp1~20260514074407.73), Debian LLD 22.1.6
config:    https://ci.syzbot.org/builds/05fa6c1d-a594-4691-ace3-ded3fc2ca4dc/config

------------[ cut here ]------------
refcount_t: addition on 0; use-after-free.
WARNING: lib/refcount.c:25 at refcount_warn_saturate+0x9f/0x110, CPU#0: kworker/u9:2/51
Modules linked in:
CPU: 0 UID: 0 PID: 51 Comm: kworker/u9:2 Not tainted syzkaller #0 PREEMPT(full) 
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.2-debian-1.16.2-1 04/01/2014
Workqueue: writeback wb_workfn (flush-8:0)
RIP: 0010:refcount_warn_saturate+0x9f/0x110
Code: eb 66 85 db 74 3e 83 fb 01 75 4c e8 8b 73 0c fd 48 8d 3d 34 58 84 0b 67 48 0f b9 3a eb 4a e8 78 73 0c fd 48 8d 3d 31 58 84 0b <67> 48 0f b9 3a eb 37 e8 65 73 0c fd 48 8d 3d 2e 58 84 0b 67 48 0f
RSP: 0018:ffffc90000bb6590 EFLAGS: 00010293
RAX: ffffffff84b9ee08 RBX: 0000000000000002 RCX: ffff8881072a8000
RDX: 0000000000000000 RSI: ffffffff8f126800 RDI: ffffffff903e4640
RBP: ffff888112257dd0 R08: ffff8881072a8000 R09: 0000000000000005
R10: 0000000000000004 R11: 0000000000000000 R12: dffffc0000000000
R13: ffff888112257d98 R14: ffff888112257e10 R15: 0000000000000008
FS:  0000000000000000(0000) GS:ffff88818dc15000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007fc831b2c080 CR3: 0000000112724000 CR4: 00000000000006f0
Call Trace:
 <TASK>
 ext4_mb_use_preallocated+0xaa0/0x14e0
 ext4_mb_new_blocks+0x5a0/0x4560
 ext4_ext_map_blocks+0x1534/0x5850
 ext4_map_create_blocks+0x116/0x530
 ext4_map_blocks+0x7e4/0x1240
 ext4_do_writepages+0x23d3/0x47a0
 ext4_writepages+0x241/0x3b0
 do_writepages+0x338/0x560
 __writeback_single_inode+0x12e/0xf90
 writeback_sb_inodes+0x9de/0x1b00
 __writeback_inodes_wb+0x114/0x240
 wb_writeback+0x42f/0xad0
 wb_workfn+0x980/0x10f0
 process_scheduled_works+0xa8e/0x14e0
 worker_thread+0xa47/0xfb0
 kthread+0x388/0x470
 ret_from_fork+0x514/0xb70
 ret_from_fork_asm+0x1a/0x30
 </TASK>


***

If these findings have caused you to resend the series or submit a
separate fix, please add the following tag to your commit message:
  Tested-by: syzbot@syzkaller.appspotmail.com

---
This report is generated by a bot. It may contain errors.
syzbot ci engineers can be reached at syzkaller@googlegroups.com.

To test a patch for this bug, please reply with `#syz test`
(should be on a separate line).

The patch should be attached to the email.
Note: arguments like custom git repos and branches are not supported.

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

end of thread, other threads:[~2026-07-20  7:25 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-20  3:44 [PATCH] ext4: convert pa_count from atomic_t to refcount_t rafad900
2026-07-20  7:25 ` [syzbot ci] " syzbot ci

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