Re: [RFC PATCH 5/6] hugetlbfs: Add controller support for private mapping
From: Aneesh Kumar K.V <hidden>
Date: 2012-02-17 08:05:33
On Fri, 17 Feb 2012 13:22:44 +0800, bill4carson [off-list ref] wrote:
On 2012年02月11日 05:36, Aneesh Kumar K.V wrote:quoted
From: "Aneesh Kumar K.V"<redacted> HugeTLB controller is different from a memory controller in that we charge controller during mmap() time and not fault time. This make sure userspace can fallback to non-hugepage allocation when mmap fails due to controller limit. For private mapping we always charge/uncharge from the current task cgroup. Charging happens during mmap(2) and uncharge happens during the vm_operations->close when resv_map refcount reaches zero. The uncharge count is stored in struct resv_map. For child task after fork the charging happens during fault time in alloc_huge_page. We also need to make sure for private mapping each vma for hugeTLB mapping have struct resv_map allocated so that we can store the uncharge count in resv_map. Signed-off-by: Aneesh Kumar K.V<redacted> --- fs/hugetlbfs/hugetlb_cgroup.c | 50 ++++++++++++++++++++++++++++++++ include/linux/hugetlb.h | 7 ++++ include/linux/hugetlb_cgroup.h | 16 ++++++++++ mm/hugetlb.c | 62 ++++++++++++++++++++++++++++++++-------- 4 files changed, 123 insertions(+), 12 deletions(-)diff --git a/fs/hugetlbfs/hugetlb_cgroup.c b/fs/hugetlbfs/hugetlb_cgroup.c index c478fb0..f828fb2 100644 --- a/fs/hugetlbfs/hugetlb_cgroup.c +++ b/fs/hugetlbfs/hugetlb_cgroup.c@@ -458,3 +458,53 @@ long hugetlb_truncate_cgroup_charge(struct hstate *h, } return chg; } + +int hugetlb_priv_page_charge(struct resv_map *map, struct hstate *h, long chg) +{ + long csize; + int idx, ret; + struct hugetlb_cgroup *h_cg; + struct res_counter *fail_res; + + /* + * Get the task cgroup within rcu_readlock and also + * get cgroup reference to make sure cgroup destroy won't + * race with page_charge. We don't allow a cgroup destroy + * when the cgroup have some charge against it + */ + rcu_read_lock(); + h_cg = task_hugetlbcgroup(current); + css_get(&h_cg->css); + rcu_read_unlock(); + + if (hugetlb_cgroup_is_root(h_cg)) { + ret = chg; + goto err_out; + } + + csize = chg * huge_page_size(h); + idx = h - hstates; + ret = res_counter_charge(&h_cg->memhuge[idx], csize,&fail_res); + if (!ret) { + map->nr_pages[idx] += chg<< huge_page_order(h); + ret = chg; + } +err_out: + css_put(&h_cg->css); + return ret; +} + +void hugetlb_priv_page_uncharge(struct resv_map *map, int idx, int nr_pages) +{ + struct hugetlb_cgroup *h_cg; + unsigned long csize = nr_pages * PAGE_SIZE; + + rcu_read_lock(); + h_cg = task_hugetlbcgroup(current); + if (!hugetlb_cgroup_is_root(h_cg)) { + res_counter_uncharge(&h_cg->memhuge[idx], csize); + map->nr_pages[idx] -= nr_pages; + } + rcu_read_unlock(); + return; +}diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index 4392b6a..e2ba381 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h@@ -233,6 +233,12 @@ struct hstate { char name[HSTATE_NAME_LEN]; }; +struct resv_map { + struct kref refs; + int nr_pages[HUGE_MAX_HSTATE]; + struct list_head regions; +}; +Please put resv_map after HUGE_MAX_HSTATE definition, otherwise it will break on non-x86 arches, which has no HUGE_MAX_HSTATE definition. #ifndef HUGE_MAX_HSTATE #define HUGE_MAX_HSTATE 1 #endif +struct resv_map { + struct kref refs; + int nr_pages[HUGE_MAX_HSTATE]; + struct list_head regions; +};
Will do in the next iteration. Thanks for the review -aneesh -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@kvack.org. For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>