ntfs: fix rollback after MFT bitmap run coalescing

After the direct allocation attempt drops lcnbmp_lock, a concurrent free
can let ntfs_cluster_alloc() return the adjacent cluster. The merged
runlist then extends the existing last run, but rollback assumes a new
run was added. A later metadata failure removes the old mapping and
frees its first cluster.

Record whether the allocated cluster is adjacent before merging the
runlists. On rollback, shorten a coalesced run by one cluster and free
only that cluster; remove the new run for a non-adjacent allocation.

Suggested-by: Baolin Liu <liubaolin@kylinos.cn>
Reviewed-by: Baolin Liu <liubaolin@kylinos.cn>
Signed-off-by: Xuewen Wang <wangxuewen@kylinos.cn>
Reviewed-by: Baolin Liu <liubaolin@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
This commit is contained in:
Xuewen Wang 2026-09-24 09:45:12 +08:00 committed by Namjae Jeon
parent 3f58365687
commit 4d179eeb91

View File

@ -1428,6 +1428,8 @@ static int ntfs_mft_bitmap_extend_allocation_nolock(struct ntfs_volume *vol)
"Failed to allocate a cluster for the mft bitmap.");
return PTR_ERR(rl2);
}
/* The adjacent cluster may have become available while unlocked. */
status.added_cluster = rl2->lcn == lcn;
rl = ntfs_runlists_merge(&mftbmp_ni->runlist, rl2, 0, &new_rl_count);
if (IS_ERR(rl)) {
up_write(&mftbmp_ni->runlist.lock);
@ -1442,8 +1444,8 @@ static int ntfs_mft_bitmap_extend_allocation_nolock(struct ntfs_volume *vol)
}
mftbmp_ni->runlist.rl = rl;
mftbmp_ni->runlist.count = new_rl_count;
status.added_run = 1;
ntfs_debug("Adding one run to mft bitmap.");
status.added_run = !status.added_cluster;
ntfs_debug("Allocated one cluster for mft bitmap.");
/* Find the last run in the new runlist. */
for (; rl[1].length; rl++)
;