1 /* 2 * Copyright IBM Corporation, 2012 3 * Author Aneesh Kumar K.V <[email protected]> 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of version 2.1 of the GNU Lesser General Public License 7 * as published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it would be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 * 13 */ 14 15 #ifndef _LINUX_HUGETLB_CGROUP_H 16 #define _LINUX_HUGETLB_CGROUP_H 17 18 #include <linux/mmdebug.h> 19 20 struct hugetlb_cgroup; 21 struct resv_map; 22 struct file_region; 23 24 #ifdef CONFIG_CGROUP_HUGETLB 25 /* 26 * Minimum page order trackable by hugetlb cgroup. 27 * At least 4 pages are necessary for all the tracking information. 28 * The second tail page (hpage[SUBPAGE_INDEX_CGROUP]) is the fault 29 * usage cgroup. The third tail page (hpage[SUBPAGE_INDEX_CGROUP_RSVD]) 30 * is the reservation usage cgroup. 31 */ 32 #define HUGETLB_CGROUP_MIN_ORDER order_base_2(__MAX_CGROUP_SUBPAGE_INDEX + 1) 33 34 enum hugetlb_memory_event { 35 HUGETLB_MAX, 36 HUGETLB_NR_MEMORY_EVENTS, 37 }; 38 39 struct hugetlb_cgroup { 40 struct cgroup_subsys_state css; 41 42 /* 43 * the counter to account for hugepages from hugetlb. 44 */ 45 struct page_counter hugepage[HUGE_MAX_HSTATE]; 46 47 /* 48 * the counter to account for hugepage reservations from hugetlb. 49 */ 50 struct page_counter rsvd_hugepage[HUGE_MAX_HSTATE]; 51 52 atomic_long_t events[HUGE_MAX_HSTATE][HUGETLB_NR_MEMORY_EVENTS]; 53 atomic_long_t events_local[HUGE_MAX_HSTATE][HUGETLB_NR_MEMORY_EVENTS]; 54 55 /* Handle for "hugetlb.events" */ 56 struct cgroup_file events_file[HUGE_MAX_HSTATE]; 57 58 /* Handle for "hugetlb.events.local" */ 59 struct cgroup_file events_local_file[HUGE_MAX_HSTATE]; 60 }; 61 62 static inline struct hugetlb_cgroup * 63 __hugetlb_cgroup_from_page(struct page *page, bool rsvd) 64 { 65 VM_BUG_ON_PAGE(!PageHuge(page), page); 66 67 if (compound_order(page) < HUGETLB_CGROUP_MIN_ORDER) 68 return NULL; 69 if (rsvd) 70 return (void *)page_private(page + SUBPAGE_INDEX_CGROUP_RSVD); 71 else 72 return (void *)page_private(page + SUBPAGE_INDEX_CGROUP); 73 } 74 75 static inline struct hugetlb_cgroup *hugetlb_cgroup_from_page(struct page *page) 76 { 77 return __hugetlb_cgroup_from_page(page, false); 78 } 79 80 static inline struct hugetlb_cgroup * 81 hugetlb_cgroup_from_page_rsvd(struct page *page) 82 { 83 return __hugetlb_cgroup_from_page(page, true); 84 } 85 86 static inline int __set_hugetlb_cgroup(struct page *page, 87 struct hugetlb_cgroup *h_cg, bool rsvd) 88 { 89 VM_BUG_ON_PAGE(!PageHuge(page), page); 90 91 if (compound_order(page) < HUGETLB_CGROUP_MIN_ORDER) 92 return -1; 93 if (rsvd) 94 set_page_private(page + SUBPAGE_INDEX_CGROUP_RSVD, 95 (unsigned long)h_cg); 96 else 97 set_page_private(page + SUBPAGE_INDEX_CGROUP, 98 (unsigned long)h_cg); 99 return 0; 100 } 101 102 static inline int set_hugetlb_cgroup(struct page *page, 103 struct hugetlb_cgroup *h_cg) 104 { 105 return __set_hugetlb_cgroup(page, h_cg, false); 106 } 107 108 static inline int set_hugetlb_cgroup_rsvd(struct page *page, 109 struct hugetlb_cgroup *h_cg) 110 { 111 return __set_hugetlb_cgroup(page, h_cg, true); 112 } 113 114 static inline bool hugetlb_cgroup_disabled(void) 115 { 116 return !cgroup_subsys_enabled(hugetlb_cgrp_subsys); 117 } 118 119 static inline void hugetlb_cgroup_put_rsvd_cgroup(struct hugetlb_cgroup *h_cg) 120 { 121 css_put(&h_cg->css); 122 } 123 124 extern int hugetlb_cgroup_charge_cgroup(int idx, unsigned long nr_pages, 125 struct hugetlb_cgroup **ptr); 126 extern int hugetlb_cgroup_charge_cgroup_rsvd(int idx, unsigned long nr_pages, 127 struct hugetlb_cgroup **ptr); 128 extern void hugetlb_cgroup_commit_charge(int idx, unsigned long nr_pages, 129 struct hugetlb_cgroup *h_cg, 130 struct page *page); 131 extern void hugetlb_cgroup_commit_charge_rsvd(int idx, unsigned long nr_pages, 132 struct hugetlb_cgroup *h_cg, 133 struct page *page); 134 extern void hugetlb_cgroup_uncharge_page(int idx, unsigned long nr_pages, 135 struct page *page); 136 extern void hugetlb_cgroup_uncharge_page_rsvd(int idx, unsigned long nr_pages, 137 struct page *page); 138 139 extern void hugetlb_cgroup_uncharge_cgroup(int idx, unsigned long nr_pages, 140 struct hugetlb_cgroup *h_cg); 141 extern void hugetlb_cgroup_uncharge_cgroup_rsvd(int idx, unsigned long nr_pages, 142 struct hugetlb_cgroup *h_cg); 143 extern void hugetlb_cgroup_uncharge_counter(struct resv_map *resv, 144 unsigned long start, 145 unsigned long end); 146 147 extern void hugetlb_cgroup_uncharge_file_region(struct resv_map *resv, 148 struct file_region *rg, 149 unsigned long nr_pages, 150 bool region_del); 151 152 extern void hugetlb_cgroup_file_init(void) __init; 153 extern void hugetlb_cgroup_migrate(struct page *oldhpage, 154 struct page *newhpage); 155 156 #else 157 static inline void hugetlb_cgroup_uncharge_file_region(struct resv_map *resv, 158 struct file_region *rg, 159 unsigned long nr_pages, 160 bool region_del) 161 { 162 } 163 164 static inline struct hugetlb_cgroup *hugetlb_cgroup_from_page(struct page *page) 165 { 166 return NULL; 167 } 168 169 static inline struct hugetlb_cgroup * 170 hugetlb_cgroup_from_page_resv(struct page *page) 171 { 172 return NULL; 173 } 174 175 static inline struct hugetlb_cgroup * 176 hugetlb_cgroup_from_page_rsvd(struct page *page) 177 { 178 return NULL; 179 } 180 181 static inline int set_hugetlb_cgroup(struct page *page, 182 struct hugetlb_cgroup *h_cg) 183 { 184 return 0; 185 } 186 187 static inline int set_hugetlb_cgroup_rsvd(struct page *page, 188 struct hugetlb_cgroup *h_cg) 189 { 190 return 0; 191 } 192 193 static inline bool hugetlb_cgroup_disabled(void) 194 { 195 return true; 196 } 197 198 static inline void hugetlb_cgroup_put_rsvd_cgroup(struct hugetlb_cgroup *h_cg) 199 { 200 } 201 202 static inline int hugetlb_cgroup_charge_cgroup(int idx, unsigned long nr_pages, 203 struct hugetlb_cgroup **ptr) 204 { 205 return 0; 206 } 207 208 static inline int hugetlb_cgroup_charge_cgroup_rsvd(int idx, 209 unsigned long nr_pages, 210 struct hugetlb_cgroup **ptr) 211 { 212 return 0; 213 } 214 215 static inline void hugetlb_cgroup_commit_charge(int idx, unsigned long nr_pages, 216 struct hugetlb_cgroup *h_cg, 217 struct page *page) 218 { 219 } 220 221 static inline void 222 hugetlb_cgroup_commit_charge_rsvd(int idx, unsigned long nr_pages, 223 struct hugetlb_cgroup *h_cg, 224 struct page *page) 225 { 226 } 227 228 static inline void hugetlb_cgroup_uncharge_page(int idx, unsigned long nr_pages, 229 struct page *page) 230 { 231 } 232 233 static inline void hugetlb_cgroup_uncharge_page_rsvd(int idx, 234 unsigned long nr_pages, 235 struct page *page) 236 { 237 } 238 static inline void hugetlb_cgroup_uncharge_cgroup(int idx, 239 unsigned long nr_pages, 240 struct hugetlb_cgroup *h_cg) 241 { 242 } 243 244 static inline void 245 hugetlb_cgroup_uncharge_cgroup_rsvd(int idx, unsigned long nr_pages, 246 struct hugetlb_cgroup *h_cg) 247 { 248 } 249 250 static inline void hugetlb_cgroup_uncharge_counter(struct resv_map *resv, 251 unsigned long start, 252 unsigned long end) 253 { 254 } 255 256 static inline void hugetlb_cgroup_file_init(void) 257 { 258 } 259 260 static inline void hugetlb_cgroup_migrate(struct page *oldhpage, 261 struct page *newhpage) 262 { 263 } 264 265 #endif /* CONFIG_MEM_RES_CTLR_HUGETLB */ 266 #endif 267