Re: [PATCH] ntfs3: fix mount failure on volumes with fragmented MFT bitmap
Konstantin Komarov <[email protected]> Tue, 7 Apr 2026 19:18:10 +0200
| Newsgroups | dev.linux.lists.ntfs3,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
On 3/28/26 11:53, Ruslan Elishev wrote: > [You don't often get email from [email protected]. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ] > > When the $MFT's $BITMAP attribute is fragmented across multiple MFT > records (base record + extent records), ntfs_fill_super() fails with > -ENOENT during wnd_init() because the MFT bitmap's run list only > contains runs from the base MFT record. > > The issue is that wnd_init() (which calls wnd_rescan()) is invoked > before ni_load_all_mi(), so the extent MFT records containing > additional $BITMAP runs have not been loaded yet. When wnd_rescan() > tries to look up a VCN beyond the base record's runs, run_lookup_entry() > fails and returns -ENOENT. > > This affects NTFS volumes with a large or heavily fragmented MFT, which > is common on long-used Windows systems where the MFT bitmap's run list > doesn't fit in the base MFT record and spills into extent records. > > Fix this by: > 1. Moving ni_load_all_mi() before wnd_init() so all extent records > are available. > 2. After ni_load_all_mi(), iterating through the attribute list to > find any $BITMAP extent attributes and unpacking their runs into > sbi->mft.bitmap.run before wnd_init() is called. > > Tested on a 664GB NTFS volume with 86 MFT bitmap runs spanning > records 0 (VCN 0-105) and 17 (VCN 106-165). Before the fix, mount > fails with -ENOENT. After the fix, mount succeeds and all read/write > operations work correctly. Stress-tested with 8 test categories > (large file integrity, 10K small files, copy, move, delete/recreate > cycles, concurrent writes, deep directories, overwrite persistence). > > Signed-off-by: Ruslan Elishev <[email protected]> > --- > fs/ntfs3/super.c | 39 +++++++++++++++++++++++++++++++++------ > 1 file changed, 33 insertions(+), 6 deletions(-) > > diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c > index abcdef..123456 100644 > --- a/fs/ntfs3/super.c > +++ b/fs/ntfs3/super.c > @@ -1364,16 +1364,43 @@ > tt = inode->i_size >> sbi->record_bits; > sbi->mft.next_free = MFT_REC_USER; > > - err = wnd_init(&sbi->mft.bitmap, sb, tt); > - if (err) > - goto put_inode_out; > - > err = ni_load_all_mi(ni); > if (err) { > ntfs_err(sb, "Failed to load $MFT's subrecords (%d).", err); > goto put_inode_out; > } > > + /* Merge MFT bitmap runs from extent records loaded by ni_load_all_mi. */ > + { > + struct ATTRIB *a = NULL; > + struct ATTR_LIST_ENTRY *le = NULL; > + > + while ((a = ni_enum_attr_ex(ni, a, &le, NULL))) { > + CLST svcn, evcn; > + u16 roff; > + > + if (a->type != ATTR_BITMAP || !a->non_res) > + continue; > + > + svcn = le64_to_cpu(a->nres.svcn); > + if (!svcn) > + continue; /* Base record runs already loaded. */ > + > + evcn = le64_to_cpu(a->nres.evcn); > + roff = le16_to_cpu(a->nres.run_off); > + > + err = run_unpack_ex(&sbi->mft.bitmap.run, sbi, > + MFT_REC_MFT, svcn, evcn, svcn, > + Add2Ptr(a, roff), > + le32_to_cpu(a->size) - roff); > + if (err < 0) { > + ntfs_err(sb, "Failed to unpack $MFT bitmap extent (%d).", err); > + goto put_inode_out; > + } > + err = 0; > + } > + } > + > + err = wnd_init(&sbi->mft.bitmap, sb, tt); > + if (err) > + goto put_inode_out; > + > sbi->mft.ni = ni; > > /* Load $Bitmap. */ > -- > 2.43.0 Hello, I've failed to apply your patch as it is. Git produced an error. But I've taken your changes unmodified. Thanks for the patch. Regards, Konstantin