diff options
author | Dan Williams <dan.j.williams@intel.com> | 2017-06-03 21:59:15 -0400 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2017-06-15 17:31:39 -0400 |
commit | c12c48ce869d72029d70666f615cbd8f67fc14e9 (patch) | |
tree | c38e0587856fdaf94d0401cf644aae05c519804a | |
parent | 564e871aa66f548a947b23808d3140f326381f0c (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.c | 53 | ||||
-rw-r--r-- | drivers/nvdimm/label.c | 3 | ||||
-rw-r--r-- | drivers/nvdimm/namespace_devs.c | 9 | ||||
-rw-r--r-- | drivers/nvdimm/nd.h | 3 | ||||
-rw-r--r-- | drivers/nvdimm/region_devs.c | 43 | ||||
-rw-r--r-- | include/linux/libnvdimm.h | 5 |
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 | ||
1666 | struct 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 | |||
1666 | static size_t sizeof_nfit_set_info(int num_mappings) | 1677 | static 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 | ||
1683 | static 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 | |||
1672 | static int cmp_map_compat(const void *m0, const void *m1) | 1689 | static 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 | ||
1710 | static 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 */ |
1694 | static struct acpi_nfit_memory_map *memdev_from_spa( | 1723 | static 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 | */ |
1700 | struct device *create_namespace_pmem(struct nd_region *nd_region, | 1700 | struct 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) | |||
336 | struct nd_region *to_nd_region(struct device *dev); | 336 | struct nd_region *to_nd_region(struct device *dev); |
337 | int nd_region_to_nstype(struct nd_region *nd_region); | 337 | int nd_region_to_nstype(struct nd_region *nd_region); |
338 | int nd_region_register_namespaces(struct nd_region *nd_region, int *err); | 338 | int nd_region_register_namespaces(struct nd_region *nd_region, int *err); |
339 | u64 nd_region_interleave_set_cookie(struct nd_region *nd_region); | 339 | u64 nd_region_interleave_set_cookie(struct nd_region *nd_region, |
340 | struct nd_namespace_index *nsindex); | ||
340 | u64 nd_region_interleave_set_altcookie(struct nd_region *nd_region); | 341 | u64 nd_region_interleave_set_altcookie(struct nd_region *nd_region); |
341 | void nvdimm_bus_lock(struct device *dev); | 342 | void nvdimm_bus_lock(struct device *dev); |
342 | void nvdimm_bus_unlock(struct device *dev); | 343 | void 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 | } |
318 | static DEVICE_ATTR_RO(set_cookie); | 346 | static DEVICE_ATTR_RO(set_cookie); |
319 | 347 | ||
@@ -564,13 +592,18 @@ struct attribute_group nd_region_attribute_group = { | |||
564 | }; | 592 | }; |
565 | EXPORT_SYMBOL_GPL(nd_region_attribute_group); | 593 | EXPORT_SYMBOL_GPL(nd_region_attribute_group); |
566 | 594 | ||
567 | u64 nd_region_interleave_set_cookie(struct nd_region *nd_region) | 595 | u64 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 | ||
576 | u64 nd_region_interleave_set_altcookie(struct nd_region *nd_region) | 609 | u64 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 | ||
73 | struct nd_interleave_set { | 73 | struct 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 | }; |