aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/mm
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2016-01-12 05:08:13 -0500
committerIngo Molnar <mingo@kernel.org>2016-01-12 05:08:13 -0500
commitc0c57019a65341f08858541d2740b74dee821cf1 (patch)
tree584ac03f7dfa26c9c45c3d66ad306222e893fa33 /arch/x86/mm
parent8c31902cffc4d716450be549c66a67a8a3dd479c (diff)
parentae8a52185e5c070cf4510b323dbc1b9e46b897d6 (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/Makefile1
-rw-r--r--arch/x86/mm/debug_pagetables.c46
-rw-r--r--arch/x86/mm/dump_pagetables.c34
-rw-r--r--arch/x86/mm/ioremap.c4
-rw-r--r--arch/x86/mm/pageattr.c10
-rw-r--r--arch/x86/mm/pat.c12
-rw-r--r--arch/x86/mm/pat_rbtree.c52
-rw-r--r--arch/x86/mm/pgtable.c7
-rw-r--r--arch/x86/mm/setup_nx.c4
-rw-r--r--arch/x86/mm/srat.c2
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
16obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o 16obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
17obj-$(CONFIG_X86_PTDUMP_CORE) += dump_pagetables.o 17obj-$(CONFIG_X86_PTDUMP_CORE) += dump_pagetables.o
18obj-$(CONFIG_X86_PTDUMP) += debug_pagetables.o
18 19
19obj-$(CONFIG_HIGHMEM) += highmem_32.o 20obj-$(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
6static int ptdump_show(struct seq_file *m, void *v)
7{
8 ptdump_walk_pgd_level(m, NULL);
9 return 0;
10}
11
12static int ptdump_open(struct inode *inode, struct file *filp)
13{
14 return single_open(filp, ptdump_show, NULL);
15}
16
17static 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
25static struct dentry *pe;
26
27static 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
37static void __exit pt_dump_debug_exit(void)
38{
39 debugfs_remove_recursive(pe);
40}
41
42module_init(pt_dump_debug_init);
43module_exit(pt_dump_debug_exit);
44MODULE_LICENSE("GPL");
45MODULE_AUTHOR("Arjan van de Ven <arjan@linux.intel.com>");
46MODULE_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}
429EXPORT_SYMBOL_GPL(ptdump_walk_pgd_level);
429 430
430void ptdump_walk_pgd_level_checkwx(void) 431void 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 436static int __init pt_dump_init(void)
436static int ptdump_show(struct seq_file *m, void *v)
437{ 437{
438 ptdump_walk_pgd_level(m, NULL);
439 return 0;
440}
441
442static int ptdump_open(struct inode *inode, struct file *filp)
443{
444 return single_open(filp, ptdump_show, NULL);
445}
446
447static 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
455static 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;
201err_free_area: 201err_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 */
130void clflush_cache_range(void *vaddr, unsigned int size) 130void 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 */
1000void untrack_pfn_moved(struct vm_area_struct *vma)
1001{
1002 vma->vm_flags &= ~VM_PAT;
1003}
1004
995pgprot_t pgprot_writecombine(pgprot_t prot) 1005pgprot_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
101static struct memtype *memtype_rb_exact_match(struct rb_root *root, 101enum {
102 u64 start, u64 end) 102 MEMTYPE_EXACT_MATCH = 0,
103 MEMTYPE_END_MATCH = 1
104};
105
106static 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
123static int memtype_rb_check_conflict(struct rb_root *root, 133static 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);
218out:
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
32void x86_configure_nx(void) 32void 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
40void __init x86_report_nx(void) 40void __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;
207out_err_bad_srat: 209out_err_bad_srat:
208 bad_srat(); 210 bad_srat();