@@ -31,6 +31,7 @@ struct vm_account {
struct task_struct *task;
struct mm_struct *mm;
struct user_struct *user;
+ struct pins_cgroup *pins_cg;
enum vm_account_flags flags;
};
@@ -453,6 +453,7 @@ void vm_account_init(struct vm_account *vm_account, struct task_struct *task,
mmgrab(task->mm);
vm_account->mm = task->mm;
+ vm_account->pins_cg = get_pins_cg(task);
vm_account->flags = flags;
}
EXPORT_SYMBOL_GPL(vm_account_init);
@@ -472,6 +473,7 @@ void vm_account_release(struct vm_account *vm_account)
free_uid(vm_account->user);
mmdrop(vm_account->mm);
+ put_pins_cg(vm_account->pins_cg);
}
EXPORT_SYMBOL_GPL(vm_account_release);
@@ -502,6 +504,17 @@ static int vm_account_cmpxchg(struct vm_account *vm_account,
}
}
+static void vm_unaccount_legacy(struct vm_account *vm_account,
+ unsigned long npages)
+{
+ if (vm_account->flags & VM_ACCOUNT_USER) {
+ atomic_long_sub(npages, &vm_account->user->locked_vm);
+ atomic64_sub(npages, &vm_account->mm->pinned_vm);
+ } else {
+ atomic64_sub(npages, &vm_account->mm->pinned_vm);
+ }
+}
+
/**
* vm_account_pinned - Charge pinned or locked memory to the vm_account.
* @vm_account: pointer to an initialised vm_account.
@@ -537,6 +550,11 @@ int vm_account_pinned(struct vm_account *vm_account, unsigned long npages)
if (vm_account->flags & VM_ACCOUNT_USER)
atomic64_add(npages, &vm_account->mm->pinned_vm);
+ if (!pins_try_charge(vm_account->pins_cg, npages)) {
+ vm_unaccount_legacy(vm_account, npages);
+ return -ENOMEM;
+ }
+
return 0;
}
EXPORT_SYMBOL_GPL(vm_account_pinned);
@@ -548,12 +566,8 @@ EXPORT_SYMBOL_GPL(vm_account_pinned);
*/
void vm_unaccount_pinned(struct vm_account *vm_account, unsigned long npages)
{
- if (vm_account->flags & VM_ACCOUNT_USER) {
- atomic_long_sub(npages, &vm_account->user->locked_vm);
- atomic64_sub(npages, &vm_account->mm->pinned_vm);
- } else {
- atomic64_sub(npages, &vm_account->mm->pinned_vm);
- }
+ vm_unaccount_legacy(vm_account, npages);
+ pins_uncharge(vm_account->pins_cg, npages);
}
EXPORT_SYMBOL_GPL(vm_unaccount_pinned);
The vm_account_pinned() functions currently only account pages against pinned_vm/locked_vm and enforce limits against RLIMIT_MEMLOCK. Extend these to account pages and enforce limits using the pin count cgroup. Accounting of pages will fail if either RLIMIT_MEMLOCK or the cgroup limit is exceeded. Unlike rlimit enforcement which can be bypassed if the user has CAP_IPC_LOCK cgroup limits can not be bypassed. Signed-off-by: Alistair Popple <apopple@nvidia.com> Cc: linux-kernel@vger.kernel.org Cc: linux-mm@kvack.org --- include/linux/vm_account.h | 1 + mm/util.c | 26 ++++++++++++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-)