mirror of https://gitee.com/openkylin/linux.git
hugetlb/cgroup: add support for cgroup removal
Add support for cgroup removal. If we don't have parent cgroup, the charges are moved to root cgroup. Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> Cc: David Rientjes <rientjes@google.com> Acked-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: Hillf Danton <dhillf@gmail.com> Reviewed-by: Michal Hocko <mhocko@suse.cz> Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
6d76dcf404
commit
da1def5591
|
@ -105,10 +105,76 @@ static void hugetlb_cgroup_destroy(struct cgroup *cgroup)
|
|||
kfree(h_cgroup);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Should be called with hugetlb_lock held.
|
||||
* Since we are holding hugetlb_lock, pages cannot get moved from
|
||||
* active list or uncharged from the cgroup, So no need to get
|
||||
* page reference and test for page active here. This function
|
||||
* cannot fail.
|
||||
*/
|
||||
static void hugetlb_cgroup_move_parent(int idx, struct cgroup *cgroup,
|
||||
struct page *page)
|
||||
{
|
||||
int csize;
|
||||
struct res_counter *counter;
|
||||
struct res_counter *fail_res;
|
||||
struct hugetlb_cgroup *page_hcg;
|
||||
struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_cgroup(cgroup);
|
||||
struct hugetlb_cgroup *parent = parent_hugetlb_cgroup(cgroup);
|
||||
|
||||
page_hcg = hugetlb_cgroup_from_page(page);
|
||||
/*
|
||||
* We can have pages in active list without any cgroup
|
||||
* ie, hugepage with less than 3 pages. We can safely
|
||||
* ignore those pages.
|
||||
*/
|
||||
if (!page_hcg || page_hcg != h_cg)
|
||||
goto out;
|
||||
|
||||
csize = PAGE_SIZE << compound_order(page);
|
||||
if (!parent) {
|
||||
parent = root_h_cgroup;
|
||||
/* root has no limit */
|
||||
res_counter_charge_nofail(&parent->hugepage[idx],
|
||||
csize, &fail_res);
|
||||
}
|
||||
counter = &h_cg->hugepage[idx];
|
||||
res_counter_uncharge_until(counter, counter->parent, csize);
|
||||
|
||||
set_hugetlb_cgroup(page, parent);
|
||||
out:
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Force the hugetlb cgroup to empty the hugetlb resources by moving them to
|
||||
* the parent cgroup.
|
||||
*/
|
||||
static int hugetlb_cgroup_pre_destroy(struct cgroup *cgroup)
|
||||
{
|
||||
/* We will add the cgroup removal support in later patches */
|
||||
return -EBUSY;
|
||||
struct hstate *h;
|
||||
struct page *page;
|
||||
int ret = 0, idx = 0;
|
||||
|
||||
do {
|
||||
if (cgroup_task_count(cgroup) ||
|
||||
!list_empty(&cgroup->children)) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
for_each_hstate(h) {
|
||||
spin_lock(&hugetlb_lock);
|
||||
list_for_each_entry(page, &h->hugepage_activelist, lru)
|
||||
hugetlb_cgroup_move_parent(idx, cgroup, page);
|
||||
|
||||
spin_unlock(&hugetlb_lock);
|
||||
idx++;
|
||||
}
|
||||
cond_resched();
|
||||
} while (hugetlb_cgroup_have_usage(cgroup));
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int hugetlb_cgroup_charge_cgroup(int idx, unsigned long nr_pages,
|
||||
|
|
Loading…
Reference in New Issue