Re: [PATCH V9 2/8] dax: Factor out dax_folio_reset_order() helper
From: Jonathan Cameron
Date: Tue Mar 24 2026 - 10:27:30 EST
On Tue, 24 Mar 2026 00:38:15 +0000
John Groves <john@xxxxxxxxxxxxxx> wrote:
> From: John Groves <John@xxxxxxxxxx>
>
> Both fs/dax.c:dax_folio_put() and drivers/dax/fsdev.c:
> fsdev_clear_folio_state() (the latter coming in the next commit after this
> one) contain nearly identical code to reset a compound DAX folio back to
> order-0 pages. Factor this out into a shared helper function.
>
> The new dax_folio_reset_order() function:
> - Clears the folio's mapping and share count
> - Resets compound folio state via folio_reset_order()
> - Clears PageHead and compound_head for each sub-page
> - Restores the pgmap pointer for each resulting order-0 folio
> - Returns the original folio order (for callers that need to advance by
> that many pages)
>
> Two intentional differences from the original dax_folio_put() logic:
>
> 1. folio->share is cleared unconditionally. This is correct because the DAX
> subsystem maintains the invariant that share != 0 only when mapping == NULL
> (enforced by dax_folio_make_shared()). dax_folio_put() ensures share has
> reached zero before calling this helper, so the unconditional clear is safe.
>
> 2. folio->pgmap is now explicitly restored for order-0 folios. For the
> dax_folio_put() caller this is a no-op (reads and writes back the same
> field). It is intentional for the upcoming fsdev_clear_folio_state()
> caller, which converts previously-compound folios and needs pgmap
> re-established for all pages regardless of order.
>
> This simplifies fsdev_clear_folio_state() from ~50 lines to ~15 lines.
>
> Suggested-by: Jonathan Cameron <jonathan.cameron@xxxxxxxxxx>
A couple of trivial "if you are respinning" line length of comments
comments inline.
Subject to DAX folk sanity checking the new comments match their
expectations.
Reviewed-by: Jonathan Cameron <jonathan.cameron@xxxxxxxxxx>
> Reviewed-by: Ira Weiny <ira.weiny@xxxxxxxxx>
> Reviewed-by: Dave Jiang <dave.jiang@xxxxxxxxx>
> Signed-off-by: John Groves <john@xxxxxxxxxx>
> ---
> fs/dax.c | 74 ++++++++++++++++++++++++++++++++++-----------
> include/linux/dax.h | 1 +
> 2 files changed, 57 insertions(+), 18 deletions(-)
>
> diff --git a/fs/dax.c b/fs/dax.c
> index 289e6254aa30..eba86802a7a7 100644
> --- a/fs/dax.c
> +++ b/fs/dax.c
> @@ -378,6 +378,59 @@ static void dax_folio_make_shared(struct folio *folio)
> folio->share = 1;
> }
>
> +/**
> + * dax_folio_reset_order - Reset a compound DAX folio to order-0 pages
> + * @folio: The folio to reset
> + *
> + * Splits a compound folio back into individual order-0 pages,
> + * clearing compound state and restoring pgmap pointers.
> + *
> + * Returns: the original folio order (0 if already order-0)
> + */
> +int dax_folio_reset_order(struct folio *folio)
> +{
> + struct dev_pagemap *pgmap = page_pgmap(&folio->page);
> + int order = folio_order(folio);
> +
> + /*
> + * DAX maintains the invariant that folio->share != 0 only when
> + * folio->mapping == NULL (enforced by dax_folio_make_shared()).
> + * Equivalently: folio->mapping != NULL implies folio->share == 0.
> + * Callers ensure share has been decremented to zero before
> + * calling here, so unconditionally clearing both fields is
> + * correct.
If you happen to spin again, wrap is a bit short of standard 80 chars.
* DAX maintains the invariant that folio->share != 0 only when
* folio->mapping == NULL (enforced by dax_folio_make_shared()).
* Equivalently: folio->mapping != NULL implies folio->share == 0.
* Callers ensure share has been decremented to zero before calling here,
* so unconditionally clearing both fields is correct.
> + */
> + folio->mapping = NULL;
> + folio->share = 0;
> +
> + if (!order) {
> + /*
> + * Restore pgmap explicitly even for order-0 folios. For
> + * the dax_folio_put() caller this is a no-op (same value),
> + * but fsdev_clear_folio_state() may call this on folios
> + * that were previously compound and need pgmap
> + * re-established.
> + */
* Restore pgmap explicitly even for order-0 folios. For the
* dax_folio_put() caller this is a no-op (same value), but
* fsdev_clear_folio_state() may call this on folios that were
* previously compound and need pgmap re-established.
*/
> + folio->pgmap = pgmap;
> + return 0;
> + }
> +
> + folio_reset_order(folio);
> +
> + for (int i = 0; i < (1UL << order); i++) {
> + struct page *page = folio_page(folio, i);
> + struct folio *f = (struct folio *)page;
> +
> + ClearPageHead(page);
> + clear_compound_head(page);
> + f->mapping = NULL;
> + f->share = 0;
> + f->pgmap = pgmap;
> + }
> +
> + return order;
> +}