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 static inline void resv_map_dup_hugetlb_cgroup_uncharge_info( 125 struct resv_map *resv_map) 126 { 127 if (resv_map->css) 128 css_get(resv_map->css); 129 } 130 131 extern int hugetlb_cgroup_charge_cgroup(int idx, unsigned long nr_pages, 132 struct hugetlb_cgroup **ptr); 133 extern int hugetlb_cgroup_charge_cgroup_rsvd(int idx, unsigned long nr_pages, 134 struct hugetlb_cgroup **ptr); 135 extern void hugetlb_cgroup_commit_charge(int idx, unsigned long nr_pages, 136 struct hugetlb_cgroup *h_cg, 137 struct page *page); 138 extern void hugetlb_cgroup_commit_charge_rsvd(int idx, unsigned long nr_pages, 139 struct hugetlb_cgroup *h_cg, 140 struct page *page); 141 extern void hugetlb_cgroup_uncharge_page(int idx, unsigned long nr_pages, 142 struct page *page); 143 extern void hugetlb_cgroup_uncharge_page_rsvd(int idx, unsigned long nr_pages, 144 struct page *page); 145 146 extern void hugetlb_cgroup_uncharge_cgroup(int idx, unsigned long nr_pages, 147 struct hugetlb_cgroup *h_cg); 148 extern void hugetlb_cgroup_uncharge_cgroup_rsvd(int idx, unsigned long nr_pages, 149 struct hugetlb_cgroup *h_cg); 150 extern void hugetlb_cgroup_uncharge_counter(struct resv_map *resv, 151 unsigned long start, 152 unsigned long end); 153 154 extern void hugetlb_cgroup_uncharge_file_region(struct resv_map *resv, 155 struct file_region *rg, 156 unsigned long nr_pages, 157 bool region_del); 158 159 extern void hugetlb_cgroup_file_init(void) __init; 160 extern void hugetlb_cgroup_migrate(struct page *oldhpage, 161 struct page *newhpage); 162 163 #else 164 static inline void hugetlb_cgroup_uncharge_file_region(struct resv_map *resv, 165 struct file_region *rg, 166 unsigned long nr_pages, 167 bool region_del) 168 { 169 } 170 171 static inline struct hugetlb_cgroup *hugetlb_cgroup_from_page(struct page *page) 172 { 173 return NULL; 174 } 175 176 static inline struct hugetlb_cgroup * 177 hugetlb_cgroup_from_page_resv(struct page *page) 178 { 179 return NULL; 180 } 181 182 static inline struct hugetlb_cgroup * 183 hugetlb_cgroup_from_page_rsvd(struct page *page) 184 { 185 return NULL; 186 } 187 188 static inline int set_hugetlb_cgroup(struct page *page, 189 struct hugetlb_cgroup *h_cg) 190 { 191 return 0; 192 } 193 194 static inline int set_hugetlb_cgroup_rsvd(struct page *page, 195 struct hugetlb_cgroup *h_cg) 196 { 197 return 0; 198 } 199 200 static inline bool hugetlb_cgroup_disabled(void) 201 { 202 return true; 203 } 204 205 static inline void hugetlb_cgroup_put_rsvd_cgroup(struct hugetlb_cgroup *h_cg) 206 { 207 } 208 209 static inline void resv_map_dup_hugetlb_cgroup_uncharge_info( 210 struct resv_map *resv_map) 211 { 212 } 213 214 static inline int hugetlb_cgroup_charge_cgroup(int idx, unsigned long nr_pages, 215 struct hugetlb_cgroup **ptr) 216 { 217 return 0; 218 } 219 220 static inline int hugetlb_cgroup_charge_cgroup_rsvd(int idx, 221 unsigned long nr_pages, 222 struct hugetlb_cgroup **ptr) 223 { 224 return 0; 225 } 226 227 static inline void hugetlb_cgroup_commit_charge(int idx, unsigned long nr_pages, 228 struct hugetlb_cgroup *h_cg, 229 struct page *page) 230 { 231 } 232 233 static inline void 234 hugetlb_cgroup_commit_charge_rsvd(int idx, unsigned long nr_pages, 235 struct hugetlb_cgroup *h_cg, 236 struct page *page) 237 { 238 } 239 240 static inline void hugetlb_cgroup_uncharge_page(int idx, unsigned long nr_pages, 241 struct page *page) 242 { 243 } 244 245 static inline void hugetlb_cgroup_uncharge_page_rsvd(int idx, 246 unsigned long nr_pages, 247 struct page *page) 248 { 249 } 250 static inline void hugetlb_cgroup_uncharge_cgroup(int idx, 251 unsigned long nr_pages, 252 struct hugetlb_cgroup *h_cg) 253 { 254 } 255 256 static inline void 257 hugetlb_cgroup_uncharge_cgroup_rsvd(int idx, unsigned long nr_pages, 258 struct hugetlb_cgroup *h_cg) 259 { 260 } 261 262 static inline void hugetlb_cgroup_uncharge_counter(struct resv_map *resv, 263 unsigned long start, 264 unsigned long end) 265 { 266 } 267 268 static inline void hugetlb_cgroup_file_init(void) 269 { 270 } 271 272 static inline void hugetlb_cgroup_migrate(struct page *oldhpage, 273 struct page *newhpage) 274 { 275 } 276 277 #endif /* CONFIG_MEM_RES_CTLR_HUGETLB */ 278 #endif 279