summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2017-06-03 21:59:15 -0400
committerDan Williams <dan.j.williams@intel.com>2017-06-15 17:31:39 -0400
commitc12c48ce869d72029d70666f615cbd8f67fc14e9 (patch)
treec38e0587856fdaf94d0401cf644aae05c519804a
parent564e871aa66f548a947b23808d3140f326381f0c (diff)
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>
-rw-r--r--drivers/acpi/nfit/core.c53
-rw-r--r--drivers/nvdimm/label.c3
-rw-r--r--drivers/nvdimm/namespace_devs.c9
-rw-r--r--drivers/nvdimm/nd.h3
-rw-r--r--drivers/nvdimm/region_devs.c43
-rw-r--r--include/linux/libnvdimm.h5
6 files changed, 104 insertions, 12 deletions
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
index 097eff0b963d..e744ab38eaf9 100644
--- a/drivers/acpi/nfit/core.c
+++ b/drivers/acpi/nfit/core.c
@@ -1663,12 +1663,29 @@ struct nfit_set_info {
1663 } mapping[0]; 1663 } mapping[0];
1664}; 1664};
1665 1665
1666struct nfit_set_info2 {
1667 struct nfit_set_info_map2 {
1668 u64 region_offset;
1669 u32 serial_number;
1670 u16 vendor_id;
1671 u16 manufacturing_date;
1672 u8 manufacturing_location;
1673 u8 reserved[31];
1674 } mapping[0];
1675};
1676
1666static size_t sizeof_nfit_set_info(int num_mappings) 1677static size_t sizeof_nfit_set_info(int num_mappings)
1667{ 1678{
1668 return sizeof(struct nfit_set_info) 1679 return sizeof(struct nfit_set_info)
1669 + num_mappings * sizeof(struct nfit_set_info_map); 1680 + num_mappings * sizeof(struct nfit_set_info_map);
1670} 1681}
1671 1682
1683static size_t sizeof_nfit_set_info2(int num_mappings)
1684{
1685 return sizeof(struct nfit_set_info2)
1686 + num_mappings * sizeof(struct nfit_set_info_map2);
1687}
1688
1672static int cmp_map_compat(const void *m0, const void *m1) 1689static int cmp_map_compat(const void *m0, const void *m1)
1673{ 1690{
1674 const struct nfit_set_info_map *map0 = m0; 1691 const struct nfit_set_info_map *map0 = m0;
@@ -1690,6 +1707,18 @@ static int cmp_map(const void *m0, const void *m1)
1690 return 0; 1707 return 0;
1691} 1708}
1692 1709
1710static int cmp_map2(const void *m0, const void *m1)
1711{
1712 const struct nfit_set_info_map2 *map0 = m0;
1713 const struct nfit_set_info_map2 *map1 = m1;
1714
1715 if (map0->region_offset < map1->region_offset)
1716 return -1;
1717 else if (map0->region_offset > map1->region_offset)
1718 return 1;
1719 return 0;
1720}
1721
1693/* Retrieve the nth entry referencing this spa */ 1722/* Retrieve the nth entry referencing this spa */
1694static struct acpi_nfit_memory_map *memdev_from_spa( 1723static struct acpi_nfit_memory_map *memdev_from_spa(
1695 struct acpi_nfit_desc *acpi_desc, u16 range_index, int n) 1724 struct acpi_nfit_desc *acpi_desc, u16 range_index, int n)
@@ -1711,6 +1740,7 @@ static int acpi_nfit_init_interleave_set(struct acpi_nfit_desc *acpi_desc,
1711 struct device *dev = acpi_desc->dev; 1740 struct device *dev = acpi_desc->dev;
1712 struct nd_interleave_set *nd_set; 1741 struct nd_interleave_set *nd_set;
1713 u16 nr = ndr_desc->num_mappings; 1742 u16 nr = ndr_desc->num_mappings;
1743 struct nfit_set_info2 *info2;
1714 struct nfit_set_info *info; 1744 struct nfit_set_info *info;
1715 1745
1716 if (spa_type == NFIT_SPA_PM || spa_type == NFIT_SPA_VOLATILE) 1746 if (spa_type == NFIT_SPA_PM || spa_type == NFIT_SPA_VOLATILE)
@@ -1725,9 +1755,15 @@ static int acpi_nfit_init_interleave_set(struct acpi_nfit_desc *acpi_desc,
1725 info = devm_kzalloc(dev, sizeof_nfit_set_info(nr), GFP_KERNEL); 1755 info = devm_kzalloc(dev, sizeof_nfit_set_info(nr), GFP_KERNEL);
1726 if (!info) 1756 if (!info)
1727 return -ENOMEM; 1757 return -ENOMEM;
1758
1759 info2 = devm_kzalloc(dev, sizeof_nfit_set_info2(nr), GFP_KERNEL);
1760 if (!info2)
1761 return -ENOMEM;
1762
1728 for (i = 0; i < nr; i++) { 1763 for (i = 0; i < nr; i++) {
1729 struct nd_mapping_desc *mapping = &ndr_desc->mapping[i]; 1764 struct nd_mapping_desc *mapping = &ndr_desc->mapping[i];
1730 struct nfit_set_info_map *map = &info->mapping[i]; 1765 struct nfit_set_info_map *map = &info->mapping[i];
1766 struct nfit_set_info_map2 *map2 = &info2->mapping[i];
1731 struct nvdimm *nvdimm = mapping->nvdimm; 1767 struct nvdimm *nvdimm = mapping->nvdimm;
1732 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); 1768 struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
1733 struct acpi_nfit_memory_map *memdev = memdev_from_spa(acpi_desc, 1769 struct acpi_nfit_memory_map *memdev = memdev_from_spa(acpi_desc,
@@ -1740,19 +1776,32 @@ static int acpi_nfit_init_interleave_set(struct acpi_nfit_desc *acpi_desc,
1740 1776
1741 map->region_offset = memdev->region_offset; 1777 map->region_offset = memdev->region_offset;
1742 map->serial_number = nfit_mem->dcr->serial_number; 1778 map->serial_number = nfit_mem->dcr->serial_number;
1779
1780 map2->region_offset = memdev->region_offset;
1781 map2->serial_number = nfit_mem->dcr->serial_number;
1782 map2->vendor_id = nfit_mem->dcr->vendor_id;
1783 map2->manufacturing_date = nfit_mem->dcr->manufacturing_date;
1784 map2->manufacturing_location = nfit_mem->dcr->manufacturing_location;
1743 } 1785 }
1744 1786
1787 /* v1.1 namespaces */
1745 sort(&info->mapping[0], nr, sizeof(struct nfit_set_info_map), 1788 sort(&info->mapping[0], nr, sizeof(struct nfit_set_info_map),
1746 cmp_map, NULL); 1789 cmp_map, NULL);
1747 nd_set->cookie = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0); 1790 nd_set->cookie1 = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0);
1791
1792 /* v1.2 namespaces */
1793 sort(&info2->mapping[0], nr, sizeof(struct nfit_set_info_map2),
1794 cmp_map2, NULL);
1795 nd_set->cookie2 = nd_fletcher64(info2, sizeof_nfit_set_info2(nr), 0);
1748 1796
1749 /* support namespaces created with the wrong sort order */ 1797 /* support v1.1 namespaces created with the wrong sort order */
1750 sort(&info->mapping[0], nr, sizeof(struct nfit_set_info_map), 1798 sort(&info->mapping[0], nr, sizeof(struct nfit_set_info_map),
1751 cmp_map_compat, NULL); 1799 cmp_map_compat, NULL);
1752 nd_set->altcookie = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0); 1800 nd_set->altcookie = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0);
1753 1801
1754 ndr_desc->nd_set = nd_set; 1802 ndr_desc->nd_set = nd_set;
1755 devm_kfree(dev, info); 1803 devm_kfree(dev, info);
1804 devm_kfree(dev, info2);
1756 1805
1757 return 0; 1806 return 0;
1758} 1807}
diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c
index d6233d220bfd..1aacd4866c76 100644
--- a/drivers/nvdimm/label.c
+++ b/drivers/nvdimm/label.c
@@ -553,7 +553,6 @@ static int __pmem_label_update(struct nd_region *nd_region,
553 struct nd_mapping *nd_mapping, struct nd_namespace_pmem *nspm, 553 struct nd_mapping *nd_mapping, struct nd_namespace_pmem *nspm,
554 int pos) 554 int pos)
555{ 555{
556 u64 cookie = nd_region_interleave_set_cookie(nd_region);
557 struct nvdimm_drvdata *ndd = to_ndd(nd_mapping); 556 struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
558 struct nd_label_ent *label_ent, *victim = NULL; 557 struct nd_label_ent *label_ent, *victim = NULL;
559 struct nd_namespace_label *nd_label; 558 struct nd_namespace_label *nd_label;
@@ -563,11 +562,13 @@ static int __pmem_label_update(struct nd_region *nd_region,
563 unsigned long *free; 562 unsigned long *free;
564 u32 nslot, slot; 563 u32 nslot, slot;
565 size_t offset; 564 size_t offset;
565 u64 cookie;
566 int rc; 566 int rc;
567 567
568 if (!preamble_next(ndd, &nsindex, &free, &nslot)) 568 if (!preamble_next(ndd, &nsindex, &free, &nslot))
569 return -ENXIO; 569 return -ENXIO;
570 570
571 cookie = nd_region_interleave_set_cookie(nd_region, nsindex);
571 nd_label_gen_id(&label_id, nspm->uuid, 0); 572 nd_label_gen_id(&label_id, nspm->uuid, 0);
572 for_each_dpa_resource(ndd, res) 573 for_each_dpa_resource(ndd, res)
573 if (strcmp(res->name, label_id.id) == 0) 574 if (strcmp(res->name, label_id.id) == 0)
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
index 2f9dfbd2dbec..51f304fe8a52 100644
--- a/drivers/nvdimm/namespace_devs.c
+++ b/drivers/nvdimm/namespace_devs.c
@@ -1698,10 +1698,11 @@ static int select_pmem_id(struct nd_region *nd_region, u8 *pmem_id)
1698 * @nd_label: target pmem namespace label to evaluate 1698 * @nd_label: target pmem namespace label to evaluate
1699 */ 1699 */
1700struct device *create_namespace_pmem(struct nd_region *nd_region, 1700struct device *create_namespace_pmem(struct nd_region *nd_region,
1701 struct nd_namespace_index *nsindex,
1701 struct nd_namespace_label *nd_label) 1702 struct nd_namespace_label *nd_label)
1702{ 1703{
1704 u64 cookie = nd_region_interleave_set_cookie(nd_region, nsindex);
1703 u64 altcookie = nd_region_interleave_set_altcookie(nd_region); 1705 u64 altcookie = nd_region_interleave_set_altcookie(nd_region);
1704 u64 cookie = nd_region_interleave_set_cookie(nd_region);
1705 struct nd_label_ent *label_ent; 1706 struct nd_label_ent *label_ent;
1706 struct nd_namespace_pmem *nspm; 1707 struct nd_namespace_pmem *nspm;
1707 struct nd_mapping *nd_mapping; 1708 struct nd_mapping *nd_mapping;
@@ -2108,7 +2109,11 @@ static struct device **scan_labels(struct nd_region *nd_region)
2108 goto err; 2109 goto err;
2109 devs[count++] = dev; 2110 devs[count++] = dev;
2110 } else { 2111 } else {
2111 dev = create_namespace_pmem(nd_region, nd_label); 2112 struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
2113 struct nd_namespace_index *nsindex;
2114
2115 nsindex = to_namespace_index(ndd, ndd->ns_current);
2116 dev = create_namespace_pmem(nd_region, nsindex, nd_label);
2112 if (IS_ERR(dev)) { 2117 if (IS_ERR(dev)) {
2113 switch (PTR_ERR(dev)) { 2118 switch (PTR_ERR(dev)) {
2114 case -EAGAIN: 2119 case -EAGAIN:
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
index 28d9f4481547..ad4e518940c9 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
@@ -336,7 +336,8 @@ static inline struct device *nd_dax_create(struct nd_region *nd_region)
336struct nd_region *to_nd_region(struct device *dev); 336struct nd_region *to_nd_region(struct device *dev);
337int nd_region_to_nstype(struct nd_region *nd_region); 337int nd_region_to_nstype(struct nd_region *nd_region);
338int nd_region_register_namespaces(struct nd_region *nd_region, int *err); 338int nd_region_register_namespaces(struct nd_region *nd_region, int *err);
339u64 nd_region_interleave_set_cookie(struct nd_region *nd_region); 339u64 nd_region_interleave_set_cookie(struct nd_region *nd_region,
340 struct nd_namespace_index *nsindex);
340u64 nd_region_interleave_set_altcookie(struct nd_region *nd_region); 341u64 nd_region_interleave_set_altcookie(struct nd_region *nd_region);
341void nvdimm_bus_lock(struct device *dev); 342void nvdimm_bus_lock(struct device *dev);
342void nvdimm_bus_unlock(struct device *dev); 343void nvdimm_bus_unlock(struct device *dev);
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c
index b550edf2571f..282b8991ea83 100644
--- a/drivers/nvdimm/region_devs.c
+++ b/drivers/nvdimm/region_devs.c
@@ -307,13 +307,41 @@ static ssize_t set_cookie_show(struct device *dev,
307{ 307{
308 struct nd_region *nd_region = to_nd_region(dev); 308 struct nd_region *nd_region = to_nd_region(dev);
309 struct nd_interleave_set *nd_set = nd_region->nd_set; 309 struct nd_interleave_set *nd_set = nd_region->nd_set;
310 ssize_t rc = 0;
310 311
311 if (is_nd_pmem(dev) && nd_set) 312 if (is_nd_pmem(dev) && nd_set)
312 /* pass, should be precluded by region_visible */; 313 /* pass, should be precluded by region_visible */;
313 else 314 else
314 return -ENXIO; 315 return -ENXIO;
315 316
316 return sprintf(buf, "%#llx\n", nd_set->cookie); 317 /*
318 * The cookie to show depends on which specification of the
319 * labels we are using. If there are not labels then default to
320 * the v1.1 namespace label cookie definition. To read all this
321 * data we need to wait for probing to settle.
322 */
323 device_lock(dev);
324 nvdimm_bus_lock(dev);
325 wait_nvdimm_bus_probe_idle(dev);
326 if (nd_region->ndr_mappings) {
327 struct nd_mapping *nd_mapping = &nd_region->mapping[0];
328 struct nvdimm_drvdata *ndd = to_ndd(nd_mapping);
329
330 if (ndd) {
331 struct nd_namespace_index *nsindex;
332
333 nsindex = to_namespace_index(ndd, ndd->ns_current);
334 rc = sprintf(buf, "%#llx\n",
335 nd_region_interleave_set_cookie(nd_region,
336 nsindex));
337 }
338 }
339 nvdimm_bus_unlock(dev);
340 device_unlock(dev);
341
342 if (rc)
343 return rc;
344 return sprintf(buf, "%#llx\n", nd_set->cookie1);
317} 345}
318static DEVICE_ATTR_RO(set_cookie); 346static DEVICE_ATTR_RO(set_cookie);
319 347
@@ -564,13 +592,18 @@ struct attribute_group nd_region_attribute_group = {
564}; 592};
565EXPORT_SYMBOL_GPL(nd_region_attribute_group); 593EXPORT_SYMBOL_GPL(nd_region_attribute_group);
566 594
567u64 nd_region_interleave_set_cookie(struct nd_region *nd_region) 595u64 nd_region_interleave_set_cookie(struct nd_region *nd_region,
596 struct nd_namespace_index *nsindex)
568{ 597{
569 struct nd_interleave_set *nd_set = nd_region->nd_set; 598 struct nd_interleave_set *nd_set = nd_region->nd_set;
570 599
571 if (nd_set) 600 if (!nd_set)
572 return nd_set->cookie; 601 return 0;
573 return 0; 602
603 if (nsindex && __le16_to_cpu(nsindex->major) == 1
604 && __le16_to_cpu(nsindex->minor) == 1)
605 return nd_set->cookie1;
606 return nd_set->cookie2;
574} 607}
575 608
576u64 nd_region_interleave_set_altcookie(struct nd_region *nd_region) 609u64 nd_region_interleave_set_altcookie(struct nd_region *nd_region)
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h
index 6c807017128d..722cdf21429f 100644
--- a/include/linux/libnvdimm.h
+++ b/include/linux/libnvdimm.h
@@ -71,7 +71,10 @@ struct nd_cmd_desc {
71}; 71};
72 72
73struct nd_interleave_set { 73struct nd_interleave_set {
74 u64 cookie; 74 /* v1.1 definition of the interleave-set-cookie algorithm */
75 u64 cookie1;
76 /* v1.2 definition of the interleave-set-cookie algorithm */
77 u64 cookie2;
75 /* compatibility with initial buggy Linux implementation */ 78 /* compatibility with initial buggy Linux implementation */
76 u64 altcookie; 79 u64 altcookie;
77}; 80};