At that point, the folio (which is taken from the i_pages xarray directly) can assume 3 different kinds of values: 1) NULL. This is the complete absence of value from the xarray. 2) An xa_value. This is generally a shadow entry in the page cache, or a swap entry in shmem page cache. 3) A real struct folio*. This is confusing. Collapse NULL and xa_value into NULL right at the top of the loop. Collapse logic generally doesn't care whether something is fully absent, or whether there's some sort of underlying shadow entry. This simplifies a bit of reading logic in prepare_collapse_file(). No functional change intended. Signed-off-by: Pedro Falcato --- mm/khugepaged.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/mm/khugepaged.c b/mm/khugepaged.c index 0fe19acf470b..ac148db2a4a0 100644 --- a/mm/khugepaged.c +++ b/mm/khugepaged.c @@ -2225,6 +2225,19 @@ struct collapse_file_state { bool readahead_done : 1; }; +/** + * real_folio() - Convert a page cache folio * into a real folio * + * @folio: struct folio * to convert. + * + * Return: NULL if the passed folio is invalid (XA value, NULL), otherwise @folio. + */ +static inline struct folio *real_folio(struct folio *folio) +{ + if (!folio || xa_is_value(folio)) + return NULL; + return folio; +} + /** * prepare_collapse_file_folio() - Prepare the collapsing of a single file folio * @index: folio index in the page cache @@ -2249,7 +2262,7 @@ prepare_collapse_file_folio(pgoff_t index, struct collapse_file_state *state) struct folio *folio = state->folio; if (is_shmem) { - if (xa_is_value(folio) || !folio_test_uptodate(folio)) { + if (!folio || !folio_test_uptodate(folio)) { xas_unlock_irq(state->xas); /* swap in or instantiate fallocated page */ if (shmem_get_folio(mapping->host, index, 0, @@ -2267,7 +2280,7 @@ prepare_collapse_file_folio(pgoff_t index, struct collapse_file_state *state) goto xa_locked; } } else { /* !is_shmem */ - if (!folio || xa_is_value(folio)) { + if (!folio) { state->do_readahead = !state->readahead_done; result = SCAN_FAIL; goto xa_unlocked; @@ -2420,8 +2433,12 @@ static enum scan_result collapse_file(struct mm_struct *mm, unsigned long addr, continue; } - /* At this point folio can be NULL, or a value. */ - state.folio = folio; + /* + * At this point folio can be a value. Make values NULL. The + * value itself isn't interesting here. Collapse only cares + * about the absence of a folio. + */ + state.folio = real_folio(folio); result = prepare_collapse_file_folio(index, &state); folio = state.folio; if (result != SCAN_SUCCEED) -- 2.56.0