]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
iomap: simplify when reads can be skipped for writes
authorJoanne Koong <joannelkoong@gmail.com>
Tue, 11 Nov 2025 19:36:55 +0000 (11:36 -0800)
committerChristian Brauner <brauner@kernel.org>
Wed, 12 Nov 2025 09:50:32 +0000 (10:50 +0100)
Currently, the logic for skipping the read range for a write is

if (!(iter->flags & IOMAP_UNSHARE) &&
    (from <= poff || from >= poff + plen) &&
    (to <= poff || to >= poff + plen))

which breaks down to skipping the read if any of these are true:
a) from <= poff && to <= poff
b) from <= poff && to >= poff + plen
c) from >= poff + plen && to <= poff
d) from >= poff + plen && to >= poff + plen

This can be simplified to
if (!(iter->flags & IOMAP_UNSHARE) && from <= poff && to >= poff + plen)

from the following reasoning:

a) from <= poff && to <= poff
This reduces to 'to <= poff' since it is guaranteed that 'from <= to'
(since to = from + len). It is not possible for 'from <= to' to be true
here because we only reach here if plen > 0 (thanks to the preceding 'if
(plen == 0)' check that would break us out of the loop). If 'to <=
poff', plen would have to be 0 since poff and plen get adjusted in
lockstep for uptodate blocks. This means we can eliminate this check.

c) from >= poff + plen && to <= poff
This is not possible since 'from <= to' and 'plen > 0'. We can eliminate
this check.

d) from >= poff + plen && to >= poff + plen
This reduces to 'from >= poff + plen' since 'from <= to'.
It is not possible for 'from >= poff + plen' to be true here. We only
reach here if plen > 0 and for writes, poff and plen will always be
block-aligned, which means poff <= from < poff + plen. We can eliminate
this check.

The only valid check is b) from <= poff && to >= poff + plen.

Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Link: https://patch.msgid.link/20251111193658.3495942-7-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>
fs/iomap/buffered-io.c

index c82b5b24d4b3f529191808475d1fecdff815bf60..17449ea13420925a2b56df676ed3fb5d1a3b84e8 100644 (file)
@@ -758,9 +758,12 @@ static int __iomap_write_begin(const struct iomap_iter *iter,
                if (plen == 0)
                        break;
 
-               if (!(iter->flags & IOMAP_UNSHARE) &&
-                   (from <= poff || from >= poff + plen) &&
-                   (to <= poff || to >= poff + plen))
+               /*
+                * If the read range will be entirely overwritten by the write,
+                * we can skip having to zero/read it in.
+                */
+               if (!(iter->flags & IOMAP_UNSHARE) && from <= poff &&
+                   to >= poff + plen)
                        continue;
 
                if (iomap_block_needs_zeroing(iter, block_start)) {