lkml.org 
[lkml]   [2008]   [Sep]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectRe: [-mm][PATCH 4/4] Add memrlimit controller accounting and control (v4)
* Andrew Morton <akpm@linux-foundation.org> [2008-09-18 13:54:30]:

> On Wed, 14 May 2008 18:39:51 +0530
> Balbir Singh <balbir@linux.vnet.ibm.com> wrote:
>
> > This patch adds support for accounting and control of virtual address space
> > limits.
>
>
> Large changes in linux-next's arch/x86/kernel/ptrace.c caused damage to
> the memrlimit patches.
>
> I decided to retain the patches because it looks repairable. The
> problem is this reject from
> memrlimit-add-memrlimit-controller-accounting-and-control.patch:
>

Andrew,

I could not apply mmotm to linux-next (both downloaded right now). I
applied the patches one-by-one resolving differences starting from #mm
in the series file.

Here is my fixed version of the patch, I compiled the patch, but could
not run it, since I could not create the full series of applied
patches. I compiled arch/x86/kernel/ds.o and ptrace.o. I've included
the patch below, please let me know if the code looks OK (via review)
and the patch applies. I'll test it once I can resonably resolve all
conflicts between linux-next and mmotm.


From: Balbir Singh <balbir@linux.vnet.ibm.com>

This patch adds support for accounting and control of virtual address space
limits. The accounting is done via the rlimit_cgroup_(un)charge_as functions.
The core of the accounting takes place during fork time in copy_process(),
may_expand_vm(), remove_vma_list() and exit_mmap().

Signed-off-by: Balbir Singh <balbir@linux.vnet.ibm.com>
Cc: Sudhir Kumar <skumar@linux.vnet.ibm.com>
Cc: YAMAMOTO Takashi <yamamoto@valinux.co.jp>
Cc: Paul Menage <menage@google.com>
Cc: Li Zefan <lizf@cn.fujitsu.com>
Cc: Pavel Emelianov <xemul@openvz.org>
Cc: Balbir Singh <balbir@linux.vnet.ibm.com>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Vivek Goyal <vgoyal@redhat.com>
Cc: Hugh Dickins <hugh@veritas.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---

arch/x86/kernel/ptrace.c | 1
include/linux/memrlimitcgroup.h | 21 ++++++
kernel/fork.c | 14 ++++
mm/memrlimitcgroup.c | 92 ++++++++++++++++++++++++++++++
mm/mmap.c | 17 ++++-
5 files changed, 142 insertions(+), 3 deletions(-)

Index: linux-next/include/linux/memrlimitcgroup.h
===================================================================
--- linux-next.orig/include/linux/memrlimitcgroup.h 2008-09-18 23:19:26.000000000 -0700
+++ linux-next/include/linux/memrlimitcgroup.h 2008-09-18 23:19:29.000000000 -0700
@@ -16,4 +16,25 @@
#ifndef LINUX_MEMRLIMITCGROUP_H
#define LINUX_MEMRLIMITCGROUP_H

+#ifdef CONFIG_CGROUP_MEMRLIMIT_CTLR
+
+int memrlimit_cgroup_charge_as(struct mm_struct *mm, unsigned long nr_pages);
+void memrlimit_cgroup_uncharge_as(struct mm_struct *mm, unsigned long nr_pages);
+
+#else /* !CONFIG_CGROUP_RLIMIT_CTLR */
+
+static inline int
+memrlimit_cgroup_charge_as(struct mm_struct *mm, unsigned long nr_pages)
+{
+ return 0;
+}
+
+static inline void
+memrlimit_cgroup_uncharge_as(struct mm_struct *mm, unsigned long nr_pages)
+{
+}
+
+#endif /* CONFIG_CGROUP_RLIMIT_CTLR */
+
+
#endif /* LINUX_MEMRLIMITCGROUP_H */
Index: linux-next/kernel/fork.c
===================================================================
--- linux-next.orig/kernel/fork.c 2008-09-18 21:32:39.000000000 -0700
+++ linux-next/kernel/fork.c 2008-09-18 23:27:21.000000000 -0700
@@ -51,6 +51,7 @@
#include <linux/acct.h>
#include <linux/tsacct_kern.h>
#include <linux/cn_proc.h>
+#include <linux/memrlimitcgroup.h>
#include <linux/freezer.h>
#include <linux/delayacct.h>
#include <linux/taskstats_kern.h>
@@ -263,7 +264,7 @@
struct vm_area_struct *mpnt, *tmp, **pprev;
struct rb_node **rb_link, *rb_parent;
int retval;
- unsigned long charge;
+ unsigned long charge, uncharged = 0;
struct mempolicy *pol;

down_write(&oldmm->mmap_sem);
@@ -273,6 +274,15 @@
*/
down_write_nested(&mm->mmap_sem, SINGLE_DEPTH_NESTING);

+ /*
+ * Uncharging as a result of failure is done by mmput()
+ * in dup_mm()
+ */
+ if (memrlimit_cgroup_charge_as(oldmm, oldmm->total_vm)) {
+ retval = -ENOMEM;
+ goto out;
+ }
+
mm->locked_vm = 0;
mm->mmap = NULL;
mm->mmap_cache = NULL;
@@ -293,6 +303,8 @@
mm->total_vm -= pages;
vm_stat_account(mm, mpnt->vm_flags, mpnt->vm_file,
-pages);
+ memrlimit_cgroup_uncharge_as(mm, pages);
+ uncharged += pages;
continue;
}
charge = 0;
Index: linux-next/mm/memrlimitcgroup.c
===================================================================
--- linux-next.orig/mm/memrlimitcgroup.c 2008-09-18 23:19:26.000000000 -0700
+++ linux-next/mm/memrlimitcgroup.c 2008-09-18 23:27:36.000000000 -0700
@@ -45,6 +45,38 @@
struct memrlimit_cgroup, css);
}

+static struct memrlimit_cgroup *
+memrlimit_cgroup_from_task(struct task_struct *p)
+{
+ return container_of(task_subsys_state(p, memrlimit_cgroup_subsys_id),
+ struct memrlimit_cgroup, css);
+}
+
+/*
+ * Charge the cgroup for address space usage - mmap(), malloc() (through
+ * brk(), sbrk()), stack expansion, mremap(), etc - called with
+ * mmap_sem held.
+ */
+int memrlimit_cgroup_charge_as(struct mm_struct *mm, unsigned long nr_pages)
+{
+ struct memrlimit_cgroup *memrcg;
+
+ memrcg = memrlimit_cgroup_from_task(mm->owner);
+ return res_counter_charge(&memrcg->as_res, (nr_pages << PAGE_SHIFT));
+}
+
+/*
+ * Uncharge the cgroup, as the address space of one of the tasks is
+ * decreasing - called with mmap_sem held.
+ */
+void memrlimit_cgroup_uncharge_as(struct mm_struct *mm, unsigned long nr_pages)
+{
+ struct memrlimit_cgroup *memrcg;
+
+ memrcg = memrlimit_cgroup_from_task(mm->owner);
+ res_counter_uncharge(&memrcg->as_res, (nr_pages << PAGE_SHIFT));
+}
+
static struct cgroup_subsys_state *
memrlimit_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cgrp)
{
@@ -121,11 +153,71 @@
ARRAY_SIZE(memrlimit_cgroup_files));
}

+static void memrlimit_cgroup_move_task(struct cgroup_subsys *ss,
+ struct cgroup *cgrp,
+ struct cgroup *old_cgrp,
+ struct task_struct *p)
+{
+ struct mm_struct *mm;
+ struct memrlimit_cgroup *memrcg, *old_memrcg;
+
+ mm = get_task_mm(p);
+ if (mm == NULL)
+ return;
+
+ /*
+ * Hold mmap_sem, so that total_vm does not change underneath us
+ */
+ down_read(&mm->mmap_sem);
+
+ rcu_read_lock();
+ if (p != rcu_dereference(mm->owner))
+ goto out;
+
+ memrcg = memrlimit_cgroup_from_cgrp(cgrp);
+ old_memrcg = memrlimit_cgroup_from_cgrp(old_cgrp);
+
+ if (memrcg == old_memrcg)
+ goto out;
+
+ if (res_counter_charge(&memrcg->as_res, (mm->total_vm << PAGE_SHIFT)))
+ goto out;
+ res_counter_uncharge(&old_memrcg->as_res, (mm->total_vm << PAGE_SHIFT));
+out:
+ rcu_read_unlock();
+ up_read(&mm->mmap_sem);
+ mmput(mm);
+}
+
+/*
+ * This callback is called with mmap_sem held
+ */
+static void memrlimit_cgroup_mm_owner_changed(struct cgroup_subsys *ss,
+ struct cgroup *cgrp,
+ struct cgroup *old_cgrp,
+ struct task_struct *p)
+{
+ struct memrlimit_cgroup *memrcg, *old_memrcg;
+ struct mm_struct *mm = get_task_mm(p);
+
+ BUG_ON(!mm);
+ memrcg = memrlimit_cgroup_from_cgrp(cgrp);
+ old_memrcg = memrlimit_cgroup_from_cgrp(old_cgrp);
+
+ if (res_counter_charge(&memrcg->as_res, (mm->total_vm << PAGE_SHIFT)))
+ goto out;
+ res_counter_uncharge(&old_memrcg->as_res, (mm->total_vm << PAGE_SHIFT));
+out:
+ mmput(mm);
+}
+
struct cgroup_subsys memrlimit_cgroup_subsys = {
.name = "memrlimit",
.subsys_id = memrlimit_cgroup_subsys_id,
.create = memrlimit_cgroup_create,
.destroy = memrlimit_cgroup_destroy,
.populate = memrlimit_cgroup_populate,
+ .attach = memrlimit_cgroup_move_task,
+ .mm_owner_changed = memrlimit_cgroup_mm_owner_changed,
.early_init = 0,
};
Index: linux-next/mm/mmap.c
===================================================================
--- linux-next.orig/mm/mmap.c 2008-09-18 23:00:18.000000000 -0700
+++ linux-next/mm/mmap.c 2008-09-18 23:27:21.000000000 -0700
@@ -23,6 +23,7 @@
#include <linux/hugetlb.h>
#include <linux/profile.h>
#include <linux/module.h>
+#include <linux/memrlimitcgroup.h>
#include <linux/mount.h>
#include <linux/mempolicy.h>
#include <linux/rmap.h>
@@ -1756,6 +1757,7 @@
long nrpages = vma_pages(vma);

mm->total_vm -= nrpages;
+ memrlimit_cgroup_uncharge_as(mm, nrpages);
vm_stat_account(mm, vma->vm_flags, vma->vm_file, -nrpages);
vma = remove_vma(vma);
} while (vma);
@@ -2106,6 +2108,7 @@
/* Use -1 here to ensure all VMAs in the mm are unmapped */
end = unmap_vmas(&tlb, vma, 0, -1, &nr_accounted, NULL);
vm_unacct_memory(nr_accounted);
+ memrlimit_cgroup_uncharge_as(mm, mm->total_vm);
free_pgtables(tlb, vma, FIRST_USER_ADDRESS, 0);
tlb_finish_mmu(tlb, 0, end);

@@ -2128,6 +2131,9 @@
struct vm_area_struct * __vma, * prev;
struct rb_node ** rb_link, * rb_parent;

+ if (memrlimit_cgroup_charge_as(mm, vma_pages(vma)))
+ return -ENOMEM;
+
/*
* The vm_pgoff of a purely anonymous vma should be irrelevant
* until its first write fault, when page's anon_vma and index
@@ -2146,12 +2152,15 @@
}
__vma = find_vma_prepare(mm,vma->vm_start,&prev,&rb_link,&rb_parent);
if (__vma && __vma->vm_start < vma->vm_end)
- return -ENOMEM;
+ goto err;
if ((vma->vm_flags & VM_ACCOUNT) &&
security_vm_enough_memory_mm(mm, vma_pages(vma)))
- return -ENOMEM;
+ goto err;
vma_link(mm, vma, prev, rb_link, rb_parent);
return 0;
+err:
+ memrlimit_cgroup_uncharge_as(mm, vma_pages(vma));
+ return -ENOMEM;
}

/*
@@ -2224,6 +2233,10 @@

if (cur + npages > lim)
return 0;
+
+ if (memrlimit_cgroup_charge_as(mm, npages))
+ return 0;
+
return 1;
}

Index: linux-next/arch/x86/kernel/ds.c
===================================================================
--- linux-next.orig/arch/x86/kernel/ds.c 2008-09-18 23:28:07.000000000 -0700
+++ linux-next/arch/x86/kernel/ds.c 2008-09-18 23:33:55.000000000 -0700
@@ -30,6 +30,7 @@
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/mm.h>
+#include <linux/memrlimitcgroup.h>


/*
@@ -339,19 +340,22 @@

pgsz = PAGE_ALIGN(size) >> PAGE_SHIFT;

+ if (memrlimit_cgroup_charge_as(current->mm, pgsz << PAGE_SHIFT))
+ return NULL;
+
rlim = current->signal->rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT;
vm = current->mm->total_vm + pgsz;
if (rlim < vm)
- return NULL;
+ goto uncharge;

rlim = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT;
vm = current->mm->locked_vm + pgsz;
if (rlim < vm)
- return NULL;
+ goto uncharge;

buffer = kzalloc(size, GFP_KERNEL);
if (!buffer)
- return NULL;
+ goto uncharge;

current->mm->total_vm += pgsz;
current->mm->locked_vm += pgsz;
@@ -360,6 +364,9 @@
*pages = pgsz;

return buffer;
+uncharge:
+ memrlimit_cgroup_uncharge_as(current->mm, pgsz << PAGE_SHIFT);
+ return NULL;
}

static int ds_request(struct task_struct *task, void *base, size_t size,
--
Balbir


\
 
 \ /
  Last update: 2008-09-19 16:23    [W:1.202 / U:0.648 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site