18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * 38c2ecf20Sopenharmony_ci * Copyright IBM Corporation, 2012 48c2ecf20Sopenharmony_ci * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Cgroup v2 78c2ecf20Sopenharmony_ci * Copyright (C) 2019 Red Hat, Inc. 88c2ecf20Sopenharmony_ci * Author: Giuseppe Scrivano <gscrivan@redhat.com> 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify it 118c2ecf20Sopenharmony_ci * under the terms of version 2.1 of the GNU Lesser General Public License 128c2ecf20Sopenharmony_ci * as published by the Free Software Foundation. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * This program is distributed in the hope that it would be useful, but 158c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of 168c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <linux/cgroup.h> 218c2ecf20Sopenharmony_ci#include <linux/page_counter.h> 228c2ecf20Sopenharmony_ci#include <linux/slab.h> 238c2ecf20Sopenharmony_ci#include <linux/hugetlb.h> 248c2ecf20Sopenharmony_ci#include <linux/hugetlb_cgroup.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define MEMFILE_PRIVATE(x, val) (((x) << 16) | (val)) 278c2ecf20Sopenharmony_ci#define MEMFILE_IDX(val) (((val) >> 16) & 0xffff) 288c2ecf20Sopenharmony_ci#define MEMFILE_ATTR(val) ((val) & 0xffff) 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define hugetlb_cgroup_from_counter(counter, idx) \ 318c2ecf20Sopenharmony_ci container_of(counter, struct hugetlb_cgroup, hugepage[idx]) 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic struct hugetlb_cgroup *root_h_cgroup __read_mostly; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic inline struct page_counter * 368c2ecf20Sopenharmony_ci__hugetlb_cgroup_counter_from_cgroup(struct hugetlb_cgroup *h_cg, int idx, 378c2ecf20Sopenharmony_ci bool rsvd) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci if (rsvd) 408c2ecf20Sopenharmony_ci return &h_cg->rsvd_hugepage[idx]; 418c2ecf20Sopenharmony_ci return &h_cg->hugepage[idx]; 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic inline struct page_counter * 458c2ecf20Sopenharmony_cihugetlb_cgroup_counter_from_cgroup(struct hugetlb_cgroup *h_cg, int idx) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci return __hugetlb_cgroup_counter_from_cgroup(h_cg, idx, false); 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic inline struct page_counter * 518c2ecf20Sopenharmony_cihugetlb_cgroup_counter_from_cgroup_rsvd(struct hugetlb_cgroup *h_cg, int idx) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci return __hugetlb_cgroup_counter_from_cgroup(h_cg, idx, true); 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic inline 578c2ecf20Sopenharmony_cistruct hugetlb_cgroup *hugetlb_cgroup_from_css(struct cgroup_subsys_state *s) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci return s ? container_of(s, struct hugetlb_cgroup, css) : NULL; 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic inline 638c2ecf20Sopenharmony_cistruct hugetlb_cgroup *hugetlb_cgroup_from_task(struct task_struct *task) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci return hugetlb_cgroup_from_css(task_css(task, hugetlb_cgrp_id)); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic inline bool hugetlb_cgroup_is_root(struct hugetlb_cgroup *h_cg) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci return (h_cg == root_h_cgroup); 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic inline struct hugetlb_cgroup * 748c2ecf20Sopenharmony_ciparent_hugetlb_cgroup(struct hugetlb_cgroup *h_cg) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci return hugetlb_cgroup_from_css(h_cg->css.parent); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic inline bool hugetlb_cgroup_have_usage(struct hugetlb_cgroup *h_cg) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci int idx; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci for (idx = 0; idx < hugetlb_max_hstate; idx++) { 848c2ecf20Sopenharmony_ci if (page_counter_read( 858c2ecf20Sopenharmony_ci hugetlb_cgroup_counter_from_cgroup(h_cg, idx))) 868c2ecf20Sopenharmony_ci return true; 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci return false; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic void hugetlb_cgroup_init(struct hugetlb_cgroup *h_cgroup, 928c2ecf20Sopenharmony_ci struct hugetlb_cgroup *parent_h_cgroup) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci int idx; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci for (idx = 0; idx < HUGE_MAX_HSTATE; idx++) { 978c2ecf20Sopenharmony_ci struct page_counter *fault_parent = NULL; 988c2ecf20Sopenharmony_ci struct page_counter *rsvd_parent = NULL; 998c2ecf20Sopenharmony_ci unsigned long limit; 1008c2ecf20Sopenharmony_ci int ret; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if (parent_h_cgroup) { 1038c2ecf20Sopenharmony_ci fault_parent = hugetlb_cgroup_counter_from_cgroup( 1048c2ecf20Sopenharmony_ci parent_h_cgroup, idx); 1058c2ecf20Sopenharmony_ci rsvd_parent = hugetlb_cgroup_counter_from_cgroup_rsvd( 1068c2ecf20Sopenharmony_ci parent_h_cgroup, idx); 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci page_counter_init(hugetlb_cgroup_counter_from_cgroup(h_cgroup, 1098c2ecf20Sopenharmony_ci idx), 1108c2ecf20Sopenharmony_ci fault_parent); 1118c2ecf20Sopenharmony_ci page_counter_init( 1128c2ecf20Sopenharmony_ci hugetlb_cgroup_counter_from_cgroup_rsvd(h_cgroup, idx), 1138c2ecf20Sopenharmony_ci rsvd_parent); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci limit = round_down(PAGE_COUNTER_MAX, 1168c2ecf20Sopenharmony_ci 1 << huge_page_order(&hstates[idx])); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci ret = page_counter_set_max( 1198c2ecf20Sopenharmony_ci hugetlb_cgroup_counter_from_cgroup(h_cgroup, idx), 1208c2ecf20Sopenharmony_ci limit); 1218c2ecf20Sopenharmony_ci VM_BUG_ON(ret); 1228c2ecf20Sopenharmony_ci ret = page_counter_set_max( 1238c2ecf20Sopenharmony_ci hugetlb_cgroup_counter_from_cgroup_rsvd(h_cgroup, idx), 1248c2ecf20Sopenharmony_ci limit); 1258c2ecf20Sopenharmony_ci VM_BUG_ON(ret); 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic struct cgroup_subsys_state * 1308c2ecf20Sopenharmony_cihugetlb_cgroup_css_alloc(struct cgroup_subsys_state *parent_css) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci struct hugetlb_cgroup *parent_h_cgroup = hugetlb_cgroup_from_css(parent_css); 1338c2ecf20Sopenharmony_ci struct hugetlb_cgroup *h_cgroup; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci h_cgroup = kzalloc(sizeof(*h_cgroup), GFP_KERNEL); 1368c2ecf20Sopenharmony_ci if (!h_cgroup) 1378c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (!parent_h_cgroup) 1408c2ecf20Sopenharmony_ci root_h_cgroup = h_cgroup; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci hugetlb_cgroup_init(h_cgroup, parent_h_cgroup); 1438c2ecf20Sopenharmony_ci return &h_cgroup->css; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic void hugetlb_cgroup_css_free(struct cgroup_subsys_state *css) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci struct hugetlb_cgroup *h_cgroup; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci h_cgroup = hugetlb_cgroup_from_css(css); 1518c2ecf20Sopenharmony_ci kfree(h_cgroup); 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci/* 1558c2ecf20Sopenharmony_ci * Should be called with hugetlb_lock held. 1568c2ecf20Sopenharmony_ci * Since we are holding hugetlb_lock, pages cannot get moved from 1578c2ecf20Sopenharmony_ci * active list or uncharged from the cgroup, So no need to get 1588c2ecf20Sopenharmony_ci * page reference and test for page active here. This function 1598c2ecf20Sopenharmony_ci * cannot fail. 1608c2ecf20Sopenharmony_ci */ 1618c2ecf20Sopenharmony_cistatic void hugetlb_cgroup_move_parent(int idx, struct hugetlb_cgroup *h_cg, 1628c2ecf20Sopenharmony_ci struct page *page) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci unsigned int nr_pages; 1658c2ecf20Sopenharmony_ci struct page_counter *counter; 1668c2ecf20Sopenharmony_ci struct hugetlb_cgroup *page_hcg; 1678c2ecf20Sopenharmony_ci struct hugetlb_cgroup *parent = parent_hugetlb_cgroup(h_cg); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci page_hcg = hugetlb_cgroup_from_page(page); 1708c2ecf20Sopenharmony_ci /* 1718c2ecf20Sopenharmony_ci * We can have pages in active list without any cgroup 1728c2ecf20Sopenharmony_ci * ie, hugepage with less than 3 pages. We can safely 1738c2ecf20Sopenharmony_ci * ignore those pages. 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_ci if (!page_hcg || page_hcg != h_cg) 1768c2ecf20Sopenharmony_ci goto out; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci nr_pages = compound_nr(page); 1798c2ecf20Sopenharmony_ci if (!parent) { 1808c2ecf20Sopenharmony_ci parent = root_h_cgroup; 1818c2ecf20Sopenharmony_ci /* root has no limit */ 1828c2ecf20Sopenharmony_ci page_counter_charge(&parent->hugepage[idx], nr_pages); 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci counter = &h_cg->hugepage[idx]; 1858c2ecf20Sopenharmony_ci /* Take the pages off the local counter */ 1868c2ecf20Sopenharmony_ci page_counter_cancel(counter, nr_pages); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci set_hugetlb_cgroup(page, parent); 1898c2ecf20Sopenharmony_ciout: 1908c2ecf20Sopenharmony_ci return; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci/* 1948c2ecf20Sopenharmony_ci * Force the hugetlb cgroup to empty the hugetlb resources by moving them to 1958c2ecf20Sopenharmony_ci * the parent cgroup. 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_cistatic void hugetlb_cgroup_css_offline(struct cgroup_subsys_state *css) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_css(css); 2008c2ecf20Sopenharmony_ci struct hstate *h; 2018c2ecf20Sopenharmony_ci struct page *page; 2028c2ecf20Sopenharmony_ci int idx; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci do { 2058c2ecf20Sopenharmony_ci idx = 0; 2068c2ecf20Sopenharmony_ci for_each_hstate(h) { 2078c2ecf20Sopenharmony_ci spin_lock(&hugetlb_lock); 2088c2ecf20Sopenharmony_ci list_for_each_entry(page, &h->hugepage_activelist, lru) 2098c2ecf20Sopenharmony_ci hugetlb_cgroup_move_parent(idx, h_cg, page); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci spin_unlock(&hugetlb_lock); 2128c2ecf20Sopenharmony_ci idx++; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci cond_resched(); 2158c2ecf20Sopenharmony_ci } while (hugetlb_cgroup_have_usage(h_cg)); 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic inline void hugetlb_event(struct hugetlb_cgroup *hugetlb, int idx, 2198c2ecf20Sopenharmony_ci enum hugetlb_memory_event event) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci atomic_long_inc(&hugetlb->events_local[idx][event]); 2228c2ecf20Sopenharmony_ci cgroup_file_notify(&hugetlb->events_local_file[idx]); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci do { 2258c2ecf20Sopenharmony_ci atomic_long_inc(&hugetlb->events[idx][event]); 2268c2ecf20Sopenharmony_ci cgroup_file_notify(&hugetlb->events_file[idx]); 2278c2ecf20Sopenharmony_ci } while ((hugetlb = parent_hugetlb_cgroup(hugetlb)) && 2288c2ecf20Sopenharmony_ci !hugetlb_cgroup_is_root(hugetlb)); 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic int __hugetlb_cgroup_charge_cgroup(int idx, unsigned long nr_pages, 2328c2ecf20Sopenharmony_ci struct hugetlb_cgroup **ptr, 2338c2ecf20Sopenharmony_ci bool rsvd) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci int ret = 0; 2368c2ecf20Sopenharmony_ci struct page_counter *counter; 2378c2ecf20Sopenharmony_ci struct hugetlb_cgroup *h_cg = NULL; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (hugetlb_cgroup_disabled()) 2408c2ecf20Sopenharmony_ci goto done; 2418c2ecf20Sopenharmony_ci /* 2428c2ecf20Sopenharmony_ci * We don't charge any cgroup if the compound page have less 2438c2ecf20Sopenharmony_ci * than 3 pages. 2448c2ecf20Sopenharmony_ci */ 2458c2ecf20Sopenharmony_ci if (huge_page_order(&hstates[idx]) < HUGETLB_CGROUP_MIN_ORDER) 2468c2ecf20Sopenharmony_ci goto done; 2478c2ecf20Sopenharmony_ciagain: 2488c2ecf20Sopenharmony_ci rcu_read_lock(); 2498c2ecf20Sopenharmony_ci h_cg = hugetlb_cgroup_from_task(current); 2508c2ecf20Sopenharmony_ci if (!css_tryget(&h_cg->css)) { 2518c2ecf20Sopenharmony_ci rcu_read_unlock(); 2528c2ecf20Sopenharmony_ci goto again; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci rcu_read_unlock(); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (!page_counter_try_charge( 2578c2ecf20Sopenharmony_ci __hugetlb_cgroup_counter_from_cgroup(h_cg, idx, rsvd), 2588c2ecf20Sopenharmony_ci nr_pages, &counter)) { 2598c2ecf20Sopenharmony_ci ret = -ENOMEM; 2608c2ecf20Sopenharmony_ci hugetlb_event(h_cg, idx, HUGETLB_MAX); 2618c2ecf20Sopenharmony_ci css_put(&h_cg->css); 2628c2ecf20Sopenharmony_ci goto done; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci /* Reservations take a reference to the css because they do not get 2658c2ecf20Sopenharmony_ci * reparented. 2668c2ecf20Sopenharmony_ci */ 2678c2ecf20Sopenharmony_ci if (!rsvd) 2688c2ecf20Sopenharmony_ci css_put(&h_cg->css); 2698c2ecf20Sopenharmony_cidone: 2708c2ecf20Sopenharmony_ci *ptr = h_cg; 2718c2ecf20Sopenharmony_ci return ret; 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ciint hugetlb_cgroup_charge_cgroup(int idx, unsigned long nr_pages, 2758c2ecf20Sopenharmony_ci struct hugetlb_cgroup **ptr) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci return __hugetlb_cgroup_charge_cgroup(idx, nr_pages, ptr, false); 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ciint hugetlb_cgroup_charge_cgroup_rsvd(int idx, unsigned long nr_pages, 2818c2ecf20Sopenharmony_ci struct hugetlb_cgroup **ptr) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci return __hugetlb_cgroup_charge_cgroup(idx, nr_pages, ptr, true); 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci/* Should be called with hugetlb_lock held */ 2878c2ecf20Sopenharmony_cistatic void __hugetlb_cgroup_commit_charge(int idx, unsigned long nr_pages, 2888c2ecf20Sopenharmony_ci struct hugetlb_cgroup *h_cg, 2898c2ecf20Sopenharmony_ci struct page *page, bool rsvd) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci if (hugetlb_cgroup_disabled() || !h_cg) 2928c2ecf20Sopenharmony_ci return; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci __set_hugetlb_cgroup(page, h_cg, rsvd); 2958c2ecf20Sopenharmony_ci return; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_civoid hugetlb_cgroup_commit_charge(int idx, unsigned long nr_pages, 2998c2ecf20Sopenharmony_ci struct hugetlb_cgroup *h_cg, 3008c2ecf20Sopenharmony_ci struct page *page) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci __hugetlb_cgroup_commit_charge(idx, nr_pages, h_cg, page, false); 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_civoid hugetlb_cgroup_commit_charge_rsvd(int idx, unsigned long nr_pages, 3068c2ecf20Sopenharmony_ci struct hugetlb_cgroup *h_cg, 3078c2ecf20Sopenharmony_ci struct page *page) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci __hugetlb_cgroup_commit_charge(idx, nr_pages, h_cg, page, true); 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci/* 3138c2ecf20Sopenharmony_ci * Should be called with hugetlb_lock held 3148c2ecf20Sopenharmony_ci */ 3158c2ecf20Sopenharmony_cistatic void __hugetlb_cgroup_uncharge_page(int idx, unsigned long nr_pages, 3168c2ecf20Sopenharmony_ci struct page *page, bool rsvd) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci struct hugetlb_cgroup *h_cg; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (hugetlb_cgroup_disabled()) 3218c2ecf20Sopenharmony_ci return; 3228c2ecf20Sopenharmony_ci lockdep_assert_held(&hugetlb_lock); 3238c2ecf20Sopenharmony_ci h_cg = __hugetlb_cgroup_from_page(page, rsvd); 3248c2ecf20Sopenharmony_ci if (unlikely(!h_cg)) 3258c2ecf20Sopenharmony_ci return; 3268c2ecf20Sopenharmony_ci __set_hugetlb_cgroup(page, NULL, rsvd); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci page_counter_uncharge(__hugetlb_cgroup_counter_from_cgroup(h_cg, idx, 3298c2ecf20Sopenharmony_ci rsvd), 3308c2ecf20Sopenharmony_ci nr_pages); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci if (rsvd) 3338c2ecf20Sopenharmony_ci css_put(&h_cg->css); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci return; 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_civoid hugetlb_cgroup_uncharge_page(int idx, unsigned long nr_pages, 3398c2ecf20Sopenharmony_ci struct page *page) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci __hugetlb_cgroup_uncharge_page(idx, nr_pages, page, false); 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_civoid hugetlb_cgroup_uncharge_page_rsvd(int idx, unsigned long nr_pages, 3458c2ecf20Sopenharmony_ci struct page *page) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci __hugetlb_cgroup_uncharge_page(idx, nr_pages, page, true); 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_cistatic void __hugetlb_cgroup_uncharge_cgroup(int idx, unsigned long nr_pages, 3518c2ecf20Sopenharmony_ci struct hugetlb_cgroup *h_cg, 3528c2ecf20Sopenharmony_ci bool rsvd) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci if (hugetlb_cgroup_disabled() || !h_cg) 3558c2ecf20Sopenharmony_ci return; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci if (huge_page_order(&hstates[idx]) < HUGETLB_CGROUP_MIN_ORDER) 3588c2ecf20Sopenharmony_ci return; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci page_counter_uncharge(__hugetlb_cgroup_counter_from_cgroup(h_cg, idx, 3618c2ecf20Sopenharmony_ci rsvd), 3628c2ecf20Sopenharmony_ci nr_pages); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci if (rsvd) 3658c2ecf20Sopenharmony_ci css_put(&h_cg->css); 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_civoid hugetlb_cgroup_uncharge_cgroup(int idx, unsigned long nr_pages, 3698c2ecf20Sopenharmony_ci struct hugetlb_cgroup *h_cg) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci __hugetlb_cgroup_uncharge_cgroup(idx, nr_pages, h_cg, false); 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_civoid hugetlb_cgroup_uncharge_cgroup_rsvd(int idx, unsigned long nr_pages, 3758c2ecf20Sopenharmony_ci struct hugetlb_cgroup *h_cg) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci __hugetlb_cgroup_uncharge_cgroup(idx, nr_pages, h_cg, true); 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_civoid hugetlb_cgroup_uncharge_counter(struct resv_map *resv, unsigned long start, 3818c2ecf20Sopenharmony_ci unsigned long end) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci if (hugetlb_cgroup_disabled() || !resv || !resv->reservation_counter || 3848c2ecf20Sopenharmony_ci !resv->css) 3858c2ecf20Sopenharmony_ci return; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci page_counter_uncharge(resv->reservation_counter, 3888c2ecf20Sopenharmony_ci (end - start) * resv->pages_per_hpage); 3898c2ecf20Sopenharmony_ci css_put(resv->css); 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_civoid hugetlb_cgroup_uncharge_file_region(struct resv_map *resv, 3938c2ecf20Sopenharmony_ci struct file_region *rg, 3948c2ecf20Sopenharmony_ci unsigned long nr_pages, 3958c2ecf20Sopenharmony_ci bool region_del) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci if (hugetlb_cgroup_disabled() || !resv || !rg || !nr_pages) 3988c2ecf20Sopenharmony_ci return; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (rg->reservation_counter && resv->pages_per_hpage && nr_pages > 0 && 4018c2ecf20Sopenharmony_ci !resv->reservation_counter) { 4028c2ecf20Sopenharmony_ci page_counter_uncharge(rg->reservation_counter, 4038c2ecf20Sopenharmony_ci nr_pages * resv->pages_per_hpage); 4048c2ecf20Sopenharmony_ci /* 4058c2ecf20Sopenharmony_ci * Only do css_put(rg->css) when we delete the entire region 4068c2ecf20Sopenharmony_ci * because one file_region must hold exactly one css reference. 4078c2ecf20Sopenharmony_ci */ 4088c2ecf20Sopenharmony_ci if (region_del) 4098c2ecf20Sopenharmony_ci css_put(rg->css); 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_cienum { 4148c2ecf20Sopenharmony_ci RES_USAGE, 4158c2ecf20Sopenharmony_ci RES_RSVD_USAGE, 4168c2ecf20Sopenharmony_ci RES_LIMIT, 4178c2ecf20Sopenharmony_ci RES_RSVD_LIMIT, 4188c2ecf20Sopenharmony_ci RES_MAX_USAGE, 4198c2ecf20Sopenharmony_ci RES_RSVD_MAX_USAGE, 4208c2ecf20Sopenharmony_ci RES_FAILCNT, 4218c2ecf20Sopenharmony_ci RES_RSVD_FAILCNT, 4228c2ecf20Sopenharmony_ci}; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_cistatic u64 hugetlb_cgroup_read_u64(struct cgroup_subsys_state *css, 4258c2ecf20Sopenharmony_ci struct cftype *cft) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci struct page_counter *counter; 4288c2ecf20Sopenharmony_ci struct page_counter *rsvd_counter; 4298c2ecf20Sopenharmony_ci struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_css(css); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci counter = &h_cg->hugepage[MEMFILE_IDX(cft->private)]; 4328c2ecf20Sopenharmony_ci rsvd_counter = &h_cg->rsvd_hugepage[MEMFILE_IDX(cft->private)]; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci switch (MEMFILE_ATTR(cft->private)) { 4358c2ecf20Sopenharmony_ci case RES_USAGE: 4368c2ecf20Sopenharmony_ci return (u64)page_counter_read(counter) * PAGE_SIZE; 4378c2ecf20Sopenharmony_ci case RES_RSVD_USAGE: 4388c2ecf20Sopenharmony_ci return (u64)page_counter_read(rsvd_counter) * PAGE_SIZE; 4398c2ecf20Sopenharmony_ci case RES_LIMIT: 4408c2ecf20Sopenharmony_ci return (u64)counter->max * PAGE_SIZE; 4418c2ecf20Sopenharmony_ci case RES_RSVD_LIMIT: 4428c2ecf20Sopenharmony_ci return (u64)rsvd_counter->max * PAGE_SIZE; 4438c2ecf20Sopenharmony_ci case RES_MAX_USAGE: 4448c2ecf20Sopenharmony_ci return (u64)counter->watermark * PAGE_SIZE; 4458c2ecf20Sopenharmony_ci case RES_RSVD_MAX_USAGE: 4468c2ecf20Sopenharmony_ci return (u64)rsvd_counter->watermark * PAGE_SIZE; 4478c2ecf20Sopenharmony_ci case RES_FAILCNT: 4488c2ecf20Sopenharmony_ci return counter->failcnt; 4498c2ecf20Sopenharmony_ci case RES_RSVD_FAILCNT: 4508c2ecf20Sopenharmony_ci return rsvd_counter->failcnt; 4518c2ecf20Sopenharmony_ci default: 4528c2ecf20Sopenharmony_ci BUG(); 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_cistatic int hugetlb_cgroup_read_u64_max(struct seq_file *seq, void *v) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci int idx; 4598c2ecf20Sopenharmony_ci u64 val; 4608c2ecf20Sopenharmony_ci struct cftype *cft = seq_cft(seq); 4618c2ecf20Sopenharmony_ci unsigned long limit; 4628c2ecf20Sopenharmony_ci struct page_counter *counter; 4638c2ecf20Sopenharmony_ci struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_css(seq_css(seq)); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci idx = MEMFILE_IDX(cft->private); 4668c2ecf20Sopenharmony_ci counter = &h_cg->hugepage[idx]; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci limit = round_down(PAGE_COUNTER_MAX, 4698c2ecf20Sopenharmony_ci 1 << huge_page_order(&hstates[idx])); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci switch (MEMFILE_ATTR(cft->private)) { 4728c2ecf20Sopenharmony_ci case RES_RSVD_USAGE: 4738c2ecf20Sopenharmony_ci counter = &h_cg->rsvd_hugepage[idx]; 4748c2ecf20Sopenharmony_ci fallthrough; 4758c2ecf20Sopenharmony_ci case RES_USAGE: 4768c2ecf20Sopenharmony_ci val = (u64)page_counter_read(counter); 4778c2ecf20Sopenharmony_ci seq_printf(seq, "%llu\n", val * PAGE_SIZE); 4788c2ecf20Sopenharmony_ci break; 4798c2ecf20Sopenharmony_ci case RES_RSVD_LIMIT: 4808c2ecf20Sopenharmony_ci counter = &h_cg->rsvd_hugepage[idx]; 4818c2ecf20Sopenharmony_ci fallthrough; 4828c2ecf20Sopenharmony_ci case RES_LIMIT: 4838c2ecf20Sopenharmony_ci val = (u64)counter->max; 4848c2ecf20Sopenharmony_ci if (val == limit) 4858c2ecf20Sopenharmony_ci seq_puts(seq, "max\n"); 4868c2ecf20Sopenharmony_ci else 4878c2ecf20Sopenharmony_ci seq_printf(seq, "%llu\n", val * PAGE_SIZE); 4888c2ecf20Sopenharmony_ci break; 4898c2ecf20Sopenharmony_ci default: 4908c2ecf20Sopenharmony_ci BUG(); 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci return 0; 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(hugetlb_limit_mutex); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_cistatic ssize_t hugetlb_cgroup_write(struct kernfs_open_file *of, 4998c2ecf20Sopenharmony_ci char *buf, size_t nbytes, loff_t off, 5008c2ecf20Sopenharmony_ci const char *max) 5018c2ecf20Sopenharmony_ci{ 5028c2ecf20Sopenharmony_ci int ret, idx; 5038c2ecf20Sopenharmony_ci unsigned long nr_pages; 5048c2ecf20Sopenharmony_ci struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_css(of_css(of)); 5058c2ecf20Sopenharmony_ci bool rsvd = false; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (hugetlb_cgroup_is_root(h_cg)) /* Can't set limit on root */ 5088c2ecf20Sopenharmony_ci return -EINVAL; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci buf = strstrip(buf); 5118c2ecf20Sopenharmony_ci ret = page_counter_memparse(buf, max, &nr_pages); 5128c2ecf20Sopenharmony_ci if (ret) 5138c2ecf20Sopenharmony_ci return ret; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci idx = MEMFILE_IDX(of_cft(of)->private); 5168c2ecf20Sopenharmony_ci nr_pages = round_down(nr_pages, 1 << huge_page_order(&hstates[idx])); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci switch (MEMFILE_ATTR(of_cft(of)->private)) { 5198c2ecf20Sopenharmony_ci case RES_RSVD_LIMIT: 5208c2ecf20Sopenharmony_ci rsvd = true; 5218c2ecf20Sopenharmony_ci fallthrough; 5228c2ecf20Sopenharmony_ci case RES_LIMIT: 5238c2ecf20Sopenharmony_ci mutex_lock(&hugetlb_limit_mutex); 5248c2ecf20Sopenharmony_ci ret = page_counter_set_max( 5258c2ecf20Sopenharmony_ci __hugetlb_cgroup_counter_from_cgroup(h_cg, idx, rsvd), 5268c2ecf20Sopenharmony_ci nr_pages); 5278c2ecf20Sopenharmony_ci mutex_unlock(&hugetlb_limit_mutex); 5288c2ecf20Sopenharmony_ci break; 5298c2ecf20Sopenharmony_ci default: 5308c2ecf20Sopenharmony_ci ret = -EINVAL; 5318c2ecf20Sopenharmony_ci break; 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci return ret ?: nbytes; 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_cistatic ssize_t hugetlb_cgroup_write_legacy(struct kernfs_open_file *of, 5378c2ecf20Sopenharmony_ci char *buf, size_t nbytes, loff_t off) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci return hugetlb_cgroup_write(of, buf, nbytes, off, "-1"); 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic ssize_t hugetlb_cgroup_write_dfl(struct kernfs_open_file *of, 5438c2ecf20Sopenharmony_ci char *buf, size_t nbytes, loff_t off) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci return hugetlb_cgroup_write(of, buf, nbytes, off, "max"); 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistatic ssize_t hugetlb_cgroup_reset(struct kernfs_open_file *of, 5498c2ecf20Sopenharmony_ci char *buf, size_t nbytes, loff_t off) 5508c2ecf20Sopenharmony_ci{ 5518c2ecf20Sopenharmony_ci int ret = 0; 5528c2ecf20Sopenharmony_ci struct page_counter *counter, *rsvd_counter; 5538c2ecf20Sopenharmony_ci struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_css(of_css(of)); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci counter = &h_cg->hugepage[MEMFILE_IDX(of_cft(of)->private)]; 5568c2ecf20Sopenharmony_ci rsvd_counter = &h_cg->rsvd_hugepage[MEMFILE_IDX(of_cft(of)->private)]; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci switch (MEMFILE_ATTR(of_cft(of)->private)) { 5598c2ecf20Sopenharmony_ci case RES_MAX_USAGE: 5608c2ecf20Sopenharmony_ci page_counter_reset_watermark(counter); 5618c2ecf20Sopenharmony_ci break; 5628c2ecf20Sopenharmony_ci case RES_RSVD_MAX_USAGE: 5638c2ecf20Sopenharmony_ci page_counter_reset_watermark(rsvd_counter); 5648c2ecf20Sopenharmony_ci break; 5658c2ecf20Sopenharmony_ci case RES_FAILCNT: 5668c2ecf20Sopenharmony_ci counter->failcnt = 0; 5678c2ecf20Sopenharmony_ci break; 5688c2ecf20Sopenharmony_ci case RES_RSVD_FAILCNT: 5698c2ecf20Sopenharmony_ci rsvd_counter->failcnt = 0; 5708c2ecf20Sopenharmony_ci break; 5718c2ecf20Sopenharmony_ci default: 5728c2ecf20Sopenharmony_ci ret = -EINVAL; 5738c2ecf20Sopenharmony_ci break; 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci return ret ?: nbytes; 5768c2ecf20Sopenharmony_ci} 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_cistatic char *mem_fmt(char *buf, int size, unsigned long hsize) 5798c2ecf20Sopenharmony_ci{ 5808c2ecf20Sopenharmony_ci if (hsize >= (1UL << 30)) 5818c2ecf20Sopenharmony_ci snprintf(buf, size, "%luGB", hsize >> 30); 5828c2ecf20Sopenharmony_ci else if (hsize >= (1UL << 20)) 5838c2ecf20Sopenharmony_ci snprintf(buf, size, "%luMB", hsize >> 20); 5848c2ecf20Sopenharmony_ci else 5858c2ecf20Sopenharmony_ci snprintf(buf, size, "%luKB", hsize >> 10); 5868c2ecf20Sopenharmony_ci return buf; 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_cistatic int __hugetlb_events_show(struct seq_file *seq, bool local) 5908c2ecf20Sopenharmony_ci{ 5918c2ecf20Sopenharmony_ci int idx; 5928c2ecf20Sopenharmony_ci long max; 5938c2ecf20Sopenharmony_ci struct cftype *cft = seq_cft(seq); 5948c2ecf20Sopenharmony_ci struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_css(seq_css(seq)); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci idx = MEMFILE_IDX(cft->private); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci if (local) 5998c2ecf20Sopenharmony_ci max = atomic_long_read(&h_cg->events_local[idx][HUGETLB_MAX]); 6008c2ecf20Sopenharmony_ci else 6018c2ecf20Sopenharmony_ci max = atomic_long_read(&h_cg->events[idx][HUGETLB_MAX]); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci seq_printf(seq, "max %lu\n", max); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci return 0; 6068c2ecf20Sopenharmony_ci} 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_cistatic int hugetlb_events_show(struct seq_file *seq, void *v) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci return __hugetlb_events_show(seq, false); 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_cistatic int hugetlb_events_local_show(struct seq_file *seq, void *v) 6148c2ecf20Sopenharmony_ci{ 6158c2ecf20Sopenharmony_ci return __hugetlb_events_show(seq, true); 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_cistatic void __init __hugetlb_cgroup_file_dfl_init(int idx) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci char buf[32]; 6218c2ecf20Sopenharmony_ci struct cftype *cft; 6228c2ecf20Sopenharmony_ci struct hstate *h = &hstates[idx]; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci /* format the size */ 6258c2ecf20Sopenharmony_ci mem_fmt(buf, sizeof(buf), huge_page_size(h)); 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci /* Add the limit file */ 6288c2ecf20Sopenharmony_ci cft = &h->cgroup_files_dfl[0]; 6298c2ecf20Sopenharmony_ci snprintf(cft->name, MAX_CFTYPE_NAME, "%s.max", buf); 6308c2ecf20Sopenharmony_ci cft->private = MEMFILE_PRIVATE(idx, RES_LIMIT); 6318c2ecf20Sopenharmony_ci cft->seq_show = hugetlb_cgroup_read_u64_max; 6328c2ecf20Sopenharmony_ci cft->write = hugetlb_cgroup_write_dfl; 6338c2ecf20Sopenharmony_ci cft->flags = CFTYPE_NOT_ON_ROOT; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci /* Add the reservation limit file */ 6368c2ecf20Sopenharmony_ci cft = &h->cgroup_files_dfl[1]; 6378c2ecf20Sopenharmony_ci snprintf(cft->name, MAX_CFTYPE_NAME, "%s.rsvd.max", buf); 6388c2ecf20Sopenharmony_ci cft->private = MEMFILE_PRIVATE(idx, RES_RSVD_LIMIT); 6398c2ecf20Sopenharmony_ci cft->seq_show = hugetlb_cgroup_read_u64_max; 6408c2ecf20Sopenharmony_ci cft->write = hugetlb_cgroup_write_dfl; 6418c2ecf20Sopenharmony_ci cft->flags = CFTYPE_NOT_ON_ROOT; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci /* Add the current usage file */ 6448c2ecf20Sopenharmony_ci cft = &h->cgroup_files_dfl[2]; 6458c2ecf20Sopenharmony_ci snprintf(cft->name, MAX_CFTYPE_NAME, "%s.current", buf); 6468c2ecf20Sopenharmony_ci cft->private = MEMFILE_PRIVATE(idx, RES_USAGE); 6478c2ecf20Sopenharmony_ci cft->seq_show = hugetlb_cgroup_read_u64_max; 6488c2ecf20Sopenharmony_ci cft->flags = CFTYPE_NOT_ON_ROOT; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci /* Add the current reservation usage file */ 6518c2ecf20Sopenharmony_ci cft = &h->cgroup_files_dfl[3]; 6528c2ecf20Sopenharmony_ci snprintf(cft->name, MAX_CFTYPE_NAME, "%s.rsvd.current", buf); 6538c2ecf20Sopenharmony_ci cft->private = MEMFILE_PRIVATE(idx, RES_RSVD_USAGE); 6548c2ecf20Sopenharmony_ci cft->seq_show = hugetlb_cgroup_read_u64_max; 6558c2ecf20Sopenharmony_ci cft->flags = CFTYPE_NOT_ON_ROOT; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci /* Add the events file */ 6588c2ecf20Sopenharmony_ci cft = &h->cgroup_files_dfl[4]; 6598c2ecf20Sopenharmony_ci snprintf(cft->name, MAX_CFTYPE_NAME, "%s.events", buf); 6608c2ecf20Sopenharmony_ci cft->private = MEMFILE_PRIVATE(idx, 0); 6618c2ecf20Sopenharmony_ci cft->seq_show = hugetlb_events_show; 6628c2ecf20Sopenharmony_ci cft->file_offset = offsetof(struct hugetlb_cgroup, events_file[idx]); 6638c2ecf20Sopenharmony_ci cft->flags = CFTYPE_NOT_ON_ROOT; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci /* Add the events.local file */ 6668c2ecf20Sopenharmony_ci cft = &h->cgroup_files_dfl[5]; 6678c2ecf20Sopenharmony_ci snprintf(cft->name, MAX_CFTYPE_NAME, "%s.events.local", buf); 6688c2ecf20Sopenharmony_ci cft->private = MEMFILE_PRIVATE(idx, 0); 6698c2ecf20Sopenharmony_ci cft->seq_show = hugetlb_events_local_show; 6708c2ecf20Sopenharmony_ci cft->file_offset = offsetof(struct hugetlb_cgroup, 6718c2ecf20Sopenharmony_ci events_local_file[idx]); 6728c2ecf20Sopenharmony_ci cft->flags = CFTYPE_NOT_ON_ROOT; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci /* NULL terminate the last cft */ 6758c2ecf20Sopenharmony_ci cft = &h->cgroup_files_dfl[6]; 6768c2ecf20Sopenharmony_ci memset(cft, 0, sizeof(*cft)); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci WARN_ON(cgroup_add_dfl_cftypes(&hugetlb_cgrp_subsys, 6798c2ecf20Sopenharmony_ci h->cgroup_files_dfl)); 6808c2ecf20Sopenharmony_ci} 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_cistatic void __init __hugetlb_cgroup_file_legacy_init(int idx) 6838c2ecf20Sopenharmony_ci{ 6848c2ecf20Sopenharmony_ci char buf[32]; 6858c2ecf20Sopenharmony_ci struct cftype *cft; 6868c2ecf20Sopenharmony_ci struct hstate *h = &hstates[idx]; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci /* format the size */ 6898c2ecf20Sopenharmony_ci mem_fmt(buf, sizeof(buf), huge_page_size(h)); 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci /* Add the limit file */ 6928c2ecf20Sopenharmony_ci cft = &h->cgroup_files_legacy[0]; 6938c2ecf20Sopenharmony_ci snprintf(cft->name, MAX_CFTYPE_NAME, "%s.limit_in_bytes", buf); 6948c2ecf20Sopenharmony_ci cft->private = MEMFILE_PRIVATE(idx, RES_LIMIT); 6958c2ecf20Sopenharmony_ci cft->read_u64 = hugetlb_cgroup_read_u64; 6968c2ecf20Sopenharmony_ci cft->write = hugetlb_cgroup_write_legacy; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci /* Add the reservation limit file */ 6998c2ecf20Sopenharmony_ci cft = &h->cgroup_files_legacy[1]; 7008c2ecf20Sopenharmony_ci snprintf(cft->name, MAX_CFTYPE_NAME, "%s.rsvd.limit_in_bytes", buf); 7018c2ecf20Sopenharmony_ci cft->private = MEMFILE_PRIVATE(idx, RES_RSVD_LIMIT); 7028c2ecf20Sopenharmony_ci cft->read_u64 = hugetlb_cgroup_read_u64; 7038c2ecf20Sopenharmony_ci cft->write = hugetlb_cgroup_write_legacy; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci /* Add the usage file */ 7068c2ecf20Sopenharmony_ci cft = &h->cgroup_files_legacy[2]; 7078c2ecf20Sopenharmony_ci snprintf(cft->name, MAX_CFTYPE_NAME, "%s.usage_in_bytes", buf); 7088c2ecf20Sopenharmony_ci cft->private = MEMFILE_PRIVATE(idx, RES_USAGE); 7098c2ecf20Sopenharmony_ci cft->read_u64 = hugetlb_cgroup_read_u64; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci /* Add the reservation usage file */ 7128c2ecf20Sopenharmony_ci cft = &h->cgroup_files_legacy[3]; 7138c2ecf20Sopenharmony_ci snprintf(cft->name, MAX_CFTYPE_NAME, "%s.rsvd.usage_in_bytes", buf); 7148c2ecf20Sopenharmony_ci cft->private = MEMFILE_PRIVATE(idx, RES_RSVD_USAGE); 7158c2ecf20Sopenharmony_ci cft->read_u64 = hugetlb_cgroup_read_u64; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci /* Add the MAX usage file */ 7188c2ecf20Sopenharmony_ci cft = &h->cgroup_files_legacy[4]; 7198c2ecf20Sopenharmony_ci snprintf(cft->name, MAX_CFTYPE_NAME, "%s.max_usage_in_bytes", buf); 7208c2ecf20Sopenharmony_ci cft->private = MEMFILE_PRIVATE(idx, RES_MAX_USAGE); 7218c2ecf20Sopenharmony_ci cft->write = hugetlb_cgroup_reset; 7228c2ecf20Sopenharmony_ci cft->read_u64 = hugetlb_cgroup_read_u64; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci /* Add the MAX reservation usage file */ 7258c2ecf20Sopenharmony_ci cft = &h->cgroup_files_legacy[5]; 7268c2ecf20Sopenharmony_ci snprintf(cft->name, MAX_CFTYPE_NAME, "%s.rsvd.max_usage_in_bytes", buf); 7278c2ecf20Sopenharmony_ci cft->private = MEMFILE_PRIVATE(idx, RES_RSVD_MAX_USAGE); 7288c2ecf20Sopenharmony_ci cft->write = hugetlb_cgroup_reset; 7298c2ecf20Sopenharmony_ci cft->read_u64 = hugetlb_cgroup_read_u64; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci /* Add the failcntfile */ 7328c2ecf20Sopenharmony_ci cft = &h->cgroup_files_legacy[6]; 7338c2ecf20Sopenharmony_ci snprintf(cft->name, MAX_CFTYPE_NAME, "%s.failcnt", buf); 7348c2ecf20Sopenharmony_ci cft->private = MEMFILE_PRIVATE(idx, RES_FAILCNT); 7358c2ecf20Sopenharmony_ci cft->write = hugetlb_cgroup_reset; 7368c2ecf20Sopenharmony_ci cft->read_u64 = hugetlb_cgroup_read_u64; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci /* Add the reservation failcntfile */ 7398c2ecf20Sopenharmony_ci cft = &h->cgroup_files_legacy[7]; 7408c2ecf20Sopenharmony_ci snprintf(cft->name, MAX_CFTYPE_NAME, "%s.rsvd.failcnt", buf); 7418c2ecf20Sopenharmony_ci cft->private = MEMFILE_PRIVATE(idx, RES_RSVD_FAILCNT); 7428c2ecf20Sopenharmony_ci cft->write = hugetlb_cgroup_reset; 7438c2ecf20Sopenharmony_ci cft->read_u64 = hugetlb_cgroup_read_u64; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci /* NULL terminate the last cft */ 7468c2ecf20Sopenharmony_ci cft = &h->cgroup_files_legacy[8]; 7478c2ecf20Sopenharmony_ci memset(cft, 0, sizeof(*cft)); 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci WARN_ON(cgroup_add_legacy_cftypes(&hugetlb_cgrp_subsys, 7508c2ecf20Sopenharmony_ci h->cgroup_files_legacy)); 7518c2ecf20Sopenharmony_ci} 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_cistatic void __init __hugetlb_cgroup_file_init(int idx) 7548c2ecf20Sopenharmony_ci{ 7558c2ecf20Sopenharmony_ci __hugetlb_cgroup_file_dfl_init(idx); 7568c2ecf20Sopenharmony_ci __hugetlb_cgroup_file_legacy_init(idx); 7578c2ecf20Sopenharmony_ci} 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_civoid __init hugetlb_cgroup_file_init(void) 7608c2ecf20Sopenharmony_ci{ 7618c2ecf20Sopenharmony_ci struct hstate *h; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci for_each_hstate(h) { 7648c2ecf20Sopenharmony_ci /* 7658c2ecf20Sopenharmony_ci * Add cgroup control files only if the huge page consists 7668c2ecf20Sopenharmony_ci * of more than two normal pages. This is because we use 7678c2ecf20Sopenharmony_ci * page[2].private for storing cgroup details. 7688c2ecf20Sopenharmony_ci */ 7698c2ecf20Sopenharmony_ci if (huge_page_order(h) >= HUGETLB_CGROUP_MIN_ORDER) 7708c2ecf20Sopenharmony_ci __hugetlb_cgroup_file_init(hstate_index(h)); 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci/* 7758c2ecf20Sopenharmony_ci * hugetlb_lock will make sure a parallel cgroup rmdir won't happen 7768c2ecf20Sopenharmony_ci * when we migrate hugepages 7778c2ecf20Sopenharmony_ci */ 7788c2ecf20Sopenharmony_civoid hugetlb_cgroup_migrate(struct page *oldhpage, struct page *newhpage) 7798c2ecf20Sopenharmony_ci{ 7808c2ecf20Sopenharmony_ci struct hugetlb_cgroup *h_cg; 7818c2ecf20Sopenharmony_ci struct hugetlb_cgroup *h_cg_rsvd; 7828c2ecf20Sopenharmony_ci struct hstate *h = page_hstate(oldhpage); 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci if (hugetlb_cgroup_disabled()) 7858c2ecf20Sopenharmony_ci return; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci VM_BUG_ON_PAGE(!PageHuge(oldhpage), oldhpage); 7888c2ecf20Sopenharmony_ci spin_lock(&hugetlb_lock); 7898c2ecf20Sopenharmony_ci h_cg = hugetlb_cgroup_from_page(oldhpage); 7908c2ecf20Sopenharmony_ci h_cg_rsvd = hugetlb_cgroup_from_page_rsvd(oldhpage); 7918c2ecf20Sopenharmony_ci set_hugetlb_cgroup(oldhpage, NULL); 7928c2ecf20Sopenharmony_ci set_hugetlb_cgroup_rsvd(oldhpage, NULL); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci /* move the h_cg details to new cgroup */ 7958c2ecf20Sopenharmony_ci set_hugetlb_cgroup(newhpage, h_cg); 7968c2ecf20Sopenharmony_ci set_hugetlb_cgroup_rsvd(newhpage, h_cg_rsvd); 7978c2ecf20Sopenharmony_ci list_move(&newhpage->lru, &h->hugepage_activelist); 7988c2ecf20Sopenharmony_ci spin_unlock(&hugetlb_lock); 7998c2ecf20Sopenharmony_ci return; 8008c2ecf20Sopenharmony_ci} 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_cistatic struct cftype hugetlb_files[] = { 8038c2ecf20Sopenharmony_ci {} /* terminate */ 8048c2ecf20Sopenharmony_ci}; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_cistruct cgroup_subsys hugetlb_cgrp_subsys = { 8078c2ecf20Sopenharmony_ci .css_alloc = hugetlb_cgroup_css_alloc, 8088c2ecf20Sopenharmony_ci .css_offline = hugetlb_cgroup_css_offline, 8098c2ecf20Sopenharmony_ci .css_free = hugetlb_cgroup_css_free, 8108c2ecf20Sopenharmony_ci .dfl_cftypes = hugetlb_files, 8118c2ecf20Sopenharmony_ci .legacy_cftypes = hugetlb_files, 8128c2ecf20Sopenharmony_ci}; 813