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