libnvdimm, label: add v1.2 interleave-set-cookie algorithm
The interleave-set-cookie algorithm is extended to incorporate all the
same components that are used to generate an nvdimm unique-id. For
backwards compatibility we still maintain the old v1.1 definition.
Reported-by: Nicholas Moulin <nicholas.w.moulin@intel.com>
Reported-by: Kaushik Kanetkar <kaushik.a.kanetkar@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
index 097eff0..e744ab3 100644
--- a/drivers/acpi/nfit/core.c
+++ b/drivers/acpi/nfit/core.c
@@ -1663,12 +1663,29 @@
} mapping[0];
};
+struct nfit_set_info2 {
+ struct nfit_set_info_map2 {
+ u64 region_offset;
+ u32 serial_number;
+ u16 vendor_id;
+ u16 manufacturing_date;
+ u8 manufacturing_location;
+ u8 reserved[31];
+ } mapping[0];
+};
+
static size_t sizeof_nfit_set_info(int num_mappings)
{
return sizeof(struct nfit_set_info)
+ num_mappings * sizeof(struct nfit_set_info_map);
}
+static size_t sizeof_nfit_set_info2(int num_mappings)
+{
+ return sizeof(struct nfit_set_info2)
+ + num_mappings * sizeof(struct nfit_set_info_map2);
+}
+
static int cmp_map_compat(const void *m0, const void *m1)
{
const struct nfit_set_info_map *map0 = m0;
@@ -1690,6 +1707,18 @@
return 0;
}
+static int cmp_map2(const void *m0, const void *m1)
+{
+ const struct nfit_set_info_map2 *map0 = m0;
+ const struct nfit_set_info_map2 *map1 = m1;
+
+ if (map0->region_offset < map1->region_offset)
+ return -1;
+ else if (map0->region_offset > map1->region_offset)
+ return 1;
+ return 0;
+}
+
/* Retrieve the nth entry referencing this spa */
static struct acpi_nfit_memory_map *memdev_from_spa(
struct acpi_nfit_desc *acpi_desc, u16 range_index, int n)
@@ -1711,6 +1740,7 @@
struct device *dev = acpi_desc->dev;
struct nd_interleave_set *nd_set;
u16 nr = ndr_desc->num_mappings;
+ struct nfit_set_info2 *info2;
struct nfit_set_info *info;
if (spa_type == NFIT_SPA_PM || spa_type == NFIT_SPA_VOLATILE)
@@ -1725,9 +1755,15 @@
info = devm_kzalloc(dev, sizeof_nfit_set_info(nr), GFP_KERNEL);
if (!info)
return -ENOMEM;
+
+ info2 = devm_kzalloc(dev, sizeof_nfit_set_info2(nr), GFP_KERNEL);
+ if (!info2)
+ return -ENOMEM;
+
for (i = 0; i < nr; i++) {
struct nd_mapping_desc *mapping = &ndr_desc->mapping[i];
struct nfit_set_info_map *map = &info->mapping[i];
+ struct nfit_set_info_map2 *map2 = &info2->mapping[i];
struct nvdimm *nvdimm = mapping->nvdimm;
struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
struct acpi_nfit_memory_map *memdev = memdev_from_spa(acpi_desc,
@@ -1740,19 +1776,32 @@
map->region_offset = memdev->region_offset;
map->serial_number = nfit_mem->dcr->serial_number;
+
+ map2->region_offset = memdev->region_offset;
+ map2->serial_number = nfit_mem->dcr->serial_number;
+ map2->vendor_id = nfit_mem->dcr->vendor_id;
+ map2->manufacturing_date = nfit_mem->dcr->manufacturing_date;
+ map2->manufacturing_location = nfit_mem->dcr->manufacturing_location;
}
+ /* v1.1 namespaces */
sort(&info->mapping[0], nr, sizeof(struct nfit_set_info_map),
cmp_map, NULL);
- nd_set->cookie = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0);
+ nd_set->cookie1 = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0);
- /* support namespaces created with the wrong sort order */
+ /* v1.2 namespaces */
+ sort(&info2->mapping[0], nr, sizeof(struct nfit_set_info_map2),
+ cmp_map2, NULL);
+ nd_set->cookie2 = nd_fletcher64(info2, sizeof_nfit_set_info2(nr), 0);
+
+ /* support v1.1 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;
devm_kfree(dev, info);
+ devm_kfree(dev, info2);
return 0;
}