From nobody Thu Apr 2 14:10:31 2026 Received: from mail-ed1-f49.google.com (mail-ed1-f49.google.com [209.85.208.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 24540346FDB for ; Sat, 28 Mar 2026 15:21:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774711264; cv=none; b=o6HDiLOtW0/99JqNNUWRmNSJRpttqa4roj7VAPJPMzvrufs25iE4xRRK28hC3u6yUwwntWDu96+XEbdbVS/YFXz5vqhi1Ksx335Pu+bC2pWuEp/g2Ac3tvgJ8EsvQuryMF4NmK6mjJnVMZjx6AaDGSjx3i2V/h7f5ilPMqmcqKM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774711264; c=relaxed/simple; bh=5BL932Zh2vm98BBiIO2Rlj+2dxSJnrQPUAH++zgp2/E=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=SLDdhwufto7KHDwRlUfEN5W25tyqPI4iJONkzepVyH2BXH+Sz61wH4ivihBfagMSVyIGRoduHKTvTkj47zS4FpI4Xrh6V0ZWIyR28jrZppAzlUHqmRr1w693g0tBHs2h/vx/HBO7aNqmZua5MBiCwsAMyDaAQ0VGmurT55v1kbQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Upy20qgR; arc=none smtp.client-ip=209.85.208.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Upy20qgR" Received: by mail-ed1-f49.google.com with SMTP id 4fb4d7f45d1cf-66971ccfcabso4186901a12.3 for ; Sat, 28 Mar 2026 08:21:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1774711261; x=1775316061; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=3OJmNZZAHzKtCtuGtuf9MesXbqfb4cueg7/dAvpH6/0=; b=Upy20qgR8UQlzHkQOwNZ8wqASShvjffn0900PUzym+U2KtbeH4OyEHEnLJZk4VONqN JhpVvAv6x98x6AvSutp348AVUfcg7ILuRVJDzgnwzxajdpQsFwL66Cnx2InNVyrr/2A1 l8l9AwzW1YbAgoLowi6v6Q2b5GYxujxYF42WTEnyZx2uZ4rpd4DS1Y4BtWOJTj7n6I6P nJGj7HUmhhGQBJ9QKQecISt5fv7WImPWxxTGF/cTlHFk0HQALBseZG8XKl2SyvtqtjIx Z9tHAJ3/q8TMP/jxooawzBiNwho3UMVQr2LXsZYDJ9cthoZ5Oag2yKnGb+vqc5jUwBHj jm8A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1774711261; x=1775316061; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=3OJmNZZAHzKtCtuGtuf9MesXbqfb4cueg7/dAvpH6/0=; b=MwrK34f1woMCiTgsSPFKjsxOic6NpcNTf+pvMBxGjutiZU/olhwsa/Sy8fG2Maj5YX EzmdUn8/xwFh8uKa6ocRzVWG25VmbQ4FEZoDpLEYo+SVKpqadU0kX4XQIeTj1OC0bBDZ ABQ804JxW91VefVgmXoich34H1+sNAVb2Rm3JUVkbVof+Qm1LPb1Bpo9qhBZWWTZl8Jq S5EnL75PCA+7GDQcy1u1ihlHrL4asNa3JWMk+Q7d9Z+ypeKJdyKc0wkKxYZeGLewqSpj mnEJkHk15DV2l9aZw2oxYBVK9UQa8LivnVEDYQmv6ggmu7EAbIs6x8chkOaL/hXXnRlB gMuA== X-Forwarded-Encrypted: i=1; AJvYcCU/7QketNgL0Ycj1WIXktcwsqY7pMgAE/CQGw5ULVvjDp5DB3M98WeipjrzlpXt7roPXTJ6j8hwgftLiuU=@vger.kernel.org X-Gm-Message-State: AOJu0Yw6Ifo8eHd+qnRE7iNCCGICCi6eyaaN1JzaxeIryyBVQ76t0o9D LCydffSDYfRAxuDiALr4/2seyh5R/7s/6frj1kYHs/6Tm3UU7TQwffzr+T3Iokj6oeTHjNr7 X-Gm-Gg: ATEYQzwqzMutm7BtXFkJL6bfY9tpymV++TM5CFvYFZK+e4ljl6NWRg5UXBZiQ/fkhCC yNraw7ERj1vE8shyiXi0043IKJGEga+VZVT/LHx8XhRg1XlqiVWHAqWPMRnGJmTZ4Hq8FsgQI0g 3ZW+zoF5pJk6OOtBtqwqfVfhH5PbHOA2VZS67dErjb3/X1BF4UmymmFv1oz8VFzha9hRpWhAEvx EPFnoE6ip12YmAqkG9zFQDpdSVVPZ3QellFZnJiNb2qjLRUd0hGjoO/Wr4DViUOMfcfrPI12eRQ uk2OIsGh8iy8bhkwfjxA/HwO1UtyGlS2EYTnQQEnLw78BLTzY3Dw23m9iYyiFil4KCNrssjYA/p Idqmv++mRGL923Go7Sqqrtqp7TqUXdqSel2blwZErVwXnkX9Wergk7tB6l6FR4ykubAeklkmwnF m5NAq/ZyChv+rcpzzG X-Received: by 2002:a05:6000:200c:b0:439:abcd:b314 with SMTP id ffacd0b85a97d-43b9ea34bfcmr9551110f8f.18.1774695190350; Sat, 28 Mar 2026 03:53:10 -0700 (PDT) Received: from pop-os.. ([94.190.180.59]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-43cf21eba4dsm4779725f8f.11.2026.03.28.03.53.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 28 Mar 2026 03:53:09 -0700 (PDT) From: Ruslan Elishev To: ntfs3@lists.linux.dev Cc: almaz.alexandrovich@paragon-software.com, linux-kernel@vger.kernel.org, Ruslan Elishev Subject: [PATCH] ntfs3: fix mount failure on volumes with fragmented MFT bitmap Date: Sat, 28 Mar 2026 12:53:08 +0200 Message-ID: <20260328105308.786150-1-relishev@gmail.com> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 --- 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 =3D inode->i_size >> sbi->record_bits; sbi->mft.next_free =3D MFT_REC_USER; - err =3D wnd_init(&sbi->mft.bitmap, sb, tt); - if (err) - goto put_inode_out; - err =3D 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 =3D NULL; + struct ATTR_LIST_ENTRY *le =3D NULL; + + while ((a =3D ni_enum_attr_ex(ni, a, &le, NULL))) { + CLST svcn, evcn; + u16 roff; + + if (a->type !=3D ATTR_BITMAP || !a->non_res) + continue; + + svcn =3D le64_to_cpu(a->nres.svcn); + if (!svcn) + continue; /* Base record runs already loaded. */ + + evcn =3D le64_to_cpu(a->nres.evcn); + roff =3D le16_to_cpu(a->nres.run_off); + + err =3D 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 =3D 0; + } + } + + err =3D wnd_init(&sbi->mft.bitmap, sb, tt); + if (err) + goto put_inode_out; + sbi->mft.ni =3D ni; /* Load $Bitmap. */ -- 2.43.0