History

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

Pull libnvdimm fixes from Dan Williams: "A regression fix for the Address Range Scrub implementation, yes another one, and support for platforms that misalign persistent memory relative to the Linux memory hotplug section constraint. Longer term, support for sub-section memory hotplug would alleviate alignment waste, but until then this hack allows a 'struct page' memmap to be established for these misaligned memory regions. These have all appeared in a -next release, and thanks to Patrick for reporting and testing the alignment padding fix. Summary: - Unless and until the core mm handles memory hotplug units smaller than a section (128M), persistent memory namespaces must be padded to section alignment. The libnvdimm core already handled section collision with "System RAM", but some configurations overlap independent "Persistent Memory" ranges within a section, so additional padding injection is added for that case. - The recent reworks of the ARS (address range scrub) state machine to reduce the number of state flags inadvertantly missed a conversion of acpi_nfit_ars_rescan() call sites. Fix the regression whereby user-requested ARS results in a "short" scrub rather than a "long" scrub. - Fixup the unit tests to handle / test the 128M section alignment of mocked test resources. * tag 'libnvdimm-fixes-4.20-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/nvdimm/nvdimm: acpi/nfit: Fix user-initiated ARS to be "ARS-long" rather than "ARS-short" libnvdimm, pfn: Pad pfn namespaces relative to other regions tools/testing/nvdimm: Align test resources to 128M

Linus Torvalds committed 7 years ago

Commit bd799eb2 parents 6ec067e b5fd2e05 files · +114 −30Browse files

Unified · Split

5 files
  1. drivers/acpi/nfit/core.c +1 −1
  2. drivers/nvdimm/nd-core.h +2 −0
  3. drivers/nvdimm/pfn_devs.c +37 −27
  4. drivers/nvdimm/region_devs.c +41 −0
  5. tools/testing/nvdimm/test/nfit.c +33 −2
drivers/acpi/nfit/core.c+1−1
@@ -1308,7 +1308,7 @@ static ssize_t scrub_store(struct device *dev, · 1307 unmodified lines
1308 if (nd_desc) {1308 if (nd_desc) {
1309 struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);1309 struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
1310 1310
1311 rc = acpi_nfit_ars_rescan(acpi_desc, 0);1311 rc = acpi_nfit_ars_rescan(acpi_desc, ARS_REQ_LONG);
1312 }1312 }
1313 device_unlock(dev);1313 device_unlock(dev);
1314 if (rc)1314 if (rc)
drivers/nvdimm/nd-core.h+2−0
@@ -111,6 +111,8 @@ resource_size_t nd_pmem_available_dpa(struct nd_region *nd_region, · 110 unmodified lines
111 struct nd_mapping *nd_mapping, resource_size_t *overlap);111 struct nd_mapping *nd_mapping, resource_size_t *overlap);
112resource_size_t nd_blk_available_dpa(struct nd_region *nd_region);112resource_size_t nd_blk_available_dpa(struct nd_region *nd_region);
113resource_size_t nd_region_available_dpa(struct nd_region *nd_region);113resource_size_t nd_region_available_dpa(struct nd_region *nd_region);
114int nd_region_conflict(struct nd_region *nd_region, resource_size_t start,
115 resource_size_t size);
114resource_size_t nvdimm_allocated_dpa(struct nvdimm_drvdata *ndd,116resource_size_t nvdimm_allocated_dpa(struct nvdimm_drvdata *ndd,
115 struct nd_label_id *label_id);117 struct nd_label_id *label_id);
116int alias_dpa_busy(struct device *dev, void *data);118int alias_dpa_busy(struct device *dev, void *data);
drivers/nvdimm/pfn_devs.c+37−27
@@ -649,14 +649,47 @@ static u64 phys_pmem_align_down(struct nd_pfn *nd_pfn, u64 phys) · 648 unmodified lines
649 ALIGN_DOWN(phys, nd_pfn->align));649 ALIGN_DOWN(phys, nd_pfn->align));
650}650}
651 651
652/*
653 * Check if pmem collides with 'System RAM', or other regions when
654 * section aligned. Trim it accordingly.
655 */
656static void trim_pfn_device(struct nd_pfn *nd_pfn, u32 *start_pad, u32 *end_trunc)
657{
658 struct nd_namespace_common *ndns = nd_pfn->ndns;
659 struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
660 struct nd_region *nd_region = to_nd_region(nd_pfn->dev.parent);
661 const resource_size_t start = nsio->res.start;
662 const resource_size_t end = start + resource_size(&nsio->res);
663 resource_size_t adjust, size;
664
665 *start_pad = 0;
666 *end_trunc = 0;
667
668 adjust = start - PHYS_SECTION_ALIGN_DOWN(start);
669 size = resource_size(&nsio->res) + adjust;
670 if (region_intersects(start - adjust, size, IORESOURCE_SYSTEM_RAM,
671 IORES_DESC_NONE) == REGION_MIXED
672 || nd_region_conflict(nd_region, start - adjust, size))
673 *start_pad = PHYS_SECTION_ALIGN_UP(start) - start;
674
675 /* Now check that end of the range does not collide. */
676 adjust = PHYS_SECTION_ALIGN_UP(end) - end;
677 size = resource_size(&nsio->res) + adjust;
678 if (region_intersects(start, size, IORESOURCE_SYSTEM_RAM,
679 IORES_DESC_NONE) == REGION_MIXED
680 || !IS_ALIGNED(end, nd_pfn->align)
681 || nd_region_conflict(nd_region, start, size + adjust))
682 *end_trunc = end - phys_pmem_align_down(nd_pfn, end);
683}
684
652static int nd_pfn_init(struct nd_pfn *nd_pfn)685static int nd_pfn_init(struct nd_pfn *nd_pfn)
653{686{
654 u32 dax_label_reserve = is_nd_dax(&nd_pfn->dev) ? SZ_128K : 0;687 u32 dax_label_reserve = is_nd_dax(&nd_pfn->dev) ? SZ_128K : 0;
655 struct nd_namespace_common *ndns = nd_pfn->ndns;688 struct nd_namespace_common *ndns = nd_pfn->ndns;
656 u32 start_pad = 0, end_trunc = 0;689 struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
657 resource_size_t start, size;690 resource_size_t start, size;
658 struct nd_namespace_io *nsio;
659 struct nd_region *nd_region;691 struct nd_region *nd_region;
692 u32 start_pad, end_trunc;
660 struct nd_pfn_sb *pfn_sb;693 struct nd_pfn_sb *pfn_sb;
661 unsigned long npfns;694 unsigned long npfns;
662 phys_addr_t offset;695 phys_addr_t offset;
@@ -688,30 +721,7 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn) · 25 unmodified lines
688 721
689 memset(pfn_sb, 0, sizeof(*pfn_sb));722 memset(pfn_sb, 0, sizeof(*pfn_sb));
690 723
691 /*724 trim_pfn_device(nd_pfn, &start_pad, &end_trunc);
692 * Check if pmem collides with 'System RAM' when section aligned and
693 * trim it accordingly
694 */
695 nsio = to_nd_namespace_io(&ndns->dev);
696 start = PHYS_SECTION_ALIGN_DOWN(nsio->res.start);
697 size = resource_size(&nsio->res);
698 if (region_intersects(start, size, IORESOURCE_SYSTEM_RAM,
699 IORES_DESC_NONE) == REGION_MIXED) {
700 start = nsio->res.start;
701 start_pad = PHYS_SECTION_ALIGN_UP(start) - start;
702 }
703
704 start = nsio->res.start;
705 size = PHYS_SECTION_ALIGN_UP(start + size) - start;
706 if (region_intersects(start, size, IORESOURCE_SYSTEM_RAM,
707 IORES_DESC_NONE) == REGION_MIXED
708 || !IS_ALIGNED(start + resource_size(&nsio->res),
709 nd_pfn->align)) {
710 size = resource_size(&nsio->res);
711 end_trunc = start + size - phys_pmem_align_down(nd_pfn,
712 start + size);
713 }
714
715 if (start_pad + end_trunc)725 if (start_pad + end_trunc)
716 dev_info(&nd_pfn->dev, "%s alignment collision, truncate %d bytes\n",726 dev_info(&nd_pfn->dev, "%s alignment collision, truncate %d bytes\n",
717 dev_name(&ndns->dev), start_pad + end_trunc);727 dev_name(&ndns->dev), start_pad + end_trunc);
@@ -722,7 +732,7 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn) · 4 unmodified lines
722 * implementation will limit the pfns advertised through732 * implementation will limit the pfns advertised through
723 * ->direct_access() to those that are included in the memmap.733 * ->direct_access() to those that are included in the memmap.
724 */734 */
725 start += start_pad;735 start = nsio->res.start + start_pad;
726 size = resource_size(&nsio->res);736 size = resource_size(&nsio->res);
727 npfns = PFN_SECTION_ALIGN_UP((size - start_pad - end_trunc - SZ_8K)737 npfns = PFN_SECTION_ALIGN_UP((size - start_pad - end_trunc - SZ_8K)
728 / PAGE_SIZE);738 / PAGE_SIZE);
drivers/nvdimm/region_devs.c+41−0
@@ -1184,6 +1184,47 @@ int nvdimm_has_cache(struct nd_region *nd_region) · 1183 unmodified lines
1184}1184}
1185EXPORT_SYMBOL_GPL(nvdimm_has_cache);1185EXPORT_SYMBOL_GPL(nvdimm_has_cache);
1186 1186
1187struct conflict_context {
1188 struct nd_region *nd_region;
1189 resource_size_t start, size;
1190};
1191
1192static int region_conflict(struct device *dev, void *data)
1193{
1194 struct nd_region *nd_region;
1195 struct conflict_context *ctx = data;
1196 resource_size_t res_end, region_end, region_start;
1197
1198 if (!is_memory(dev))
1199 return 0;
1200
1201 nd_region = to_nd_region(dev);
1202 if (nd_region == ctx->nd_region)
1203 return 0;
1204
1205 res_end = ctx->start + ctx->size;
1206 region_start = nd_region->ndr_start;
1207 region_end = region_start + nd_region->ndr_size;
1208 if (ctx->start >= region_start && ctx->start < region_end)
1209 return -EBUSY;
1210 if (res_end > region_start && res_end <= region_end)
1211 return -EBUSY;
1212 return 0;
1213}
1214
1215int nd_region_conflict(struct nd_region *nd_region, resource_size_t start,
1216 resource_size_t size)
1217{
1218 struct nvdimm_bus *nvdimm_bus = walk_to_nvdimm_bus(&nd_region->dev);
1219 struct conflict_context ctx = {
1220 .nd_region = nd_region,
1221 .start = start,
1222 .size = size,
1223 };
1224
1225 return device_for_each_child(&nvdimm_bus->dev, &ctx, region_conflict);
1226}
1227
1187void __exit nd_region_devs_exit(void)1228void __exit nd_region_devs_exit(void)
1188{1229{
1189 ida_destroy(&region_ida);1230 ida_destroy(&region_ida);
tools/testing/nvdimm/test/nfit.c+33−2
@@ -15,6 +15,7 @@ · 14 unmodified lines
15#include <linux/dma-mapping.h>15#include <linux/dma-mapping.h>
16#include <linux/workqueue.h>16#include <linux/workqueue.h>
17#include <linux/libnvdimm.h>17#include <linux/libnvdimm.h>
18#include <linux/genalloc.h>
18#include <linux/vmalloc.h>19#include <linux/vmalloc.h>
19#include <linux/device.h>20#include <linux/device.h>
20#include <linux/module.h>21#include <linux/module.h>
@@ -215,6 +216,8 @@ struct nfit_test { · 194 unmodified lines
215 216
216static struct workqueue_struct *nfit_wq;217static struct workqueue_struct *nfit_wq;
217 218
219static struct gen_pool *nfit_pool;
220
218static struct nfit_test *to_nfit_test(struct device *dev)221static struct nfit_test *to_nfit_test(struct device *dev)
219{222{
220 struct platform_device *pdev = to_platform_device(dev);223 struct platform_device *pdev = to_platform_device(dev);
@@ -1132,6 +1135,9 @@ static void release_nfit_res(void *data) · 911 unmodified lines
1132 list_del(&nfit_res->list);1135 list_del(&nfit_res->list);
1133 spin_unlock(&nfit_test_lock);1136 spin_unlock(&nfit_test_lock);
1134 1137
1138 if (resource_size(&nfit_res->res) >= DIMM_SIZE)
1139 gen_pool_free(nfit_pool, nfit_res->res.start,
1140 resource_size(&nfit_res->res));
1135 vfree(nfit_res->buf);1141 vfree(nfit_res->buf);
1136 kfree(nfit_res);1142 kfree(nfit_res);
1137}1143}
@@ -1144,7 +1150,7 @@ static void *__test_alloc(struct nfit_test *t, size_t size, dma_addr_t *dma, · 6 unmodified lines
1144 GFP_KERNEL);1150 GFP_KERNEL);
1145 int rc;1151 int rc;
1146 1152
1147 if (!buf || !nfit_res)1153 if (!buf || !nfit_res || !*dma)
1148 goto err;1154 goto err;
1149 rc = devm_add_action(dev, release_nfit_res, nfit_res);1155 rc = devm_add_action(dev, release_nfit_res, nfit_res);
1150 if (rc)1156 if (rc)
@@ -1164,6 +1170,8 @@ static void *__test_alloc(struct nfit_test *t, size_t size, dma_addr_t *dma, · 13 unmodified lines
1164 1170
1165 return nfit_res->buf;1171 return nfit_res->buf;
1166 err:1172 err:
1173 if (*dma && size >= DIMM_SIZE)
1174 gen_pool_free(nfit_pool, *dma, size);
1167 if (buf)1175 if (buf)
1168 vfree(buf);1176 vfree(buf);
1169 kfree(nfit_res);1177 kfree(nfit_res);
@@ -1172,9 +1180,16 @@ static void *__test_alloc(struct nfit_test *t, size_t size, dma_addr_t *dma, · 2 unmodified lines
1172 1180
1173static void *test_alloc(struct nfit_test *t, size_t size, dma_addr_t *dma)1181static void *test_alloc(struct nfit_test *t, size_t size, dma_addr_t *dma)
1174{1182{
1183 struct genpool_data_align data = {
1184 .align = SZ_128M,
1185 };
1175 void *buf = vmalloc(size);1186 void *buf = vmalloc(size);
1176 1187
1177 *dma = (unsigned long) buf;1188 if (size >= DIMM_SIZE)
1189 *dma = gen_pool_alloc_algo(nfit_pool, size,
1190 gen_pool_first_fit_align, &data);
1191 else
1192 *dma = (unsigned long) buf;
1178 return __test_alloc(t, size, dma, buf);1193 return __test_alloc(t, size, dma, buf);
1179}1194}
1180 1195
@@ -2839,6 +2854,17 @@ static __init int nfit_test_init(void) · 1658 unmodified lines
2839 goto err_register;2854 goto err_register;
2840 }2855 }
2841 2856
2857 nfit_pool = gen_pool_create(ilog2(SZ_4M), NUMA_NO_NODE);
2858 if (!nfit_pool) {
2859 rc = -ENOMEM;
2860 goto err_register;
2861 }
2862
2863 if (gen_pool_add(nfit_pool, SZ_4G, SZ_4G, NUMA_NO_NODE)) {
2864 rc = -ENOMEM;
2865 goto err_register;
2866 }
2867
2842 for (i = 0; i < NUM_NFITS; i++) {2868 for (i = 0; i < NUM_NFITS; i++) {
2843 struct nfit_test *nfit_test;2869 struct nfit_test *nfit_test;
2844 struct platform_device *pdev;2870 struct platform_device *pdev;
@@ -2894,6 +2920,9 @@ static __init int nfit_test_init(void) · 49 unmodified lines
2894 return 0;2920 return 0;
2895 2921
2896 err_register:2922 err_register:
2923 if (nfit_pool)
2924 gen_pool_destroy(nfit_pool);
2925
2897 destroy_workqueue(nfit_wq);2926 destroy_workqueue(nfit_wq);
2898 for (i = 0; i < NUM_NFITS; i++)2927 for (i = 0; i < NUM_NFITS; i++)
2899 if (instances[i])2928 if (instances[i])
@@ -2917,6 +2946,8 @@ static __exit void nfit_test_exit(void) · 17 unmodified lines
2917 platform_driver_unregister(&nfit_test_driver);2946 platform_driver_unregister(&nfit_test_driver);
2918 nfit_test_teardown();2947 nfit_test_teardown();
2919 2948
2949 gen_pool_destroy(nfit_pool);
2950
2920 for (i = 0; i < NUM_NFITS; i++)2951 for (i = 0; i < NUM_NFITS; i++)
2921 put_device(&instances[i]->pdev.dev);2952 put_device(&instances[i]->pdev.dev);
2922 class_destroy(nfit_test_dimm);2953 class_destroy(nfit_test_dimm);