Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d9cbe09d authored by Dan Williams's avatar Dan Williams
Browse files

libnvdimm, pmem: fix 'pfn' support for section-misaligned namespaces



The altmap for a section-misaligned namespace needs to arrange for the
base_pfn to be section-aligned.  As a result the 'reserve' region (pfns
from base that do not have a struct page) must be increased.  Otherwise
we trip the altmap validation check in __add_pages:

	if (altmap->base_pfn != phys_start_pfn
			|| vmem_altmap_offset(altmap) > nr_pages) {
		pr_warn_once("memory add fail, invalid altmap\n");
		return -EINVAL;
	}

Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent bc94b996
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#define __NVDIMM_PFN_H

#include <linux/types.h>
#include <linux/mmzone.h>

#define PFN_SIG_LEN 16
#define PFN_SIG "NVDIMM_PFN_INFO\0"
@@ -32,4 +33,16 @@ struct nd_pfn_sb {
	u8 padding[4012];
	__le64 checksum;
};

#ifdef CONFIG_SPARSEMEM
#define PFN_SECTION_ALIGN_DOWN(x) SECTION_ALIGN_DOWN(x)
#define PFN_SECTION_ALIGN_UP(x) SECTION_ALIGN_UP(x)
#else
/*
 * In this case ZONE_DEVICE=n and we will disable 'pfn' device support,
 * but we still want pmem to compile.
 */
#define PFN_SECTION_ALIGN_DOWN(x) (x)
#define PFN_SECTION_ALIGN_UP(x) (x)
#endif
#endif /* __NVDIMM_PFN_H */
+22 −2
Original line number Diff line number Diff line
@@ -356,6 +356,26 @@ static int nvdimm_namespace_detach_pfn(struct nd_namespace_common *ndns)
	return 0;
}

/*
 * We hotplug memory at section granularity, pad the reserved area from
 * the previous section base to the namespace base address.
 */
static unsigned long init_altmap_base(resource_size_t base)
{
	unsigned long base_pfn = __phys_to_pfn(base);

	return PFN_SECTION_ALIGN_DOWN(base_pfn);
}

static unsigned long init_altmap_reserve(resource_size_t base)
{
	unsigned long reserve = __phys_to_pfn(SZ_8K);
	unsigned long base_pfn = __phys_to_pfn(base);

	reserve += base_pfn - PFN_SECTION_ALIGN_DOWN(base_pfn);
	return reserve;
}

static int nvdimm_namespace_attach_pfn(struct nd_namespace_common *ndns)
{
	struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
@@ -369,8 +389,8 @@ static int nvdimm_namespace_attach_pfn(struct nd_namespace_common *ndns)
	phys_addr_t offset;
	int rc;
	struct vmem_altmap __altmap = {
		.base_pfn = __phys_to_pfn(nsio->res.start),
		.reserve = __phys_to_pfn(SZ_8K),
		.base_pfn = init_altmap_base(nsio->res.start),
		.reserve = init_altmap_reserve(nsio->res.start),
	};

	if (!nd_pfn->uuid || !nd_pfn->ndns)