Re: [PATCH v2] ext4: fix race in ext4_mb_check_group_pa

Andreas Dilger <[email protected]>
Newsgroups org.kernel.vger.linux-ext4,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
On Jul 20, 2026, at 00:54, rafad900 <[email protected]> wrote:
> ext4_mb_check_group_pa drops the reference count on the previous
> best PA using atomic_dec(&cpa->pa_count) without holding the
> cpa->pa_lock.
> 
> This causes race with ext4_discard_preallocations() which checks
> pa_count to decide whether a PA is still in use. If the pa_count
> is dec between the check and the discard, the PA can be freed
> while ext4_mb_check_group_pa() still holds a reference to it.

Can you please explain this race condition further?  I don't see where
ext4_mb_check_group_pa() is using cpa after the reference is dropped.

> Fix this by taking the cpa->pa_lock around the atomic_dec.
> Similar to pa->pa_lock which is taken outside of the
> ext4_mb_check_group_pa() function.

At this point, it wouldn't be clear why `pa_count` needs to be an
atomic at all, if `pa_lock` is always held during inc/dec/check?

> diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
> index ed1bd00e11cd..c9a118ae4658 100644
> --- a/fs/ext4/mballoc.c
> +++ b/fs/ext4/mballoc.c
> @@ -4833,7 +4833,9 @@ ext4_mb_check_group_pa(ext4_fsblk_t goal_block,
> return cpa;
> 
> 	/* drop the previous reference */
> +	spin_lock(&cpa->pa_lock);
>  	atomic_dec(&cpa->pa_count);
> +	spin_unlock(&cpa->pa_lock);
>  	atomic_inc(&pa->pa_count);
>  	return pa;
>  }

In ext4_mb_check_group_pa() there is no reference to `cpa` after the
refcount is dropped.  In its one caller ext4_mb_use_preallocated():

		list_for_each_entry_rcu(tmp_pa, &lg->lg_prealloc_list[i],
					pa_node.lg_list) {
			spin_lock(&tmp_pa->pa_lock);
			if (tmp_pa->pa_deleted == 0 &&
			    tmp_pa->pa_free >= ac->ac_o_ex.fe_len) {
				cpa = ext4_mb_check_group_pa(goal_block,
							     tmp_pa, cpa);
			}
			spin_unlock(&tmp_pa->pa_lock);
		}
		rcu_read_unlock();
	}
	if (cpa) {
		ext4_mb_use_group_pa(ac, cpa);
		return true;
	}
	return false;
}

It *looks* like 'cpa' is used after ext4_mb_check_group_pa(), but it is
replaced on the return by 'tmp_pa' in that case, so there is no further
use after the refcount is dropped AFAICS.  Even the list iteration is
using 'tmp_pa', so that couldn't be it either.

There may be a race condition somewhere, but the commit message doesn't
provide clear details of what it is.

Cheers, Andreas
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.