aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-04-28 13:43:15 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-04-28 13:43:15 -0400
commit0d82044e1b7e5497c2177abd39b31e9ba27be8b7 (patch)
tree0d9f3ea99c192831c428e76c9e6789170e7fe484
parent975a0f400f2e1b5f585fec0b8b4c5942c3b05792 (diff)
parent7a3a4d763837d3aa654cd1059030950410c04d77 (diff)
Merge tag 'powerpc-5.1-6' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux
Pull powerpc fixes from Michael Ellerman: "A one-liner to make our Radix MMU support depend on HUGETLB_PAGE. We use some of the hugetlb inlines (eg. pud_huge()) when operating on the linear mapping and if they're compiled into empty wrappers we can corrupt memory. Then two fixes to our VFIO IOMMU code. The first is not a regression but fixes the locking to avoid a user-triggerable deadlock. The second does fix a regression since rc1, and depends on the first fix. It makes it possible to run guests with large amounts of memory again (~256GB). Thanks to Alexey Kardashevskiy" * tag 'powerpc-5.1-6' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux: powerpc/mm_iommu: Allow pinning large regions powerpc/mm_iommu: Fix potential deadlock powerpc/mm/radix: Make Radix require HUGETLB_PAGE
-rw-r--r--arch/powerpc/configs/skiroot_defconfig1
-rw-r--r--arch/powerpc/mm/mmu_context_iommu.c97
-rw-r--r--arch/powerpc/platforms/Kconfig.cputype2
3 files changed, 60 insertions, 40 deletions
diff --git a/arch/powerpc/configs/skiroot_defconfig b/arch/powerpc/configs/skiroot_defconfig
index 5ba131c30f6b..1bcd468ab422 100644
--- a/arch/powerpc/configs/skiroot_defconfig
+++ b/arch/powerpc/configs/skiroot_defconfig
@@ -266,6 +266,7 @@ CONFIG_UDF_FS=m
266CONFIG_MSDOS_FS=m 266CONFIG_MSDOS_FS=m
267CONFIG_VFAT_FS=m 267CONFIG_VFAT_FS=m
268CONFIG_PROC_KCORE=y 268CONFIG_PROC_KCORE=y
269CONFIG_HUGETLBFS=y
269# CONFIG_MISC_FILESYSTEMS is not set 270# CONFIG_MISC_FILESYSTEMS is not set
270# CONFIG_NETWORK_FILESYSTEMS is not set 271# CONFIG_NETWORK_FILESYSTEMS is not set
271CONFIG_NLS=y 272CONFIG_NLS=y
diff --git a/arch/powerpc/mm/mmu_context_iommu.c b/arch/powerpc/mm/mmu_context_iommu.c
index e7a9c4f6bfca..8330f135294f 100644
--- a/arch/powerpc/mm/mmu_context_iommu.c
+++ b/arch/powerpc/mm/mmu_context_iommu.c
@@ -95,28 +95,15 @@ static long mm_iommu_do_alloc(struct mm_struct *mm, unsigned long ua,
95 unsigned long entries, unsigned long dev_hpa, 95 unsigned long entries, unsigned long dev_hpa,
96 struct mm_iommu_table_group_mem_t **pmem) 96 struct mm_iommu_table_group_mem_t **pmem)
97{ 97{
98 struct mm_iommu_table_group_mem_t *mem; 98 struct mm_iommu_table_group_mem_t *mem, *mem2;
99 long i, ret, locked_entries = 0; 99 long i, ret, locked_entries = 0, pinned = 0;
100 unsigned int pageshift; 100 unsigned int pageshift;
101 101 unsigned long entry, chunk;
102 mutex_lock(&mem_list_mutex);
103
104 list_for_each_entry_rcu(mem, &mm->context.iommu_group_mem_list,
105 next) {
106 /* Overlap? */
107 if ((mem->ua < (ua + (entries << PAGE_SHIFT))) &&
108 (ua < (mem->ua +
109 (mem->entries << PAGE_SHIFT)))) {
110 ret = -EINVAL;
111 goto unlock_exit;
112 }
113
114 }
115 102
116 if (dev_hpa == MM_IOMMU_TABLE_INVALID_HPA) { 103 if (dev_hpa == MM_IOMMU_TABLE_INVALID_HPA) {
117 ret = mm_iommu_adjust_locked_vm(mm, entries, true); 104 ret = mm_iommu_adjust_locked_vm(mm, entries, true);
118 if (ret) 105 if (ret)
119 goto unlock_exit; 106 return ret;
120 107
121 locked_entries = entries; 108 locked_entries = entries;
122 } 109 }
@@ -148,17 +135,27 @@ static long mm_iommu_do_alloc(struct mm_struct *mm, unsigned long ua,
148 } 135 }
149 136
150 down_read(&mm->mmap_sem); 137 down_read(&mm->mmap_sem);
151 ret = get_user_pages_longterm(ua, entries, FOLL_WRITE, mem->hpages, NULL); 138 chunk = (1UL << (PAGE_SHIFT + MAX_ORDER - 1)) /
139 sizeof(struct vm_area_struct *);
140 chunk = min(chunk, entries);
141 for (entry = 0; entry < entries; entry += chunk) {
142 unsigned long n = min(entries - entry, chunk);
143
144 ret = get_user_pages_longterm(ua + (entry << PAGE_SHIFT), n,
145 FOLL_WRITE, mem->hpages + entry, NULL);
146 if (ret == n) {
147 pinned += n;
148 continue;
149 }
150 if (ret > 0)
151 pinned += ret;
152 break;
153 }
152 up_read(&mm->mmap_sem); 154 up_read(&mm->mmap_sem);
153 if (ret != entries) { 155 if (pinned != entries) {
154 /* free the reference taken */ 156 if (!ret)
155 for (i = 0; i < ret; i++) 157 ret = -EFAULT;
156 put_page(mem->hpages[i]); 158 goto free_exit;
157
158 vfree(mem->hpas);
159 kfree(mem);
160 ret = -EFAULT;
161 goto unlock_exit;
162 } 159 }
163 160
164 pageshift = PAGE_SHIFT; 161 pageshift = PAGE_SHIFT;
@@ -183,21 +180,43 @@ static long mm_iommu_do_alloc(struct mm_struct *mm, unsigned long ua,
183 } 180 }
184 181
185good_exit: 182good_exit:
186 ret = 0;
187 atomic64_set(&mem->mapped, 1); 183 atomic64_set(&mem->mapped, 1);
188 mem->used = 1; 184 mem->used = 1;
189 mem->ua = ua; 185 mem->ua = ua;
190 mem->entries = entries; 186 mem->entries = entries;
191 *pmem = mem;
192 187
193 list_add_rcu(&mem->next, &mm->context.iommu_group_mem_list); 188 mutex_lock(&mem_list_mutex);
194 189
195unlock_exit: 190 list_for_each_entry_rcu(mem2, &mm->context.iommu_group_mem_list, next) {
196 if (locked_entries && ret) 191 /* Overlap? */
197 mm_iommu_adjust_locked_vm(mm, locked_entries, false); 192 if ((mem2->ua < (ua + (entries << PAGE_SHIFT))) &&
193 (ua < (mem2->ua +
194 (mem2->entries << PAGE_SHIFT)))) {
195 ret = -EINVAL;
196 mutex_unlock(&mem_list_mutex);
197 goto free_exit;
198 }
199 }
200
201 list_add_rcu(&mem->next, &mm->context.iommu_group_mem_list);
198 202
199 mutex_unlock(&mem_list_mutex); 203 mutex_unlock(&mem_list_mutex);
200 204
205 *pmem = mem;
206
207 return 0;
208
209free_exit:
210 /* free the reference taken */
211 for (i = 0; i < pinned; i++)
212 put_page(mem->hpages[i]);
213
214 vfree(mem->hpas);
215 kfree(mem);
216
217unlock_exit:
218 mm_iommu_adjust_locked_vm(mm, locked_entries, false);
219
201 return ret; 220 return ret;
202} 221}
203 222
@@ -266,7 +285,7 @@ static void mm_iommu_release(struct mm_iommu_table_group_mem_t *mem)
266long mm_iommu_put(struct mm_struct *mm, struct mm_iommu_table_group_mem_t *mem) 285long mm_iommu_put(struct mm_struct *mm, struct mm_iommu_table_group_mem_t *mem)
267{ 286{
268 long ret = 0; 287 long ret = 0;
269 unsigned long entries, dev_hpa; 288 unsigned long unlock_entries = 0;
270 289
271 mutex_lock(&mem_list_mutex); 290 mutex_lock(&mem_list_mutex);
272 291
@@ -287,17 +306,17 @@ long mm_iommu_put(struct mm_struct *mm, struct mm_iommu_table_group_mem_t *mem)
287 goto unlock_exit; 306 goto unlock_exit;
288 } 307 }
289 308
309 if (mem->dev_hpa == MM_IOMMU_TABLE_INVALID_HPA)
310 unlock_entries = mem->entries;
311
290 /* @mapped became 0 so now mappings are disabled, release the region */ 312 /* @mapped became 0 so now mappings are disabled, release the region */
291 entries = mem->entries;
292 dev_hpa = mem->dev_hpa;
293 mm_iommu_release(mem); 313 mm_iommu_release(mem);
294 314
295 if (dev_hpa == MM_IOMMU_TABLE_INVALID_HPA)
296 mm_iommu_adjust_locked_vm(mm, entries, false);
297
298unlock_exit: 315unlock_exit:
299 mutex_unlock(&mem_list_mutex); 316 mutex_unlock(&mem_list_mutex);
300 317
318 mm_iommu_adjust_locked_vm(mm, unlock_entries, false);
319
301 return ret; 320 return ret;
302} 321}
303EXPORT_SYMBOL_GPL(mm_iommu_put); 322EXPORT_SYMBOL_GPL(mm_iommu_put);
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 842b2c7e156a..50cd09b4e05d 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -324,7 +324,7 @@ config ARCH_ENABLE_SPLIT_PMD_PTLOCK
324 324
325config PPC_RADIX_MMU 325config PPC_RADIX_MMU
326 bool "Radix MMU Support" 326 bool "Radix MMU Support"
327 depends on PPC_BOOK3S_64 327 depends on PPC_BOOK3S_64 && HUGETLB_PAGE
328 select ARCH_HAS_GIGANTIC_PAGE if (MEMORY_ISOLATION && COMPACTION) || CMA 328 select ARCH_HAS_GIGANTIC_PAGE if (MEMORY_ISOLATION && COMPACTION) || CMA
329 default y 329 default y
330 help 330 help