xref: /linux/mm/hugetlb_cgroup.c (revision ad804a0b2a769a0eed29015c53fe395449c09d13)
12bc64a20SAneesh Kumar K.V /*
22bc64a20SAneesh Kumar K.V  *
32bc64a20SAneesh Kumar K.V  * Copyright IBM Corporation, 2012
42bc64a20SAneesh Kumar K.V  * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
52bc64a20SAneesh Kumar K.V  *
62bc64a20SAneesh Kumar K.V  * This program is free software; you can redistribute it and/or modify it
72bc64a20SAneesh Kumar K.V  * under the terms of version 2.1 of the GNU Lesser General Public License
82bc64a20SAneesh Kumar K.V  * as published by the Free Software Foundation.
92bc64a20SAneesh Kumar K.V  *
102bc64a20SAneesh Kumar K.V  * This program is distributed in the hope that it would be useful, but
112bc64a20SAneesh Kumar K.V  * WITHOUT ANY WARRANTY; without even the implied warranty of
122bc64a20SAneesh Kumar K.V  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
132bc64a20SAneesh Kumar K.V  *
142bc64a20SAneesh Kumar K.V  */
152bc64a20SAneesh Kumar K.V 
162bc64a20SAneesh Kumar K.V #include <linux/cgroup.h>
1771f87beeSJohannes Weiner #include <linux/page_counter.h>
182bc64a20SAneesh Kumar K.V #include <linux/slab.h>
192bc64a20SAneesh Kumar K.V #include <linux/hugetlb.h>
202bc64a20SAneesh Kumar K.V #include <linux/hugetlb_cgroup.h>
212bc64a20SAneesh Kumar K.V 
222bc64a20SAneesh Kumar K.V struct hugetlb_cgroup {
232bc64a20SAneesh Kumar K.V 	struct cgroup_subsys_state css;
242bc64a20SAneesh Kumar K.V 	/*
252bc64a20SAneesh Kumar K.V 	 * the counter to account for hugepages from hugetlb.
262bc64a20SAneesh Kumar K.V 	 */
2771f87beeSJohannes Weiner 	struct page_counter hugepage[HUGE_MAX_HSTATE];
282bc64a20SAneesh Kumar K.V };
292bc64a20SAneesh Kumar K.V 
30abb8206cSAneesh Kumar K.V #define MEMFILE_PRIVATE(x, val)	(((x) << 16) | (val))
31abb8206cSAneesh Kumar K.V #define MEMFILE_IDX(val)	(((val) >> 16) & 0xffff)
32abb8206cSAneesh Kumar K.V #define MEMFILE_ATTR(val)	((val) & 0xffff)
33abb8206cSAneesh Kumar K.V 
342bc64a20SAneesh Kumar K.V static struct hugetlb_cgroup *root_h_cgroup __read_mostly;
352bc64a20SAneesh Kumar K.V 
362bc64a20SAneesh Kumar K.V static inline
372bc64a20SAneesh Kumar K.V struct hugetlb_cgroup *hugetlb_cgroup_from_css(struct cgroup_subsys_state *s)
382bc64a20SAneesh Kumar K.V {
39a7c6d554STejun Heo 	return s ? container_of(s, struct hugetlb_cgroup, css) : NULL;
402bc64a20SAneesh Kumar K.V }
412bc64a20SAneesh Kumar K.V 
422bc64a20SAneesh Kumar K.V static inline
432bc64a20SAneesh Kumar K.V struct hugetlb_cgroup *hugetlb_cgroup_from_task(struct task_struct *task)
442bc64a20SAneesh Kumar K.V {
45073219e9STejun Heo 	return hugetlb_cgroup_from_css(task_css(task, hugetlb_cgrp_id));
462bc64a20SAneesh Kumar K.V }
472bc64a20SAneesh Kumar K.V 
482bc64a20SAneesh Kumar K.V static inline bool hugetlb_cgroup_is_root(struct hugetlb_cgroup *h_cg)
492bc64a20SAneesh Kumar K.V {
502bc64a20SAneesh Kumar K.V 	return (h_cg == root_h_cgroup);
512bc64a20SAneesh Kumar K.V }
522bc64a20SAneesh Kumar K.V 
533f798518STejun Heo static inline struct hugetlb_cgroup *
543f798518STejun Heo parent_hugetlb_cgroup(struct hugetlb_cgroup *h_cg)
552bc64a20SAneesh Kumar K.V {
565c9d535bSTejun Heo 	return hugetlb_cgroup_from_css(h_cg->css.parent);
572bc64a20SAneesh Kumar K.V }
582bc64a20SAneesh Kumar K.V 
593f798518STejun Heo static inline bool hugetlb_cgroup_have_usage(struct hugetlb_cgroup *h_cg)
602bc64a20SAneesh Kumar K.V {
612bc64a20SAneesh Kumar K.V 	int idx;
622bc64a20SAneesh Kumar K.V 
632bc64a20SAneesh Kumar K.V 	for (idx = 0; idx < hugetlb_max_hstate; idx++) {
6471f87beeSJohannes Weiner 		if (page_counter_read(&h_cg->hugepage[idx]))
652bc64a20SAneesh Kumar K.V 			return true;
662bc64a20SAneesh Kumar K.V 	}
672bc64a20SAneesh Kumar K.V 	return false;
682bc64a20SAneesh Kumar K.V }
692bc64a20SAneesh Kumar K.V 
70eb95419bSTejun Heo static struct cgroup_subsys_state *
71eb95419bSTejun Heo hugetlb_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
722bc64a20SAneesh Kumar K.V {
73eb95419bSTejun Heo 	struct hugetlb_cgroup *parent_h_cgroup = hugetlb_cgroup_from_css(parent_css);
74eb95419bSTejun Heo 	struct hugetlb_cgroup *h_cgroup;
752bc64a20SAneesh Kumar K.V 	int idx;
762bc64a20SAneesh Kumar K.V 
772bc64a20SAneesh Kumar K.V 	h_cgroup = kzalloc(sizeof(*h_cgroup), GFP_KERNEL);
782bc64a20SAneesh Kumar K.V 	if (!h_cgroup)
792bc64a20SAneesh Kumar K.V 		return ERR_PTR(-ENOMEM);
802bc64a20SAneesh Kumar K.V 
81eb95419bSTejun Heo 	if (parent_h_cgroup) {
822bc64a20SAneesh Kumar K.V 		for (idx = 0; idx < HUGE_MAX_HSTATE; idx++)
8371f87beeSJohannes Weiner 			page_counter_init(&h_cgroup->hugepage[idx],
842bc64a20SAneesh Kumar K.V 					  &parent_h_cgroup->hugepage[idx]);
852bc64a20SAneesh Kumar K.V 	} else {
862bc64a20SAneesh Kumar K.V 		root_h_cgroup = h_cgroup;
872bc64a20SAneesh Kumar K.V 		for (idx = 0; idx < HUGE_MAX_HSTATE; idx++)
8871f87beeSJohannes Weiner 			page_counter_init(&h_cgroup->hugepage[idx], NULL);
892bc64a20SAneesh Kumar K.V 	}
902bc64a20SAneesh Kumar K.V 	return &h_cgroup->css;
912bc64a20SAneesh Kumar K.V }
922bc64a20SAneesh Kumar K.V 
93eb95419bSTejun Heo static void hugetlb_cgroup_css_free(struct cgroup_subsys_state *css)
942bc64a20SAneesh Kumar K.V {
952bc64a20SAneesh Kumar K.V 	struct hugetlb_cgroup *h_cgroup;
962bc64a20SAneesh Kumar K.V 
97eb95419bSTejun Heo 	h_cgroup = hugetlb_cgroup_from_css(css);
982bc64a20SAneesh Kumar K.V 	kfree(h_cgroup);
992bc64a20SAneesh Kumar K.V }
1002bc64a20SAneesh Kumar K.V 
101da1def55SAneesh Kumar K.V 
102da1def55SAneesh Kumar K.V /*
103da1def55SAneesh Kumar K.V  * Should be called with hugetlb_lock held.
104da1def55SAneesh Kumar K.V  * Since we are holding hugetlb_lock, pages cannot get moved from
105da1def55SAneesh Kumar K.V  * active list or uncharged from the cgroup, So no need to get
106da1def55SAneesh Kumar K.V  * page reference and test for page active here. This function
107da1def55SAneesh Kumar K.V  * cannot fail.
108da1def55SAneesh Kumar K.V  */
1093f798518STejun Heo static void hugetlb_cgroup_move_parent(int idx, struct hugetlb_cgroup *h_cg,
110da1def55SAneesh Kumar K.V 				       struct page *page)
111da1def55SAneesh Kumar K.V {
11271f87beeSJohannes Weiner 	unsigned int nr_pages;
11371f87beeSJohannes Weiner 	struct page_counter *counter;
114da1def55SAneesh Kumar K.V 	struct hugetlb_cgroup *page_hcg;
1153f798518STejun Heo 	struct hugetlb_cgroup *parent = parent_hugetlb_cgroup(h_cg);
116da1def55SAneesh Kumar K.V 
117da1def55SAneesh Kumar K.V 	page_hcg = hugetlb_cgroup_from_page(page);
118da1def55SAneesh Kumar K.V 	/*
119da1def55SAneesh Kumar K.V 	 * We can have pages in active list without any cgroup
120da1def55SAneesh Kumar K.V 	 * ie, hugepage with less than 3 pages. We can safely
121da1def55SAneesh Kumar K.V 	 * ignore those pages.
122da1def55SAneesh Kumar K.V 	 */
123da1def55SAneesh Kumar K.V 	if (!page_hcg || page_hcg != h_cg)
124da1def55SAneesh Kumar K.V 		goto out;
125da1def55SAneesh Kumar K.V 
12671f87beeSJohannes Weiner 	nr_pages = 1 << compound_order(page);
127da1def55SAneesh Kumar K.V 	if (!parent) {
128da1def55SAneesh Kumar K.V 		parent = root_h_cgroup;
129da1def55SAneesh Kumar K.V 		/* root has no limit */
13071f87beeSJohannes Weiner 		page_counter_charge(&parent->hugepage[idx], nr_pages);
131da1def55SAneesh Kumar K.V 	}
132da1def55SAneesh Kumar K.V 	counter = &h_cg->hugepage[idx];
13371f87beeSJohannes Weiner 	/* Take the pages off the local counter */
13471f87beeSJohannes Weiner 	page_counter_cancel(counter, nr_pages);
135da1def55SAneesh Kumar K.V 
136da1def55SAneesh Kumar K.V 	set_hugetlb_cgroup(page, parent);
137da1def55SAneesh Kumar K.V out:
138da1def55SAneesh Kumar K.V 	return;
139da1def55SAneesh Kumar K.V }
140da1def55SAneesh Kumar K.V 
141da1def55SAneesh Kumar K.V /*
142da1def55SAneesh Kumar K.V  * Force the hugetlb cgroup to empty the hugetlb resources by moving them to
143da1def55SAneesh Kumar K.V  * the parent cgroup.
144da1def55SAneesh Kumar K.V  */
145eb95419bSTejun Heo static void hugetlb_cgroup_css_offline(struct cgroup_subsys_state *css)
1462bc64a20SAneesh Kumar K.V {
147eb95419bSTejun Heo 	struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_css(css);
148da1def55SAneesh Kumar K.V 	struct hstate *h;
149da1def55SAneesh Kumar K.V 	struct page *page;
1509d093cb1SMichal Hocko 	int idx = 0;
151da1def55SAneesh Kumar K.V 
152da1def55SAneesh Kumar K.V 	do {
153da1def55SAneesh Kumar K.V 		for_each_hstate(h) {
154da1def55SAneesh Kumar K.V 			spin_lock(&hugetlb_lock);
155da1def55SAneesh Kumar K.V 			list_for_each_entry(page, &h->hugepage_activelist, lru)
1563f798518STejun Heo 				hugetlb_cgroup_move_parent(idx, h_cg, page);
157da1def55SAneesh Kumar K.V 
158da1def55SAneesh Kumar K.V 			spin_unlock(&hugetlb_lock);
159da1def55SAneesh Kumar K.V 			idx++;
160da1def55SAneesh Kumar K.V 		}
161da1def55SAneesh Kumar K.V 		cond_resched();
1623f798518STejun Heo 	} while (hugetlb_cgroup_have_usage(h_cg));
1632bc64a20SAneesh Kumar K.V }
1642bc64a20SAneesh Kumar K.V 
1656d76dcf4SAneesh Kumar K.V int hugetlb_cgroup_charge_cgroup(int idx, unsigned long nr_pages,
1666d76dcf4SAneesh Kumar K.V 				 struct hugetlb_cgroup **ptr)
1676d76dcf4SAneesh Kumar K.V {
1686d76dcf4SAneesh Kumar K.V 	int ret = 0;
16971f87beeSJohannes Weiner 	struct page_counter *counter;
1706d76dcf4SAneesh Kumar K.V 	struct hugetlb_cgroup *h_cg = NULL;
1716d76dcf4SAneesh Kumar K.V 
1726d76dcf4SAneesh Kumar K.V 	if (hugetlb_cgroup_disabled())
1736d76dcf4SAneesh Kumar K.V 		goto done;
1746d76dcf4SAneesh Kumar K.V 	/*
1756d76dcf4SAneesh Kumar K.V 	 * We don't charge any cgroup if the compound page have less
1766d76dcf4SAneesh Kumar K.V 	 * than 3 pages.
1776d76dcf4SAneesh Kumar K.V 	 */
1786d76dcf4SAneesh Kumar K.V 	if (huge_page_order(&hstates[idx]) < HUGETLB_CGROUP_MIN_ORDER)
1796d76dcf4SAneesh Kumar K.V 		goto done;
1806d76dcf4SAneesh Kumar K.V again:
1816d76dcf4SAneesh Kumar K.V 	rcu_read_lock();
1826d76dcf4SAneesh Kumar K.V 	h_cg = hugetlb_cgroup_from_task(current);
183ec903c0cSTejun Heo 	if (!css_tryget_online(&h_cg->css)) {
1846d76dcf4SAneesh Kumar K.V 		rcu_read_unlock();
1856d76dcf4SAneesh Kumar K.V 		goto again;
1866d76dcf4SAneesh Kumar K.V 	}
1876d76dcf4SAneesh Kumar K.V 	rcu_read_unlock();
1886d76dcf4SAneesh Kumar K.V 
1896071ca52SJohannes Weiner 	if (!page_counter_try_charge(&h_cg->hugepage[idx], nr_pages, &counter))
1906071ca52SJohannes Weiner 		ret = -ENOMEM;
1916d76dcf4SAneesh Kumar K.V 	css_put(&h_cg->css);
1926d76dcf4SAneesh Kumar K.V done:
1936d76dcf4SAneesh Kumar K.V 	*ptr = h_cg;
1946d76dcf4SAneesh Kumar K.V 	return ret;
1956d76dcf4SAneesh Kumar K.V }
1966d76dcf4SAneesh Kumar K.V 
19794ae8ba7SAneesh Kumar K.V /* Should be called with hugetlb_lock held */
1986d76dcf4SAneesh Kumar K.V void hugetlb_cgroup_commit_charge(int idx, unsigned long nr_pages,
1996d76dcf4SAneesh Kumar K.V 				  struct hugetlb_cgroup *h_cg,
2006d76dcf4SAneesh Kumar K.V 				  struct page *page)
2016d76dcf4SAneesh Kumar K.V {
2026d76dcf4SAneesh Kumar K.V 	if (hugetlb_cgroup_disabled() || !h_cg)
2036d76dcf4SAneesh Kumar K.V 		return;
2046d76dcf4SAneesh Kumar K.V 
2056d76dcf4SAneesh Kumar K.V 	set_hugetlb_cgroup(page, h_cg);
2066d76dcf4SAneesh Kumar K.V 	return;
2076d76dcf4SAneesh Kumar K.V }
2086d76dcf4SAneesh Kumar K.V 
2096d76dcf4SAneesh Kumar K.V /*
2106d76dcf4SAneesh Kumar K.V  * Should be called with hugetlb_lock held
2116d76dcf4SAneesh Kumar K.V  */
2126d76dcf4SAneesh Kumar K.V void hugetlb_cgroup_uncharge_page(int idx, unsigned long nr_pages,
2136d76dcf4SAneesh Kumar K.V 				  struct page *page)
2146d76dcf4SAneesh Kumar K.V {
2156d76dcf4SAneesh Kumar K.V 	struct hugetlb_cgroup *h_cg;
2166d76dcf4SAneesh Kumar K.V 
2176d76dcf4SAneesh Kumar K.V 	if (hugetlb_cgroup_disabled())
2186d76dcf4SAneesh Kumar K.V 		return;
2197ea8574eSMichal Hocko 	lockdep_assert_held(&hugetlb_lock);
2206d76dcf4SAneesh Kumar K.V 	h_cg = hugetlb_cgroup_from_page(page);
2216d76dcf4SAneesh Kumar K.V 	if (unlikely(!h_cg))
2226d76dcf4SAneesh Kumar K.V 		return;
2236d76dcf4SAneesh Kumar K.V 	set_hugetlb_cgroup(page, NULL);
22471f87beeSJohannes Weiner 	page_counter_uncharge(&h_cg->hugepage[idx], nr_pages);
2256d76dcf4SAneesh Kumar K.V 	return;
2266d76dcf4SAneesh Kumar K.V }
2276d76dcf4SAneesh Kumar K.V 
2286d76dcf4SAneesh Kumar K.V void hugetlb_cgroup_uncharge_cgroup(int idx, unsigned long nr_pages,
2296d76dcf4SAneesh Kumar K.V 				    struct hugetlb_cgroup *h_cg)
2306d76dcf4SAneesh Kumar K.V {
2316d76dcf4SAneesh Kumar K.V 	if (hugetlb_cgroup_disabled() || !h_cg)
2326d76dcf4SAneesh Kumar K.V 		return;
2336d76dcf4SAneesh Kumar K.V 
2346d76dcf4SAneesh Kumar K.V 	if (huge_page_order(&hstates[idx]) < HUGETLB_CGROUP_MIN_ORDER)
2356d76dcf4SAneesh Kumar K.V 		return;
2366d76dcf4SAneesh Kumar K.V 
23771f87beeSJohannes Weiner 	page_counter_uncharge(&h_cg->hugepage[idx], nr_pages);
2386d76dcf4SAneesh Kumar K.V 	return;
2396d76dcf4SAneesh Kumar K.V }
2406d76dcf4SAneesh Kumar K.V 
24171f87beeSJohannes Weiner enum {
24271f87beeSJohannes Weiner 	RES_USAGE,
24371f87beeSJohannes Weiner 	RES_LIMIT,
24471f87beeSJohannes Weiner 	RES_MAX_USAGE,
24571f87beeSJohannes Weiner 	RES_FAILCNT,
24671f87beeSJohannes Weiner };
24771f87beeSJohannes Weiner 
248716f479dSTejun Heo static u64 hugetlb_cgroup_read_u64(struct cgroup_subsys_state *css,
249716f479dSTejun Heo 				   struct cftype *cft)
250abb8206cSAneesh Kumar K.V {
25171f87beeSJohannes Weiner 	struct page_counter *counter;
252182446d0STejun Heo 	struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_css(css);
253abb8206cSAneesh Kumar K.V 
25471f87beeSJohannes Weiner 	counter = &h_cg->hugepage[MEMFILE_IDX(cft->private)];
255abb8206cSAneesh Kumar K.V 
25671f87beeSJohannes Weiner 	switch (MEMFILE_ATTR(cft->private)) {
25771f87beeSJohannes Weiner 	case RES_USAGE:
25871f87beeSJohannes Weiner 		return (u64)page_counter_read(counter) * PAGE_SIZE;
25971f87beeSJohannes Weiner 	case RES_LIMIT:
26071f87beeSJohannes Weiner 		return (u64)counter->limit * PAGE_SIZE;
26171f87beeSJohannes Weiner 	case RES_MAX_USAGE:
26271f87beeSJohannes Weiner 		return (u64)counter->watermark * PAGE_SIZE;
26371f87beeSJohannes Weiner 	case RES_FAILCNT:
26471f87beeSJohannes Weiner 		return counter->failcnt;
26571f87beeSJohannes Weiner 	default:
26671f87beeSJohannes Weiner 		BUG();
267abb8206cSAneesh Kumar K.V 	}
26871f87beeSJohannes Weiner }
26971f87beeSJohannes Weiner 
27071f87beeSJohannes Weiner static DEFINE_MUTEX(hugetlb_limit_mutex);
271abb8206cSAneesh Kumar K.V 
272451af504STejun Heo static ssize_t hugetlb_cgroup_write(struct kernfs_open_file *of,
273451af504STejun Heo 				    char *buf, size_t nbytes, loff_t off)
274abb8206cSAneesh Kumar K.V {
27571f87beeSJohannes Weiner 	int ret, idx;
27671f87beeSJohannes Weiner 	unsigned long nr_pages;
277451af504STejun Heo 	struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_css(of_css(of));
278abb8206cSAneesh Kumar K.V 
27971f87beeSJohannes Weiner 	if (hugetlb_cgroup_is_root(h_cg)) /* Can't set limit on root */
28071f87beeSJohannes Weiner 		return -EINVAL;
281abb8206cSAneesh Kumar K.V 
28271f87beeSJohannes Weiner 	buf = strstrip(buf);
283650c5e56SJohannes Weiner 	ret = page_counter_memparse(buf, "-1", &nr_pages);
284abb8206cSAneesh Kumar K.V 	if (ret)
28571f87beeSJohannes Weiner 		return ret;
28671f87beeSJohannes Weiner 
28771f87beeSJohannes Weiner 	idx = MEMFILE_IDX(of_cft(of)->private);
28871f87beeSJohannes Weiner 
28971f87beeSJohannes Weiner 	switch (MEMFILE_ATTR(of_cft(of)->private)) {
29071f87beeSJohannes Weiner 	case RES_LIMIT:
29171f87beeSJohannes Weiner 		mutex_lock(&hugetlb_limit_mutex);
29271f87beeSJohannes Weiner 		ret = page_counter_limit(&h_cg->hugepage[idx], nr_pages);
29371f87beeSJohannes Weiner 		mutex_unlock(&hugetlb_limit_mutex);
294abb8206cSAneesh Kumar K.V 		break;
295abb8206cSAneesh Kumar K.V 	default:
296abb8206cSAneesh Kumar K.V 		ret = -EINVAL;
297abb8206cSAneesh Kumar K.V 		break;
298abb8206cSAneesh Kumar K.V 	}
299451af504STejun Heo 	return ret ?: nbytes;
300abb8206cSAneesh Kumar K.V }
301abb8206cSAneesh Kumar K.V 
3026770c64eSTejun Heo static ssize_t hugetlb_cgroup_reset(struct kernfs_open_file *of,
3036770c64eSTejun Heo 				    char *buf, size_t nbytes, loff_t off)
304abb8206cSAneesh Kumar K.V {
30571f87beeSJohannes Weiner 	int ret = 0;
30671f87beeSJohannes Weiner 	struct page_counter *counter;
3076770c64eSTejun Heo 	struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_css(of_css(of));
308abb8206cSAneesh Kumar K.V 
30971f87beeSJohannes Weiner 	counter = &h_cg->hugepage[MEMFILE_IDX(of_cft(of)->private)];
310abb8206cSAneesh Kumar K.V 
31171f87beeSJohannes Weiner 	switch (MEMFILE_ATTR(of_cft(of)->private)) {
312abb8206cSAneesh Kumar K.V 	case RES_MAX_USAGE:
31371f87beeSJohannes Weiner 		page_counter_reset_watermark(counter);
314abb8206cSAneesh Kumar K.V 		break;
315abb8206cSAneesh Kumar K.V 	case RES_FAILCNT:
31671f87beeSJohannes Weiner 		counter->failcnt = 0;
317abb8206cSAneesh Kumar K.V 		break;
318abb8206cSAneesh Kumar K.V 	default:
319abb8206cSAneesh Kumar K.V 		ret = -EINVAL;
320abb8206cSAneesh Kumar K.V 		break;
321abb8206cSAneesh Kumar K.V 	}
3226770c64eSTejun Heo 	return ret ?: nbytes;
323abb8206cSAneesh Kumar K.V }
324abb8206cSAneesh Kumar K.V 
325abb8206cSAneesh Kumar K.V static char *mem_fmt(char *buf, int size, unsigned long hsize)
326abb8206cSAneesh Kumar K.V {
327abb8206cSAneesh Kumar K.V 	if (hsize >= (1UL << 30))
328abb8206cSAneesh Kumar K.V 		snprintf(buf, size, "%luGB", hsize >> 30);
329abb8206cSAneesh Kumar K.V 	else if (hsize >= (1UL << 20))
330abb8206cSAneesh Kumar K.V 		snprintf(buf, size, "%luMB", hsize >> 20);
331abb8206cSAneesh Kumar K.V 	else
332abb8206cSAneesh Kumar K.V 		snprintf(buf, size, "%luKB", hsize >> 10);
333abb8206cSAneesh Kumar K.V 	return buf;
334abb8206cSAneesh Kumar K.V }
335abb8206cSAneesh Kumar K.V 
3367179e7bfSJianguo Wu static void __init __hugetlb_cgroup_file_init(int idx)
337abb8206cSAneesh Kumar K.V {
338abb8206cSAneesh Kumar K.V 	char buf[32];
339abb8206cSAneesh Kumar K.V 	struct cftype *cft;
340abb8206cSAneesh Kumar K.V 	struct hstate *h = &hstates[idx];
341abb8206cSAneesh Kumar K.V 
342abb8206cSAneesh Kumar K.V 	/* format the size */
343abb8206cSAneesh Kumar K.V 	mem_fmt(buf, 32, huge_page_size(h));
344abb8206cSAneesh Kumar K.V 
345abb8206cSAneesh Kumar K.V 	/* Add the limit file */
346abb8206cSAneesh Kumar K.V 	cft = &h->cgroup_files[0];
347abb8206cSAneesh Kumar K.V 	snprintf(cft->name, MAX_CFTYPE_NAME, "%s.limit_in_bytes", buf);
348abb8206cSAneesh Kumar K.V 	cft->private = MEMFILE_PRIVATE(idx, RES_LIMIT);
349716f479dSTejun Heo 	cft->read_u64 = hugetlb_cgroup_read_u64;
350451af504STejun Heo 	cft->write = hugetlb_cgroup_write;
351abb8206cSAneesh Kumar K.V 
352abb8206cSAneesh Kumar K.V 	/* Add the usage file */
353abb8206cSAneesh Kumar K.V 	cft = &h->cgroup_files[1];
354abb8206cSAneesh Kumar K.V 	snprintf(cft->name, MAX_CFTYPE_NAME, "%s.usage_in_bytes", buf);
355abb8206cSAneesh Kumar K.V 	cft->private = MEMFILE_PRIVATE(idx, RES_USAGE);
356716f479dSTejun Heo 	cft->read_u64 = hugetlb_cgroup_read_u64;
357abb8206cSAneesh Kumar K.V 
358abb8206cSAneesh Kumar K.V 	/* Add the MAX usage file */
359abb8206cSAneesh Kumar K.V 	cft = &h->cgroup_files[2];
360abb8206cSAneesh Kumar K.V 	snprintf(cft->name, MAX_CFTYPE_NAME, "%s.max_usage_in_bytes", buf);
361abb8206cSAneesh Kumar K.V 	cft->private = MEMFILE_PRIVATE(idx, RES_MAX_USAGE);
3626770c64eSTejun Heo 	cft->write = hugetlb_cgroup_reset;
363716f479dSTejun Heo 	cft->read_u64 = hugetlb_cgroup_read_u64;
364abb8206cSAneesh Kumar K.V 
365abb8206cSAneesh Kumar K.V 	/* Add the failcntfile */
366abb8206cSAneesh Kumar K.V 	cft = &h->cgroup_files[3];
367abb8206cSAneesh Kumar K.V 	snprintf(cft->name, MAX_CFTYPE_NAME, "%s.failcnt", buf);
368abb8206cSAneesh Kumar K.V 	cft->private  = MEMFILE_PRIVATE(idx, RES_FAILCNT);
3696770c64eSTejun Heo 	cft->write = hugetlb_cgroup_reset;
370716f479dSTejun Heo 	cft->read_u64 = hugetlb_cgroup_read_u64;
371abb8206cSAneesh Kumar K.V 
372abb8206cSAneesh Kumar K.V 	/* NULL terminate the last cft */
373abb8206cSAneesh Kumar K.V 	cft = &h->cgroup_files[4];
374abb8206cSAneesh Kumar K.V 	memset(cft, 0, sizeof(*cft));
375abb8206cSAneesh Kumar K.V 
3762cf669a5STejun Heo 	WARN_ON(cgroup_add_legacy_cftypes(&hugetlb_cgrp_subsys,
3772cf669a5STejun Heo 					  h->cgroup_files));
3787179e7bfSJianguo Wu }
3797179e7bfSJianguo Wu 
3807179e7bfSJianguo Wu void __init hugetlb_cgroup_file_init(void)
3817179e7bfSJianguo Wu {
3827179e7bfSJianguo Wu 	struct hstate *h;
3837179e7bfSJianguo Wu 
3847179e7bfSJianguo Wu 	for_each_hstate(h) {
3857179e7bfSJianguo Wu 		/*
3867179e7bfSJianguo Wu 		 * Add cgroup control files only if the huge page consists
3877179e7bfSJianguo Wu 		 * of more than two normal pages. This is because we use
3881d798ca3SKirill A. Shutemov 		 * page[2].private for storing cgroup details.
3897179e7bfSJianguo Wu 		 */
3907179e7bfSJianguo Wu 		if (huge_page_order(h) >= HUGETLB_CGROUP_MIN_ORDER)
3917179e7bfSJianguo Wu 			__hugetlb_cgroup_file_init(hstate_index(h));
3927179e7bfSJianguo Wu 	}
393abb8206cSAneesh Kumar K.V }
394abb8206cSAneesh Kumar K.V 
39575754681SAneesh Kumar K.V /*
39675754681SAneesh Kumar K.V  * hugetlb_lock will make sure a parallel cgroup rmdir won't happen
39775754681SAneesh Kumar K.V  * when we migrate hugepages
39875754681SAneesh Kumar K.V  */
3998e6ac7faSAneesh Kumar K.V void hugetlb_cgroup_migrate(struct page *oldhpage, struct page *newhpage)
4008e6ac7faSAneesh Kumar K.V {
4018e6ac7faSAneesh Kumar K.V 	struct hugetlb_cgroup *h_cg;
40294ae8ba7SAneesh Kumar K.V 	struct hstate *h = page_hstate(oldhpage);
4038e6ac7faSAneesh Kumar K.V 
4048e6ac7faSAneesh Kumar K.V 	if (hugetlb_cgroup_disabled())
4058e6ac7faSAneesh Kumar K.V 		return;
4068e6ac7faSAneesh Kumar K.V 
407309381feSSasha Levin 	VM_BUG_ON_PAGE(!PageHuge(oldhpage), oldhpage);
4088e6ac7faSAneesh Kumar K.V 	spin_lock(&hugetlb_lock);
4098e6ac7faSAneesh Kumar K.V 	h_cg = hugetlb_cgroup_from_page(oldhpage);
4108e6ac7faSAneesh Kumar K.V 	set_hugetlb_cgroup(oldhpage, NULL);
4118e6ac7faSAneesh Kumar K.V 
4128e6ac7faSAneesh Kumar K.V 	/* move the h_cg details to new cgroup */
4138e6ac7faSAneesh Kumar K.V 	set_hugetlb_cgroup(newhpage, h_cg);
41494ae8ba7SAneesh Kumar K.V 	list_move(&newhpage->lru, &h->hugepage_activelist);
4158e6ac7faSAneesh Kumar K.V 	spin_unlock(&hugetlb_lock);
4168e6ac7faSAneesh Kumar K.V 	return;
4178e6ac7faSAneesh Kumar K.V }
4188e6ac7faSAneesh Kumar K.V 
419073219e9STejun Heo struct cgroup_subsys hugetlb_cgrp_subsys = {
42092fb9748STejun Heo 	.css_alloc	= hugetlb_cgroup_css_alloc,
42192fb9748STejun Heo 	.css_offline	= hugetlb_cgroup_css_offline,
42292fb9748STejun Heo 	.css_free	= hugetlb_cgroup_css_free,
4232bc64a20SAneesh Kumar K.V };
424