summaryrefslogtreecommitdiff
path: root/mm/khugepaged.c
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-07-18 16:55:52 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-07-18 16:55:52 +0200
commit93467b31bec6da512b51544e5e4584f2745e995e (patch)
tree2ea2be38c5e4dc9aafffbbc0db5aae0f6513a1d9 /mm/khugepaged.c
parent8ca1f4c6fb1462ee120730ea75c19da10d2f2d6f (diff)
parent7a5cef0db4795d9d453a12e0f61b5b7634fc4d40 (diff)
downloadlinux-stable-linux-rolling-stable.tar.gz
linux-stable-linux-rolling-stable.zip
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'mm/khugepaged.c')
-rw-r--r--mm/khugepaged.c39
1 files changed, 25 insertions, 14 deletions
diff --git a/mm/khugepaged.c b/mm/khugepaged.c
index b8452dbdb043..d6e04041f5dc 100644
--- a/mm/khugepaged.c
+++ b/mm/khugepaged.c
@@ -2094,32 +2094,43 @@ out_unlock:
goto xa_unlocked;
}
- if (!is_shmem) {
+xa_locked:
+ xas_unlock_irq(&xas);
+xa_unlocked:
+
+ /*
+ * If collapse is successful, flush must be done now before copying.
+ * If collapse is unsuccessful, does flush actually need to be done?
+ * Do it anyway, to clear the state.
+ */
+ try_to_unmap_flush();
+
+ if (result == SCAN_SUCCEED && !is_shmem && !mapping_large_folio_support(mapping)) {
+ /*
+ * invalidate_lock as shared excludes against concurrent opens
+ * in do_dentry_open() truncating the page cache. This is
+ * particularly important if there are dirty folios in transit.
+ */
+ filemap_invalidate_lock_shared(mapping);
filemap_nr_thps_inc(mapping);
/*
* Paired with the fence in do_dentry_open() -> get_write_access()
* to ensure i_writecount is up to date and the update to nr_thps
* is visible. Ensures the page cache will be truncated if the
- * file is opened writable.
+ * file is opened writable. If collapse looks to be successful,
+ * flush any dirty pages out the page cache. With the nr_thps
+ * incremented, there won't be any new writers (nor new dirties).
*/
smp_mb();
- if (inode_is_open_for_write(mapping->host)) {
+ if (inode_is_open_for_write(mapping->host) || filemap_write_and_wait(mapping)) {
result = SCAN_FAIL;
filemap_nr_thps_dec(mapping);
+ filemap_invalidate_unlock_shared(mapping);
+ goto rollback;
}
+ filemap_invalidate_unlock_shared(mapping);
}
-xa_locked:
- xas_unlock_irq(&xas);
-xa_unlocked:
-
- /*
- * If collapse is successful, flush must be done now before copying.
- * If collapse is unsuccessful, does flush actually need to be done?
- * Do it anyway, to clear the state.
- */
- try_to_unmap_flush();
-
if (result == SCAN_SUCCEED && nr_none &&
!shmem_charge(mapping->host, nr_none))
result = SCAN_FAIL;