[PATCH 4/8] mm/khugepaged: simplify prepare folio locking and exit paths
From: Pedro Falcato
Date: Mon Jul 20 2026 - 11:29:16 EST
folio_trylock() + folio_get() do the exact same thing on both is_shmem
and !is_shmem paths. Unify them into one path.
At the end of the day, there are two large invariants for the function:
- xarray lock is not held at exit. Either it was dropped on error, or
dropped on success/IO.
- success always means a locked-and-ref'd-up folio.
After this transformation, it's trivial to notice how simple the error
paths are, so do away with the gotos and hoist some code.
Signed-off-by: Pedro Falcato <pfalcato@xxxxxxx>
---
mm/khugepaged.c | 36 +++++++++++++-----------------------
1 file changed, 13 insertions(+), 23 deletions(-)
diff --git a/mm/khugepaged.c b/mm/khugepaged.c
index ed5d23317177..d170b64378e6 100644
--- a/mm/khugepaged.c
+++ b/mm/khugepaged.c
@@ -2259,8 +2259,8 @@ static struct folio *collapse_read_folio(pgoff_t index, struct collapse_file_sta
static enum scan_result prepare_collapse_file_folio(pgoff_t index, struct collapse_file_state *state)
{
struct address_space *mapping = state->mapping;
- enum scan_result result = SCAN_SUCCEED;
const int is_shmem = state->is_shmem;
+ enum scan_result ret = SCAN_SUCCEED;
struct folio *folio;
bool dirty;
@@ -2276,7 +2276,8 @@ static enum scan_result prepare_collapse_file_folio(pgoff_t index, struct collap
* will not succeed.
*/
lru_add_drain();
- goto xa_unlocked;
+ state->folio = folio;
+ return SCAN_SUCCEED;
}
if (!is_shmem) {
@@ -2299,32 +2300,21 @@ static enum scan_result prepare_collapse_file_folio(pgoff_t index, struct collap
xas_unlock_irq(state->xas);
if (dirty && !inode_is_open_for_write(mapping->host))
filemap_flush(mapping);
- result = SCAN_PAGE_DIRTY_OR_WRITEBACK;
- goto xa_unlocked;
+ return SCAN_PAGE_DIRTY_OR_WRITEBACK;
}
}
- if (is_shmem) {
- if (folio_trylock(folio)) {
- folio_get(folio);
- } else {
- result = SCAN_PAGE_LOCK;
- goto xa_locked;
- }
- } else { /* !is_shmem */
- if (folio_trylock(folio)) {
- folio_get(folio);
- } else {
- result = SCAN_PAGE_LOCK;
- goto xa_locked;
- }
- }
-xa_locked:
+ /*
+ * Note: trylock + simple folio_get() is safe here due to the i_pages
+ * lock being held; this excludes truncation happening in parallel.
+ */
+ if (!folio_trylock(folio))
+ ret = SCAN_PAGE_LOCK;
+ else
+ folio_get(folio);
xas_unlock_irq(state->xas);
-xa_unlocked:
- state->folio = folio;
- return result;
+ return ret;
}
/**
--
2.55.0