Commit 0b94da8d authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'libnvdimm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm

Pull libnvdimm fixes from Dan Williams:
 "A fix and regression test case for nvdimm namespace label
  compatibility.

  Details:

   - An "nvdimm namespace label" is metadata on an nvdimm that
     provisions dimm capacity into a "namespace" that can host a block
     device / dax-filesytem, or a device-dax character device.

     A namespace is an object that other operating environment and
     platform firmware needs to comprehend for capabilities like booting
     from an nvdimm.

     The label metadata contains a checksum that Linux was not
     calculating correctly leading to other environments rejecting the
     Linux label.

   These have received a build success notification from the kbuild
   robot, and a positive test result from Nick who reported the problem"

* 'libnvdimm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm:
  nfit, libnvdimm: fix interleave set cookie calculation
  tools/testing/nvdimm: make iset cookie predictable
parents e27fd02d 86ef58a4
...@@ -1603,7 +1603,7 @@ static size_t sizeof_nfit_set_info(int num_mappings) ...@@ -1603,7 +1603,7 @@ static size_t sizeof_nfit_set_info(int num_mappings)
+ num_mappings * sizeof(struct nfit_set_info_map); + num_mappings * sizeof(struct nfit_set_info_map);
} }
static int cmp_map(const void *m0, const void *m1) static int cmp_map_compat(const void *m0, const void *m1)
{ {
const struct nfit_set_info_map *map0 = m0; const struct nfit_set_info_map *map0 = m0;
const struct nfit_set_info_map *map1 = m1; const struct nfit_set_info_map *map1 = m1;
...@@ -1612,6 +1612,14 @@ static int cmp_map(const void *m0, const void *m1) ...@@ -1612,6 +1612,14 @@ static int cmp_map(const void *m0, const void *m1)
sizeof(u64)); sizeof(u64));
} }
static int cmp_map(const void *m0, const void *m1)
{
const struct nfit_set_info_map *map0 = m0;
const struct nfit_set_info_map *map1 = m1;
return map0->region_offset - map1->region_offset;
}
/* Retrieve the nth entry referencing this spa */ /* Retrieve the nth entry referencing this spa */
static struct acpi_nfit_memory_map *memdev_from_spa( static struct acpi_nfit_memory_map *memdev_from_spa(
struct acpi_nfit_desc *acpi_desc, u16 range_index, int n) struct acpi_nfit_desc *acpi_desc, u16 range_index, int n)
...@@ -1667,6 +1675,12 @@ static int acpi_nfit_init_interleave_set(struct acpi_nfit_desc *acpi_desc, ...@@ -1667,6 +1675,12 @@ static int acpi_nfit_init_interleave_set(struct acpi_nfit_desc *acpi_desc,
sort(&info->mapping[0], nr, sizeof(struct nfit_set_info_map), sort(&info->mapping[0], nr, sizeof(struct nfit_set_info_map),
cmp_map, NULL); cmp_map, NULL);
nd_set->cookie = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0); nd_set->cookie = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0);
/* support namespaces created with the wrong sort order */
sort(&info->mapping[0], nr, sizeof(struct nfit_set_info_map),
cmp_map_compat, NULL);
nd_set->altcookie = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0);
ndr_desc->nd_set = nd_set; ndr_desc->nd_set = nd_set;
devm_kfree(dev, info); devm_kfree(dev, info);
......
...@@ -1700,6 +1700,7 @@ static int select_pmem_id(struct nd_region *nd_region, u8 *pmem_id) ...@@ -1700,6 +1700,7 @@ static int select_pmem_id(struct nd_region *nd_region, u8 *pmem_id)
struct device *create_namespace_pmem(struct nd_region *nd_region, struct device *create_namespace_pmem(struct nd_region *nd_region,
struct nd_namespace_label *nd_label) struct nd_namespace_label *nd_label)
{ {
u64 altcookie = nd_region_interleave_set_altcookie(nd_region);
u64 cookie = nd_region_interleave_set_cookie(nd_region); u64 cookie = nd_region_interleave_set_cookie(nd_region);
struct nd_label_ent *label_ent; struct nd_label_ent *label_ent;
struct nd_namespace_pmem *nspm; struct nd_namespace_pmem *nspm;
...@@ -1718,7 +1719,11 @@ struct device *create_namespace_pmem(struct nd_region *nd_region, ...@@ -1718,7 +1719,11 @@ struct device *create_namespace_pmem(struct nd_region *nd_region,
if (__le64_to_cpu(nd_label->isetcookie) != cookie) { if (__le64_to_cpu(nd_label->isetcookie) != cookie) {
dev_dbg(&nd_region->dev, "invalid cookie in label: %pUb\n", dev_dbg(&nd_region->dev, "invalid cookie in label: %pUb\n",
nd_label->uuid); nd_label->uuid);
return ERR_PTR(-EAGAIN); if (__le64_to_cpu(nd_label->isetcookie) != altcookie)
return ERR_PTR(-EAGAIN);
dev_dbg(&nd_region->dev, "valid altcookie in label: %pUb\n",
nd_label->uuid);
} }
nspm = kzalloc(sizeof(*nspm), GFP_KERNEL); nspm = kzalloc(sizeof(*nspm), GFP_KERNEL);
...@@ -1733,9 +1738,14 @@ struct device *create_namespace_pmem(struct nd_region *nd_region, ...@@ -1733,9 +1738,14 @@ struct device *create_namespace_pmem(struct nd_region *nd_region,
res->name = dev_name(&nd_region->dev); res->name = dev_name(&nd_region->dev);
res->flags = IORESOURCE_MEM; res->flags = IORESOURCE_MEM;
for (i = 0; i < nd_region->ndr_mappings; i++) for (i = 0; i < nd_region->ndr_mappings; i++) {
if (!has_uuid_at_pos(nd_region, nd_label->uuid, cookie, i)) if (has_uuid_at_pos(nd_region, nd_label->uuid, cookie, i))
break; continue;
if (has_uuid_at_pos(nd_region, nd_label->uuid, altcookie, i))
continue;
break;
}
if (i < nd_region->ndr_mappings) { if (i < nd_region->ndr_mappings) {
struct nvdimm_drvdata *ndd = to_ndd(&nd_region->mapping[i]); struct nvdimm_drvdata *ndd = to_ndd(&nd_region->mapping[i]);
......
...@@ -328,6 +328,7 @@ struct nd_region *to_nd_region(struct device *dev); ...@@ -328,6 +328,7 @@ struct nd_region *to_nd_region(struct device *dev);
int nd_region_to_nstype(struct nd_region *nd_region); int nd_region_to_nstype(struct nd_region *nd_region);
int nd_region_register_namespaces(struct nd_region *nd_region, int *err); int nd_region_register_namespaces(struct nd_region *nd_region, int *err);
u64 nd_region_interleave_set_cookie(struct nd_region *nd_region); u64 nd_region_interleave_set_cookie(struct nd_region *nd_region);
u64 nd_region_interleave_set_altcookie(struct nd_region *nd_region);
void nvdimm_bus_lock(struct device *dev); void nvdimm_bus_lock(struct device *dev);
void nvdimm_bus_unlock(struct device *dev); void nvdimm_bus_unlock(struct device *dev);
bool is_nvdimm_bus_locked(struct device *dev); bool is_nvdimm_bus_locked(struct device *dev);
......
...@@ -505,6 +505,15 @@ u64 nd_region_interleave_set_cookie(struct nd_region *nd_region) ...@@ -505,6 +505,15 @@ u64 nd_region_interleave_set_cookie(struct nd_region *nd_region)
return 0; return 0;
} }
u64 nd_region_interleave_set_altcookie(struct nd_region *nd_region)
{
struct nd_interleave_set *nd_set = nd_region->nd_set;
if (nd_set)
return nd_set->altcookie;
return 0;
}
void nd_mapping_free_labels(struct nd_mapping *nd_mapping) void nd_mapping_free_labels(struct nd_mapping *nd_mapping)
{ {
struct nd_label_ent *label_ent, *e; struct nd_label_ent *label_ent, *e;
......
...@@ -70,6 +70,8 @@ struct nd_cmd_desc { ...@@ -70,6 +70,8 @@ struct nd_cmd_desc {
struct nd_interleave_set { struct nd_interleave_set {
u64 cookie; u64 cookie;
/* compatibility with initial buggy Linux implementation */
u64 altcookie;
}; };
struct nd_mapping_desc { struct nd_mapping_desc {
......
...@@ -887,7 +887,7 @@ static void nfit_test0_setup(struct nfit_test *t) ...@@ -887,7 +887,7 @@ static void nfit_test0_setup(struct nfit_test *t)
memdev->range_index = 0+1; memdev->range_index = 0+1;
memdev->region_index = 4+1; memdev->region_index = 4+1;
memdev->region_size = SPA0_SIZE/2; memdev->region_size = SPA0_SIZE/2;
memdev->region_offset = t->spa_set_dma[0]; memdev->region_offset = 1;
memdev->address = 0; memdev->address = 0;
memdev->interleave_index = 0; memdev->interleave_index = 0;
memdev->interleave_ways = 2; memdev->interleave_ways = 2;
...@@ -902,7 +902,7 @@ static void nfit_test0_setup(struct nfit_test *t) ...@@ -902,7 +902,7 @@ static void nfit_test0_setup(struct nfit_test *t)
memdev->range_index = 0+1; memdev->range_index = 0+1;
memdev->region_index = 5+1; memdev->region_index = 5+1;
memdev->region_size = SPA0_SIZE/2; memdev->region_size = SPA0_SIZE/2;
memdev->region_offset = t->spa_set_dma[0] + SPA0_SIZE/2; memdev->region_offset = (1 << 8);
memdev->address = 0; memdev->address = 0;
memdev->interleave_index = 0; memdev->interleave_index = 0;
memdev->interleave_ways = 2; memdev->interleave_ways = 2;
...@@ -917,7 +917,7 @@ static void nfit_test0_setup(struct nfit_test *t) ...@@ -917,7 +917,7 @@ static void nfit_test0_setup(struct nfit_test *t)
memdev->range_index = 1+1; memdev->range_index = 1+1;
memdev->region_index = 4+1; memdev->region_index = 4+1;
memdev->region_size = SPA1_SIZE/4; memdev->region_size = SPA1_SIZE/4;
memdev->region_offset = t->spa_set_dma[1]; memdev->region_offset = (1 << 16);
memdev->address = SPA0_SIZE/2; memdev->address = SPA0_SIZE/2;
memdev->interleave_index = 0; memdev->interleave_index = 0;
memdev->interleave_ways = 4; memdev->interleave_ways = 4;
...@@ -932,7 +932,7 @@ static void nfit_test0_setup(struct nfit_test *t) ...@@ -932,7 +932,7 @@ static void nfit_test0_setup(struct nfit_test *t)
memdev->range_index = 1+1; memdev->range_index = 1+1;
memdev->region_index = 5+1; memdev->region_index = 5+1;
memdev->region_size = SPA1_SIZE/4; memdev->region_size = SPA1_SIZE/4;
memdev->region_offset = t->spa_set_dma[1] + SPA1_SIZE/4; memdev->region_offset = (1 << 24);
memdev->address = SPA0_SIZE/2; memdev->address = SPA0_SIZE/2;
memdev->interleave_index = 0; memdev->interleave_index = 0;
memdev->interleave_ways = 4; memdev->interleave_ways = 4;
...@@ -947,7 +947,7 @@ static void nfit_test0_setup(struct nfit_test *t) ...@@ -947,7 +947,7 @@ static void nfit_test0_setup(struct nfit_test *t)
memdev->range_index = 1+1; memdev->range_index = 1+1;
memdev->region_index = 6+1; memdev->region_index = 6+1;
memdev->region_size = SPA1_SIZE/4; memdev->region_size = SPA1_SIZE/4;
memdev->region_offset = t->spa_set_dma[1] + 2*SPA1_SIZE/4; memdev->region_offset = (1ULL << 32);
memdev->address = SPA0_SIZE/2; memdev->address = SPA0_SIZE/2;
memdev->interleave_index = 0; memdev->interleave_index = 0;
memdev->interleave_ways = 4; memdev->interleave_ways = 4;
...@@ -962,7 +962,7 @@ static void nfit_test0_setup(struct nfit_test *t) ...@@ -962,7 +962,7 @@ static void nfit_test0_setup(struct nfit_test *t)
memdev->range_index = 1+1; memdev->range_index = 1+1;
memdev->region_index = 7+1; memdev->region_index = 7+1;
memdev->region_size = SPA1_SIZE/4; memdev->region_size = SPA1_SIZE/4;
memdev->region_offset = t->spa_set_dma[1] + 3*SPA1_SIZE/4; memdev->region_offset = (1ULL << 40);
memdev->address = SPA0_SIZE/2; memdev->address = SPA0_SIZE/2;
memdev->interleave_index = 0; memdev->interleave_index = 0;
memdev->interleave_ways = 4; memdev->interleave_ways = 4;
...@@ -1380,7 +1380,7 @@ static void nfit_test0_setup(struct nfit_test *t) ...@@ -1380,7 +1380,7 @@ static void nfit_test0_setup(struct nfit_test *t)
memdev->range_index = 11+1; memdev->range_index = 11+1;
memdev->region_index = 9+1; memdev->region_index = 9+1;
memdev->region_size = SPA0_SIZE; memdev->region_size = SPA0_SIZE;
memdev->region_offset = t->spa_set_dma[2]; memdev->region_offset = (1ULL << 48);
memdev->address = 0; memdev->address = 0;
memdev->interleave_index = 0; memdev->interleave_index = 0;
memdev->interleave_ways = 1; memdev->interleave_ways = 1;
......
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