Skip to content

Commit

Permalink
memcg: memory cgroup resource counters for hierarchy
Browse files Browse the repository at this point in the history
Add support for building hierarchies in resource counters.  Cgroups allows
us to build a deep hierarchy, but we currently don't link the resource
counters belonging to the memory controller control groups, in the same
fashion as the corresponding cgroup entries in the cgroup hierarchy.  This
patch provides the infrastructure for resource counters that have the same
hiearchy as their cgroup counter parts.

These set of patches are based on the resource counter hiearchy patches
posted by Pavel Emelianov.

NOTE: Building hiearchies is expensive, deeper hierarchies imply charging
the all the way up to the root.  It is known that hiearchies are
expensive, so the user needs to be careful and aware of the trade-offs
before creating very deep ones.

[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: Balbir Singh <balbir@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: David Rientjes <rientjes@google.com>
Cc: Pavel Emelianov <xemul@openvz.org>
Cc: Dhaval Giani <dhaval@linux.vnet.ibm.com>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Balbir Singh authored and Linus Torvalds committed Jan 8, 2009
1 parent 52bc0d8 commit 28dbc4b
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 18 deletions.
8 changes: 6 additions & 2 deletions include/linux/res_counter.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ struct res_counter {
* the routines below consider this to be IRQ-safe
*/
spinlock_t lock;
/*
* Parent counter, used for hierarchial resource accounting
*/
struct res_counter *parent;
};

/**
Expand Down Expand Up @@ -87,7 +91,7 @@ enum {
* helpers for accounting
*/

void res_counter_init(struct res_counter *counter);
void res_counter_init(struct res_counter *counter, struct res_counter *parent);

/*
* charge - try to consume more resource.
Expand All @@ -103,7 +107,7 @@ void res_counter_init(struct res_counter *counter);
int __must_check res_counter_charge_locked(struct res_counter *counter,
unsigned long val);
int __must_check res_counter_charge(struct res_counter *counter,
unsigned long val);
unsigned long val, struct res_counter **limit_fail_at);

/*
* uncharge - tell that some portion of the resource is released
Expand Down
44 changes: 35 additions & 9 deletions kernel/res_counter.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@
#include <linux/uaccess.h>
#include <linux/mm.h>

void res_counter_init(struct res_counter *counter)
void res_counter_init(struct res_counter *counter, struct res_counter *parent)
{
spin_lock_init(&counter->lock);
counter->limit = (unsigned long long)LLONG_MAX;
counter->parent = parent;
}

int res_counter_charge_locked(struct res_counter *counter, unsigned long val)
Expand All @@ -34,14 +35,34 @@ int res_counter_charge_locked(struct res_counter *counter, unsigned long val)
return 0;
}

int res_counter_charge(struct res_counter *counter, unsigned long val)
int res_counter_charge(struct res_counter *counter, unsigned long val,
struct res_counter **limit_fail_at)
{
int ret;
unsigned long flags;

spin_lock_irqsave(&counter->lock, flags);
ret = res_counter_charge_locked(counter, val);
spin_unlock_irqrestore(&counter->lock, flags);
struct res_counter *c, *u;

*limit_fail_at = NULL;
local_irq_save(flags);
for (c = counter; c != NULL; c = c->parent) {
spin_lock(&c->lock);
ret = res_counter_charge_locked(c, val);
spin_unlock(&c->lock);
if (ret < 0) {
*limit_fail_at = c;
goto undo;
}
}
ret = 0;
goto done;
undo:
for (u = counter; u != c; u = u->parent) {
spin_lock(&u->lock);
res_counter_uncharge_locked(u, val);
spin_unlock(&u->lock);
}
done:
local_irq_restore(flags);
return ret;
}

Expand All @@ -56,10 +77,15 @@ void res_counter_uncharge_locked(struct res_counter *counter, unsigned long val)
void res_counter_uncharge(struct res_counter *counter, unsigned long val)
{
unsigned long flags;
struct res_counter *c;

spin_lock_irqsave(&counter->lock, flags);
res_counter_uncharge_locked(counter, val);
spin_unlock_irqrestore(&counter->lock, flags);
local_irq_save(flags);
for (c = counter; c != NULL; c = c->parent) {
spin_lock(&c->lock);
res_counter_uncharge_locked(c, val);
spin_unlock(&c->lock);
}
local_irq_restore(flags);
}


Expand Down
20 changes: 13 additions & 7 deletions mm/memcontrol.c
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,7 @@ static int __mem_cgroup_try_charge(struct mm_struct *mm,
{
struct mem_cgroup *mem;
int nr_retries = MEM_CGROUP_RECLAIM_RETRIES;
struct res_counter *fail_res;
/*
* We always charge the cgroup the mm_struct belongs to.
* The mm_struct's mem_cgroup changes on task migration if the
Expand Down Expand Up @@ -499,11 +500,12 @@ static int __mem_cgroup_try_charge(struct mm_struct *mm,
int ret;
bool noswap = false;

ret = res_counter_charge(&mem->res, PAGE_SIZE);
ret = res_counter_charge(&mem->res, PAGE_SIZE, &fail_res);
if (likely(!ret)) {
if (!do_swap_account)
break;
ret = res_counter_charge(&mem->memsw, PAGE_SIZE);
ret = res_counter_charge(&mem->memsw, PAGE_SIZE,
&fail_res);
if (likely(!ret))
break;
/* mem+swap counter fails */
Expand Down Expand Up @@ -1709,22 +1711,26 @@ static void __init enable_swap_cgroup(void)
static struct cgroup_subsys_state *
mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
{
struct mem_cgroup *mem;
struct mem_cgroup *mem, *parent;
int node;

mem = mem_cgroup_alloc();
if (!mem)
return ERR_PTR(-ENOMEM);

res_counter_init(&mem->res);
res_counter_init(&mem->memsw);

for_each_node_state(node, N_POSSIBLE)
if (alloc_mem_cgroup_per_zone_info(mem, node))
goto free_out;
/* root ? */
if (cont->parent == NULL)
if (cont->parent == NULL) {
enable_swap_cgroup();
parent = NULL;
} else
parent = mem_cgroup_from_cont(cont->parent);

res_counter_init(&mem->res, parent ? &parent->res : NULL);
res_counter_init(&mem->memsw, parent ? &parent->memsw : NULL);


return &mem->css;
free_out:
Expand Down

0 comments on commit 28dbc4b

Please sign in to comment.