Commit 274b9240 authored by Jeff Moyer's avatar Jeff Moyer Committed by Dan Williams

libnvdimm/pfn: Fix namespace creation on misaligned addresses

Yi reported[1] that after commit a3619190 ("libnvdimm/pfn: stop
padding pmem namespaces to section alignment"), it was no longer
possible to create a device dax namespace with a 1G alignment.  The
reason was that the pmem region was not itself 1G-aligned.  The code
happily skips past the first 512M, but fails to account for a now
misaligned end offset (since space was allocated starting at that
misaligned address, and extending for size GBs).  Reintroduce
end_trunc, so that the code correctly handles the misaligned end
address.  This results in the same behavior as before the introduction
of the offending commit.

[1] https://lists.01.org/pipermail/linux-nvdimm/2019-July/022813.html

Fixes: a3619190 ("libnvdimm/pfn: stop padding pmem namespaces ...")
Reported-and-tested-by: default avatarYi Zhang <yi.zhang@redhat.com>
Signed-off-by: default avatarJeff Moyer <jmoyer@redhat.com>
Link: https://lore.kernel.org/r/x49ftll8f39.fsf@segfault.boston.devel.redhat.comSigned-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent a55aa89a
...@@ -655,6 +655,7 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn) ...@@ -655,6 +655,7 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
resource_size_t start, size; resource_size_t start, size;
struct nd_region *nd_region; struct nd_region *nd_region;
unsigned long npfns, align; unsigned long npfns, align;
u32 end_trunc;
struct nd_pfn_sb *pfn_sb; struct nd_pfn_sb *pfn_sb;
phys_addr_t offset; phys_addr_t offset;
const char *sig; const char *sig;
...@@ -696,6 +697,7 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn) ...@@ -696,6 +697,7 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
size = resource_size(&nsio->res); size = resource_size(&nsio->res);
npfns = PHYS_PFN(size - SZ_8K); npfns = PHYS_PFN(size - SZ_8K);
align = max(nd_pfn->align, (1UL << SUBSECTION_SHIFT)); align = max(nd_pfn->align, (1UL << SUBSECTION_SHIFT));
end_trunc = start + size - ALIGN_DOWN(start + size, align);
if (nd_pfn->mode == PFN_MODE_PMEM) { if (nd_pfn->mode == PFN_MODE_PMEM) {
/* /*
* The altmap should be padded out to the block size used * The altmap should be padded out to the block size used
...@@ -714,7 +716,7 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn) ...@@ -714,7 +716,7 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
return -ENXIO; return -ENXIO;
} }
npfns = PHYS_PFN(size - offset); npfns = PHYS_PFN(size - offset - end_trunc);
pfn_sb->mode = cpu_to_le32(nd_pfn->mode); pfn_sb->mode = cpu_to_le32(nd_pfn->mode);
pfn_sb->dataoff = cpu_to_le64(offset); pfn_sb->dataoff = cpu_to_le64(offset);
pfn_sb->npfns = cpu_to_le64(npfns); pfn_sb->npfns = cpu_to_le64(npfns);
...@@ -723,6 +725,7 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn) ...@@ -723,6 +725,7 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn)
memcpy(pfn_sb->parent_uuid, nd_dev_to_uuid(&ndns->dev), 16); memcpy(pfn_sb->parent_uuid, nd_dev_to_uuid(&ndns->dev), 16);
pfn_sb->version_major = cpu_to_le16(1); pfn_sb->version_major = cpu_to_le16(1);
pfn_sb->version_minor = cpu_to_le16(3); pfn_sb->version_minor = cpu_to_le16(3);
pfn_sb->end_trunc = cpu_to_le32(end_trunc);
pfn_sb->align = cpu_to_le32(nd_pfn->align); pfn_sb->align = cpu_to_le32(nd_pfn->align);
checksum = nd_sb_checksum((struct nd_gen_sb *) pfn_sb); checksum = nd_sb_checksum((struct nd_gen_sb *) pfn_sb);
pfn_sb->checksum = cpu_to_le64(checksum); pfn_sb->checksum = cpu_to_le64(checksum);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment