From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pj1-f52.google.com (mail-pj1-f52.google.com [209.85.216.52]) (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 8AB7A4AEEF for ; Sun, 23 Aug 2026 07:13:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.52 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787469212; cv=none; b=mfBuilWAFXyKGQlGyPBJUruZLIVWBCTr3myjXA6fVzVOM8IcY0+dQ0u8tW8O/PMsANJyI5W6B8xThA4LDNLyjEnFXM4GguCeQOn2tVZsKPrI9ClOqDoilo40R6fcGC5qVKNNjqFNoSWqeH2Hfmh+y24jvNZPk1oAmVdomtpf5vE= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787469212; c=relaxed/simple; bh=uCTGtqJXrK8lwhvEJIOKmTFFVlddUz3i6sN9V9Rec3Y=; h=Message-ID:Date:From:To:Cc:Subject:MIME-Version:Content-Type: Content-Disposition; b=DhwqYvgmSQVtzuww3L7o1gb/GCtq9uNgKHkLaUlgfoxJ/wEXcz/BNA19Ta+aK/rux5afsApiRvVrxv53p6wO25+FEUrrccK3yGd/BJnB3e33FnZpy9AJw1rXG+BHQKXzcXnfcnLngM1aKJjoxNjF7FWdbkibHSah89hl/lVjOwQ= 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=PEbDJTUl; arc=none smtp.client-ip=209.85.216.52 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="PEbDJTUl" Received: by mail-pj1-f52.google.com with SMTP id 98e67ed59e1d1-383b4a3755fso2519124a91.3 for ; Sun, 23 Aug 2026 00:13:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787469211; x=1788074011; darn=vger.kernel.org; h=content-disposition:content-type:mime-version:subject:cc:to:from :date:message-id:from:to:cc:subject:date:message-id:reply-to :content-type; bh=BPYc6Oovb7zE053E0oPNH9wsZBParJtaMt+S6mevKmU=; b=PEbDJTUl0erxJOI5hUu08KKn/tXa+G0NULCbgCkrRFqGf5S00nDcN25a00Ym9LdOrC 5bHprow7ki2hPWEuBWYHxSIEEzCk91NJQ4bUvIlBhlatQf0FZZRNs7QhlGM08P1ECeiS ETi7GMqR5SyyLQw6CC/+E+KNXDXAmW4f8yvR29IiqBlBNlLCi9r5Zb7gQddCFic6OkjP C+OcBAHut7SUM3gr70kE3Ptuzght+gtcj9D2vKBZPPanT5QjUBQEZvzyuEu2T/zzqEUi phyt22vGsNG7dVJvzJ6p5BHXeS7eS/1r3aFTFbzPo2fWgkWPcK+F+ouHIrRWyF0ofUIz W3xQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787469211; x=1788074011; h=content-disposition:content-type:mime-version:subject:cc:to:from :date:message-id:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=BPYc6Oovb7zE053E0oPNH9wsZBParJtaMt+S6mevKmU=; b=g7Dp72WUXcALTC/NkFvWQdpDxveMkXNAtxuRmOmWJB00Gu9sD/aINejDwf78MAzCzG 4e3teSQCJ9V8g1UgtFxg8dQGlP6AW2ElAJ3eTrqNTWkoBVYx7+Vu2BteBE/hNWmazrfV 5u2wZP4FA1Cncf7+95d6ejqadb/JFJn2z4dKZu4UPK6vIjMtFiZd9aylHXxsu5s255SX wE7f9tkd8Fn32j84aH/dIDfERzX01/cDvSVRELOGIRGYk9F3U+B7re66Z6kbxqA1PY3R uwU0J2zcACIpRv9NGd0k3jHzUpqhgtQpMa+kojLvreiyDI1C4CVdblmbydvhfoX+8ana mZtQ== X-Forwarded-Encrypted: i=1; AHgh+Rqjieod5+tYNe4kHefe0hz64RxzVzztuZS5c79uLduGULB1aUSrHW3cTI/v4i9AjHKLSlyMaMbYqz0TQPU=@vger.kernel.org X-Gm-Message-State: AFuF++nFxPO6SPH7d3DIhFVpmtLp2tnYh9SrnHBKUx+fF3tpeEubG2LB zdU7mEpR/WfvFcIBsApvibwjXo56a+9UOI0EGnyXgSuEATZDdeBPweXw X-Gm-Gg: AR+sD12NknGG5VrWDBWzRjQHn1buPaUChzkXh2BpIWJ1+OHuMP6RgIHWncjqRUI7rDA 3adcU0AixyUkRItjctiy6Ui/vObQvaho4MoQO6Renpb/lp4x6ZWCx09HOKDBl9GYSyfmWvQXBdY 35NrWgRPxzgCH7hBPCWo111eHLjCAnAPSdDtr7vnzKxbatbZV2pY0+0RohPHc/7yAD6vm9Oz75y opfy2nKuHA+NNETuwb/GGcu8+DcJeteezhzLsIIXkmSHna7PZUaUxI8n0Vw2BV8iAGnPNlIbT33 PCHtRwWFMkNCmIjj+PLQfqIC+ULFB1cvPafzg8Msk8jRh22LnXZqNH1LPPS+NrA7f7Uisv2UL9u WHu+yhVCAZ+VFcjWzM3lIrRANpsEOcK3VH1a2/GypLySup6EihbTmO6qrQ7BbHwoZr/yPkNvg5K I4rGuW+Qc5oVQi/NdO0YRpXPdBflsc59aV6A14xQYgmvyY8G2iMI8HoviXHK0wQhkhPu0MpNYg9 6kQ1iBk6uxweQ4D9MJtmYKfo4nmOLmbv4ueaTExo/tZig== X-Received: by 2002:a17:90b:3c84:b0:390:b41a:b92b with SMTP id 98e67ed59e1d1-395c3542369mr35043137a91.4.1787469210789; Sun, 23 Aug 2026 00:13:30 -0700 (PDT) Received: from localhost (75-172-9-230.tukw.qwest.net. [75.172.9.230]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-395e49985fcsm5214872a91.7.2026.08.23.00.13.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 23 Aug 2026 00:13:30 -0700 (PDT) Message-ID: <6a8a9d9a.fdee0002.34cbe9.559f@mx.google.com> X-Google-Original-Message-ID: Date: Sun, 23 Aug 2026 00:13:25 -0700 From: Dennis Tighe To: Namjae Jeon , Hyunchul Lee Cc: ntfs@lists.linux.dev, linux-kernel@vger.kernel.org Subject: [PATCH] ntfs: compute bi_sector in 512-byte units Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline bi_sector counts in 512 byte sectors and not in multiples of the volume's sector size. Under "normal" circumstances (with 512 byte sectors in NTFS) the current code works as is; however, when we have a 4k sector size on the volume the current usage of NTFS_B_TO_SECTOR() and ntfs_bytes_to_sector() end up converting to the number of 4k sectors after mount. Reads work today on 4k volumes as bdev-io.c as performing the shift correctly inline. With writes, we end up with significant silent disk corruption on these volumes. This fixes changes to use the new ntfs_bytes_to_bio_sector() function everywhere we're performing this calculation (including the existing read path). For the change in inode.c it removes a dead code block rather than updating. Fixes: 40796051991d ("ntfs: update in-memory, on-disk structures and headers") Assisted-by: Claude:claude-opus-5 Signed-off-by: Dennis Tighe --- I tested this with local volumes that were created with 4k logical sector sizes. This change seems to prevent the primary silent corruption that was occuring without it (due to writes being made in unrelated places). Note this was found and test with AI assistance. fs/ntfs/bdev-io.c | 2 +- fs/ntfs/compress.c | 2 +- fs/ntfs/inode.c | 10 ++-------- fs/ntfs/mft.c | 12 ++++++------ fs/ntfs/ntfs.h | 10 ++++------ 5 files changed, 14 insertions(+), 22 deletions(-) diff --git a/fs/ntfs/bdev-io.c b/fs/ntfs/bdev-io.c index 86db4d9298ed..4f27eed3b072 100644 --- a/fs/ntfs/bdev-io.c +++ b/fs/ntfs/bdev-io.c @@ -34,7 +34,7 @@ int ntfs_bdev_read(struct block_device *bdev, char *data, loff_t start, size_t s int error; struct bio *bio; blk_opf_t op; - sector_t sector = start >> SECTOR_SHIFT; + sector_t sector = ntfs_bytes_to_bio_sector(start); if (start & (SECTOR_SIZE - 1)) return -EINVAL; diff --git a/fs/ntfs/compress.c b/fs/ntfs/compress.c index 2225630b19d7..197d8607fc63 100644 --- a/fs/ntfs/compress.c +++ b/fs/ntfs/compress.c @@ -1414,7 +1414,7 @@ static int ntfs_write_cb(struct ntfs_inode *ni, loff_t pos, struct page **pages, bio_pos = ntfs_cluster_to_bytes(vol, bio_lcn); bio = bio_alloc(vol->sb->s_bdev, DIV_ROUND_UP(bio_size, PAGE_SIZE), REQ_OP_WRITE, GFP_NOIO); - bio->bi_iter.bi_sector = ntfs_bytes_to_sector(vol, bio_pos); + bio->bi_iter.bi_sector = ntfs_bytes_to_bio_sector(bio_pos); for (i = 0; bio_size; i++) { unsigned int len = min_t(unsigned int, bio_size, PAGE_SIZE); diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 32edb4045178..5aedc045f65a 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -1852,7 +1852,7 @@ int ntfs_read_inode_mount(struct inode *vi) struct mft_record *m = NULL; struct attr_record *a; struct ntfs_attr_search_ctx *ctx; - unsigned int i, nr_blocks; + unsigned int i; int err; size_t new_rl_count; @@ -1896,11 +1896,6 @@ int ntfs_read_inode_mount(struct inode *vi) goto err_out; } - /* Determine the first block of the $MFT/$DATA attribute. */ - nr_blocks = ntfs_bytes_to_sector(vol, vol->mft_record_size); - if (!nr_blocks) - nr_blocks = 1; - /* Load $MFT/$DATA's first mft record. */ err = ntfs_bdev_read(sb->s_bdev, (char *)m, ntfs_cluster_to_bytes(vol, vol->mft_lcn), i); @@ -3780,8 +3775,7 @@ static s64 __ntfs_inode_non_resident_attr_pwrite(struct inode *vi, bio = bio_alloc(vol->sb->s_bdev, 1, REQ_OP_WRITE, GFP_NOIO); bio->bi_iter.bi_sector = - ntfs_bytes_to_sector(vol, - ntfs_cluster_to_bytes(vol, lcn) + + ntfs_bytes_to_bio_sector(ntfs_cluster_to_bytes(vol, lcn) + lcn_folio_off); length = min_t(unsigned long, diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c index 984a0827f9ac..299a1d0dd6df 100644 --- a/fs/ntfs/mft.c +++ b/fs/ntfs/mft.c @@ -499,8 +499,8 @@ int ntfs_sync_mft_mirror(struct ntfs_volume *vol, const u64 mft_no, bio = bio_alloc(vol->sb->s_bdev, 1, REQ_OP_WRITE, GFP_NOIO); bio->bi_iter.bi_sector = - NTFS_B_TO_SECTOR(vol, NTFS_CLU_TO_B(vol, vol->mftmirr_lcn) + - lcn_folio_off + folio_ofs); + ntfs_bytes_to_bio_sector(NTFS_CLU_TO_B(vol, vol->mftmirr_lcn) + + lcn_folio_off + folio_ofs); if (bio_add_folio(bio, folio, vol->mft_record_size, folio_ofs)) err = submit_bio_wait(bio); @@ -592,8 +592,8 @@ int write_mft_record_nolock(struct ntfs_inode *ni, struct mft_record *m, int syn bio = bio_alloc(vol->sb->s_bdev, 1, REQ_OP_WRITE, GFP_NOIO); bio->bi_iter.bi_sector = - NTFS_B_TO_SECTOR(vol, NTFS_CLU_TO_B(vol, ni->mft_lcn[i]) + - clu_off); + ntfs_bytes_to_bio_sector(NTFS_CLU_TO_B(vol, ni->mft_lcn[i]) + + clu_off); if (!bio_add_folio(bio, folio, folio_size, ni->folio_ofs + offset)) { @@ -2740,8 +2740,8 @@ static int ntfs_write_mft_block(struct folio *folio, struct writeback_control *w bio = bio_alloc(vol->sb->s_bdev, 1, REQ_OP_WRITE, GFP_NOIO); bio->bi_iter.bi_sector = - ntfs_bytes_to_sector(vol, - ntfs_cluster_to_bytes(vol, lcn) + off); + ntfs_bytes_to_bio_sector( + ntfs_cluster_to_bytes(vol, lcn) + off); } if (vol->cluster_size == NTFS_BLOCK_SIZE && diff --git a/fs/ntfs/ntfs.h b/fs/ntfs/ntfs.h index df5a75d506f6..45f77848a9cf 100644 --- a/fs/ntfs/ntfs.h +++ b/fs/ntfs/ntfs.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "volume.h" @@ -71,8 +72,6 @@ #define NTFS_CLU_TO_POFS(vol, clu) (((u64)(clu) << (vol)->cluster_size_bits) & \ ~PAGE_MASK) -#define NTFS_B_TO_SECTOR(vol, b) ((b) >> ((vol)->sb)->s_blocksize_bits) - enum { NTFS_BLOCK_SIZE = 512, NTFS_BLOCK_SIZE_BITS = 9, @@ -154,11 +153,10 @@ static inline u64 ntfs_cluster_to_poff(const struct ntfs_volume *vol, return (clu << vol->cluster_size_bits) & ~PAGE_MASK; } -/* Convert byte offset to sector (block) number. */ -static inline sector_t ntfs_bytes_to_sector(const struct ntfs_volume *vol, - u64 bytes) +/* Convert a byte offset on the volume to a bio sector number. */ +static inline sector_t ntfs_bytes_to_bio_sector(u64 bytes) { - return bytes >> vol->sb->s_blocksize_bits; + return bytes >> SECTOR_SHIFT; } /* Global variables. */ -- 2.43.0