Re: [PATCH 1/8] mm/khugepaged: separate out windy folio logic from collapse_file
From: Lorenzo Stoakes (ARM)
Date: Mon Jul 20 2026 - 12:26:13 EST
On Mon, 20 Jul 2026 15:29:06 +0100, Pedro Falcato <pfalcato@xxxxxxx> wrote:
> Separate out complex folio-related logic from the main collapse_file()
> loop, and introduce a new helper struct to help marshal arguments back
> and forth.
>
> Signed-off-by: Pedro Falcato <pfalcato@xxxxxxx>
THANK YOU for doing this :) even looking into this bit of code is horrifying so
I can see you're putting yourself through it to make these changes... :)
I checked carefully and the logic looks to be identical, just various nits
etc. below.
>
>
> diff --git a/mm/khugepaged.c b/mm/khugepaged.c
> index 27e8f3077e80..d4de507ac001 100644
> --- a/mm/khugepaged.c
> +++ b/mm/khugepaged.c
> @@ -2218,6 +2218,92 @@ static void retract_page_tables(struct address_space *mapping, pgoff_t pgoff)
> i_mmap_unlock_read(mapping);
> }
>
> +struct collapse_file_state {
You had me at helper struct ;)
> + /* in-out parameter */
I think we can drop this comment, though hm it is useful to know this is updated
and the 'product' of the operation.
Maybe something like:
struct collapse_file_state {
/* Inputs */
struct file *file;
struct address_space *mapping;
struct xa_state *xas;
const pgoff_t pgoff_start, pgoff_end;
struct folio *folio;
};
Renaming index -> pgoff_start and end -> pgoff_end and keeping them both in the
struct rather than passing the index as a separate parameter implies the folio
is separate?
(Though any such renames should be a separate patch...)
> + struct folio *folio;
> + /* in parameters */
> + struct address_space *mapping;
> + struct file *file;
> + struct xa_state *xas;
Can we just make these input fields const + have the code tell you they're input
only? Though perhaps callers expect non-const (esp. the pointers, ugh.
> + /* collapse end index */
This feels a little superfluous? Feels odd not to have a start too but I guess
not necessary.
> + pgoff_t end;
> + unsigned int is_shmem : 1;
> +};
> +
> +static enum scan_result prepare_collapse_file_folio(pgoff_t index, struct collapse_file_state *state)
NIT - this is 101 chars :)
Either:
static enum scan_result
prepare_collapse_file_folio(pgoff_t index, struct collapse_file_state *state)
OR:
static enum scan_result prepare_collapse_file_folio(pgoff_t index,
struct collapse_file_state *state)
Resolves this :)
Also - why are we passing index and not just putting that in the helper struct?
> [ ... skip 54 lines ... ]
> + } else if (folio_test_writeback(folio)) {
> + xas_unlock_irq(state->xas);
> + result = SCAN_PAGE_DIRTY_OR_WRITEBACK;
> + goto xa_unlocked;
> + } else if (folio_trylock(folio)) {
> + folio_get(folio);
I see you drop the xas_unlock_irq(&xas) here because xa_locked has you covered
below, slight inconsistency in terms of the mechnical change but I think
unavoidable.
> + } else {
> + result = SCAN_PAGE_LOCK;
> + goto xa_locked;
I wonder if we could do away with this goto? That makes it match the
removed code less but you are already having to do that as above.
> + }
> + }
> +
> +xa_locked:
> + xas_unlock_irq(state->xas);
> +xa_unlocked:
> + state->folio = folio;
> + return result;
> +}
I'm guessing this will get some more cleanup in subsequent patches? As a little
long as-is.
But obviously makes sense to separate out into broadly mechanical moves first.
> @@ -2298,87 +2391,29 @@ static enum scan_result collapse_file(struct mm_struct *mm, unsigned long addr,
> [ ... skip 95 lines ... ]
> }
>
> + /* At this point folio can be NULL, or a value. */
> + state.folio = folio;
> + result = prepare_collapse_file_folio(index, &state);
> + folio = state.folio;
This is a little ugly, but I think probably necessarily at this point in the
operation!
> + if (result != SCAN_SUCCEED)
> + goto xa_unlocked;
> /*
> * The folio must be locked, so we can drop the i_pages lock
> * without racing with truncate.
I looked through the rest of the logic and it all seems to be correct!
Cheers, Lorenzo
NIT: This is 101 chars,
NIT: This is 101 chars,
--
Lorenzo Stoakes (ARM) <ljs@xxxxxxxxxx>