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@xxxxxxxxxx> Cc: linux-kernel@xxxxxxxxxxxxxxx Cc: linux-mm@xxxxxxxxx --- include/linux/vm_account.h | 1 + mm/util.c | 26 ++++++++++++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/include/linux/vm_account.h b/include/linux/vm_account.h index b4b2e90..4fd5d3a 100644 --- a/include/linux/vm_account.h +++ b/include/linux/vm_account.h @@ -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; }; diff --git a/mm/util.c b/mm/util.c index d8c19f8..0e93625 100644 --- a/mm/util.c +++ b/mm/util.c @@ -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); -- git-series 0.9.1