This check ensures the correctness of collapse read-only THPs for FSes after READ_ONLY_THP_FOR_FS is enabled by default for all FSes supporting PMD THP pagecache.
READ_ONLY_THP_FOR_FS only supports read-only fd and uses mapping->nr_thps and inode->i_writecount to prevent any write to read-only to-be-collapsed folios. In upcoming commits, READ_ONLY_THP_FOR_FS will be removed and the aforementioned mechanism will go away too. To ensure khugepaged functions as expected after the changes, rollback if any folio is dirty after try_to_unmap_flush() to , since a dirty folio means this read-only folio got some writes via mmap can happen between try_to_unmap() and try_to_unmap_flush() via cached TLB entries and khugepaged does not support collapse writable pagecache folios. Signed-off-by: Zi Yan <[email protected]> --- mm/khugepaged.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/mm/khugepaged.c b/mm/khugepaged.c index d2f0acd2dac2..ec609e53082e 100644 --- a/mm/khugepaged.c +++ b/mm/khugepaged.c @@ -2121,6 +2121,24 @@ static enum scan_result collapse_file(struct mm_struct *mm, unsigned long addr, */ try_to_unmap_flush(); + /* + * At this point, all folios are locked, unmapped, and all cached + * mappings in TLBs are flushed. No one else is able to write to these + * folios, since + * 1. writes via FS ops require folio locks (see write_begin_get_folio()); + * 2. writes via mmap require taking a fault and locking folio locks. + * + * khugepaged only works for read-only fd, make sure all folios are + * clean, since writes via mmap can happen between try_to_unmap() and + * try_to_unmap_flush() via cached TLB entries. + */ + list_for_each_entry(folio, &pagelist, lru) { + if (!is_shmem && (folio_test_dirty(folio))) { + result = SCAN_PAGE_DIRTY_OR_WRITEBACK; + goto rollback; + } + } + if (result == SCAN_SUCCEED && nr_none && !shmem_charge(mapping->host, nr_none)) result = SCAN_FAIL; -- 2.43.0

