aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/kvm/book3s_64_vio.c44
-rw-r--r--arch/powerpc/mm/book3s64/iommu_api.c41
-rw-r--r--drivers/fpga/dfl-afu-dma-region.c53
-rw-r--r--drivers/vfio/vfio_iommu_spapr_tce.c54
-rw-r--r--drivers/vfio/vfio_iommu_type1.c17
-rw-r--r--include/linux/mm.h4
-rw-r--r--mm/util.c75
7 files changed, 98 insertions, 190 deletions
diff --git a/arch/powerpc/kvm/book3s_64_vio.c b/arch/powerpc/kvm/book3s_64_vio.c
index 5bf05cc774e2..e99a14798ab0 100644
--- a/arch/powerpc/kvm/book3s_64_vio.c
+++ b/arch/powerpc/kvm/book3s_64_vio.c
@@ -19,6 +19,7 @@
19#include <linux/anon_inodes.h> 19#include <linux/anon_inodes.h>
20#include <linux/iommu.h> 20#include <linux/iommu.h>
21#include <linux/file.h> 21#include <linux/file.h>
22#include <linux/mm.h>
22 23
23#include <asm/kvm_ppc.h> 24#include <asm/kvm_ppc.h>
24#include <asm/kvm_book3s.h> 25#include <asm/kvm_book3s.h>
@@ -45,43 +46,6 @@ static unsigned long kvmppc_stt_pages(unsigned long tce_pages)
45 return tce_pages + ALIGN(stt_bytes, PAGE_SIZE) / PAGE_SIZE; 46 return tce_pages + ALIGN(stt_bytes, PAGE_SIZE) / PAGE_SIZE;
46} 47}
47 48
48static long kvmppc_account_memlimit(unsigned long stt_pages, bool inc)
49{
50 long ret = 0;
51
52 if (!current || !current->mm)
53 return ret; /* process exited */
54
55 down_write(&current->mm->mmap_sem);
56
57 if (inc) {
58 unsigned long locked, lock_limit;
59
60 locked = current->mm->locked_vm + stt_pages;
61 lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
62 if (locked > lock_limit && !capable(CAP_IPC_LOCK))
63 ret = -ENOMEM;
64 else
65 current->mm->locked_vm += stt_pages;
66 } else {
67 if (WARN_ON_ONCE(stt_pages > current->mm->locked_vm))
68 stt_pages = current->mm->locked_vm;
69
70 current->mm->locked_vm -= stt_pages;
71 }
72
73 pr_debug("[%d] RLIMIT_MEMLOCK KVM %c%ld %ld/%ld%s\n", current->pid,
74 inc ? '+' : '-',
75 stt_pages << PAGE_SHIFT,
76 current->mm->locked_vm << PAGE_SHIFT,
77 rlimit(RLIMIT_MEMLOCK),
78 ret ? " - exceeded" : "");
79
80 up_write(&current->mm->mmap_sem);
81
82 return ret;
83}
84
85static void kvm_spapr_tce_iommu_table_free(struct rcu_head *head) 49static void kvm_spapr_tce_iommu_table_free(struct rcu_head *head)
86{ 50{
87 struct kvmppc_spapr_tce_iommu_table *stit = container_of(head, 51 struct kvmppc_spapr_tce_iommu_table *stit = container_of(head,
@@ -291,7 +255,7 @@ static int kvm_spapr_tce_release(struct inode *inode, struct file *filp)
291 255
292 kvm_put_kvm(stt->kvm); 256 kvm_put_kvm(stt->kvm);
293 257
294 kvmppc_account_memlimit( 258 account_locked_vm(current->mm,
295 kvmppc_stt_pages(kvmppc_tce_pages(stt->size)), false); 259 kvmppc_stt_pages(kvmppc_tce_pages(stt->size)), false);
296 call_rcu(&stt->rcu, release_spapr_tce_table); 260 call_rcu(&stt->rcu, release_spapr_tce_table);
297 261
@@ -316,7 +280,7 @@ long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
316 return -EINVAL; 280 return -EINVAL;
317 281
318 npages = kvmppc_tce_pages(size); 282 npages = kvmppc_tce_pages(size);
319 ret = kvmppc_account_memlimit(kvmppc_stt_pages(npages), true); 283 ret = account_locked_vm(current->mm, kvmppc_stt_pages(npages), true);
320 if (ret) 284 if (ret)
321 return ret; 285 return ret;
322 286
@@ -362,7 +326,7 @@ long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
362 326
363 kfree(stt); 327 kfree(stt);
364 fail_acct: 328 fail_acct:
365 kvmppc_account_memlimit(kvmppc_stt_pages(npages), false); 329 account_locked_vm(current->mm, kvmppc_stt_pages(npages), false);
366 return ret; 330 return ret;
367} 331}
368 332
diff --git a/arch/powerpc/mm/book3s64/iommu_api.c b/arch/powerpc/mm/book3s64/iommu_api.c
index 90ee3a89722c..b056cae3388b 100644
--- a/arch/powerpc/mm/book3s64/iommu_api.c
+++ b/arch/powerpc/mm/book3s64/iommu_api.c
@@ -14,6 +14,7 @@
14#include <linux/hugetlb.h> 14#include <linux/hugetlb.h>
15#include <linux/swap.h> 15#include <linux/swap.h>
16#include <linux/sizes.h> 16#include <linux/sizes.h>
17#include <linux/mm.h>
17#include <asm/mmu_context.h> 18#include <asm/mmu_context.h>
18#include <asm/pte-walk.h> 19#include <asm/pte-walk.h>
19#include <linux/mm_inline.h> 20#include <linux/mm_inline.h>
@@ -46,40 +47,6 @@ struct mm_iommu_table_group_mem_t {
46 u64 dev_hpa; /* Device memory base address */ 47 u64 dev_hpa; /* Device memory base address */
47}; 48};
48 49
49static long mm_iommu_adjust_locked_vm(struct mm_struct *mm,
50 unsigned long npages, bool incr)
51{
52 long ret = 0, locked, lock_limit;
53
54 if (!npages)
55 return 0;
56
57 down_write(&mm->mmap_sem);
58
59 if (incr) {
60 locked = mm->locked_vm + npages;
61 lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
62 if (locked > lock_limit && !capable(CAP_IPC_LOCK))
63 ret = -ENOMEM;
64 else
65 mm->locked_vm += npages;
66 } else {
67 if (WARN_ON_ONCE(npages > mm->locked_vm))
68 npages = mm->locked_vm;
69 mm->locked_vm -= npages;
70 }
71
72 pr_debug("[%d] RLIMIT_MEMLOCK HASH64 %c%ld %ld/%ld\n",
73 current ? current->pid : 0,
74 incr ? '+' : '-',
75 npages << PAGE_SHIFT,
76 mm->locked_vm << PAGE_SHIFT,
77 rlimit(RLIMIT_MEMLOCK));
78 up_write(&mm->mmap_sem);
79
80 return ret;
81}
82
83bool mm_iommu_preregistered(struct mm_struct *mm) 50bool mm_iommu_preregistered(struct mm_struct *mm)
84{ 51{
85 return !list_empty(&mm->context.iommu_group_mem_list); 52 return !list_empty(&mm->context.iommu_group_mem_list);
@@ -96,7 +63,7 @@ static long mm_iommu_do_alloc(struct mm_struct *mm, unsigned long ua,
96 unsigned long entry, chunk; 63 unsigned long entry, chunk;
97 64
98 if (dev_hpa == MM_IOMMU_TABLE_INVALID_HPA) { 65 if (dev_hpa == MM_IOMMU_TABLE_INVALID_HPA) {
99 ret = mm_iommu_adjust_locked_vm(mm, entries, true); 66 ret = account_locked_vm(mm, entries, true);
100 if (ret) 67 if (ret)
101 return ret; 68 return ret;
102 69
@@ -211,7 +178,7 @@ free_exit:
211 kfree(mem); 178 kfree(mem);
212 179
213unlock_exit: 180unlock_exit:
214 mm_iommu_adjust_locked_vm(mm, locked_entries, false); 181 account_locked_vm(mm, locked_entries, false);
215 182
216 return ret; 183 return ret;
217} 184}
@@ -311,7 +278,7 @@ long mm_iommu_put(struct mm_struct *mm, struct mm_iommu_table_group_mem_t *mem)
311unlock_exit: 278unlock_exit:
312 mutex_unlock(&mem_list_mutex); 279 mutex_unlock(&mem_list_mutex);
313 280
314 mm_iommu_adjust_locked_vm(mm, unlock_entries, false); 281 account_locked_vm(mm, unlock_entries, false);
315 282
316 return ret; 283 return ret;
317} 284}
diff --git a/drivers/fpga/dfl-afu-dma-region.c b/drivers/fpga/dfl-afu-dma-region.c
index dcd80b088c7b..62f924489db5 100644
--- a/drivers/fpga/dfl-afu-dma-region.c
+++ b/drivers/fpga/dfl-afu-dma-region.c
@@ -12,6 +12,7 @@
12#include <linux/dma-mapping.h> 12#include <linux/dma-mapping.h>
13#include <linux/sched/signal.h> 13#include <linux/sched/signal.h>
14#include <linux/uaccess.h> 14#include <linux/uaccess.h>
15#include <linux/mm.h>
15 16
16#include "dfl-afu.h" 17#include "dfl-afu.h"
17 18
@@ -32,52 +33,6 @@ void afu_dma_region_init(struct dfl_feature_platform_data *pdata)
32} 33}
33 34
34/** 35/**
35 * afu_dma_adjust_locked_vm - adjust locked memory
36 * @dev: port device
37 * @npages: number of pages
38 * @incr: increase or decrease locked memory
39 *
40 * Increase or decrease the locked memory size with npages input.
41 *
42 * Return 0 on success.
43 * Return -ENOMEM if locked memory size is over the limit and no CAP_IPC_LOCK.
44 */
45static int afu_dma_adjust_locked_vm(struct device *dev, long npages, bool incr)
46{
47 unsigned long locked, lock_limit;
48 int ret = 0;
49
50 /* the task is exiting. */
51 if (!current->mm)
52 return 0;
53
54 down_write(&current->mm->mmap_sem);
55
56 if (incr) {
57 locked = current->mm->locked_vm + npages;
58 lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
59
60 if (locked > lock_limit && !capable(CAP_IPC_LOCK))
61 ret = -ENOMEM;
62 else
63 current->mm->locked_vm += npages;
64 } else {
65 if (WARN_ON_ONCE(npages > current->mm->locked_vm))
66 npages = current->mm->locked_vm;
67 current->mm->locked_vm -= npages;
68 }
69
70 dev_dbg(dev, "[%d] RLIMIT_MEMLOCK %c%ld %ld/%ld%s\n", current->pid,
71 incr ? '+' : '-', npages << PAGE_SHIFT,
72 current->mm->locked_vm << PAGE_SHIFT, rlimit(RLIMIT_MEMLOCK),
73 ret ? "- exceeded" : "");
74
75 up_write(&current->mm->mmap_sem);
76
77 return ret;
78}
79
80/**
81 * afu_dma_pin_pages - pin pages of given dma memory region 36 * afu_dma_pin_pages - pin pages of given dma memory region
82 * @pdata: feature device platform data 37 * @pdata: feature device platform data
83 * @region: dma memory region to be pinned 38 * @region: dma memory region to be pinned
@@ -92,7 +47,7 @@ static int afu_dma_pin_pages(struct dfl_feature_platform_data *pdata,
92 struct device *dev = &pdata->dev->dev; 47 struct device *dev = &pdata->dev->dev;
93 int ret, pinned; 48 int ret, pinned;
94 49
95 ret = afu_dma_adjust_locked_vm(dev, npages, true); 50 ret = account_locked_vm(current->mm, npages, true);
96 if (ret) 51 if (ret)
97 return ret; 52 return ret;
98 53
@@ -121,7 +76,7 @@ put_pages:
121free_pages: 76free_pages:
122 kfree(region->pages); 77 kfree(region->pages);
123unlock_vm: 78unlock_vm:
124 afu_dma_adjust_locked_vm(dev, npages, false); 79 account_locked_vm(current->mm, npages, false);
125 return ret; 80 return ret;
126} 81}
127 82
@@ -141,7 +96,7 @@ static void afu_dma_unpin_pages(struct dfl_feature_platform_data *pdata,
141 96
142 put_all_pages(region->pages, npages); 97 put_all_pages(region->pages, npages);
143 kfree(region->pages); 98 kfree(region->pages);
144 afu_dma_adjust_locked_vm(dev, npages, false); 99 account_locked_vm(current->mm, npages, false);
145 100
146 dev_dbg(dev, "%ld pages unpinned\n", npages); 101 dev_dbg(dev, "%ld pages unpinned\n", npages);
147} 102}
diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c
index 7048c9198c21..8ce9ad21129f 100644
--- a/drivers/vfio/vfio_iommu_spapr_tce.c
+++ b/drivers/vfio/vfio_iommu_spapr_tce.c
@@ -19,6 +19,7 @@
19#include <linux/vmalloc.h> 19#include <linux/vmalloc.h>
20#include <linux/sched/mm.h> 20#include <linux/sched/mm.h>
21#include <linux/sched/signal.h> 21#include <linux/sched/signal.h>
22#include <linux/mm.h>
22 23
23#include <asm/iommu.h> 24#include <asm/iommu.h>
24#include <asm/tce.h> 25#include <asm/tce.h>
@@ -31,51 +32,6 @@
31static void tce_iommu_detach_group(void *iommu_data, 32static void tce_iommu_detach_group(void *iommu_data,
32 struct iommu_group *iommu_group); 33 struct iommu_group *iommu_group);
33 34
34static long try_increment_locked_vm(struct mm_struct *mm, long npages)
35{
36 long ret = 0, locked, lock_limit;
37
38 if (WARN_ON_ONCE(!mm))
39 return -EPERM;
40
41 if (!npages)
42 return 0;
43
44 down_write(&mm->mmap_sem);
45 locked = mm->locked_vm + npages;
46 lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
47 if (locked > lock_limit && !capable(CAP_IPC_LOCK))
48 ret = -ENOMEM;
49 else
50 mm->locked_vm += npages;
51
52 pr_debug("[%d] RLIMIT_MEMLOCK +%ld %ld/%ld%s\n", current->pid,
53 npages << PAGE_SHIFT,
54 mm->locked_vm << PAGE_SHIFT,
55 rlimit(RLIMIT_MEMLOCK),
56 ret ? " - exceeded" : "");
57
58 up_write(&mm->mmap_sem);
59
60 return ret;
61}
62
63static void decrement_locked_vm(struct mm_struct *mm, long npages)
64{
65 if (!mm || !npages)
66 return;
67
68 down_write(&mm->mmap_sem);
69 if (WARN_ON_ONCE(npages > mm->locked_vm))
70 npages = mm->locked_vm;
71 mm->locked_vm -= npages;
72 pr_debug("[%d] RLIMIT_MEMLOCK -%ld %ld/%ld\n", current->pid,
73 npages << PAGE_SHIFT,
74 mm->locked_vm << PAGE_SHIFT,
75 rlimit(RLIMIT_MEMLOCK));
76 up_write(&mm->mmap_sem);
77}
78
79/* 35/*
80 * VFIO IOMMU fd for SPAPR_TCE IOMMU implementation 36 * VFIO IOMMU fd for SPAPR_TCE IOMMU implementation
81 * 37 *
@@ -333,7 +289,7 @@ static int tce_iommu_enable(struct tce_container *container)
333 return ret; 289 return ret;
334 290
335 locked = table_group->tce32_size >> PAGE_SHIFT; 291 locked = table_group->tce32_size >> PAGE_SHIFT;
336 ret = try_increment_locked_vm(container->mm, locked); 292 ret = account_locked_vm(container->mm, locked, true);
337 if (ret) 293 if (ret)
338 return ret; 294 return ret;
339 295
@@ -352,7 +308,7 @@ static void tce_iommu_disable(struct tce_container *container)
352 container->enabled = false; 308 container->enabled = false;
353 309
354 BUG_ON(!container->mm); 310 BUG_ON(!container->mm);
355 decrement_locked_vm(container->mm, container->locked_pages); 311 account_locked_vm(container->mm, container->locked_pages, false);
356} 312}
357 313
358static void *tce_iommu_open(unsigned long arg) 314static void *tce_iommu_open(unsigned long arg)
@@ -656,7 +612,7 @@ static long tce_iommu_create_table(struct tce_container *container,
656 if (!table_size) 612 if (!table_size)
657 return -EINVAL; 613 return -EINVAL;
658 614
659 ret = try_increment_locked_vm(container->mm, table_size >> PAGE_SHIFT); 615 ret = account_locked_vm(container->mm, table_size >> PAGE_SHIFT, true);
660 if (ret) 616 if (ret)
661 return ret; 617 return ret;
662 618
@@ -675,7 +631,7 @@ static void tce_iommu_free_table(struct tce_container *container,
675 unsigned long pages = tbl->it_allocated_size >> PAGE_SHIFT; 631 unsigned long pages = tbl->it_allocated_size >> PAGE_SHIFT;
676 632
677 iommu_tce_table_put(tbl); 633 iommu_tce_table_put(tbl);
678 decrement_locked_vm(container->mm, pages); 634 account_locked_vm(container->mm, pages, false);
679} 635}
680 636
681static long tce_iommu_create_window(struct tce_container *container, 637static long tce_iommu_create_window(struct tce_container *container,
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index add34adfadc7..054391f30fa8 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -272,21 +272,8 @@ static int vfio_lock_acct(struct vfio_dma *dma, long npage, bool async)
272 272
273 ret = down_write_killable(&mm->mmap_sem); 273 ret = down_write_killable(&mm->mmap_sem);
274 if (!ret) { 274 if (!ret) {
275 if (npage > 0) { 275 ret = __account_locked_vm(mm, abs(npage), npage > 0, dma->task,
276 if (!dma->lock_cap) { 276 dma->lock_cap);
277 unsigned long limit;
278
279 limit = task_rlimit(dma->task,
280 RLIMIT_MEMLOCK) >> PAGE_SHIFT;
281
282 if (mm->locked_vm + npage > limit)
283 ret = -ENOMEM;
284 }
285 }
286
287 if (!ret)
288 mm->locked_vm += npage;
289
290 up_write(&mm->mmap_sem); 277 up_write(&mm->mmap_sem);
291 } 278 }
292 279
diff --git a/include/linux/mm.h b/include/linux/mm.h
index f43f4de4de68..bd6512559bed 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1543,6 +1543,10 @@ long get_user_pages_unlocked(unsigned long start, unsigned long nr_pages,
1543int get_user_pages_fast(unsigned long start, int nr_pages, 1543int get_user_pages_fast(unsigned long start, int nr_pages,
1544 unsigned int gup_flags, struct page **pages); 1544 unsigned int gup_flags, struct page **pages);
1545 1545
1546int account_locked_vm(struct mm_struct *mm, unsigned long pages, bool inc);
1547int __account_locked_vm(struct mm_struct *mm, unsigned long pages, bool inc,
1548 struct task_struct *task, bool bypass_rlim);
1549
1546/* Container for pinned pfns / pages */ 1550/* Container for pinned pfns / pages */
1547struct frame_vector { 1551struct frame_vector {
1548 unsigned int nr_allocated; /* Number of frames we have space for */ 1552 unsigned int nr_allocated; /* Number of frames we have space for */
diff --git a/mm/util.c b/mm/util.c
index 68575a315dc5..e6351a80f248 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -7,6 +7,7 @@
7#include <linux/err.h> 7#include <linux/err.h>
8#include <linux/sched.h> 8#include <linux/sched.h>
9#include <linux/sched/mm.h> 9#include <linux/sched/mm.h>
10#include <linux/sched/signal.h>
10#include <linux/sched/task_stack.h> 11#include <linux/sched/task_stack.h>
11#include <linux/security.h> 12#include <linux/security.h>
12#include <linux/swap.h> 13#include <linux/swap.h>
@@ -300,6 +301,80 @@ void arch_pick_mmap_layout(struct mm_struct *mm, struct rlimit *rlim_stack)
300} 301}
301#endif 302#endif
302 303
304/**
305 * __account_locked_vm - account locked pages to an mm's locked_vm
306 * @mm: mm to account against
307 * @pages: number of pages to account
308 * @inc: %true if @pages should be considered positive, %false if not
309 * @task: task used to check RLIMIT_MEMLOCK
310 * @bypass_rlim: %true if checking RLIMIT_MEMLOCK should be skipped
311 *
312 * Assumes @task and @mm are valid (i.e. at least one reference on each), and
313 * that mmap_sem is held as writer.
314 *
315 * Return:
316 * * 0 on success
317 * * -ENOMEM if RLIMIT_MEMLOCK would be exceeded.
318 */
319int __account_locked_vm(struct mm_struct *mm, unsigned long pages, bool inc,
320 struct task_struct *task, bool bypass_rlim)
321{
322 unsigned long locked_vm, limit;
323 int ret = 0;
324
325 lockdep_assert_held_write(&mm->mmap_sem);
326
327 locked_vm = mm->locked_vm;
328 if (inc) {
329 if (!bypass_rlim) {
330 limit = task_rlimit(task, RLIMIT_MEMLOCK) >> PAGE_SHIFT;
331 if (locked_vm + pages > limit)
332 ret = -ENOMEM;
333 }
334 if (!ret)
335 mm->locked_vm = locked_vm + pages;
336 } else {
337 WARN_ON_ONCE(pages > locked_vm);
338 mm->locked_vm = locked_vm - pages;
339 }
340
341 pr_debug("%s: [%d] caller %ps %c%lu %lu/%lu%s\n", __func__, task->pid,
342 (void *)_RET_IP_, (inc) ? '+' : '-', pages << PAGE_SHIFT,
343 locked_vm << PAGE_SHIFT, task_rlimit(task, RLIMIT_MEMLOCK),
344 ret ? " - exceeded" : "");
345
346 return ret;
347}
348EXPORT_SYMBOL_GPL(__account_locked_vm);
349
350/**
351 * account_locked_vm - account locked pages to an mm's locked_vm
352 * @mm: mm to account against, may be NULL
353 * @pages: number of pages to account
354 * @inc: %true if @pages should be considered positive, %false if not
355 *
356 * Assumes a non-NULL @mm is valid (i.e. at least one reference on it).
357 *
358 * Return:
359 * * 0 on success, or if mm is NULL
360 * * -ENOMEM if RLIMIT_MEMLOCK would be exceeded.
361 */
362int account_locked_vm(struct mm_struct *mm, unsigned long pages, bool inc)
363{
364 int ret;
365
366 if (pages == 0 || !mm)
367 return 0;
368
369 down_write(&mm->mmap_sem);
370 ret = __account_locked_vm(mm, pages, inc, current,
371 capable(CAP_IPC_LOCK));
372 up_write(&mm->mmap_sem);
373
374 return ret;
375}
376EXPORT_SYMBOL_GPL(account_locked_vm);
377
303unsigned long vm_mmap_pgoff(struct file *file, unsigned long addr, 378unsigned long vm_mmap_pgoff(struct file *file, unsigned long addr,
304 unsigned long len, unsigned long prot, 379 unsigned long len, unsigned long prot,
305 unsigned long flag, unsigned long pgoff) 380 unsigned long flag, unsigned long pgoff)