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=1794065063; b=BF/TqcHHSFs8QMpDRhSo3hAZ8v+k6AwqTtqvUQqTKLgCJ7Svwl1CQ5dWn77O9YHbUOhM GotZQouh0lecpy9m2wJiU4LNkMMlc9synzfYuaNVnzdjB1qrMIPgr5EbX8m2+Meccuhyd HRSP6B39UpFdyS2ba7O76gNW4A/zWmyKbxDgXMO7JT/g93S87ule2VvAFSvnCJxGnMPXY QtWD1vPF4hIfwO6VvGR1zcv5L01TOea9A5Oy5JmyVN9vh9UcHioeaHc43iMSaChO6Ytae KBhDuIlLf3Q+n5cwUVpKmxsSO5z8FdQ6TJWlJbDpJG6fmxh80kVBx0u39FfQS/r7ZuA== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794065063; 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=9r9yRQ+w2iwCkvExea3+tteSQrSDu09RYPlycUUYWHg=; b=gzo4oDvHOsGMuL3JydNoyiQXNVnA23WInatsrU97abo9mjvg7yb0kWhKNaIdXgM75sMx ID9QbJbW6Hq0+L56UJ6IrJz1qYdW7dVTdUkEcBc3S42A/QHopBswTlsQ/j4x3hqluTVEh 2jRU+Ob9shE6jv1+Ui8uRGjxmzkLLXfxFnsoGtQL9t1+ncLLDk1m3T+b1cEhmc8ucU0PE ZuUnQbQAaVGxMaE3plHMrwkHZKSN38ka9f/HXFCwQvI5sFfVaJdkXXCkJ6QXaijb7a+w1 2ZnEQFseoXyb9BXCJtyqnNl2YDKWktBwPp3xRLfC6MPIwU9MqXNBEBL66JvttC+7AIQ== 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=xTJp8lhW; 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 86A84606A338; Sat, 7 Nov 2026 15:24:23 +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=xTJp8lhW Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0EA3D1F0089F; Sat, 7 Nov 2026 15:24:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1794065063; bh=9r9yRQ+w2iwCkvExea3+tteSQrSDu09RYPlycUUYWHg=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=xTJp8lhWdkhw2rZvZHdgSxzDf7oZxkaV2LW7G2P+Lar4lrZh0DHuAa96FAdhYyxVL yhHVMQvk1WKjP9qIRj1q95R4zWAanUPg7CEhYCapnKjunXQIw+ys6Uh/mfoJNQheKk fmnE8SWYQ3DWaY0eihZJA/LNaJP4FX+gZe9KA9jE= 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 0907/1257] ntfs: write MFT mirror data in mapped I/O units Date: Sat, 7 Nov 2026 08:53:23 -0500 Message-ID: <20261107135004.389608035@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 b9fa884a39874091a10706fca69483ca957138f3 ] Replace the record-specific mirror writer with a unit-based helper and use a stack-allocated BIO for synchronous mirror writes. Route write_mft_record_nolock() and ntfs_write_mft_block() through the common mirror primitive. The helper only returns errors, So callers handle volume error reporting and retry policy. 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 | 142 ++++++++++++++++++++++++++------------------------ fs/ntfs/mft.h | 2 - 2 files changed, 73 insertions(+), 71 deletions(-) diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c index c9ea11198aa64..b102e0204eba9 100644 --- a/fs/ntfs/mft.c +++ b/fs/ntfs/mft.c @@ -429,6 +429,12 @@ void __mark_mft_record_dirty(struct ntfs_inode *ni) __mark_inode_dirty(VFS_I(base_ni), I_DIRTY_DATASYNC); } +struct ntfs_mft_io_unit { + sector_t sector; + unsigned int folio_ofs; + unsigned int len; +}; + /* * ntfs_bio_end_io - bio completion callback for MFT record writes * @@ -445,65 +451,60 @@ static void ntfs_bio_end_io(struct bio *bio) } /* - * ntfs_sync_mft_mirror - synchronize an mft record to the mft mirror - * @vol: ntfs volume on which the mft record to synchronize resides - * @mft_no: mft record number of mft record to synchronize - * @m: mapped, mst protected (extent) mft record to synchronize - * - * Write the mapped, mst protected (extent) mft record @m with mft record - * number @mft_no to the mft mirror ($MFTMirr) of the ntfs volume @vol. - * - * On success return 0. On error return -errno and set the volume errors flag - * in the ntfs volume @vol. - * - * NOTE: We always perform synchronous i/o. + * Write one MFT I/O unit to $MFTMirr. The source folio contains the MST + * protected image that will be written to $MFT. */ -int ntfs_sync_mft_mirror(struct ntfs_volume *vol, const u64 mft_no, - struct mft_record *m) +static int ntfs_sync_mft_mirror_unit(struct ntfs_volume *vol, + struct folio *source, u64 mirror_file_ofs, + const struct ntfs_mft_io_unit *unit) { - u8 *kmirr; - struct folio *folio; - unsigned int folio_ofs; - int err = 0; - struct bio *bio; + struct folio *mirror; + struct bio_vec bvec; + struct bio bio; + u64 mirror_size; + unsigned int mirror_ofs; + u8 *src, *dst; + int err; - ntfs_debug("Entering for inode 0x%llx.", mft_no); + if (unlikely(!vol->mftmirr_ino)) + return -EIO; + + mirror_size = (u64)vol->mftmirr_size * vol->mft_record_size; + if (mirror_file_ofs >= mirror_size || + unit->len > mirror_size - mirror_file_ofs) + return -EIO; + if (unit->folio_ofs + unit->len > folio_size(source)) + return -EIO; - if (unlikely(!vol->mftmirr_ino)) { - /* This could happen during umount... */ + mirror = read_mapping_folio(vol->mftmirr_ino->i_mapping, + mirror_file_ofs >> PAGE_SHIFT, NULL); + if (IS_ERR(mirror)) + return PTR_ERR(mirror); + + folio_lock(mirror); + if (folio_test_writeback(mirror)) + folio_wait_writeback(mirror); + mirror_ofs = mirror_file_ofs - folio_pos(mirror); + if (mirror_ofs + unit->len > folio_size(mirror)) { err = -EIO; - goto err_out; - } - /* Get the page containing the mirror copy of the mft record @m. */ - folio = read_mapping_folio(vol->mftmirr_ino->i_mapping, - NTFS_MFT_NR_TO_PIDX(vol, mft_no), NULL); - if (IS_ERR(folio)) { - ntfs_error(vol->sb, "Failed to map mft mirror page."); - err = PTR_ERR(folio); - goto err_out; + goto out_unlock; } - folio_lock(folio); - folio_clear_uptodate(folio); - /* Offset of the mft mirror record inside the page. */ - folio_ofs = NTFS_MFT_NR_TO_POFS(vol, mft_no); - /* The address in the page of the mirror copy of the mft record @m. */ - kmirr = kmap_local_folio(folio, 0) + folio_ofs; - /* Copy the mst protected mft record to the mirror. */ - memcpy(kmirr, m, vol->mft_record_size); - kunmap_local(kmirr); - - bio = bio_alloc(vol->sb->s_bdev, 1, REQ_OP_WRITE, GFP_NOIO); - bio->bi_iter.bi_sector = - ntfs_bytes_to_bio_sector(NTFS_CLU_TO_B(vol, vol->mftmirr_lcn) + - ((u64)folio->index << PAGE_SHIFT) + - folio_ofs); - - if (bio_add_folio(bio, folio, vol->mft_record_size, folio_ofs)) - err = submit_bio_wait(bio); - else + folio_clear_uptodate(mirror); + src = kmap_local_folio(source, unit->folio_ofs); + dst = kmap_local_folio(mirror, mirror_ofs); + memcpy(dst, src, unit->len); + kunmap_local(dst); + kunmap_local(src); + + bio_init(&bio, vol->sb->s_bdev, &bvec, 1, REQ_OP_WRITE); + bio.bi_iter.bi_sector = ntfs_bytes_to_bio_sector(NTFS_CLU_TO_B(vol, vol->mftmirr_lcn) + + mirror_file_ofs); + if (!bio_add_folio(&bio, mirror, unit->len, mirror_ofs)) err = -EIO; - bio_put(bio); + else + err = submit_bio_wait(&bio); + bio_uninit(&bio); /* * The in-memory mirror is now valid because we just memcpy()'d the @@ -512,23 +513,26 @@ int ntfs_sync_mft_mirror(struct ntfs_volume *vol, const u64 mft_no, * the stale on-disk mirror and overwrite this copy. The error is * propagated to the caller via @err. */ - folio_mark_uptodate(folio); + folio_mark_uptodate(mirror); - folio_unlock(folio); - folio_put(folio); - if (likely(!err)) { - ntfs_debug("Done."); - } else { - ntfs_error(vol->sb, "I/O error while writing mft mirror record 0x%llx!", mft_no); -err_out: - ntfs_error(vol->sb, - "Failed to synchronize $MFTMirr (error code %i). Volume will be left marked dirty on umount. Run chkdsk on the partition after umounting to correct this.", - err); - NVolSetErrors(vol); - } +out_unlock: + folio_unlock(mirror); + folio_put(mirror); return err; } +static int ntfs_sync_mft_mirror_record(struct ntfs_volume *vol, + struct folio *source, const u64 mft_no) +{ + 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); +} + /* * write_mft_record_nolock - write out a mapped (extent) mft record * @ni: ntfs inode describing the mapped (extent) mft record @@ -600,8 +604,8 @@ int write_mft_record_nolock(struct ntfs_inode *ni, struct mft_record *m, int syn /* Synchronize the mft mirror now if not @sync. */ if (!sync && ni->mft_no < vol->mftmirr_size) { - int sub_err = ntfs_sync_mft_mirror(vol, ni->mft_no, - fixup_m); + int sub_err = ntfs_sync_mft_mirror_record(vol, folio, + ni->mft_no); if (unlikely(sub_err) && !err) err = sub_err; } @@ -624,7 +628,8 @@ int write_mft_record_nolock(struct ntfs_inode *ni, struct mft_record *m, int syn /* If @sync, now synchronize the mft mirror. */ if (sync && ni->mft_no < vol->mftmirr_size) { - int sub_err = ntfs_sync_mft_mirror(vol, ni->mft_no, fixup_m); + int sub_err = + ntfs_sync_mft_mirror_record(vol, folio, ni->mft_no); if (unlikely(sub_err) && !err) err = sub_err; @@ -3031,8 +3036,7 @@ static int ntfs_write_mft_block(struct folio *folio, struct writeback_control *w prev_mft_ofs = mft_ofs; if (mft_no < vol->mftmirr_size) { - int sub_err = ntfs_sync_mft_mirror(vol, mft_no, - (struct mft_record *)(kaddr + mft_ofs)); + int sub_err = ntfs_sync_mft_mirror_record(vol, folio, mft_no); if (unlikely(sub_err) && !err) err = sub_err; diff --git a/fs/ntfs/mft.h b/fs/ntfs/mft.h index ed5c1d595c0d3..eb8a6f0d7944f 100644 --- a/fs/ntfs/mft.h +++ b/fs/ntfs/mft.h @@ -42,8 +42,6 @@ static inline void mark_mft_record_dirty(struct ntfs_inode *ni) __mark_mft_record_dirty(ni); } -int ntfs_sync_mft_mirror(struct ntfs_volume *vol, const u64 mft_no, - struct mft_record *m); int write_mft_record_nolock(struct ntfs_inode *ni, struct mft_record *m, int sync); /* -- 2.53.0