summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoanne Koong <joannelkoong@gmail.com>2025-11-11 22:36:51 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-01-11 17:21:41 +0300
commit011e356fe41e2d72a68468fec00ca70dd9b61769 (patch)
treea5d58fb0c418d0e9021b2d7993cd959eff80b3f0
parent82b60ffbb532d919959702768dca04c3c0500ae5 (diff)
downloadlinux-011e356fe41e2d72a68468fec00ca70dd9b61769.tar.xz
iomap: account for unaligned end offsets when truncating read range
[ Upstream commit 9d875e0eef8ec15b6b1da0cb9a0f8ed13efee89e ] The end position to start truncating from may be at an offset into a block, which under the current logic would result in overtruncation. Adjust the calculation to account for unaligned end offsets. Signed-off-by: Joanne Koong <joannelkoong@gmail.com> Link: https://patch.msgid.link/20251111193658.3495942-3-joannelkoong@gmail.com Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Darrick J. Wong <djwong@kernel.org> Signed-off-by: Christian Brauner <brauner@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
-rw-r--r--fs/iomap/buffered-io.c22
1 files changed, 20 insertions, 2 deletions
diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c
index 13a5f4422c79..7e9480150d61 100644
--- a/fs/iomap/buffered-io.c
+++ b/fs/iomap/buffered-io.c
@@ -189,6 +189,22 @@ static void ifs_free(struct folio *folio)
}
/*
+ * Calculate how many bytes to truncate based off the number of blocks to
+ * truncate and the end position to start truncating from.
+ */
+static size_t iomap_bytes_to_truncate(loff_t end_pos, unsigned block_bits,
+ unsigned blocks_truncated)
+{
+ unsigned block_size = 1 << block_bits;
+ unsigned block_offset = end_pos & (block_size - 1);
+
+ if (!block_offset)
+ return blocks_truncated << block_bits;
+
+ return ((blocks_truncated - 1) << block_bits) + block_offset;
+}
+
+/*
* Calculate the range inside the folio that we actually need to read.
*/
static void iomap_adjust_read_range(struct inode *inode, struct folio *folio,
@@ -233,7 +249,8 @@ static void iomap_adjust_read_range(struct inode *inode, struct folio *folio,
/* truncate len if we find any trailing uptodate block(s) */
while (++i <= last) {
if (ifs_block_is_uptodate(ifs, i)) {
- plen -= (last - i + 1) * block_size;
+ plen -= iomap_bytes_to_truncate(*pos + plen,
+ block_bits, last - i + 1);
last = i - 1;
break;
}
@@ -249,7 +266,8 @@ static void iomap_adjust_read_range(struct inode *inode, struct folio *folio,
unsigned end = offset_in_folio(folio, isize - 1) >> block_bits;
if (first <= end && last > end)
- plen -= (last - end) * block_size;
+ plen -= iomap_bytes_to_truncate(*pos + plen, block_bits,
+ last - end);
}
*offp = poff;