Skip to content

Commit 59eb73b

Browse files
jagalacticweiny2
authored andcommitted
dax: Factor out dax_folio_reset_order() helper
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@huawei.com> Reviewed-by: Ira Weiny <ira.weiny@intel.com> Reviewed-by: Dave Jiang <dave.jiang@intel.com> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com> Signed-off-by: John Groves <john@groves.net> Link: https://patch.msgid.link/0100019d311cc6b9-5be7428a-7f16-4774-8f90-a44b88ac5660-000000@email.amazonses.com Signed-off-by: Ira Weiny <ira.weiny@intel.com>
1 parent a73cc50 commit 59eb73b

2 files changed

Lines changed: 56 additions & 18 deletions

File tree

fs/dax.c

Lines changed: 55 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,58 @@ static void dax_folio_make_shared(struct folio *folio)
378378
folio->share = 1;
379379
}
380380

381+
/**
382+
* dax_folio_reset_order - Reset a compound DAX folio to order-0 pages
383+
* @folio: The folio to reset
384+
*
385+
* Splits a compound folio back into individual order-0 pages,
386+
* clearing compound state and restoring pgmap pointers.
387+
*
388+
* Returns: the original folio order (0 if already order-0)
389+
*/
390+
int dax_folio_reset_order(struct folio *folio)
391+
{
392+
struct dev_pagemap *pgmap = page_pgmap(&folio->page);
393+
int order = folio_order(folio);
394+
395+
/*
396+
* DAX maintains the invariant that folio->share != 0 only when
397+
* folio->mapping == NULL (enforced by dax_folio_make_shared()).
398+
* Equivalently: folio->mapping != NULL implies folio->share == 0.
399+
* Callers ensure share has been decremented to zero before
400+
* calling here, so unconditionally clearing both fields is
401+
* correct.
402+
*/
403+
folio->mapping = NULL;
404+
folio->share = 0;
405+
406+
if (!order) {
407+
/*
408+
* Restore pgmap explicitly even for order-0 folios. For the
409+
* dax_folio_put() caller this is a no-op (same value), but
410+
* fsdev_clear_folio_state() may call this on folios that
411+
* were previously compound and need pgmap re-established.
412+
*/
413+
folio->pgmap = pgmap;
414+
return 0;
415+
}
416+
417+
folio_reset_order(folio);
418+
419+
for (int i = 0; i < (1UL << order); i++) {
420+
struct page *page = folio_page(folio, i);
421+
struct folio *f = (struct folio *)page;
422+
423+
ClearPageHead(page);
424+
clear_compound_head(page);
425+
f->mapping = NULL;
426+
f->share = 0;
427+
f->pgmap = pgmap;
428+
}
429+
430+
return order;
431+
}
432+
381433
static inline unsigned long dax_folio_put(struct folio *folio)
382434
{
383435
unsigned long ref;
@@ -391,28 +443,13 @@ static inline unsigned long dax_folio_put(struct folio *folio)
391443
if (ref)
392444
return ref;
393445

394-
folio->mapping = NULL;
395-
order = folio_order(folio);
396-
if (!order)
397-
return 0;
398-
folio_reset_order(folio);
446+
order = dax_folio_reset_order(folio);
399447

448+
/* Debug check: verify refcounts are zero for all sub-folios */
400449
for (i = 0; i < (1UL << order); i++) {
401-
struct dev_pagemap *pgmap = page_pgmap(&folio->page);
402450
struct page *page = folio_page(folio, i);
403-
struct folio *new_folio = (struct folio *)page;
404-
405-
ClearPageHead(page);
406-
clear_compound_head(page);
407451

408-
new_folio->mapping = NULL;
409-
/*
410-
* Reset pgmap which was over-written by
411-
* prep_compound_page().
412-
*/
413-
new_folio->pgmap = pgmap;
414-
new_folio->share = 0;
415-
WARN_ON_ONCE(folio_ref_count(new_folio));
452+
WARN_ON_ONCE(folio_ref_count((struct folio *)page));
416453
}
417454

418455
return ref;

include/linux/dax.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ static inline void fs_put_dax(struct dax_device *dax_dev, void *holder)
153153
#if IS_ENABLED(CONFIG_FS_DAX)
154154
int dax_writeback_mapping_range(struct address_space *mapping,
155155
struct dax_device *dax_dev, struct writeback_control *wbc);
156+
int dax_folio_reset_order(struct folio *folio);
156157

157158
struct page *dax_layout_busy_page(struct address_space *mapping);
158159
struct page *dax_layout_busy_page_range(struct address_space *mapping, loff_t start, loff_t end);

0 commit comments

Comments
 (0)