Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

John Groves and committed by
Ira Weiny
59eb73b9 a73cc506

+56 -18
+55 -18
fs/dax.c
··· 378 378 folio->share = 1; 379 379 } 380 380 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 + 381 433 static inline unsigned long dax_folio_put(struct folio *folio) 382 434 { 383 435 unsigned long ref; ··· 443 391 if (ref) 444 392 return ref; 445 393 446 - folio->mapping = NULL; 447 - order = folio_order(folio); 448 - if (!order) 449 - return 0; 450 - folio_reset_order(folio); 394 + order = dax_folio_reset_order(folio); 451 395 396 + /* Debug check: verify refcounts are zero for all sub-folios */ 452 397 for (i = 0; i < (1UL << order); i++) { 453 - struct dev_pagemap *pgmap = page_pgmap(&folio->page); 454 398 struct page *page = folio_page(folio, i); 455 - struct folio *new_folio = (struct folio *)page; 456 399 457 - ClearPageHead(page); 458 - clear_compound_head(page); 459 - 460 - new_folio->mapping = NULL; 461 - /* 462 - * Reset pgmap which was over-written by 463 - * prep_compound_page(). 464 - */ 465 - new_folio->pgmap = pgmap; 466 - new_folio->share = 0; 467 - WARN_ON_ONCE(folio_ref_count(new_folio)); 400 + WARN_ON_ONCE(folio_ref_count((struct folio *)page)); 468 401 } 469 402 470 403 return ref;
+1
include/linux/dax.h
··· 153 153 #if IS_ENABLED(CONFIG_FS_DAX) 154 154 int dax_writeback_mapping_range(struct address_space *mapping, 155 155 struct dax_device *dax_dev, struct writeback_control *wbc); 156 + int dax_folio_reset_order(struct folio *folio); 156 157 157 158 struct page *dax_layout_busy_page(struct address_space *mapping); 158 159 struct page *dax_layout_busy_page_range(struct address_space *mapping, loff_t start, loff_t end);