Skip to content

Commit 35d30c9

Browse files
author
Darrick J. Wong
committed
iomap: don't skip reading in !uptodate folios when unsharing a range
Prior to commit a01b8f2, we would always read in the contents of a !uptodate folio prior to writing userspace data into the folio, allocated a folio state object, etc. Ritesh introduced an optimization that skips all of that if the write would cover the entire folio. Unfortunately, the optimization misses the unshare case, where we always have to read in the folio contents since there isn't a data buffer supplied by userspace. This can result in stale kernel memory exposure if userspace issues a FALLOC_FL_UNSHARE_RANGE call on part of a shared file that isn't already cached. This was caught by observing fstests regressions in the "unshare around" mechanism that is used for unaligned writes to a reflinked realtime volume when the realtime extent size is larger than 1FSB, though I think it applies to any shared file. Cc: ritesh.list@gmail.com, willy@infradead.org Fixes: a01b8f2 ("iomap: Allocate ifs in ->write_begin() early") Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
1 parent 4aa8cdd commit 35d30c9

File tree

1 file changed

+4
-2
lines changed

1 file changed

+4
-2
lines changed

fs/iomap/buffered-io.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -640,11 +640,13 @@ static int __iomap_write_begin(const struct iomap_iter *iter, loff_t pos,
640640
size_t poff, plen;
641641

642642
/*
643-
* If the write completely overlaps the current folio, then
643+
* If the write or zeroing completely overlaps the current folio, then
644644
* entire folio will be dirtied so there is no need for
645645
* per-block state tracking structures to be attached to this folio.
646+
* For the unshare case, we must read in the ondisk contents because we
647+
* are not changing pagecache contents.
646648
*/
647-
if (pos <= folio_pos(folio) &&
649+
if (!(iter->flags & IOMAP_UNSHARE) && pos <= folio_pos(folio) &&
648650
pos + len >= folio_pos(folio) + folio_size(folio))
649651
return 0;
650652

0 commit comments

Comments
 (0)