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
13081308 if (nd_desc) {
13091309 struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
13101310
1311− rc = acpi_nfit_ars_rescan(acpi_desc, 0);
1311+ rc = acpi_nfit_ars_rescan(acpi_desc, ARS_REQ_LONG);
13121312 }
13131313 device_unlock(dev);
13141314 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
111111 struct nd_mapping *nd_mapping, resource_size_t *overlap);
112112 resource_size_t nd_blk_available_dpa(struct nd_region *nd_region);
113113 resource_size_t nd_region_available_dpa(struct nd_region *nd_region);
114+int nd_region_conflict(struct nd_region *nd_region, resource_size_t start,
115+ resource_size_t size);
114116 resource_size_t nvdimm_allocated_dpa(struct nvdimm_drvdata *ndd,
115117 struct nd_label_id *label_id);
116118 int 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
649649 ALIGN_DOWN(phys, nd_pfn->align));
650650 }
651651
652+/*
653+ * Check if pmem collides with 'System RAM', or other regions when
654+ * section aligned. Trim it accordingly.
655+ */
656+static 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+
652685 static int nd_pfn_init(struct nd_pfn *nd_pfn)
653686 {
654687 u32 dax_label_reserve = is_nd_dax(&nd_pfn->dev) ? SZ_128K : 0;
655688 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);
657690 resource_size_t start, size;
658− struct nd_namespace_io *nsio;
659691 struct nd_region *nd_region;
692+ u32 start_pad, end_trunc;
660693 struct nd_pfn_sb *pfn_sb;
661694 unsigned long npfns;
662695 phys_addr_t offset;
@@ -688,30 +721,7 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn) · 25 unmodified lines
688721
689722 memset(pfn_sb, 0, sizeof(*pfn_sb));
690723
691− /*
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−
724+ trim_pfn_device(nd_pfn, &start_pad, &end_trunc);
715725 if (start_pad + end_trunc)
716726 dev_info(&nd_pfn->dev, "%s alignment collision, truncate %d bytes\n",
717727 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
722732 * implementation will limit the pfns advertised through
723733 * ->direct_access() to those that are included in the memmap.
724734 */
725− start += start_pad;
735+ start = nsio->res.start + start_pad;
726736 size = resource_size(&nsio->res);
727737 npfns = PFN_SECTION_ALIGN_UP((size - start_pad - end_trunc - SZ_8K)
728738 / 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
11841184 }
11851185 EXPORT_SYMBOL_GPL(nvdimm_has_cache);
11861186
1187+struct conflict_context {
1188+ struct nd_region *nd_region;
1189+ resource_size_t start, size;
1190+};
1191+
1192+static 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+
1215+int 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+
11871228 void __exit nd_region_devs_exit(void)
11881229 {
11891230 ida_destroy(&region_ida);
tools/testing/nvdimm/test/nfit.c+33−2
@@ -15,6 +15,7 @@ · 14 unmodified lines
1515 #include <linux/dma-mapping.h>
1616 #include <linux/workqueue.h>
1717 #include <linux/libnvdimm.h>
18+#include <linux/genalloc.h>
1819 #include <linux/vmalloc.h>
1920 #include <linux/device.h>
2021 #include <linux/module.h>
@@ -215,6 +216,8 @@ struct nfit_test { · 194 unmodified lines
215216
216217 static struct workqueue_struct *nfit_wq;
217218
219+static struct gen_pool *nfit_pool;
220+
218221 static struct nfit_test *to_nfit_test(struct device *dev)
219222 {
220223 struct platform_device *pdev = to_platform_device(dev);
@@ -1132,6 +1135,9 @@ static void release_nfit_res(void *data) · 911 unmodified lines
11321135 list_del(&nfit_res->list);
11331136 spin_unlock(&nfit_test_lock);
11341137
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));
11351141 vfree(nfit_res->buf);
11361142 kfree(nfit_res);
11371143 }
@@ -1144,7 +1150,7 @@ static void *__test_alloc(struct nfit_test *t, size_t size, dma_addr_t *dma, · 6 unmodified lines
11441150 GFP_KERNEL);
11451151 int rc;
11461152
1147− if (!buf || !nfit_res)
1153+ if (!buf || !nfit_res || !*dma)
11481154 goto err;
11491155 rc = devm_add_action(dev, release_nfit_res, nfit_res);
11501156 if (rc)
@@ -1164,6 +1170,8 @@ static void *__test_alloc(struct nfit_test *t, size_t size, dma_addr_t *dma, · 13 unmodified lines
11641170
11651171 return nfit_res->buf;
11661172 err:
1173+ if (*dma && size >= DIMM_SIZE)
1174+ gen_pool_free(nfit_pool, *dma, size);
11671175 if (buf)
11681176 vfree(buf);
11691177 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
11721180
11731181 static void *test_alloc(struct nfit_test *t, size_t size, dma_addr_t *dma)
11741182 {
1183+ struct genpool_data_align data = {
1184+ .align = SZ_128M,
1185+ };
11751186 void *buf = vmalloc(size);
11761187
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;
11781193 return __test_alloc(t, size, dma, buf);
11791194 }
11801195
@@ -2839,6 +2854,17 @@ static __init int nfit_test_init(void) · 1658 unmodified lines
28392854 goto err_register;
28402855 }
28412856
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+
28422868 for (i = 0; i < NUM_NFITS; i++) {
28432869 struct nfit_test *nfit_test;
28442870 struct platform_device *pdev;
@@ -2894,6 +2920,9 @@ static __init int nfit_test_init(void) · 49 unmodified lines
28942920 return 0;
28952921
28962922 err_register:
2923+ if (nfit_pool)
2924+ gen_pool_destroy(nfit_pool);
2925+
28972926 destroy_workqueue(nfit_wq);
28982927 for (i = 0; i < NUM_NFITS; i++)
28992928 if (instances[i])
@@ -2917,6 +2946,8 @@ static __exit void nfit_test_exit(void) · 17 unmodified lines
29172946 platform_driver_unregister(&nfit_test_driver);
29182947 nfit_test_teardown();
29192948
2949+ gen_pool_destroy(nfit_pool);
2950+
29202951 for (i = 0; i < NUM_NFITS; i++)
29212952 put_device(&instances[i]->pdev.dev);
29222953 class_destroy(nfit_test_dimm);