From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1794065071; b=iOMZFTPbnqACTQQMk7PlHMfGOgZ4tq1Una2SKzGdaENIx2UFVDmthJxCHFFVrg0hP7Ta XvWwdRcwptCj7Huyuwx5aPRRGbW8YsMUlQe38bgqQbhqOL5KnP+KdMhtoAjWZkYb1VkIL xQDtXvS0fVqcIvpumjlFuj+LwfqZ9eg4FWZ9cWdMDzs9hQbB7PFUd127nXG5amj6Am7mM CDB3zUukAzIaL9SnDHp3Ngkm8ItEKmRoRmTexCSvqMzNvTC2bvH1gtYL/9kPHUGHJwLjJ JT2AehGBuLFo2EedU7kOKVx1ovjUad7zO3KNO5aj6ffMAHo3SLGZm+aGv01roR+IQ7g== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794065071; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:User-Agent:X-stable:X-Patchwork-Hint: MIME-Version:Content-Transfer-Encoding; bh=4SK4MZKhVPkvNjxmR4bZttGp0EqynwqynBqJSWAqJB4=; b=gjFE9ee54aApSj7y5Of7BRPq9dv2uMXv1qb+4ZevaL4GEqrauRo6BKwuuktDGeu3pVOc +i+WHAvyd+yxVGvlI44TyViIaBktvix7E+HDwjpz0OV8OpRYQL+XeX7gks49r/Zs7Ds7R yDVMfCajG9S0+3cjFPMsk4atXcnQ8//AWmBylxN6FcXx8gwz87HuUEQdp+IvJoFKnSxJk wzItymfE+1JAizQOF9O3Bp5ALYgbqFTlbulC0+EHrY6265m514g3MceN1qlCm1Dq9ayzO F0msbHLp1AH7DacU69vE9ScckG9rFlJLxxVRaTMK1Swsvd7NGPhQcVmtsc4bzC/0rhw== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=linuxfoundation.org header.i=@linuxfoundation.org header.a=rsa-sha256 header.s=korg header.b=0LKhzpeZ; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 27A62606A330; Sat, 7 Nov 2026 15:24:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.a=rsa-sha256 header.s=korg header.b=0LKhzpeZ Received: by smtp.kernel.org (Postfix) with ESMTPSA id 00F231F0089F; Sat, 7 Nov 2026 15:24:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1794065071; bh=4SK4MZKhVPkvNjxmR4bZttGp0EqynwqynBqJSWAqJB4=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=0LKhzpeZ23oCwWk8XFc3btlGBvd8BmBEcdNJFU0qcYblScaJijTzS6LG45UMVC7iV mmiIYVV8/5Q5+xe4HumapcwIiNFT/R1O+Z7ZSrYjP9Cq3F9Ml1e2n8Bpmwl2xiszXu CsE2lP3KJ3VD2vcchu0w+9DS3qV2ikeuJ3L3R7AU= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, Hyunchul Lee , Namjae Jeon , Sasha Levin Subject: [PATCH 7.3 0911/1257] ntfs: write MFT records through containing I/O units Date: Sat, 7 Nov 2026 08:53:27 -0500 Message-ID: <20261107135004.506658357@linuxfoundation.org> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261107134939.434104957@linuxfoundation.org> References: <20261107134939.434104957@linuxfoundation.org> User-Agent: quilt/0.69 X-stable: review X-Patchwork-Hint: ignore X-Mailing-List: stable@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 7.3-stable review patch. If anyone has any objections, please let me know. ------------------ From: Hyunchul Lee [ Upstream commit 4437d9d787185520c4798a942de9b5ef986d2141 ] Use the configured MFT I/O unit for direct writes, mirror updates, and generic folio writeback. On native 4Kn devices, multiple MFT records can share a device block, so submit complete containing units while preserving unselected neighboring records. Track selected records separately from records owned by direct inode writeback, and retain the existing runlist and cluster-boundary checks. Force direct MFT writes to complete synchronously when the I/O unit is larger than an individual record. the following patch restores caller-controlled completion. Fixes: 115380f9a2f9 ("ntfs: update mft operations") Cc: stable@vger.kernel.org Signed-off-by: Hyunchul Lee Signed-off-by: Namjae Jeon Signed-off-by: Sasha Levin --- fs/ntfs/mft.c | 61 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c index bbbe0d4426ecf..77acc26a85d90 100644 --- a/fs/ntfs/mft.c +++ b/fs/ntfs/mft.c @@ -597,13 +597,18 @@ static int ntfs_sync_mft_mirror_unit(struct ntfs_volume *vol, static int ntfs_sync_mft_mirror_record(struct ntfs_volume *vol, struct folio *source, const u64 mft_no) { + u64 mirror_file_ofs = (u64)mft_no * vol->mft_record_size; struct ntfs_mft_io_unit unit = { .folio_ofs = NTFS_MFT_NR_TO_POFS(vol, mft_no), .len = vol->mft_record_size, }; - return ntfs_sync_mft_mirror_unit(vol, source, - (u64)mft_no * vol->mft_record_size, &unit); + mirror_file_ofs = + round_down(mirror_file_ofs, (u64)vol->mft_io_unit_size); + unit.folio_ofs = round_down(unit.folio_ofs, vol->mft_io_unit_size); + unit.len = vol->mft_io_unit_size; + + return ntfs_sync_mft_mirror_unit(vol, source, mirror_file_ofs, &unit); } static int ntfs_prepare_mft_record_io_units(struct ntfs_inode *ni, @@ -623,6 +628,18 @@ static int ntfs_prepare_mft_record_io_units(struct ntfs_inode *ni, return -EIO; cluster_ofs = ntfs_bytes_to_cluster_off(vol, record_byte); + if (vol->mft_io_unit_size > vol->mft_record_size) { + cluster_ofs = round_down(cluster_ofs, vol->mft_io_unit_size); + disk_byte = NTFS_CLU_TO_B(vol, ni->mft_lcn[0]) + cluster_ofs; + units[0] = (struct ntfs_mft_io_unit){ + .sector = ntfs_bytes_to_bio_sector(disk_byte), + .folio_ofs = round_down(ni->folio_ofs, + vol->mft_io_unit_size), + .len = vol->mft_io_unit_size, + }; + return 1; + } + disk_byte = NTFS_CLU_TO_B(vol, ni->mft_lcn[0]) + cluster_ofs; units[0] = (struct ntfs_mft_io_unit){ .sector = ntfs_bytes_to_bio_sector(disk_byte), @@ -676,6 +693,8 @@ int write_mft_record_nolock(struct ntfs_inode *ni, struct mft_record *m, int syn WARN_ON(NInoAttr(ni)); WARN_ON(!folio_test_locked(folio)); + if (vol->mft_io_unit_size > vol->mft_record_size) + sync = 1; if (folio_test_writeback(folio)) folio_wait_writeback(folio); @@ -3063,7 +3082,7 @@ static int ntfs_map_mft_io_for_folio(struct ntfs_inode *ni, u64 folio_byte, static int ntfs_prepare_mft_folio_units(struct ntfs_inode *ni, u64 folio_byte, u64 file_limit, - const unsigned long *record_writable, + const unsigned long *record_selected, struct ntfs_mft_io_unit *units, unsigned int *nr_units, unsigned int max_units, bool *defer) @@ -3075,28 +3094,37 @@ static int ntfs_prepare_mft_folio_units(struct ntfs_inode *ni, u64 folio_byte, while (unit_byte < folio_end && unit_byte < file_limit) { struct ntfs_mft_io_unit unit; u64 record_byte; - u64 cluster_end = ntfs_cluster_to_bytes( - vol, ntfs_bytes_to_cluster(vol, unit_byte) + 1); - u64 record_end = - round_down(unit_byte, (u64)vol->mft_record_size) + - vol->mft_record_size; - u64 unit_end = min3(record_end, cluster_end, folio_end); - bool writable = false; + u64 unit_end; + u64 io_unit_end; + u64 cluster_end; + bool selected = false; int err; + io_unit_end = + round_down(unit_byte, (u64)vol->mft_io_unit_size) + + vol->mft_io_unit_size; + cluster_end = ntfs_cluster_to_bytes( + vol, ntfs_bytes_to_cluster(vol, unit_byte) + 1); + unit_end = min3(io_unit_end, cluster_end, folio_end); + record_byte = round_down(unit_byte, (u64)vol->mft_record_size); while (record_byte < min(unit_end, file_limit)) { unsigned int record; record = div_u64(record_byte - folio_byte, vol->mft_record_size); - if (test_bit(record, record_writable)) { - writable = true; + if (test_bit(record, record_selected)) { + selected = true; break; } record_byte += vol->mft_record_size; } - if (!writable) + /* + * Direct inode writeback owns unselected records. Their folio + * images are stable while this folio is locked, so a containing + * unit can preserve them when writing a selected record. + */ + if (!selected) goto next; unit = (struct ntfs_mft_io_unit){ @@ -3153,7 +3181,7 @@ static int ntfs_write_mft_block(struct folio *folio, struct writeback_control *w struct bio *parent = NULL, *child = NULL; struct ntfs_mft_write_ctx *ctx = NULL; u8 *kaddr = NULL; - DECLARE_BITMAP(record_writable, PAGE_SIZE / NTFS_BLOCK_SIZE) = {}; + DECLARE_BITMAP(record_selected, PAGE_SIZE / NTFS_BLOCK_SIZE) = {}; u64 folio_byte, file_limit, folio_end, mirror_size; unsigned int nr_records, nr_units = 0, max_units; unsigned int nr_locked_nis = 0, nr_ref_inos = 0; @@ -3221,11 +3249,11 @@ static int ntfs_write_mft_block(struct folio *folio, struct writeback_control *w tni->ext.base_ntfs_ino == NTFS_I(vol->mft_ino)) continue; } - __set_bit(record, record_writable); + __set_bit(record, record_selected); } err = ntfs_prepare_mft_folio_units(ni, folio_byte, file_limit, - record_writable, units, &nr_units, + record_selected, units, &nr_units, max_units, &defer); if (err) goto out_noio; @@ -3309,6 +3337,7 @@ static int ntfs_write_mft_block(struct folio *folio, struct writeback_control *w submit_bio(parent); ntfs_release_mft_write_refs(locked_nis, nr_locked_nis, ref_inos, nr_ref_inos); + return 0; out_noio: -- 2.53.0