aboutsummaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-04-21 14:12:01 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-04-21 14:12:01 -0700
commitbb0bc49a1cef574646eb25d74709c5ff200903a8 (patch)
treedaef4973bd2a20c71ba549fe8a97441dddf21364 /fs
parentc94faa7cc414698d7c32cd43b7d02f34709a71f6 (diff)
parent45df9111692c62d5f09fc4345ae36dae31024797 (diff)
Merge tag 'libnvdimm-for-7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm
Pull dax updates from Ira Weiny: "The series adds DAX support required for the upcoming fuse/famfs file system.[1] The support here is required because famfs is backed by devdax rather than pmem. This all lays the groundwork for using shared memory as a file system" Link: https://lore.kernel.org/all/0100019d43e5f632-f5862a3e-361c-4b54-a9a6-96c242a8f17a-000000@email.amazonses.com/ [1] * tag 'libnvdimm-for-7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm: dax/fsdev: fix uninitialized kaddr in fsdev_dax_zero_page_range() dax: export dax_dev_get() dax: Add fs_dax_get() func to prepare dax for fs-dax usage dax: Add dax_set_ops() for setting dax_operations at bind time dax: Add dax_operations for use by fs-dax on fsdev dax dax: Save the kva from memremap dax: add fsdev.c driver for fs-dax on character dax dax: Factor out dax_folio_reset_order() helper dax: move dax_pgoff_to_phys from [drivers/dax/] device.c to bus.c
Diffstat (limited to 'fs')
-rw-r--r--fs/dax.c74
1 files changed, 56 insertions, 18 deletions
diff --git a/fs/dax.c b/fs/dax.c
index a5237169b467..6d175cd47a99 100644
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -377,6 +377,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.
+ */
+ 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.
+ */
+ 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;
+}
+EXPORT_SYMBOL_GPL(dax_folio_reset_order);
+
static inline unsigned long dax_folio_put(struct folio *folio)
{
unsigned long ref;
@@ -390,28 +443,13 @@ static inline unsigned long dax_folio_put(struct folio *folio)
if (ref)
return ref;
- folio->mapping = NULL;
- order = folio_order(folio);
- if (!order)
- return 0;
- folio_reset_order(folio);
+ order = dax_folio_reset_order(folio);
+ /* Debug check: verify refcounts are zero for all sub-folios */
for (i = 0; i < (1UL << order); i++) {
- struct dev_pagemap *pgmap = page_pgmap(&folio->page);
struct page *page = folio_page(folio, i);
- struct folio *new_folio = (struct folio *)page;
-
- ClearPageHead(page);
- clear_compound_head(page);
- new_folio->mapping = NULL;
- /*
- * Reset pgmap which was over-written by
- * prep_compound_page().
- */
- new_folio->pgmap = pgmap;
- new_folio->share = 0;
- WARN_ON_ONCE(folio_ref_count(new_folio));
+ WARN_ON_ONCE(folio_ref_count((struct folio *)page));
}
return ref;