Skip to content

Commit 9049771

Browse files
committed
mm: fix cache mode of dax pmd mappings
track_pfn_insert() in vmf_insert_pfn_pmd() is marking dax mappings as uncacheable rendering them impractical for application usage. DAX-pte mappings are cached and the goal of establishing DAX-pmd mappings is to attain more performance, not dramatically less (3 orders of magnitude). track_pfn_insert() relies on a previous call to reserve_memtype() to establish the expected page_cache_mode for the range. While memremap() arranges for reserve_memtype() to be called, devm_memremap_pages() does not. So, teach track_pfn_insert() and untrack_pfn() how to handle tracking without a vma, and arrange for devm_memremap_pages() to establish the write-back-cache reservation in the memtype tree. Cc: <[email protected]> Cc: Matthew Wilcox <[email protected]> Cc: Ross Zwisler <[email protected]> Cc: Nilesh Choudhury <[email protected]> Cc: Kirill A. Shutemov <[email protected]> Reported-by: Toshi Kani <[email protected]> Reported-by: Kai Zhang <[email protected]> Acked-by: Andrew Morton <[email protected]> Signed-off-by: Dan Williams <[email protected]>
1 parent ca120cf commit 9049771

File tree

2 files changed

+19
-7
lines changed

2 files changed

+19
-7
lines changed

arch/x86/mm/pat.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -927,9 +927,10 @@ int track_pfn_copy(struct vm_area_struct *vma)
927927
}
928928

929929
/*
930-
* prot is passed in as a parameter for the new mapping. If the vma has a
931-
* linear pfn mapping for the entire range reserve the entire vma range with
932-
* single reserve_pfn_range call.
930+
* prot is passed in as a parameter for the new mapping. If the vma has
931+
* a linear pfn mapping for the entire range, or no vma is provided,
932+
* reserve the entire pfn + size range with single reserve_pfn_range
933+
* call.
933934
*/
934935
int track_pfn_remap(struct vm_area_struct *vma, pgprot_t *prot,
935936
unsigned long pfn, unsigned long addr, unsigned long size)
@@ -938,11 +939,12 @@ int track_pfn_remap(struct vm_area_struct *vma, pgprot_t *prot,
938939
enum page_cache_mode pcm;
939940

940941
/* reserve the whole chunk starting from paddr */
941-
if (addr == vma->vm_start && size == (vma->vm_end - vma->vm_start)) {
942+
if (!vma || (addr == vma->vm_start
943+
&& size == (vma->vm_end - vma->vm_start))) {
942944
int ret;
943945

944946
ret = reserve_pfn_range(paddr, size, prot, 0);
945-
if (!ret)
947+
if (ret == 0 && vma)
946948
vma->vm_flags |= VM_PAT;
947949
return ret;
948950
}
@@ -997,7 +999,7 @@ void untrack_pfn(struct vm_area_struct *vma, unsigned long pfn,
997999
resource_size_t paddr;
9981000
unsigned long prot;
9991001

1000-
if (!(vma->vm_flags & VM_PAT))
1002+
if (vma && !(vma->vm_flags & VM_PAT))
10011003
return;
10021004

10031005
/* free the chunk starting from pfn or the whole chunk */
@@ -1011,7 +1013,8 @@ void untrack_pfn(struct vm_area_struct *vma, unsigned long pfn,
10111013
size = vma->vm_end - vma->vm_start;
10121014
}
10131015
free_pfn_range(paddr, size);
1014-
vma->vm_flags &= ~VM_PAT;
1016+
if (vma)
1017+
vma->vm_flags &= ~VM_PAT;
10151018
}
10161019

10171020
/*

kernel/memremap.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ static void devm_memremap_pages_release(struct device *dev, void *data)
247247
align_start = res->start & ~(SECTION_SIZE - 1);
248248
align_size = ALIGN(resource_size(res), SECTION_SIZE);
249249
arch_remove_memory(align_start, align_size);
250+
untrack_pfn(NULL, PHYS_PFN(align_start), align_size);
250251
pgmap_radix_release(res);
251252
dev_WARN_ONCE(dev, pgmap->altmap && pgmap->altmap->alloc,
252253
"%s: failed to free all reserved pages\n", __func__);
@@ -282,6 +283,7 @@ void *devm_memremap_pages(struct device *dev, struct resource *res,
282283
struct percpu_ref *ref, struct vmem_altmap *altmap)
283284
{
284285
resource_size_t key, align_start, align_size, align_end;
286+
pgprot_t pgprot = PAGE_KERNEL;
285287
struct dev_pagemap *pgmap;
286288
struct page_map *page_map;
287289
int error, nid, is_ram;
@@ -351,6 +353,11 @@ void *devm_memremap_pages(struct device *dev, struct resource *res,
351353
if (nid < 0)
352354
nid = numa_mem_id();
353355

356+
error = track_pfn_remap(NULL, &pgprot, PHYS_PFN(align_start), 0,
357+
align_size);
358+
if (error)
359+
goto err_pfn_remap;
360+
354361
error = arch_add_memory(nid, align_start, align_size, true);
355362
if (error)
356363
goto err_add_memory;
@@ -371,6 +378,8 @@ void *devm_memremap_pages(struct device *dev, struct resource *res,
371378
return __va(res->start);
372379

373380
err_add_memory:
381+
untrack_pfn(NULL, PHYS_PFN(align_start), align_size);
382+
err_pfn_remap:
374383
err_radix:
375384
pgmap_radix_release(res);
376385
devres_free(page_map);

0 commit comments

Comments
 (0)