From efebc711180f7fed701f6e23f23814fcfda7fbfc Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 7 Apr 2017 15:33:36 -0700 Subject: device-dax, tools/testing/nvdimm: enable device-dax with mock resources Provide a replacement pgoff_to_phys() that translates an nfit_test resource (allocated by vmalloc()) to a pfn. Signed-off-by: Dave Jiang Reviewed-by: Johannes Thumshirn Signed-off-by: Dan Williams --- tools/testing/nvdimm/Kbuild | 3 ++- tools/testing/nvdimm/dax-dev.c | 49 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 tools/testing/nvdimm/dax-dev.c (limited to 'tools') diff --git a/tools/testing/nvdimm/Kbuild b/tools/testing/nvdimm/Kbuild index 405212be044a..6dcb3c4d53be 100644 --- a/tools/testing/nvdimm/Kbuild +++ b/tools/testing/nvdimm/Kbuild @@ -28,7 +28,7 @@ obj-$(CONFIG_ND_BTT) += nd_btt.o obj-$(CONFIG_ND_BLK) += nd_blk.o obj-$(CONFIG_X86_PMEM_LEGACY) += nd_e820.o obj-$(CONFIG_ACPI_NFIT) += nfit.o -obj-$(CONFIG_DEV_DAX) += dax.o +obj-$(CONFIG_DEV_DAX) += dax.o dax-dev.o obj-$(CONFIG_DEV_DAX_PMEM) += dax_pmem.o nfit-y := $(ACPI_SRC)/core.o @@ -49,6 +49,7 @@ nd_e820-y := $(NVDIMM_SRC)/e820.o nd_e820-y += config_check.o dax-y := $(DAX_SRC)/dax.o +dax-y += dax-dev.o dax-y += config_check.o dax_pmem-y := $(DAX_SRC)/pmem.o diff --git a/tools/testing/nvdimm/dax-dev.c b/tools/testing/nvdimm/dax-dev.c new file mode 100644 index 000000000000..e89721d8924c --- /dev/null +++ b/tools/testing/nvdimm/dax-dev.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ +#include "test/nfit_test.h" +#include +#include "../../../drivers/dax/dax-private.h" + +phys_addr_t dax_pgoff_to_phys(struct dax_dev *dax_dev, pgoff_t pgoff, + unsigned long size) +{ + struct resource *res; + phys_addr_t addr; + int i; + + for (i = 0; i < dax_dev->num_resources; i++) { + res = &dax_dev->res[i]; + addr = pgoff * PAGE_SIZE + res->start; + if (addr >= res->start && addr <= res->end) + break; + pgoff -= PHYS_PFN(resource_size(res)); + } + + if (i < dax_dev->num_resources) { + res = &dax_dev->res[i]; + if (addr + size - 1 <= res->end) { + if (get_nfit_res(addr)) { + struct page *page; + + if (dax_dev->region->align > PAGE_SIZE) + return -1; + + page = vmalloc_to_page((void *)addr); + return PFN_PHYS(page_to_pfn(page)); + } else + return addr; + } + } + + return -1; +} -- cgit v1.2.3 From 7b6be8444e0f0dd675b54d059793423d3c9b4c03 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 11 Apr 2017 09:49:49 -0700 Subject: dax: refactor dax-fs into a generic provider of 'struct dax_device' instances We want dax capable drivers to be able to publish a set of dax operations [1]. However, we do not want to further abuse block_devices to advertise these operations. Instead we will attach these operations to a dax device and add a lookup mechanism to go from block device path to a dax device. A dax capable driver like pmem or brd is responsible for registering a dax device, alongside a block device, and then a dax capable filesystem is responsible for retrieving the dax device by path name if it wants to call dax_operations. For now, we refactor the dax pseudo-fs to be a generic facility, rather than an implementation detail, of the device-dax use case. Where a "dax device" is just an inode + dax infrastructure, and "Device DAX" is a mapping service layered on top of that base 'struct dax_device'. "Filesystem DAX" is then a mapping service that layers a filesystem on top of that same base device. Filesystem DAX is associated with a block_device for now, but perhaps directly to a dax device in the future, or for new pmem-only filesystems. [1]: https://lkml.org/lkml/2017/1/19/880 Suggested-by: Christoph Hellwig Signed-off-by: Dan Williams --- tools/testing/nvdimm/Kbuild | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/testing/nvdimm/Kbuild b/tools/testing/nvdimm/Kbuild index 405212be044a..2033ad03b8cd 100644 --- a/tools/testing/nvdimm/Kbuild +++ b/tools/testing/nvdimm/Kbuild @@ -28,7 +28,10 @@ obj-$(CONFIG_ND_BTT) += nd_btt.o obj-$(CONFIG_ND_BLK) += nd_blk.o obj-$(CONFIG_X86_PMEM_LEGACY) += nd_e820.o obj-$(CONFIG_ACPI_NFIT) += nfit.o -obj-$(CONFIG_DEV_DAX) += dax.o +ifeq ($(CONFIG_DAX),m) +obj-$(CONFIG_DAX) += dax.o +endif +obj-$(CONFIG_DEV_DAX) += device_dax.o obj-$(CONFIG_DEV_DAX_PMEM) += dax_pmem.o nfit-y := $(ACPI_SRC)/core.o @@ -48,9 +51,12 @@ nd_blk-y += config_check.o nd_e820-y := $(NVDIMM_SRC)/e820.o nd_e820-y += config_check.o -dax-y := $(DAX_SRC)/dax.o +dax-y := $(DAX_SRC)/super.o dax-y += config_check.o +device_dax-y := $(DAX_SRC)/device.o +device_dax-y += config_check.o + dax_pmem-y := $(DAX_SRC)/pmem.o dax_pmem-y += config_check.o -- cgit v1.2.3 From ac40b675c74b9243069aba3a5799481dbcb9d2ef Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 13 Apr 2017 15:17:38 -0700 Subject: tools/testing/nvdimm: test acpi 6.1 health state flags Add a simulated dimm with an ACPI_NFIT_MEM_MAP_FAILED indication, and set the ACPI_NFIT_MEM_HEALTH_ENABLED flag on all the dimms where nfit_test simulates health events, but spread it out over several redundant memdev entries to test that the nfit driver coalesces all the flags. Signed-off-by: Dan Williams --- tools/testing/nvdimm/test/nfit.c | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) (limited to 'tools') diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index 798f17655433..bc02f28ed8b8 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c @@ -132,6 +132,7 @@ static u32 handle[] = { [3] = NFIT_DIMM_HANDLE(0, 0, 1, 0, 1), [4] = NFIT_DIMM_HANDLE(0, 1, 0, 0, 0), [5] = NFIT_DIMM_HANDLE(1, 0, 0, 0, 0), + [6] = NFIT_DIMM_HANDLE(1, 0, 0, 0, 1), }; static unsigned long dimm_fail_cmd_flags[NUM_DCR]; @@ -728,8 +729,8 @@ static int nfit_test0_alloc(struct nfit_test *t) static int nfit_test1_alloc(struct nfit_test *t) { size_t nfit_size = sizeof(struct acpi_nfit_system_address) * 2 - + sizeof(struct acpi_nfit_memory_map) - + offsetof(struct acpi_nfit_control_region, window_size); + + sizeof(struct acpi_nfit_memory_map) * 2 + + offsetof(struct acpi_nfit_control_region, window_size) * 2; int i; t->nfit_buf = test_alloc(t, nfit_size, &t->nfit_dma); @@ -906,6 +907,7 @@ static void nfit_test0_setup(struct nfit_test *t) memdev->address = 0; memdev->interleave_index = 0; memdev->interleave_ways = 2; + memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; /* mem-region2 (spa1, dimm0) */ memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 2; @@ -921,6 +923,7 @@ static void nfit_test0_setup(struct nfit_test *t) memdev->address = SPA0_SIZE/2; memdev->interleave_index = 0; memdev->interleave_ways = 4; + memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; /* mem-region3 (spa1, dimm1) */ memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 3; @@ -951,6 +954,7 @@ static void nfit_test0_setup(struct nfit_test *t) memdev->address = SPA0_SIZE/2; memdev->interleave_index = 0; memdev->interleave_ways = 4; + memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; /* mem-region5 (spa1, dimm3) */ memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 5; @@ -1086,6 +1090,7 @@ static void nfit_test0_setup(struct nfit_test *t) memdev->address = 0; memdev->interleave_index = 0; memdev->interleave_ways = 1; + memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; offset = offset + sizeof(struct acpi_nfit_memory_map) * 14; /* dcr-descriptor0: blk */ @@ -1384,6 +1389,7 @@ static void nfit_test0_setup(struct nfit_test *t) memdev->address = 0; memdev->interleave_index = 0; memdev->interleave_ways = 1; + memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; /* mem-region16 (spa/bdw4, dimm4) */ memdev = nfit_buf + offset + @@ -1486,6 +1492,34 @@ static void nfit_test1_setup(struct nfit_test *t) dcr->code = NFIT_FIC_BYTE; dcr->windows = 0; + offset += dcr->header.length; + memdev = nfit_buf + offset; + memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; + memdev->header.length = sizeof(*memdev); + memdev->device_handle = handle[6]; + memdev->physical_id = 0; + memdev->region_id = 0; + memdev->range_index = 0; + memdev->region_index = 0+2; + memdev->region_size = SPA2_SIZE; + memdev->region_offset = 0; + memdev->address = 0; + memdev->interleave_index = 0; + memdev->interleave_ways = 1; + memdev->flags = ACPI_NFIT_MEM_MAP_FAILED; + + /* dcr-descriptor1 */ + offset += sizeof(*memdev); + dcr = nfit_buf + offset; + dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; + dcr->header.length = offsetof(struct acpi_nfit_control_region, + window_size); + dcr->region_index = 0+2; + dcr_common_init(dcr); + dcr->serial_number = ~handle[6]; + dcr->code = NFIT_FIC_BYTE; + dcr->windows = 0; + post_ars_status(&t->ars_state, t->spa_set_dma[0], SPA2_SIZE); acpi_desc = &t->acpi_desc; @@ -1907,7 +1941,7 @@ static __init int nfit_test_init(void) case 1: nfit_test->num_pm = 1; nfit_test->dcr_idx = NUM_DCR; - nfit_test->num_dcr = 1; + nfit_test->num_dcr = 2; nfit_test->alloc = nfit_test1_alloc; nfit_test->setup = nfit_test1_setup; break; -- cgit v1.2.3 From 8b06b884cd98f7ec8b5028680b99fabfb7b3e192 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 13 Apr 2017 23:14:34 -0700 Subject: tools/testing/nvdimm: fix nfit_test shutdown crash Keep the nfit_test instances alive until after nfit_test_teardown(), as we may be doing resource lookups until the final un-registrations have completed. This fixes crashes of the form. BUG: unable to handle kernel NULL pointer dereference at 0000000000000038 IP: __release_resource+0x12/0x90 Call Trace: remove_resource+0x23/0x40 __wrap_remove_resource+0x29/0x30 [nfit_test_iomap] acpi_nfit_remove_resource+0xe/0x10 [nfit] devm_action_release+0xf/0x20 release_nodes+0x16d/0x2b0 devres_release_all+0x3c/0x60 device_release+0x21/0x90 kobject_release+0x6a/0x170 kobject_put+0x2f/0x60 put_device+0x17/0x20 platform_device_unregister+0x20/0x30 nfit_test_exit+0x36/0x960 [nfit_test] Reported-by: Linda Knippers Signed-off-by: Dan Williams --- tools/testing/nvdimm/test/nfit.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index bc02f28ed8b8..d7fb1b894128 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c @@ -1958,6 +1958,7 @@ static __init int nfit_test_init(void) put_device(&pdev->dev); goto err_register; } + get_device(&pdev->dev); rc = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); if (rc) @@ -1976,6 +1977,10 @@ static __init int nfit_test_init(void) if (instances[i]) platform_device_unregister(&instances[i]->pdev); nfit_test_teardown(); + for (i = 0; i < NUM_NFITS; i++) + if (instances[i]) + put_device(&instances[i]->pdev.dev); + return rc; } @@ -1983,10 +1988,13 @@ static __exit void nfit_test_exit(void) { int i; - platform_driver_unregister(&nfit_test_driver); for (i = 0; i < NUM_NFITS; i++) platform_device_unregister(&instances[i]->pdev); + platform_driver_unregister(&nfit_test_driver); nfit_test_teardown(); + + for (i = 0; i < NUM_NFITS; i++) + put_device(&instances[i]->pdev.dev); class_destroy(nfit_test_dimm); } -- cgit v1.2.3 From fbabd829fe76a72a6444f64361cf8b2a9848639d Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 18 Apr 2017 09:56:31 -0700 Subject: acpi, nfit: fix module unload vs workqueue shutdown race The workqueue may still be running when the devres callbacks start firing to deallocate an acpi_nfit_desc instance. Stop and flush the workqueue before letting any other devres de-allocations proceed. Reported-by: Linda Knippers Signed-off-by: Dan Williams --- tools/testing/nvdimm/test/nfit.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'tools') diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index d7fb1b894128..c2187178fb13 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c @@ -1851,6 +1851,10 @@ static int nfit_test_probe(struct platform_device *pdev) if (rc) return rc; + rc = devm_add_action_or_reset(&pdev->dev, acpi_nfit_shutdown, acpi_desc); + if (rc) + return rc; + if (nfit_test->setup != nfit_test0_setup) return 0; -- cgit v1.2.3 From c1d6e828a35df524df2af277eedd1471d05e4f4c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 24 Jan 2017 23:02:09 -0800 Subject: pmem: add dax_operations support Setup a dax_device to have the same lifetime as the pmem block device and add a ->direct_access() method that is equivalent to pmem_direct_access(). Once fs/dax.c has been converted to use dax_operations the old pmem_direct_access() will be removed. Signed-off-by: Dan Williams --- tools/testing/nvdimm/pmem-dax.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'tools') diff --git a/tools/testing/nvdimm/pmem-dax.c b/tools/testing/nvdimm/pmem-dax.c index c9b8c48f85fc..b53596ad601b 100644 --- a/tools/testing/nvdimm/pmem-dax.c +++ b/tools/testing/nvdimm/pmem-dax.c @@ -15,13 +15,13 @@ #include #include -long pmem_direct_access(struct block_device *bdev, sector_t sector, - void **kaddr, pfn_t *pfn, long size) +long __pmem_direct_access(struct pmem_device *pmem, pgoff_t pgoff, + long nr_pages, void **kaddr, pfn_t *pfn) { - struct pmem_device *pmem = bdev->bd_queue->queuedata; - resource_size_t offset = sector * 512 + pmem->data_offset; + resource_size_t offset = PFN_PHYS(pgoff) + pmem->data_offset; - if (unlikely(is_bad_pmem(&pmem->bb, sector, size))) + if (unlikely(is_bad_pmem(&pmem->bb, PFN_PHYS(pgoff) / 512, + PFN_PHYS(nr_pages)))) return -EIO; /* @@ -34,11 +34,10 @@ long pmem_direct_access(struct block_device *bdev, sector_t sector, *kaddr = pmem->virt_addr + offset; page = vmalloc_to_page(pmem->virt_addr + offset); *pfn = page_to_pfn_t(page); - dev_dbg_ratelimited(disk_to_dev(bdev->bd_disk)->parent, - "%s: sector: %#llx pfn: %#lx\n", __func__, - (unsigned long long) sector, page_to_pfn(page)); + pr_debug_ratelimited("%s: pmem: %p pgoff: %#lx pfn: %#lx\n", + __func__, pmem, pgoff, page_to_pfn(page)); - return PAGE_SIZE; + return 1; } *kaddr = pmem->virt_addr + offset; @@ -49,6 +48,6 @@ long pmem_direct_access(struct block_device *bdev, sector_t sector, * requested range. */ if (unlikely(pmem->bb.count)) - return size; - return pmem->size - pmem->pfn_pad - offset; + return nr_pages; + return PHYS_PFN(pmem->size - pmem->pfn_pad - offset); } -- cgit v1.2.3