diff options
author | Ingo Molnar <mingo@kernel.org> | 2016-01-12 05:08:13 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-01-12 05:08:13 -0500 |
commit | c0c57019a65341f08858541d2740b74dee821cf1 (patch) | |
tree | 584ac03f7dfa26c9c45c3d66ad306222e893fa33 /arch/x86/mm | |
parent | 8c31902cffc4d716450be549c66a67a8a3dd479c (diff) | |
parent | ae8a52185e5c070cf4510b323dbc1b9e46b897d6 (diff) |
Merge commit 'linus' into x86/urgent, to pick up recent x86 changes
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch/x86/mm')
-rw-r--r-- | arch/x86/mm/Makefile | 1 | ||||
-rw-r--r-- | arch/x86/mm/debug_pagetables.c | 46 | ||||
-rw-r--r-- | arch/x86/mm/dump_pagetables.c | 34 | ||||
-rw-r--r-- | arch/x86/mm/ioremap.c | 4 | ||||
-rw-r--r-- | arch/x86/mm/pageattr.c | 10 | ||||
-rw-r--r-- | arch/x86/mm/pat.c | 12 | ||||
-rw-r--r-- | arch/x86/mm/pat_rbtree.c | 52 | ||||
-rw-r--r-- | arch/x86/mm/pgtable.c | 7 | ||||
-rw-r--r-- | arch/x86/mm/setup_nx.c | 4 | ||||
-rw-r--r-- | arch/x86/mm/srat.c | 2 |
10 files changed, 116 insertions, 56 deletions
diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile index 65c47fda26fc..f9d38a48e3c8 100644 --- a/arch/x86/mm/Makefile +++ b/arch/x86/mm/Makefile | |||
@@ -15,6 +15,7 @@ obj-$(CONFIG_X86_32) += pgtable_32.o iomap_32.o | |||
15 | 15 | ||
16 | obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o | 16 | obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o |
17 | obj-$(CONFIG_X86_PTDUMP_CORE) += dump_pagetables.o | 17 | obj-$(CONFIG_X86_PTDUMP_CORE) += dump_pagetables.o |
18 | obj-$(CONFIG_X86_PTDUMP) += debug_pagetables.o | ||
18 | 19 | ||
19 | obj-$(CONFIG_HIGHMEM) += highmem_32.o | 20 | obj-$(CONFIG_HIGHMEM) += highmem_32.o |
20 | 21 | ||
diff --git a/arch/x86/mm/debug_pagetables.c b/arch/x86/mm/debug_pagetables.c new file mode 100644 index 000000000000..bfcffdf6c577 --- /dev/null +++ b/arch/x86/mm/debug_pagetables.c | |||
@@ -0,0 +1,46 @@ | |||
1 | #include <linux/debugfs.h> | ||
2 | #include <linux/module.h> | ||
3 | #include <linux/seq_file.h> | ||
4 | #include <asm/pgtable.h> | ||
5 | |||
6 | static int ptdump_show(struct seq_file *m, void *v) | ||
7 | { | ||
8 | ptdump_walk_pgd_level(m, NULL); | ||
9 | return 0; | ||
10 | } | ||
11 | |||
12 | static int ptdump_open(struct inode *inode, struct file *filp) | ||
13 | { | ||
14 | return single_open(filp, ptdump_show, NULL); | ||
15 | } | ||
16 | |||
17 | static const struct file_operations ptdump_fops = { | ||
18 | .owner = THIS_MODULE, | ||
19 | .open = ptdump_open, | ||
20 | .read = seq_read, | ||
21 | .llseek = seq_lseek, | ||
22 | .release = single_release, | ||
23 | }; | ||
24 | |||
25 | static struct dentry *pe; | ||
26 | |||
27 | static int __init pt_dump_debug_init(void) | ||
28 | { | ||
29 | pe = debugfs_create_file("kernel_page_tables", S_IRUSR, NULL, NULL, | ||
30 | &ptdump_fops); | ||
31 | if (!pe) | ||
32 | return -ENOMEM; | ||
33 | |||
34 | return 0; | ||
35 | } | ||
36 | |||
37 | static void __exit pt_dump_debug_exit(void) | ||
38 | { | ||
39 | debugfs_remove_recursive(pe); | ||
40 | } | ||
41 | |||
42 | module_init(pt_dump_debug_init); | ||
43 | module_exit(pt_dump_debug_exit); | ||
44 | MODULE_LICENSE("GPL"); | ||
45 | MODULE_AUTHOR("Arjan van de Ven <arjan@linux.intel.com>"); | ||
46 | MODULE_DESCRIPTION("Kernel debugging helper that dumps pagetables"); | ||
diff --git a/arch/x86/mm/dump_pagetables.c b/arch/x86/mm/dump_pagetables.c index 0f1c6fc3ddd8..4a6f1d9b5106 100644 --- a/arch/x86/mm/dump_pagetables.c +++ b/arch/x86/mm/dump_pagetables.c | |||
@@ -426,38 +426,15 @@ void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd) | |||
426 | { | 426 | { |
427 | ptdump_walk_pgd_level_core(m, pgd, false); | 427 | ptdump_walk_pgd_level_core(m, pgd, false); |
428 | } | 428 | } |
429 | EXPORT_SYMBOL_GPL(ptdump_walk_pgd_level); | ||
429 | 430 | ||
430 | void ptdump_walk_pgd_level_checkwx(void) | 431 | void ptdump_walk_pgd_level_checkwx(void) |
431 | { | 432 | { |
432 | ptdump_walk_pgd_level_core(NULL, NULL, true); | 433 | ptdump_walk_pgd_level_core(NULL, NULL, true); |
433 | } | 434 | } |
434 | 435 | ||
435 | #ifdef CONFIG_X86_PTDUMP | 436 | static int __init pt_dump_init(void) |
436 | static int ptdump_show(struct seq_file *m, void *v) | ||
437 | { | 437 | { |
438 | ptdump_walk_pgd_level(m, NULL); | ||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | static int ptdump_open(struct inode *inode, struct file *filp) | ||
443 | { | ||
444 | return single_open(filp, ptdump_show, NULL); | ||
445 | } | ||
446 | |||
447 | static const struct file_operations ptdump_fops = { | ||
448 | .open = ptdump_open, | ||
449 | .read = seq_read, | ||
450 | .llseek = seq_lseek, | ||
451 | .release = single_release, | ||
452 | }; | ||
453 | #endif | ||
454 | |||
455 | static int pt_dump_init(void) | ||
456 | { | ||
457 | #ifdef CONFIG_X86_PTDUMP | ||
458 | struct dentry *pe; | ||
459 | #endif | ||
460 | |||
461 | #ifdef CONFIG_X86_32 | 438 | #ifdef CONFIG_X86_32 |
462 | /* Not a compile-time constant on x86-32 */ | 439 | /* Not a compile-time constant on x86-32 */ |
463 | address_markers[VMALLOC_START_NR].start_address = VMALLOC_START; | 440 | address_markers[VMALLOC_START_NR].start_address = VMALLOC_START; |
@@ -468,13 +445,6 @@ static int pt_dump_init(void) | |||
468 | address_markers[FIXADDR_START_NR].start_address = FIXADDR_START; | 445 | address_markers[FIXADDR_START_NR].start_address = FIXADDR_START; |
469 | #endif | 446 | #endif |
470 | 447 | ||
471 | #ifdef CONFIG_X86_PTDUMP | ||
472 | pe = debugfs_create_file("kernel_page_tables", 0600, NULL, NULL, | ||
473 | &ptdump_fops); | ||
474 | if (!pe) | ||
475 | return -ENOMEM; | ||
476 | #endif | ||
477 | |||
478 | return 0; | 448 | return 0; |
479 | } | 449 | } |
480 | 450 | ||
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c index b9c78f3bcd67..0d8d53d1f5cc 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c | |||
@@ -194,8 +194,8 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr, | |||
194 | * Check if the request spans more than any BAR in the iomem resource | 194 | * Check if the request spans more than any BAR in the iomem resource |
195 | * tree. | 195 | * tree. |
196 | */ | 196 | */ |
197 | WARN_ONCE(iomem_map_sanity_check(unaligned_phys_addr, unaligned_size), | 197 | if (iomem_map_sanity_check(unaligned_phys_addr, unaligned_size)) |
198 | KERN_INFO "Info: mapping multiple BARs. Your kernel is fine."); | 198 | pr_warn("caller %pS mapping multiple BARs\n", caller); |
199 | 199 | ||
200 | return ret_addr; | 200 | return ret_addr; |
201 | err_free_area: | 201 | err_free_area: |
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index a3137a4feed1..6000ad7f560c 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
@@ -129,14 +129,16 @@ within(unsigned long addr, unsigned long start, unsigned long end) | |||
129 | */ | 129 | */ |
130 | void clflush_cache_range(void *vaddr, unsigned int size) | 130 | void clflush_cache_range(void *vaddr, unsigned int size) |
131 | { | 131 | { |
132 | unsigned long clflush_mask = boot_cpu_data.x86_clflush_size - 1; | 132 | const unsigned long clflush_size = boot_cpu_data.x86_clflush_size; |
133 | void *p = (void *)((unsigned long)vaddr & ~(clflush_size - 1)); | ||
133 | void *vend = vaddr + size; | 134 | void *vend = vaddr + size; |
134 | void *p; | 135 | |
136 | if (p >= vend) | ||
137 | return; | ||
135 | 138 | ||
136 | mb(); | 139 | mb(); |
137 | 140 | ||
138 | for (p = (void *)((unsigned long)vaddr & ~clflush_mask); | 141 | for (; p < vend; p += clflush_size) |
139 | p < vend; p += boot_cpu_data.x86_clflush_size) | ||
140 | clflushopt(p); | 142 | clflushopt(p); |
141 | 143 | ||
142 | mb(); | 144 | mb(); |
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index 188e3e07eeeb..031782e74231 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c | |||
@@ -586,7 +586,7 @@ int free_memtype(u64 start, u64 end) | |||
586 | entry = rbt_memtype_erase(start, end); | 586 | entry = rbt_memtype_erase(start, end); |
587 | spin_unlock(&memtype_lock); | 587 | spin_unlock(&memtype_lock); |
588 | 588 | ||
589 | if (!entry) { | 589 | if (IS_ERR(entry)) { |
590 | pr_info("x86/PAT: %s:%d freeing invalid memtype [mem %#010Lx-%#010Lx]\n", | 590 | pr_info("x86/PAT: %s:%d freeing invalid memtype [mem %#010Lx-%#010Lx]\n", |
591 | current->comm, current->pid, start, end - 1); | 591 | current->comm, current->pid, start, end - 1); |
592 | return -EINVAL; | 592 | return -EINVAL; |
@@ -992,6 +992,16 @@ void untrack_pfn(struct vm_area_struct *vma, unsigned long pfn, | |||
992 | vma->vm_flags &= ~VM_PAT; | 992 | vma->vm_flags &= ~VM_PAT; |
993 | } | 993 | } |
994 | 994 | ||
995 | /* | ||
996 | * untrack_pfn_moved is called, while mremapping a pfnmap for a new region, | ||
997 | * with the old vma after its pfnmap page table has been removed. The new | ||
998 | * vma has a new pfnmap to the same pfn & cache type with VM_PAT set. | ||
999 | */ | ||
1000 | void untrack_pfn_moved(struct vm_area_struct *vma) | ||
1001 | { | ||
1002 | vma->vm_flags &= ~VM_PAT; | ||
1003 | } | ||
1004 | |||
995 | pgprot_t pgprot_writecombine(pgprot_t prot) | 1005 | pgprot_t pgprot_writecombine(pgprot_t prot) |
996 | { | 1006 | { |
997 | return __pgprot(pgprot_val(prot) | | 1007 | return __pgprot(pgprot_val(prot) | |
diff --git a/arch/x86/mm/pat_rbtree.c b/arch/x86/mm/pat_rbtree.c index 63931080366a..2f7702253ccf 100644 --- a/arch/x86/mm/pat_rbtree.c +++ b/arch/x86/mm/pat_rbtree.c | |||
@@ -98,8 +98,13 @@ static struct memtype *memtype_rb_lowest_match(struct rb_root *root, | |||
98 | return last_lower; /* Returns NULL if there is no overlap */ | 98 | return last_lower; /* Returns NULL if there is no overlap */ |
99 | } | 99 | } |
100 | 100 | ||
101 | static struct memtype *memtype_rb_exact_match(struct rb_root *root, | 101 | enum { |
102 | u64 start, u64 end) | 102 | MEMTYPE_EXACT_MATCH = 0, |
103 | MEMTYPE_END_MATCH = 1 | ||
104 | }; | ||
105 | |||
106 | static struct memtype *memtype_rb_match(struct rb_root *root, | ||
107 | u64 start, u64 end, int match_type) | ||
103 | { | 108 | { |
104 | struct memtype *match; | 109 | struct memtype *match; |
105 | 110 | ||
@@ -107,7 +112,12 @@ static struct memtype *memtype_rb_exact_match(struct rb_root *root, | |||
107 | while (match != NULL && match->start < end) { | 112 | while (match != NULL && match->start < end) { |
108 | struct rb_node *node; | 113 | struct rb_node *node; |
109 | 114 | ||
110 | if (match->start == start && match->end == end) | 115 | if ((match_type == MEMTYPE_EXACT_MATCH) && |
116 | (match->start == start) && (match->end == end)) | ||
117 | return match; | ||
118 | |||
119 | if ((match_type == MEMTYPE_END_MATCH) && | ||
120 | (match->start < start) && (match->end == end)) | ||
111 | return match; | 121 | return match; |
112 | 122 | ||
113 | node = rb_next(&match->rb); | 123 | node = rb_next(&match->rb); |
@@ -117,7 +127,7 @@ static struct memtype *memtype_rb_exact_match(struct rb_root *root, | |||
117 | match = NULL; | 127 | match = NULL; |
118 | } | 128 | } |
119 | 129 | ||
120 | return NULL; /* Returns NULL if there is no exact match */ | 130 | return NULL; /* Returns NULL if there is no match */ |
121 | } | 131 | } |
122 | 132 | ||
123 | static int memtype_rb_check_conflict(struct rb_root *root, | 133 | static int memtype_rb_check_conflict(struct rb_root *root, |
@@ -210,12 +220,36 @@ struct memtype *rbt_memtype_erase(u64 start, u64 end) | |||
210 | { | 220 | { |
211 | struct memtype *data; | 221 | struct memtype *data; |
212 | 222 | ||
213 | data = memtype_rb_exact_match(&memtype_rbroot, start, end); | 223 | /* |
214 | if (!data) | 224 | * Since the memtype_rbroot tree allows overlapping ranges, |
215 | goto out; | 225 | * rbt_memtype_erase() checks with EXACT_MATCH first, i.e. free |
226 | * a whole node for the munmap case. If no such entry is found, | ||
227 | * it then checks with END_MATCH, i.e. shrink the size of a node | ||
228 | * from the end for the mremap case. | ||
229 | */ | ||
230 | data = memtype_rb_match(&memtype_rbroot, start, end, | ||
231 | MEMTYPE_EXACT_MATCH); | ||
232 | if (!data) { | ||
233 | data = memtype_rb_match(&memtype_rbroot, start, end, | ||
234 | MEMTYPE_END_MATCH); | ||
235 | if (!data) | ||
236 | return ERR_PTR(-EINVAL); | ||
237 | } | ||
238 | |||
239 | if (data->start == start) { | ||
240 | /* munmap: erase this node */ | ||
241 | rb_erase_augmented(&data->rb, &memtype_rbroot, | ||
242 | &memtype_rb_augment_cb); | ||
243 | } else { | ||
244 | /* mremap: update the end value of this node */ | ||
245 | rb_erase_augmented(&data->rb, &memtype_rbroot, | ||
246 | &memtype_rb_augment_cb); | ||
247 | data->end = start; | ||
248 | data->subtree_max_end = data->end; | ||
249 | memtype_rb_insert(&memtype_rbroot, data); | ||
250 | return NULL; | ||
251 | } | ||
216 | 252 | ||
217 | rb_erase_augmented(&data->rb, &memtype_rbroot, &memtype_rb_augment_cb); | ||
218 | out: | ||
219 | return data; | 253 | return data; |
220 | } | 254 | } |
221 | 255 | ||
diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c index fb0a9dd1d6e4..ee9c2e3a7199 100644 --- a/arch/x86/mm/pgtable.c +++ b/arch/x86/mm/pgtable.c | |||
@@ -414,7 +414,7 @@ int ptep_set_access_flags(struct vm_area_struct *vma, | |||
414 | 414 | ||
415 | if (changed && dirty) { | 415 | if (changed && dirty) { |
416 | *ptep = entry; | 416 | *ptep = entry; |
417 | pte_update_defer(vma->vm_mm, address, ptep); | 417 | pte_update(vma->vm_mm, address, ptep); |
418 | } | 418 | } |
419 | 419 | ||
420 | return changed; | 420 | return changed; |
@@ -431,7 +431,6 @@ int pmdp_set_access_flags(struct vm_area_struct *vma, | |||
431 | 431 | ||
432 | if (changed && dirty) { | 432 | if (changed && dirty) { |
433 | *pmdp = entry; | 433 | *pmdp = entry; |
434 | pmd_update_defer(vma->vm_mm, address, pmdp); | ||
435 | /* | 434 | /* |
436 | * We had a write-protection fault here and changed the pmd | 435 | * We had a write-protection fault here and changed the pmd |
437 | * to to more permissive. No need to flush the TLB for that, | 436 | * to to more permissive. No need to flush the TLB for that, |
@@ -469,9 +468,6 @@ int pmdp_test_and_clear_young(struct vm_area_struct *vma, | |||
469 | ret = test_and_clear_bit(_PAGE_BIT_ACCESSED, | 468 | ret = test_and_clear_bit(_PAGE_BIT_ACCESSED, |
470 | (unsigned long *)pmdp); | 469 | (unsigned long *)pmdp); |
471 | 470 | ||
472 | if (ret) | ||
473 | pmd_update(vma->vm_mm, addr, pmdp); | ||
474 | |||
475 | return ret; | 471 | return ret; |
476 | } | 472 | } |
477 | #endif | 473 | #endif |
@@ -518,7 +514,6 @@ void pmdp_splitting_flush(struct vm_area_struct *vma, | |||
518 | set = !test_and_set_bit(_PAGE_BIT_SPLITTING, | 514 | set = !test_and_set_bit(_PAGE_BIT_SPLITTING, |
519 | (unsigned long *)pmdp); | 515 | (unsigned long *)pmdp); |
520 | if (set) { | 516 | if (set) { |
521 | pmd_update(vma->vm_mm, address, pmdp); | ||
522 | /* need tlb flush only to serialize against gup-fast */ | 517 | /* need tlb flush only to serialize against gup-fast */ |
523 | flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE); | 518 | flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE); |
524 | } | 519 | } |
diff --git a/arch/x86/mm/setup_nx.c b/arch/x86/mm/setup_nx.c index 90555bf60aa4..92e2eacb3321 100644 --- a/arch/x86/mm/setup_nx.c +++ b/arch/x86/mm/setup_nx.c | |||
@@ -31,7 +31,7 @@ early_param("noexec", noexec_setup); | |||
31 | 31 | ||
32 | void x86_configure_nx(void) | 32 | void x86_configure_nx(void) |
33 | { | 33 | { |
34 | if (cpu_has_nx && !disable_nx) | 34 | if (boot_cpu_has(X86_FEATURE_NX) && !disable_nx) |
35 | __supported_pte_mask |= _PAGE_NX; | 35 | __supported_pte_mask |= _PAGE_NX; |
36 | else | 36 | else |
37 | __supported_pte_mask &= ~_PAGE_NX; | 37 | __supported_pte_mask &= ~_PAGE_NX; |
@@ -39,7 +39,7 @@ void x86_configure_nx(void) | |||
39 | 39 | ||
40 | void __init x86_report_nx(void) | 40 | void __init x86_report_nx(void) |
41 | { | 41 | { |
42 | if (!cpu_has_nx) { | 42 | if (!boot_cpu_has(X86_FEATURE_NX)) { |
43 | printk(KERN_NOTICE "Notice: NX (Execute Disable) protection " | 43 | printk(KERN_NOTICE "Notice: NX (Execute Disable) protection " |
44 | "missing in CPU!\n"); | 44 | "missing in CPU!\n"); |
45 | } else { | 45 | } else { |
diff --git a/arch/x86/mm/srat.c b/arch/x86/mm/srat.c index c2aea63bee20..b5f821881465 100644 --- a/arch/x86/mm/srat.c +++ b/arch/x86/mm/srat.c | |||
@@ -203,6 +203,8 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) | |||
203 | pr_warn("SRAT: Failed to mark hotplug range [mem %#010Lx-%#010Lx] in memblock\n", | 203 | pr_warn("SRAT: Failed to mark hotplug range [mem %#010Lx-%#010Lx] in memblock\n", |
204 | (unsigned long long)start, (unsigned long long)end - 1); | 204 | (unsigned long long)start, (unsigned long long)end - 1); |
205 | 205 | ||
206 | max_possible_pfn = max(max_possible_pfn, PFN_UP(end - 1)); | ||
207 | |||
206 | return 0; | 208 | return 0; |
207 | out_err_bad_srat: | 209 | out_err_bad_srat: |
208 | bad_srat(); | 210 | bad_srat(); |