[RFC PATCH RESEND] fs/ntfs3: avoid recursive MFT bitmap locking for external attributes
From: Pavel Zun
Date: Wed Nov 04 2026 - 04:57:43 EST
ntfs_look_free_mft() holds the MFT bitmap write lock while extending
$MFT. Growing $MFT::$BITMAP can require an external attribute record,
which makes ni_ins_attr_ext() call ntfs_look_free_mft() again.
ni_ins_attr_ext() passes is_mft_data to the allocator, so the nested
call for ATTR_BITMAP takes the ordinary-file path and attempts to
acquire the same rwsem. This leaves the allocating task blocked on
its own lock and blocks other users of the filesystem behind it.
The following stack was observed on 7.1.13-2-MANJARO during file
creation, with the hung-task report identifying the same task as the
likely rwsem owner:
down_write
ntfs_look_free_mft+0x1e7
ni_ins_attr_ext+0x1ac
ni_insert_attr
ni_insert_nonresident
attr_set_size_ex
ntfs_extend_mft+0xef
ntfs_look_free_mft+0x262
ntfs_create_inode
Disassembly of the matching ntfs3 module identifies the extension as
ATTR_BITMAP, not ATTR_DATA.
Pass is_mft instead. This selects the caller-locked, reserved-record
allocation path for all $MFT attributes, matching ni_create_attr_list()
and the ntfs_mark_rec_free() error path. Keep is_mft_data for the
unnamed $DATA bootstrapping constraints, which do not apply to BITMAP.
Fixes: 4342306f0f0d ("fs/ntfs3: Add file operations and implementation")
---
RFC notes:
This is a request for review of the locking/record-allocation fix.
I have not yet booted a patched kernel or reproduced the original
failure on a disposable NTFS image. Please do not treat the following
host-side checks as native filesystem validation.
Validation completed on mainline at
734bef548a96e8774d6eef5dfa2026c6edc4e80b and stable v7.1.13:
- Complete fs/ntfs3/ object builds, x86-64 defconfig plus NTFS3,
POSIX ACL and LZX/XPRESS, GCC 16.2.1, W=1: no warnings.
- A host harness compiled the actual ni_ins_attr_ext(),
ntfs_look_free_mft() and ntfs_mark_rec_free() functions with
instrumented lock/bitmap dependencies. Seven targeted cases detect
recursive locking before the change; all 17 scenarios pass after it.
Controls cover ordinary allocations, DATA bootstrapping and cleanup.
- checkpatch --strict --no-signoff: no errors or warnings.
The affected module's build ID matches the hung-task trace:
1f6011352f196196d266069023704fdf61030248. Its disassembly maps
ntfs_extend_mft+0xef to the ATTR_BITMAP resize call, and the inner
ntfs_look_free_mft+0x1e7 to the repeated write-lock acquisition.
The original kernel reported taints P W O E.
The investigation and patch were prepared with AI assistance.
The original production volume was not used for experimental testing.
A detailed report, sanitized trace/disassembly and host harness are
available for follow-up. This RFC has no DCO sign-off and is for
technical discussion, not a request to merge as-is.
Does using the existing is_mft allocation path for BITMAP match the
intended locking/reserved-record contract, or is there another MFT
attribute path that needs to be handled before this is submitted
for inclusion?
fs/ntfs3/frecord.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/ntfs3/frecord.c b/fs/ntfs3/frecord.c
index bead01a95..a4c6fa019 100644
--- a/fs/ntfs3/frecord.c
+++ b/fs/ntfs3/frecord.c
@@ -1019,7 +1019,7 @@ static int ni_ins_attr_ext(struct ntfs_inode
*ni, struct ATTR_LIST_ENTRY *le,
insert_ext:
/* We have to allocate a new child subrecord. */
- err = ntfs_look_free_mft(sbi, &rno, is_mft_data, ni, &mi);
+ err = ntfs_look_free_mft(sbi, &rno, is_mft, ni, &mi);
if (err)
goto out;
--
2.55.0