diff options
author | Dan Williams <dan.j.williams@intel.com> | 2017-12-04 17:07:43 -0500 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2017-12-19 18:37:34 -0500 |
commit | 41fce90f26333c4fa82e8e43b9ace86c4e8a0120 (patch) | |
tree | 3d7083541ddb4e75d8224d4616177895dc9f2c9f | |
parent | 19deaa217bc04e83b59b5e8c8229eb0e53ad9efc (diff) |
libnvdimm, dax: fix 1GB-aligned namespaces vs physical misalignment
The following namespace configuration attempt:
# ndctl create-namespace -e namespace0.0 -m devdax -a 1G -f
libndctl: ndctl_dax_enable: dax0.1: failed to enable
Error: namespace0.0: failed to enable
failed to reconfigure namespace: No such device or address
...fails when the backing memory range is not physically aligned to 1G:
# cat /proc/iomem | grep Persistent
210000000-30fffffff : Persistent Memory (legacy)
In the above example the 4G persistent memory range starts and ends on a
256MB boundary.
We handle this case correctly when needing to handle cases that violate
section alignment (128MB) collisions against "System RAM", and we simply
need to extend that padding/truncation for the 1GB alignment use case.
Cc: <stable@vger.kernel.org>
Fixes: 315c562536c4 ("libnvdimm, pfn: add 'align' attribute...")
Reported-and-tested-by: Jane Chu <jane.chu@oracle.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
-rw-r--r-- | drivers/nvdimm/pfn_devs.c | 15 |
1 files changed, 12 insertions, 3 deletions
diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c index db2fc7c02e01..2adada1a5855 100644 --- a/drivers/nvdimm/pfn_devs.c +++ b/drivers/nvdimm/pfn_devs.c | |||
@@ -583,6 +583,12 @@ static struct vmem_altmap *__nvdimm_setup_pfn(struct nd_pfn *nd_pfn, | |||
583 | return altmap; | 583 | return altmap; |
584 | } | 584 | } |
585 | 585 | ||
586 | static u64 phys_pmem_align_down(struct nd_pfn *nd_pfn, u64 phys) | ||
587 | { | ||
588 | return min_t(u64, PHYS_SECTION_ALIGN_DOWN(phys), | ||
589 | ALIGN_DOWN(phys, nd_pfn->align)); | ||
590 | } | ||
591 | |||
586 | static int nd_pfn_init(struct nd_pfn *nd_pfn) | 592 | static int nd_pfn_init(struct nd_pfn *nd_pfn) |
587 | { | 593 | { |
588 | u32 dax_label_reserve = is_nd_dax(&nd_pfn->dev) ? SZ_128K : 0; | 594 | u32 dax_label_reserve = is_nd_dax(&nd_pfn->dev) ? SZ_128K : 0; |
@@ -638,13 +644,16 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn) | |||
638 | start = nsio->res.start; | 644 | start = nsio->res.start; |
639 | size = PHYS_SECTION_ALIGN_UP(start + size) - start; | 645 | size = PHYS_SECTION_ALIGN_UP(start + size) - start; |
640 | if (region_intersects(start, size, IORESOURCE_SYSTEM_RAM, | 646 | if (region_intersects(start, size, IORESOURCE_SYSTEM_RAM, |
641 | IORES_DESC_NONE) == REGION_MIXED) { | 647 | IORES_DESC_NONE) == REGION_MIXED |
648 | || !IS_ALIGNED(start + resource_size(&nsio->res), | ||
649 | nd_pfn->align)) { | ||
642 | size = resource_size(&nsio->res); | 650 | size = resource_size(&nsio->res); |
643 | end_trunc = start + size - PHYS_SECTION_ALIGN_DOWN(start + size); | 651 | end_trunc = start + size - phys_pmem_align_down(nd_pfn, |
652 | start + size); | ||
644 | } | 653 | } |
645 | 654 | ||
646 | if (start_pad + end_trunc) | 655 | if (start_pad + end_trunc) |
647 | dev_info(&nd_pfn->dev, "%s section collision, truncate %d bytes\n", | 656 | dev_info(&nd_pfn->dev, "%s alignment collision, truncate %d bytes\n", |
648 | dev_name(&ndns->dev), start_pad + end_trunc); | 657 | dev_name(&ndns->dev), start_pad + end_trunc); |
649 | 658 | ||
650 | /* | 659 | /* |