On Tue, 24 Mar 2026 00:38:15 +0000
John Groves <[email protected]> wrote:

> From: John Groves <[email protected]>
> 
> 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 <[email protected]>
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 <[email protected]>


> Reviewed-by: Ira Weiny <[email protected]>
> Reviewed-by: Dave Jiang <[email protected]>
> Signed-off-by: John Groves <[email protected]>
> ---
>  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;
> +}


Reply via email to