[PATCH 4/4] fsdax: materialize pmem vmemmap metadata on faults
From: Muchun Song
Date: Thu Sep 03 2026 - 09:43:51 EST
Pmem FS-DAX registers the device range as ZONE_DEVICE memory, and the
kernel normally allocates and initializes vmemmap storage for every
advertised PFN up front. Sparse backing storage and workloads that only use
the DAX direct-access path may never need writable per-PFN state for most
of that range, but still pay the memory and initialization cost.
Opt pmem FS-DAX into the shared read-only vmemmap mode and materialize
private metadata before inserting a PFN into a userspace mapping. PMD
faults materialize the whole PMD-sized metadata range. PFNs that are never
faulted continue to use the shared metadata.
This shifts private vmemmap allocation from device registration to the
first DAX fault for each metadata page, so the struct page overhead tracks
the faulted DAX working set instead of the full advertised pmem device
size.
Signed-off-by: Muchun Song <songmuchun@xxxxxxxxxxxxx>
---
drivers/nvdimm/pmem.c | 1 +
fs/dax.c | 5 +++++
2 files changed, 6 insertions(+)
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index b14f75daeda7..5530b32163d3 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -543,6 +543,7 @@ static int pmem_attach_disk(struct device *dev,
pmem->pgmap.nr_range = 1;
pmem->pgmap.type = MEMORY_DEVICE_FS_DAX;
pmem->pgmap.ops = &fsdax_pagemap_ops;
+ pmem->pgmap.flags |= PGMAP_VMEMMAP_OPTIMIZATION;
addr = devm_memremap_pages(dev, &pmem->pgmap);
bb_range = pmem->pgmap.range;
} else {
diff --git a/fs/dax.c b/fs/dax.c
index 1fbba0d21c13..89377301d51b 100644
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -13,6 +13,7 @@
#include <linux/fs.h>
#include <linux/highmem.h>
#include <linux/memcontrol.h>
+#include <linux/memremap.h>
#include <linux/mm.h>
#include <linux/mutex.h>
#include <linux/sched.h>
@@ -1877,6 +1878,10 @@ static vm_fault_t dax_fault_iter(struct vm_fault *vmf,
if (err)
return pmd ? VM_FAULT_FALLBACK : dax_fault_return(err);
+ err = vmemmap_materialize_page(pfn_to_page(pfn), pmd ? PMD_ORDER : 0);
+ if (err)
+ return dax_fault_return(err);
+
*entry = dax_insert_entry(xas, vmf, iter, *entry, pfn, entry_flags);
if (write && iomap->flags & IOMAP_F_SHARED) {
--
2.54.0