summaryrefslogtreecommitdiffstats
path: root/x86-get-user-pages-kmap-atomic-fix-32bit.patch
blob: e46106e6fba3168f48fc82abde65e06972e0538a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
From 65ee09cc76c422057f84cdcd6d0a88fa75546f91 Mon Sep 17 00:00:00 2001
From: Thomas Gleixner <tglx@linutronix.de>
Date: Fri, 3 Jul 2009 08:44:33 -0500
Subject: [PATCH] x86: get user pages kmap atomic fix (32bit)

commit 6c8a72dd4bcd3576b6a2758a9ce7e82cb39461df in tip.

[PG: add paravirt_types.h change from big 33rt merge commit, then
 delete paravirt parts that go away due to upstream dad52fc0116]

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
---
 arch/x86/include/asm/highmem.h    |    8 ++++++++
 arch/x86/include/asm/pgtable_32.h |    6 ++++++
 arch/x86/include/asm/pgtable_64.h |    6 ++++--
 arch/x86/mm/gup.c                 |    6 +++---
 arch/x86/mm/highmem_32.c          |    6 ++++++
 5 files changed, 27 insertions(+), 5 deletions(-)

diff --git a/arch/x86/include/asm/highmem.h b/arch/x86/include/asm/highmem.h
index 8391a46..28f471b 100644
--- a/arch/x86/include/asm/highmem.h
+++ b/arch/x86/include/asm/highmem.h
@@ -64,6 +64,7 @@ void kunmap(struct page *page);
 
 void *__kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot);
 void *__kmap_atomic(struct page *page, enum km_type type);
+void *__kmap_atomic_direct(struct page *page, enum km_type type);
 void __kunmap_atomic(void *kvaddr, enum km_type type);
 void *__kmap_atomic_pfn(unsigned long pfn, enum km_type type);
 struct page *__kmap_atomic_to_page(void *ptr);
@@ -76,6 +77,9 @@ void *kmap_atomic_pfn(unsigned long pfn, enum km_type type);
 void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot);
 struct page *kmap_atomic_to_page(void *ptr);
 
+#define kmap_atomic_pte(page, type)		kmap_atomic(page, type)
+#define kmap_atomic_pte_direct(page, type)	kmap_atomic_direct(page, type)
+
 #define flush_cache_kmaps()	do { } while (0)
 
 extern void add_highpages_with_active_regions(int nid, unsigned long start_pfn,
@@ -90,12 +94,16 @@ extern void add_highpages_with_active_regions(int nid, unsigned long start_pfn,
 # define kmap_atomic_pfn(pfn, type)	kmap(pfn_to_page(pfn))
 # define kunmap_atomic(kvaddr, type)	do { pagefault_enable(); kunmap_virt(kvaddr); } while(0)
 # define kmap_atomic_to_page(kvaddr)	kmap_to_page(kvaddr)
+# define kmap_atomic_direct(page, type)	__kmap_atomic_direct(page, type)
+# define kunmap_atomic_direct(kvaddr, type)	__kunmap_atomic(kvaddr, type)
 #else
 # define kmap_atomic_prot(page, type, prot)	__kmap_atomic_prot(page, type, prot)
 # define kmap_atomic(page, type)	__kmap_atomic(page, type)
 # define kmap_atomic_pfn(pfn, type)	__kmap_atomic_pfn(pfn, type)
 # define kunmap_atomic(kvaddr, type)	__kunmap_atomic(kvaddr, type)
 # define kmap_atomic_to_page(kvaddr)	__kmap_atomic_to_page(kvaddr)
+# define kmap_atomic_direct(page, type)	__kmap_atomic(page, type)
+# define kunmap_atomic_direct(kvaddr, type)	__kunmap_atomic(kvaddr, type)
 #endif
 
 #endif /* __KERNEL__ */
diff --git a/arch/x86/include/asm/pgtable_32.h b/arch/x86/include/asm/pgtable_32.h
index 2984a25..0d16f33 100644
--- a/arch/x86/include/asm/pgtable_32.h
+++ b/arch/x86/include/asm/pgtable_32.h
@@ -58,14 +58,20 @@ extern void set_pmd_pfn(unsigned long, unsigned long, pgprot_t);
 #define pte_offset_map_nested(dir, address)				\
 	((pte_t *)kmap_atomic(pmd_page(*(dir)), KM_PTE1) +		\
 	 pte_index((address)))
+#define pte_offset_map_direct(dir, address)				\
+	((pte_t *)kmap_atomic_pte_direct(pmd_page(*(dir)), __KM_PTE) +	\
+	 pte_index((address)))
 #define pte_unmap(pte) kunmap_atomic((pte), __KM_PTE)
 #define pte_unmap_nested(pte) kunmap_atomic((pte), KM_PTE1)
+#define pte_unmap_direct(pte) kunmap_atomic_direct((pte), __KM_PTE)
 #else
 #define pte_offset_map(dir, address)					\
 	((pte_t *)page_address(pmd_page(*(dir))) + pte_index((address)))
 #define pte_offset_map_nested(dir, address) pte_offset_map((dir), (address))
+#define pte_offset_map_direct(dir, address) pte_offset_map((dir), (address))
 #define pte_unmap(pte) do { } while (0)
 #define pte_unmap_nested(pte) do { } while (0)
+#define pte_unmap_direct(pte) do { } while (0)
 #endif
 
 /* Clear a kernel PTE and flush it from the TLB */
diff --git a/arch/x86/include/asm/pgtable_64.h b/arch/x86/include/asm/pgtable_64.h
index 181be52..3057193 100644
--- a/arch/x86/include/asm/pgtable_64.h
+++ b/arch/x86/include/asm/pgtable_64.h
@@ -126,8 +126,10 @@ static inline int pgd_large(pgd_t pgd) { return 0; }
 /* x86-64 always has all page tables mapped. */
 #define pte_offset_map(dir, address) pte_offset_kernel((dir), (address))
 #define pte_offset_map_nested(dir, address) pte_offset_kernel((dir), (address))
-#define pte_unmap(pte) /* NOP */
-#define pte_unmap_nested(pte) /* NOP */
+#define pte_offset_map_direct(dir, address) pte_offset_kernel((dir), (address))
+#define pte_unmap(pte) do { } while (0)
+#define pte_unmap_nested(pte) do { }  while (0)
+#define pte_unmap_direct(pte) do { }  while (0)
 
 #define update_mmu_cache(vma, address, ptep) do { } while (0)
 
diff --git a/arch/x86/mm/gup.c b/arch/x86/mm/gup.c
index 738e659..5aeae53 100644
--- a/arch/x86/mm/gup.c
+++ b/arch/x86/mm/gup.c
@@ -77,13 +77,13 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
 	if (write)
 		mask |= _PAGE_RW;
 
-	ptep = pte_offset_map(&pmd, addr);
+	ptep = pte_offset_map_direct(&pmd, addr);
 	do {
 		pte_t pte = gup_get_pte(ptep);
 		struct page *page;
 
 		if ((pte_flags(pte) & (mask | _PAGE_SPECIAL)) != mask) {
-			pte_unmap(ptep);
+			pte_unmap_direct(ptep);
 			return 0;
 		}
 		VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
@@ -93,7 +93,7 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
 		(*nr)++;
 
 	} while (ptep++, addr += PAGE_SIZE, addr != end);
-	pte_unmap(ptep - 1);
+	pte_unmap_direct(ptep - 1);
 
 	return 1;
 }
diff --git a/arch/x86/mm/highmem_32.c b/arch/x86/mm/highmem_32.c
index 419d8f6..dcb1899 100644
--- a/arch/x86/mm/highmem_32.c
+++ b/arch/x86/mm/highmem_32.c
@@ -70,6 +70,11 @@ void *__kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
 	return (void *)vaddr;
 }
 
+void *__kmap_atomic_direct(struct page *page, enum km_type type)
+{
+	return __kmap_atomic_prot(page, type, kmap_prot);
+}
+
 void *__kmap_atomic(struct page *page, enum km_type type)
 {
 	return kmap_atomic_prot(page, type, kmap_prot);
@@ -105,6 +110,7 @@ void __kunmap_atomic(void *kvaddr, enum km_type type)
  */
 void *__kmap_atomic_pfn(unsigned long pfn, enum km_type type)
 {
+	preempt_disable();
 	return kmap_atomic_prot_pfn(pfn, type, kmap_prot);
 }
 EXPORT_SYMBOL_GPL(__kmap_atomic_pfn); /* temporarily in use by i915 GEM until vmap */
-- 
1.7.0.4