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

memremap: change devm_memremap_pages interface to use struct dev_pagemap

This new interface is similar to how struct device (and many others)
work. The caller initializes a 'struct dev_pagemap' as required
and calls 'devm_memremap_pages'. This allows the pagemap structure to
be embedded in another structure and thus container_of can be used. In
this way application specific members can be stored in a containing
struct.

This will be used by the P2P infrastructure and HMM could probably
be cleaned up to use it as well (instead of having it's own, similar
'hmm_devmem_pages_create' function).

Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>

authored by

Christoph Hellwig and committed by
Dan Williams
e8d51348 e7744aa2

+81 -85
+11 -9
drivers/dax/pmem.c
··· 21 21 struct dax_pmem { 22 22 struct device *dev; 23 23 struct percpu_ref ref; 24 + struct dev_pagemap pgmap; 24 25 struct completion cmp; 25 26 }; 26 27 ··· 70 69 struct nd_namespace_common *ndns; 71 70 struct nd_dax *nd_dax = to_nd_dax(dev); 72 71 struct nd_pfn *nd_pfn = &nd_dax->nd_pfn; 73 - struct vmem_altmap __altmap, *altmap = NULL; 74 72 75 73 ndns = nvdimm_namespace_common_probe(dev); 76 74 if (IS_ERR(ndns)) 77 75 return PTR_ERR(ndns); 78 76 nsio = to_nd_namespace_io(&ndns->dev); 79 77 78 + dax_pmem = devm_kzalloc(dev, sizeof(*dax_pmem), GFP_KERNEL); 79 + if (!dax_pmem) 80 + return -ENOMEM; 81 + 80 82 /* parse the 'pfn' info block via ->rw_bytes */ 81 83 rc = devm_nsio_enable(dev, nsio); 82 84 if (rc) 83 85 return rc; 84 - altmap = nvdimm_setup_pfn(nd_pfn, &res, &__altmap); 85 - if (IS_ERR(altmap)) 86 - return PTR_ERR(altmap); 86 + rc = nvdimm_setup_pfn(nd_pfn, &dax_pmem->pgmap); 87 + if (rc) 88 + return rc; 87 89 devm_nsio_disable(dev, nsio); 88 90 89 91 pfn_sb = nd_pfn->pfn_sb; ··· 97 93 dev_warn(dev, "could not reserve region %pR\n", &nsio->res); 98 94 return -EBUSY; 99 95 } 100 - 101 - dax_pmem = devm_kzalloc(dev, sizeof(*dax_pmem), GFP_KERNEL); 102 - if (!dax_pmem) 103 - return -ENOMEM; 104 96 105 97 dax_pmem->dev = dev; 106 98 init_completion(&dax_pmem->cmp); ··· 110 110 if (rc) 111 111 return rc; 112 112 113 - addr = devm_memremap_pages(dev, &res, &dax_pmem->ref, altmap); 113 + dax_pmem->pgmap.ref = &dax_pmem->ref; 114 + addr = devm_memremap_pages(dev, &dax_pmem->pgmap); 114 115 if (IS_ERR(addr)) 115 116 return PTR_ERR(addr); 116 117 ··· 121 120 return rc; 122 121 123 122 /* adjust the dax_region resource to the start of data */ 123 + memcpy(&res, &dax_pmem->pgmap.res, sizeof(res)); 124 124 res.start += le64_to_cpu(pfn_sb->dataoff); 125 125 126 126 rc = sscanf(dev_name(&ndns->dev), "namespace%d.%d", &region_id, &id);
+4 -5
drivers/nvdimm/nd.h
··· 368 368 void nvdimm_badblocks_populate(struct nd_region *nd_region, 369 369 struct badblocks *bb, const struct resource *res); 370 370 #if IS_ENABLED(CONFIG_ND_CLAIM) 371 - struct vmem_altmap *nvdimm_setup_pfn(struct nd_pfn *nd_pfn, 372 - struct resource *res, struct vmem_altmap *altmap); 371 + int nvdimm_setup_pfn(struct nd_pfn *nd_pfn, struct dev_pagemap *pgmap); 373 372 int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio); 374 373 void devm_nsio_disable(struct device *dev, struct nd_namespace_io *nsio); 375 374 #else 376 - static inline struct vmem_altmap *nvdimm_setup_pfn(struct nd_pfn *nd_pfn, 377 - struct resource *res, struct vmem_altmap *altmap) 375 + static inline int nvdimm_setup_pfn(struct nd_pfn *nd_pfn, 376 + struct dev_pagemap *pgmap) 378 377 { 379 - return ERR_PTR(-ENXIO); 378 + return -ENXIO; 380 379 } 381 380 static inline int devm_nsio_enable(struct device *dev, 382 381 struct nd_namespace_io *nsio)
+15 -12
drivers/nvdimm/pfn_devs.c
··· 542 542 return reserve; 543 543 } 544 544 545 - static struct vmem_altmap *__nvdimm_setup_pfn(struct nd_pfn *nd_pfn, 546 - struct resource *res, struct vmem_altmap *altmap) 545 + static int __nvdimm_setup_pfn(struct nd_pfn *nd_pfn, struct dev_pagemap *pgmap) 547 546 { 547 + struct resource *res = &pgmap->res; 548 + struct vmem_altmap *altmap = &pgmap->altmap; 548 549 struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb; 549 550 u64 offset = le64_to_cpu(pfn_sb->dataoff); 550 551 u32 start_pad = __le32_to_cpu(pfn_sb->start_pad); ··· 562 561 res->start += start_pad; 563 562 res->end -= end_trunc; 564 563 564 + pgmap->type = MEMORY_DEVICE_HOST; 565 + 565 566 if (nd_pfn->mode == PFN_MODE_RAM) { 566 567 if (offset < SZ_8K) 567 - return ERR_PTR(-EINVAL); 568 + return -EINVAL; 568 569 nd_pfn->npfns = le64_to_cpu(pfn_sb->npfns); 569 - altmap = NULL; 570 + pgmap->altmap_valid = false; 570 571 } else if (nd_pfn->mode == PFN_MODE_PMEM) { 571 572 nd_pfn->npfns = PFN_SECTION_ALIGN_UP((resource_size(res) 572 573 - offset) / PAGE_SIZE); ··· 580 577 memcpy(altmap, &__altmap, sizeof(*altmap)); 581 578 altmap->free = PHYS_PFN(offset - SZ_8K); 582 579 altmap->alloc = 0; 580 + pgmap->altmap_valid = true; 583 581 } else 584 - return ERR_PTR(-ENXIO); 582 + return -ENXIO; 585 583 586 - return altmap; 584 + return 0; 587 585 } 588 586 589 587 static u64 phys_pmem_align_down(struct nd_pfn *nd_pfn, u64 phys) ··· 712 708 * Determine the effective resource range and vmem_altmap from an nd_pfn 713 709 * instance. 714 710 */ 715 - struct vmem_altmap *nvdimm_setup_pfn(struct nd_pfn *nd_pfn, 716 - struct resource *res, struct vmem_altmap *altmap) 711 + int nvdimm_setup_pfn(struct nd_pfn *nd_pfn, struct dev_pagemap *pgmap) 717 712 { 718 713 int rc; 719 714 720 715 if (!nd_pfn->uuid || !nd_pfn->ndns) 721 - return ERR_PTR(-ENODEV); 716 + return -ENODEV; 722 717 723 718 rc = nd_pfn_init(nd_pfn); 724 719 if (rc) 725 - return ERR_PTR(rc); 720 + return rc; 726 721 727 - /* we need a valid pfn_sb before we can init a vmem_altmap */ 728 - return __nvdimm_setup_pfn(nd_pfn, res, altmap); 722 + /* we need a valid pfn_sb before we can init a dev_pagemap */ 723 + return __nvdimm_setup_pfn(nd_pfn, pgmap); 729 724 } 730 725 EXPORT_SYMBOL_GPL(nvdimm_setup_pfn);
+24 -21
drivers/nvdimm/pmem.c
··· 298 298 { 299 299 struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev); 300 300 struct nd_region *nd_region = to_nd_region(dev->parent); 301 - struct vmem_altmap __altmap, *altmap = NULL; 302 301 int nid = dev_to_node(dev), fua, wbc; 303 302 struct resource *res = &nsio->res; 303 + struct resource bb_res; 304 304 struct nd_pfn *nd_pfn = NULL; 305 305 struct dax_device *dax_dev; 306 306 struct nd_pfn_sb *pfn_sb; 307 307 struct pmem_device *pmem; 308 - struct resource pfn_res; 309 308 struct request_queue *q; 310 309 struct device *gendev; 311 310 struct gendisk *disk; 312 311 void *addr; 313 - 314 - /* while nsio_rw_bytes is active, parse a pfn info block if present */ 315 - if (is_nd_pfn(dev)) { 316 - nd_pfn = to_nd_pfn(dev); 317 - altmap = nvdimm_setup_pfn(nd_pfn, &pfn_res, &__altmap); 318 - if (IS_ERR(altmap)) 319 - return PTR_ERR(altmap); 320 - } 321 - 322 - /* we're attaching a block device, disable raw namespace access */ 323 - devm_nsio_disable(dev, nsio); 312 + int rc; 324 313 325 314 pmem = devm_kzalloc(dev, sizeof(*pmem), GFP_KERNEL); 326 315 if (!pmem) 327 316 return -ENOMEM; 317 + 318 + /* while nsio_rw_bytes is active, parse a pfn info block if present */ 319 + if (is_nd_pfn(dev)) { 320 + nd_pfn = to_nd_pfn(dev); 321 + rc = nvdimm_setup_pfn(nd_pfn, &pmem->pgmap); 322 + if (rc) 323 + return rc; 324 + } 325 + 326 + /* we're attaching a block device, disable raw namespace access */ 327 + devm_nsio_disable(dev, nsio); 328 328 329 329 dev_set_drvdata(dev, pmem); 330 330 pmem->phys_addr = res->start; ··· 350 350 return -ENOMEM; 351 351 352 352 pmem->pfn_flags = PFN_DEV; 353 + pmem->pgmap.ref = &q->q_usage_counter; 353 354 if (is_nd_pfn(dev)) { 354 - addr = devm_memremap_pages(dev, &pfn_res, &q->q_usage_counter, 355 - altmap); 355 + addr = devm_memremap_pages(dev, &pmem->pgmap); 356 356 pfn_sb = nd_pfn->pfn_sb; 357 357 pmem->data_offset = le64_to_cpu(pfn_sb->dataoff); 358 - pmem->pfn_pad = resource_size(res) - resource_size(&pfn_res); 358 + pmem->pfn_pad = resource_size(res) - 359 + resource_size(&pmem->pgmap.res); 359 360 pmem->pfn_flags |= PFN_MAP; 360 - res = &pfn_res; /* for badblocks populate */ 361 - res->start += pmem->data_offset; 361 + memcpy(&bb_res, &pmem->pgmap.res, sizeof(bb_res)); 362 + bb_res.start += pmem->data_offset; 362 363 } else if (pmem_should_map_pages(dev)) { 363 - addr = devm_memremap_pages(dev, &nsio->res, 364 - &q->q_usage_counter, NULL); 364 + memcpy(&pmem->pgmap.res, &nsio->res, sizeof(pmem->pgmap.res)); 365 + pmem->pgmap.altmap_valid = false; 366 + addr = devm_memremap_pages(dev, &pmem->pgmap); 365 367 pmem->pfn_flags |= PFN_MAP; 368 + memcpy(&bb_res, &pmem->pgmap.res, sizeof(bb_res)); 366 369 } else 367 370 addr = devm_memremap(dev, pmem->phys_addr, 368 371 pmem->size, ARCH_MEMREMAP_PMEM); ··· 404 401 / 512); 405 402 if (devm_init_badblocks(dev, &pmem->bb)) 406 403 return -ENOMEM; 407 - nvdimm_badblocks_populate(nd_region, &pmem->bb, res); 404 + nvdimm_badblocks_populate(nd_region, &pmem->bb, &bb_res); 408 405 disk->bb = &pmem->bb; 409 406 410 407 dax_dev = alloc_dax(pmem, disk->disk_name, &pmem_dax_ops);
+1
drivers/nvdimm/pmem.h
··· 22 22 struct badblocks bb; 23 23 struct dax_device *dax_dev; 24 24 struct gendisk *disk; 25 + struct dev_pagemap pgmap; 25 26 }; 26 27 27 28 long __pmem_direct_access(struct pmem_device *pmem, pgoff_t pgoff,
+2 -4
include/linux/memremap.h
··· 123 123 }; 124 124 125 125 #ifdef CONFIG_ZONE_DEVICE 126 - void *devm_memremap_pages(struct device *dev, struct resource *res, 127 - struct percpu_ref *ref, struct vmem_altmap *altmap); 126 + void *devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap); 128 127 struct dev_pagemap *get_dev_pagemap(unsigned long pfn, 129 128 struct dev_pagemap *pgmap); 130 129 ··· 133 134 static inline bool is_zone_device_page(const struct page *page); 134 135 #else 135 136 static inline void *devm_memremap_pages(struct device *dev, 136 - struct resource *res, struct percpu_ref *ref, 137 - struct vmem_altmap *altmap) 137 + struct dev_pagemap *pgmap) 138 138 { 139 139 /* 140 140 * Fail attempts to call devm_memremap_pages() without
+21 -30
kernel/memremap.c
··· 275 275 #define for_each_device_pfn(pfn, map) \ 276 276 for (pfn = pfn_first(map); pfn < pfn_end(map); pfn++) 277 277 278 - static void devm_memremap_pages_release(struct device *dev, void *data) 278 + static void devm_memremap_pages_release(void *data) 279 279 { 280 280 struct dev_pagemap *pgmap = data; 281 + struct device *dev = pgmap->dev; 281 282 struct resource *res = &pgmap->res; 282 283 resource_size_t align_start, align_size; 283 284 unsigned long pfn; ··· 317 316 /** 318 317 * devm_memremap_pages - remap and provide memmap backing for the given resource 319 318 * @dev: hosting device for @res 320 - * @res: "host memory" address range 321 - * @ref: a live per-cpu reference count 322 - * @altmap: optional descriptor for allocating the memmap from @res 319 + * @pgmap: pointer to a struct dev_pgmap 323 320 * 324 321 * Notes: 325 - * 1/ @ref must be 'live' on entry and 'dead' before devm_memunmap_pages() time 326 - * (or devm release event). The expected order of events is that @ref has 322 + * 1/ At a minimum the res, ref and type members of @pgmap must be initialized 323 + * by the caller before passing it to this function 324 + * 325 + * 2/ The altmap field may optionally be initialized, in which case altmap_valid 326 + * must be set to true 327 + * 328 + * 3/ pgmap.ref must be 'live' on entry and 'dead' before devm_memunmap_pages() 329 + * time (or devm release event). The expected order of events is that ref has 327 330 * been through percpu_ref_kill() before devm_memremap_pages_release(). The 328 331 * wait for the completion of all references being dropped and 329 332 * percpu_ref_exit() must occur after devm_memremap_pages_release(). 330 333 * 331 - * 2/ @res is expected to be a host memory range that could feasibly be 334 + * 4/ res is expected to be a host memory range that could feasibly be 332 335 * treated as a "System RAM" range, i.e. not a device mmio range, but 333 336 * this is not enforced. 334 337 */ 335 - void *devm_memremap_pages(struct device *dev, struct resource *res, 336 - struct percpu_ref *ref, struct vmem_altmap *altmap) 338 + void *devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap) 337 339 { 338 340 resource_size_t align_start, align_size, align_end; 341 + struct vmem_altmap *altmap = pgmap->altmap_valid ? 342 + &pgmap->altmap : NULL; 339 343 unsigned long pfn, pgoff, order; 340 344 pgprot_t pgprot = PAGE_KERNEL; 341 - struct dev_pagemap *pgmap; 342 345 int error, nid, is_ram, i = 0; 346 + struct resource *res = &pgmap->res; 343 347 344 348 align_start = res->start & ~(SECTION_SIZE - 1); 345 349 align_size = ALIGN(res->start + resource_size(res), SECTION_SIZE) ··· 361 355 if (is_ram == REGION_INTERSECTS) 362 356 return __va(res->start); 363 357 364 - if (!ref) 358 + if (!pgmap->ref) 365 359 return ERR_PTR(-EINVAL); 366 360 367 - pgmap = devres_alloc_node(devm_memremap_pages_release, 368 - sizeof(*pgmap), GFP_KERNEL, dev_to_node(dev)); 369 - if (!pgmap) 370 - return ERR_PTR(-ENOMEM); 371 - 372 - memcpy(&pgmap->res, res, sizeof(*res)); 373 - 374 361 pgmap->dev = dev; 375 - if (altmap) { 376 - memcpy(&pgmap->altmap, altmap, sizeof(*altmap)); 377 - pgmap->altmap_valid = true; 378 - altmap = &pgmap->altmap; 379 - } 380 - pgmap->ref = ref; 381 - pgmap->type = MEMORY_DEVICE_HOST; 382 - pgmap->page_fault = NULL; 383 - pgmap->page_free = NULL; 384 - pgmap->data = NULL; 385 362 386 363 mutex_lock(&pgmap_lock); 387 364 error = 0; ··· 412 423 */ 413 424 list_del(&page->lru); 414 425 page->pgmap = pgmap; 415 - percpu_ref_get(ref); 426 + percpu_ref_get(pgmap->ref); 416 427 if (!(++i % 1024)) 417 428 cond_resched(); 418 429 } 419 - devres_add(dev, pgmap); 430 + 431 + devm_add_action(dev, devm_memremap_pages_release, pgmap); 432 + 420 433 return __va(res->start); 421 434 422 435 err_add_memory:
+3 -4
tools/testing/nvdimm/test/iomap.c
··· 104 104 } 105 105 EXPORT_SYMBOL(__wrap_devm_memremap); 106 106 107 - void *__wrap_devm_memremap_pages(struct device *dev, struct resource *res, 108 - struct percpu_ref *ref, struct vmem_altmap *altmap) 107 + void *__wrap_devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap) 109 108 { 110 - resource_size_t offset = res->start; 109 + resource_size_t offset = pgmap->res.start; 111 110 struct nfit_test_resource *nfit_res = get_nfit_res(offset); 112 111 113 112 if (nfit_res) 114 113 return nfit_res->buf + offset - nfit_res->res.start; 115 - return devm_memremap_pages(dev, res, ref, altmap); 114 + return devm_memremap_pages(dev, pgmap); 116 115 } 117 116 EXPORT_SYMBOL(__wrap_devm_memremap_pages); 118 117