libnvdimm/pfn: Fix namespace creation on misaligned addresses
Yi reported[1] that after commita3619190d6
("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:a3619190d6
("libnvdimm/pfn: stop padding pmem namespaces ...") Reported-and-tested-by: Yi Zhang <yi.zhang@redhat.com> Signed-off-by: Jeff Moyer <jmoyer@redhat.com> Link: https://lore.kernel.org/r/x49ftll8f39.fsf@segfault.boston.devel.redhat.com Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
parent
a55aa89aab
commit
274b924088
|
@ -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)
|
||||||
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)
|
||||||
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)
|
||||||
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);
|
||||||
|
|
Loading…
Reference in a new issue