Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

libnvdimm, pmem: allow nfit_test to override pmem_direct_access()

Currently phys_to_pfn_t() is an exported symbol to allow nfit_test to
override it and indicate that nfit_test-pmem is not device-mapped. Now,
we want to enable nfit_test to operate without DMA_CMA and the pmem it
provides will no longer be physically contiguous, i.e. won't be capable
of supporting direct_access requests larger than a page. Make
pmem_direct_access() a weak symbol so that it can be replaced by the
tools/testing/nvdimm/ version, and move phys_to_pfn_t() to a static
inline now that it no longer needs to be overridden.

Acked-by: Johannes Thumshirn <jthumshirn@suse.de>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>

+79 -24
+3 -15
drivers/nvdimm/pmem.c
··· 29 29 #include <linux/slab.h> 30 30 #include <linux/pmem.h> 31 31 #include <linux/nd.h> 32 + #include "pmem.h" 32 33 #include "pfn.h" 33 34 #include "nd.h" 34 - 35 - struct pmem_device { 36 - /* One contiguous memory region per device */ 37 - phys_addr_t phys_addr; 38 - /* when non-zero this device is hosting a 'pfn' instance */ 39 - phys_addr_t data_offset; 40 - u64 pfn_flags; 41 - void __pmem *virt_addr; 42 - /* immutable base size of the namespace */ 43 - size_t size; 44 - /* trim size when namespace capacity has been section aligned */ 45 - u32 pfn_pad; 46 - struct badblocks bb; 47 - }; 48 35 49 36 static void pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset, 50 37 unsigned int len) ··· 150 163 return rc; 151 164 } 152 165 153 - static long pmem_direct_access(struct block_device *bdev, sector_t sector, 166 + /* see "strong" declaration in tools/testing/nvdimm/pmem-dax.c */ 167 + __weak long pmem_direct_access(struct block_device *bdev, sector_t sector, 154 168 void __pmem **kaddr, pfn_t *pfn, long size) 155 169 { 156 170 struct pmem_device *pmem = bdev->bd_queue->queuedata;
+24
drivers/nvdimm/pmem.h
··· 1 + #ifndef __NVDIMM_PMEM_H__ 2 + #define __NVDIMM_PMEM_H__ 3 + #include <linux/badblocks.h> 4 + #include <linux/types.h> 5 + #include <linux/pfn_t.h> 6 + #include <linux/fs.h> 7 + 8 + long pmem_direct_access(struct block_device *bdev, sector_t sector, 9 + void __pmem **kaddr, pfn_t *pfn, long size); 10 + /* this definition is in it's own header for tools/testing/nvdimm to consume */ 11 + struct pmem_device { 12 + /* One contiguous memory region per device */ 13 + phys_addr_t phys_addr; 14 + /* when non-zero this device is hosting a 'pfn' instance */ 15 + phys_addr_t data_offset; 16 + u64 pfn_flags; 17 + void __pmem *virt_addr; 18 + /* immutable base size of the namespace */ 19 + size_t size; 20 + /* trim size when namespace capacity has been section aligned */ 21 + u32 pfn_pad; 22 + struct badblocks bb; 23 + }; 24 + #endif /* __NVDIMM_PMEM_H__ */
+4 -1
include/linux/pfn_t.h
··· 28 28 return __pfn_to_pfn_t(pfn, 0); 29 29 } 30 30 31 - extern pfn_t phys_to_pfn_t(phys_addr_t addr, u64 flags); 31 + static inline pfn_t phys_to_pfn_t(phys_addr_t addr, u64 flags) 32 + { 33 + return __pfn_to_pfn_t(addr >> PAGE_SHIFT, flags); 34 + } 32 35 33 36 static inline bool pfn_t_has_page(pfn_t pfn) 34 37 {
-6
kernel/memremap.c
··· 169 169 } 170 170 EXPORT_SYMBOL(devm_memunmap); 171 171 172 - pfn_t phys_to_pfn_t(phys_addr_t addr, u64 flags) 173 - { 174 - return __pfn_to_pfn_t(addr >> PAGE_SHIFT, flags); 175 - } 176 - EXPORT_SYMBOL(phys_to_pfn_t); 177 - 178 172 #ifdef CONFIG_ZONE_DEVICE 179 173 static DEFINE_MUTEX(pgmap_lock); 180 174 static RADIX_TREE(pgmap_radix, GFP_KERNEL);
+2 -1
tools/testing/nvdimm/Kbuild
··· 11 11 ldflags-y += --wrap=__request_region 12 12 ldflags-y += --wrap=__release_region 13 13 ldflags-y += --wrap=devm_memremap_pages 14 - ldflags-y += --wrap=phys_to_pfn_t 15 14 16 15 DRIVERS := ../../../drivers 17 16 NVDIMM_SRC := $(DRIVERS)/nvdimm 18 17 ACPI_SRC := $(DRIVERS)/acpi 19 18 DAX_SRC := $(DRIVERS)/dax 19 + ccflags-y := -I$(src)/$(NVDIMM_SRC)/ 20 20 21 21 obj-$(CONFIG_LIBNVDIMM) += libnvdimm.o 22 22 obj-$(CONFIG_BLK_DEV_PMEM) += nd_pmem.o ··· 31 31 nfit-y += config_check.o 32 32 33 33 nd_pmem-y := $(NVDIMM_SRC)/pmem.o 34 + nd_pmem-y += pmem-dax.o 34 35 nd_pmem-y += config_check.o 35 36 36 37 nd_btt-y := $(NVDIMM_SRC)/btt.o
+42
tools/testing/nvdimm/pmem-dax.c
··· 1 + /* 2 + * Copyright (c) 2014-2016, Intel Corporation. 3 + * 4 + * This program is free software; you can redistribute it and/or modify it 5 + * under the terms and conditions of the GNU General Public License, 6 + * version 2, as published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope it will be useful, but WITHOUT 9 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 + * more details. 12 + */ 13 + #include "test/nfit_test.h" 14 + #include <linux/blkdev.h> 15 + #include <pmem.h> 16 + #include <nd.h> 17 + 18 + long pmem_direct_access(struct block_device *bdev, sector_t sector, 19 + void __pmem **kaddr, pfn_t *pfn, long size) 20 + { 21 + struct pmem_device *pmem = bdev->bd_queue->queuedata; 22 + resource_size_t offset = sector * 512 + pmem->data_offset; 23 + 24 + /* disable DAX for nfit_test pmem devices */ 25 + if (get_nfit_res(pmem->phys_addr + offset)) { 26 + dev_info_once(pmem->bb.dev, "dax is disabled for nfit_test\n"); 27 + return -EIO; 28 + } 29 + 30 + if (unlikely(is_bad_pmem(&pmem->bb, sector, size))) 31 + return -EIO; 32 + *kaddr = pmem->virt_addr + offset; 33 + *pfn = phys_to_pfn_t(pmem->phys_addr + offset, pmem->pfn_flags); 34 + 35 + /* 36 + * If badblocks are present, limit known good range to the 37 + * requested range. 38 + */ 39 + if (unlikely(pmem->bb.count)) 40 + return size; 41 + return pmem->size - pmem->pfn_pad - offset; 42 + }
+2 -1
tools/testing/nvdimm/test/iomap.c
··· 52 52 return NULL; 53 53 } 54 54 55 - static struct nfit_test_resource *get_nfit_res(resource_size_t resource) 55 + struct nfit_test_resource *get_nfit_res(resource_size_t resource) 56 56 { 57 57 struct nfit_test_resource *res; 58 58 ··· 62 62 63 63 return res; 64 64 } 65 + EXPORT_SYMBOL(get_nfit_res); 65 66 66 67 void __iomem *__nfit_test_ioremap(resource_size_t offset, unsigned long size, 67 68 void __iomem *(*fallback_fn)(resource_size_t, unsigned long))
+2
tools/testing/nvdimm/test/nfit_test.h
··· 12 12 */ 13 13 #ifndef __NFIT_TEST_H__ 14 14 #define __NFIT_TEST_H__ 15 + #include <linux/list.h> 15 16 16 17 struct nfit_test_resource { 17 18 struct list_head list; ··· 27 26 void __wrap_iounmap(volatile void __iomem *addr); 28 27 void nfit_test_setup(nfit_test_lookup_fn lookup); 29 28 void nfit_test_teardown(void); 29 + struct nfit_test_resource *get_nfit_res(resource_size_t resource); 30 30 #endif