diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-03-03 19:48:48 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-03-03 19:48:48 -0500 |
commit | 0b94da8dfc26ec2eb3e6640726e434abf8c53e49 (patch) | |
tree | 43bf09811495b0452a7a8714341ec6f36a91d6fa | |
parent | e27fd02d92817845471a196b3020c5694cbe5ff3 (diff) | |
parent | 86ef58a4e35e8fa66afb5898cf6dec6a3bb29f67 (diff) |
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
-rw-r--r-- | drivers/acpi/nfit/core.c | 16 | ||||
-rw-r--r-- | drivers/nvdimm/namespace_devs.c | 18 | ||||
-rw-r--r-- | drivers/nvdimm/nd.h | 1 | ||||
-rw-r--r-- | drivers/nvdimm/region_devs.c | 9 | ||||
-rw-r--r-- | include/linux/libnvdimm.h | 2 | ||||
-rw-r--r-- | tools/testing/nvdimm/test/nfit.c | 14 |
6 files changed, 48 insertions, 12 deletions
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 7361d00818e2..662036bdc65e 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c | |||
@@ -1603,7 +1603,7 @@ static size_t sizeof_nfit_set_info(int num_mappings) | |||
1603 | + num_mappings * sizeof(struct nfit_set_info_map); | 1603 | + num_mappings * sizeof(struct nfit_set_info_map); |
1604 | } | 1604 | } |
1605 | 1605 | ||
1606 | static int cmp_map(const void *m0, const void *m1) | 1606 | static int cmp_map_compat(const void *m0, const void *m1) |
1607 | { | 1607 | { |
1608 | const struct nfit_set_info_map *map0 = m0; | 1608 | const struct nfit_set_info_map *map0 = m0; |
1609 | const struct nfit_set_info_map *map1 = m1; | 1609 | const struct nfit_set_info_map *map1 = m1; |
@@ -1612,6 +1612,14 @@ static int cmp_map(const void *m0, const void *m1) | |||
1612 | sizeof(u64)); | 1612 | sizeof(u64)); |
1613 | } | 1613 | } |
1614 | 1614 | ||
1615 | static int cmp_map(const void *m0, const void *m1) | ||
1616 | { | ||
1617 | const struct nfit_set_info_map *map0 = m0; | ||
1618 | const struct nfit_set_info_map *map1 = m1; | ||
1619 | |||
1620 | return map0->region_offset - map1->region_offset; | ||
1621 | } | ||
1622 | |||
1615 | /* Retrieve the nth entry referencing this spa */ | 1623 | /* Retrieve the nth entry referencing this spa */ |
1616 | static struct acpi_nfit_memory_map *memdev_from_spa( | 1624 | static struct acpi_nfit_memory_map *memdev_from_spa( |
1617 | struct acpi_nfit_desc *acpi_desc, u16 range_index, int n) | 1625 | 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 | sort(&info->mapping[0], nr, sizeof(struct nfit_set_info_map), | 1675 | sort(&info->mapping[0], nr, sizeof(struct nfit_set_info_map), |
1668 | cmp_map, NULL); | 1676 | cmp_map, NULL); |
1669 | nd_set->cookie = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0); | 1677 | nd_set->cookie = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0); |
1678 | |||
1679 | /* support namespaces created with the wrong sort order */ | ||
1680 | sort(&info->mapping[0], nr, sizeof(struct nfit_set_info_map), | ||
1681 | cmp_map_compat, NULL); | ||
1682 | nd_set->altcookie = nd_fletcher64(info, sizeof_nfit_set_info(nr), 0); | ||
1683 | |||
1670 | ndr_desc->nd_set = nd_set; | 1684 | ndr_desc->nd_set = nd_set; |
1671 | devm_kfree(dev, info); | 1685 | devm_kfree(dev, info); |
1672 | 1686 | ||
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index ce3e8dfa10ad..1b481a5fb966 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c | |||
@@ -1700,6 +1700,7 @@ static int select_pmem_id(struct nd_region *nd_region, u8 *pmem_id) | |||
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_label *nd_label) | 1701 | struct nd_namespace_label *nd_label) |
1702 | { | 1702 | { |
1703 | u64 altcookie = nd_region_interleave_set_altcookie(nd_region); | ||
1703 | u64 cookie = nd_region_interleave_set_cookie(nd_region); | 1704 | u64 cookie = nd_region_interleave_set_cookie(nd_region); |
1704 | struct nd_label_ent *label_ent; | 1705 | struct nd_label_ent *label_ent; |
1705 | struct nd_namespace_pmem *nspm; | 1706 | struct nd_namespace_pmem *nspm; |
@@ -1718,7 +1719,11 @@ struct device *create_namespace_pmem(struct nd_region *nd_region, | |||
1718 | if (__le64_to_cpu(nd_label->isetcookie) != cookie) { | 1719 | if (__le64_to_cpu(nd_label->isetcookie) != cookie) { |
1719 | dev_dbg(&nd_region->dev, "invalid cookie in label: %pUb\n", | 1720 | dev_dbg(&nd_region->dev, "invalid cookie in label: %pUb\n", |
1720 | nd_label->uuid); | 1721 | nd_label->uuid); |
1721 | return ERR_PTR(-EAGAIN); | 1722 | if (__le64_to_cpu(nd_label->isetcookie) != altcookie) |
1723 | return ERR_PTR(-EAGAIN); | ||
1724 | |||
1725 | dev_dbg(&nd_region->dev, "valid altcookie in label: %pUb\n", | ||
1726 | nd_label->uuid); | ||
1722 | } | 1727 | } |
1723 | 1728 | ||
1724 | nspm = kzalloc(sizeof(*nspm), GFP_KERNEL); | 1729 | nspm = kzalloc(sizeof(*nspm), GFP_KERNEL); |
@@ -1733,9 +1738,14 @@ struct device *create_namespace_pmem(struct nd_region *nd_region, | |||
1733 | res->name = dev_name(&nd_region->dev); | 1738 | res->name = dev_name(&nd_region->dev); |
1734 | res->flags = IORESOURCE_MEM; | 1739 | res->flags = IORESOURCE_MEM; |
1735 | 1740 | ||
1736 | for (i = 0; i < nd_region->ndr_mappings; i++) | 1741 | for (i = 0; i < nd_region->ndr_mappings; i++) { |
1737 | if (!has_uuid_at_pos(nd_region, nd_label->uuid, cookie, i)) | 1742 | if (has_uuid_at_pos(nd_region, nd_label->uuid, cookie, i)) |
1738 | break; | 1743 | continue; |
1744 | if (has_uuid_at_pos(nd_region, nd_label->uuid, altcookie, i)) | ||
1745 | continue; | ||
1746 | break; | ||
1747 | } | ||
1748 | |||
1739 | if (i < nd_region->ndr_mappings) { | 1749 | if (i < nd_region->ndr_mappings) { |
1740 | struct nvdimm_drvdata *ndd = to_ndd(&nd_region->mapping[i]); | 1750 | struct nvdimm_drvdata *ndd = to_ndd(&nd_region->mapping[i]); |
1741 | 1751 | ||
diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index 35dd75057e16..2a99c83aa19f 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h | |||
@@ -328,6 +328,7 @@ struct nd_region *to_nd_region(struct device *dev); | |||
328 | int nd_region_to_nstype(struct nd_region *nd_region); | 328 | int nd_region_to_nstype(struct nd_region *nd_region); |
329 | int nd_region_register_namespaces(struct nd_region *nd_region, int *err); | 329 | int nd_region_register_namespaces(struct nd_region *nd_region, int *err); |
330 | u64 nd_region_interleave_set_cookie(struct nd_region *nd_region); | 330 | u64 nd_region_interleave_set_cookie(struct nd_region *nd_region); |
331 | u64 nd_region_interleave_set_altcookie(struct nd_region *nd_region); | ||
331 | void nvdimm_bus_lock(struct device *dev); | 332 | void nvdimm_bus_lock(struct device *dev); |
332 | void nvdimm_bus_unlock(struct device *dev); | 333 | void nvdimm_bus_unlock(struct device *dev); |
333 | bool is_nvdimm_bus_locked(struct device *dev); | 334 | bool is_nvdimm_bus_locked(struct device *dev); |
diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index 7cd705f3247c..b7cb5066d961 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c | |||
@@ -505,6 +505,15 @@ u64 nd_region_interleave_set_cookie(struct nd_region *nd_region) | |||
505 | return 0; | 505 | return 0; |
506 | } | 506 | } |
507 | 507 | ||
508 | u64 nd_region_interleave_set_altcookie(struct nd_region *nd_region) | ||
509 | { | ||
510 | struct nd_interleave_set *nd_set = nd_region->nd_set; | ||
511 | |||
512 | if (nd_set) | ||
513 | return nd_set->altcookie; | ||
514 | return 0; | ||
515 | } | ||
516 | |||
508 | void nd_mapping_free_labels(struct nd_mapping *nd_mapping) | 517 | void nd_mapping_free_labels(struct nd_mapping *nd_mapping) |
509 | { | 518 | { |
510 | struct nd_label_ent *label_ent, *e; | 519 | struct nd_label_ent *label_ent, *e; |
diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h index 8458c5351e56..77e7af32543f 100644 --- a/include/linux/libnvdimm.h +++ b/include/linux/libnvdimm.h | |||
@@ -70,6 +70,8 @@ struct nd_cmd_desc { | |||
70 | 70 | ||
71 | struct nd_interleave_set { | 71 | struct nd_interleave_set { |
72 | u64 cookie; | 72 | u64 cookie; |
73 | /* compatibility with initial buggy Linux implementation */ | ||
74 | u64 altcookie; | ||
73 | }; | 75 | }; |
74 | 76 | ||
75 | struct nd_mapping_desc { | 77 | struct nd_mapping_desc { |
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index 45be8b55a663..798f17655433 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c | |||
@@ -887,7 +887,7 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
887 | memdev->range_index = 0+1; | 887 | memdev->range_index = 0+1; |
888 | memdev->region_index = 4+1; | 888 | memdev->region_index = 4+1; |
889 | memdev->region_size = SPA0_SIZE/2; | 889 | memdev->region_size = SPA0_SIZE/2; |
890 | memdev->region_offset = t->spa_set_dma[0]; | 890 | memdev->region_offset = 1; |
891 | memdev->address = 0; | 891 | memdev->address = 0; |
892 | memdev->interleave_index = 0; | 892 | memdev->interleave_index = 0; |
893 | memdev->interleave_ways = 2; | 893 | memdev->interleave_ways = 2; |
@@ -902,7 +902,7 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
902 | memdev->range_index = 0+1; | 902 | memdev->range_index = 0+1; |
903 | memdev->region_index = 5+1; | 903 | memdev->region_index = 5+1; |
904 | memdev->region_size = SPA0_SIZE/2; | 904 | memdev->region_size = SPA0_SIZE/2; |
905 | memdev->region_offset = t->spa_set_dma[0] + SPA0_SIZE/2; | 905 | memdev->region_offset = (1 << 8); |
906 | memdev->address = 0; | 906 | memdev->address = 0; |
907 | memdev->interleave_index = 0; | 907 | memdev->interleave_index = 0; |
908 | memdev->interleave_ways = 2; | 908 | memdev->interleave_ways = 2; |
@@ -917,7 +917,7 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
917 | memdev->range_index = 1+1; | 917 | memdev->range_index = 1+1; |
918 | memdev->region_index = 4+1; | 918 | memdev->region_index = 4+1; |
919 | memdev->region_size = SPA1_SIZE/4; | 919 | memdev->region_size = SPA1_SIZE/4; |
920 | memdev->region_offset = t->spa_set_dma[1]; | 920 | memdev->region_offset = (1 << 16); |
921 | memdev->address = SPA0_SIZE/2; | 921 | memdev->address = SPA0_SIZE/2; |
922 | memdev->interleave_index = 0; | 922 | memdev->interleave_index = 0; |
923 | memdev->interleave_ways = 4; | 923 | memdev->interleave_ways = 4; |
@@ -932,7 +932,7 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
932 | memdev->range_index = 1+1; | 932 | memdev->range_index = 1+1; |
933 | memdev->region_index = 5+1; | 933 | memdev->region_index = 5+1; |
934 | memdev->region_size = SPA1_SIZE/4; | 934 | memdev->region_size = SPA1_SIZE/4; |
935 | memdev->region_offset = t->spa_set_dma[1] + SPA1_SIZE/4; | 935 | memdev->region_offset = (1 << 24); |
936 | memdev->address = SPA0_SIZE/2; | 936 | memdev->address = SPA0_SIZE/2; |
937 | memdev->interleave_index = 0; | 937 | memdev->interleave_index = 0; |
938 | memdev->interleave_ways = 4; | 938 | memdev->interleave_ways = 4; |
@@ -947,7 +947,7 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
947 | memdev->range_index = 1+1; | 947 | memdev->range_index = 1+1; |
948 | memdev->region_index = 6+1; | 948 | memdev->region_index = 6+1; |
949 | memdev->region_size = SPA1_SIZE/4; | 949 | memdev->region_size = SPA1_SIZE/4; |
950 | memdev->region_offset = t->spa_set_dma[1] + 2*SPA1_SIZE/4; | 950 | memdev->region_offset = (1ULL << 32); |
951 | memdev->address = SPA0_SIZE/2; | 951 | memdev->address = SPA0_SIZE/2; |
952 | memdev->interleave_index = 0; | 952 | memdev->interleave_index = 0; |
953 | memdev->interleave_ways = 4; | 953 | memdev->interleave_ways = 4; |
@@ -962,7 +962,7 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
962 | memdev->range_index = 1+1; | 962 | memdev->range_index = 1+1; |
963 | memdev->region_index = 7+1; | 963 | memdev->region_index = 7+1; |
964 | memdev->region_size = SPA1_SIZE/4; | 964 | memdev->region_size = SPA1_SIZE/4; |
965 | memdev->region_offset = t->spa_set_dma[1] + 3*SPA1_SIZE/4; | 965 | memdev->region_offset = (1ULL << 40); |
966 | memdev->address = SPA0_SIZE/2; | 966 | memdev->address = SPA0_SIZE/2; |
967 | memdev->interleave_index = 0; | 967 | memdev->interleave_index = 0; |
968 | memdev->interleave_ways = 4; | 968 | memdev->interleave_ways = 4; |
@@ -1380,7 +1380,7 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
1380 | memdev->range_index = 11+1; | 1380 | memdev->range_index = 11+1; |
1381 | memdev->region_index = 9+1; | 1381 | memdev->region_index = 9+1; |
1382 | memdev->region_size = SPA0_SIZE; | 1382 | memdev->region_size = SPA0_SIZE; |
1383 | memdev->region_offset = t->spa_set_dma[2]; | 1383 | memdev->region_offset = (1ULL << 48); |
1384 | memdev->address = 0; | 1384 | memdev->address = 0; |
1385 | memdev->interleave_index = 0; | 1385 | memdev->interleave_index = 0; |
1386 | memdev->interleave_ways = 1; | 1386 | memdev->interleave_ways = 1; |