1/*
2 * Copyright IBM Corporation, 2012
3 * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
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
20struct hugetlb_cgroup;
21struct resv_map;
22struct file_region;
23
24#ifdef CONFIG_CGROUP_HUGETLB
25enum hugetlb_memory_event {
26	HUGETLB_MAX,
27	HUGETLB_NR_MEMORY_EVENTS,
28};
29
30struct hugetlb_cgroup_per_node {
31	/* hugetlb usage in pages over all hstates. */
32	unsigned long usage[HUGE_MAX_HSTATE];
33};
34
35struct hugetlb_cgroup {
36	struct cgroup_subsys_state css;
37
38	/*
39	 * the counter to account for hugepages from hugetlb.
40	 */
41	struct page_counter hugepage[HUGE_MAX_HSTATE];
42
43	/*
44	 * the counter to account for hugepage reservations from hugetlb.
45	 */
46	struct page_counter rsvd_hugepage[HUGE_MAX_HSTATE];
47
48	atomic_long_t events[HUGE_MAX_HSTATE][HUGETLB_NR_MEMORY_EVENTS];
49	atomic_long_t events_local[HUGE_MAX_HSTATE][HUGETLB_NR_MEMORY_EVENTS];
50
51	/* Handle for "hugetlb.events" */
52	struct cgroup_file events_file[HUGE_MAX_HSTATE];
53
54	/* Handle for "hugetlb.events.local" */
55	struct cgroup_file events_local_file[HUGE_MAX_HSTATE];
56
57	struct hugetlb_cgroup_per_node *nodeinfo[];
58};
59
60static inline struct hugetlb_cgroup *
61__hugetlb_cgroup_from_folio(struct folio *folio, bool rsvd)
62{
63	VM_BUG_ON_FOLIO(!folio_test_hugetlb(folio), folio);
64	if (rsvd)
65		return folio->_hugetlb_cgroup_rsvd;
66	else
67		return folio->_hugetlb_cgroup;
68}
69
70static inline struct hugetlb_cgroup *hugetlb_cgroup_from_folio(struct folio *folio)
71{
72	return __hugetlb_cgroup_from_folio(folio, false);
73}
74
75static inline struct hugetlb_cgroup *
76hugetlb_cgroup_from_folio_rsvd(struct folio *folio)
77{
78	return __hugetlb_cgroup_from_folio(folio, true);
79}
80
81static inline void __set_hugetlb_cgroup(struct folio *folio,
82				       struct hugetlb_cgroup *h_cg, bool rsvd)
83{
84	VM_BUG_ON_FOLIO(!folio_test_hugetlb(folio), folio);
85	if (rsvd)
86		folio->_hugetlb_cgroup_rsvd = h_cg;
87	else
88		folio->_hugetlb_cgroup = h_cg;
89}
90
91static inline void set_hugetlb_cgroup(struct folio *folio,
92				     struct hugetlb_cgroup *h_cg)
93{
94	__set_hugetlb_cgroup(folio, h_cg, false);
95}
96
97static inline void set_hugetlb_cgroup_rsvd(struct folio *folio,
98					  struct hugetlb_cgroup *h_cg)
99{
100	__set_hugetlb_cgroup(folio, h_cg, true);
101}
102
103static inline bool hugetlb_cgroup_disabled(void)
104{
105	return !cgroup_subsys_enabled(hugetlb_cgrp_subsys);
106}
107
108static inline void hugetlb_cgroup_put_rsvd_cgroup(struct hugetlb_cgroup *h_cg)
109{
110	css_put(&h_cg->css);
111}
112
113static inline void resv_map_dup_hugetlb_cgroup_uncharge_info(
114						struct resv_map *resv_map)
115{
116	if (resv_map->css)
117		css_get(resv_map->css);
118}
119
120static inline void resv_map_put_hugetlb_cgroup_uncharge_info(
121						struct resv_map *resv_map)
122{
123	if (resv_map->css)
124		css_put(resv_map->css);
125}
126
127extern int hugetlb_cgroup_charge_cgroup(int idx, unsigned long nr_pages,
128					struct hugetlb_cgroup **ptr);
129extern int hugetlb_cgroup_charge_cgroup_rsvd(int idx, unsigned long nr_pages,
130					     struct hugetlb_cgroup **ptr);
131extern void hugetlb_cgroup_commit_charge(int idx, unsigned long nr_pages,
132					 struct hugetlb_cgroup *h_cg,
133					 struct folio *folio);
134extern void hugetlb_cgroup_commit_charge_rsvd(int idx, unsigned long nr_pages,
135					      struct hugetlb_cgroup *h_cg,
136					      struct folio *folio);
137extern void hugetlb_cgroup_uncharge_folio(int idx, unsigned long nr_pages,
138					 struct folio *folio);
139extern void hugetlb_cgroup_uncharge_folio_rsvd(int idx, unsigned long nr_pages,
140					      struct folio *folio);
141
142extern void hugetlb_cgroup_uncharge_cgroup(int idx, unsigned long nr_pages,
143					   struct hugetlb_cgroup *h_cg);
144extern void hugetlb_cgroup_uncharge_cgroup_rsvd(int idx, unsigned long nr_pages,
145						struct hugetlb_cgroup *h_cg);
146extern void hugetlb_cgroup_uncharge_counter(struct resv_map *resv,
147					    unsigned long start,
148					    unsigned long end);
149
150extern void hugetlb_cgroup_uncharge_file_region(struct resv_map *resv,
151						struct file_region *rg,
152						unsigned long nr_pages,
153						bool region_del);
154
155extern void hugetlb_cgroup_file_init(void) __init;
156extern void hugetlb_cgroup_migrate(struct folio *old_folio,
157				   struct folio *new_folio);
158
159#else
160static inline void hugetlb_cgroup_uncharge_file_region(struct resv_map *resv,
161						       struct file_region *rg,
162						       unsigned long nr_pages,
163						       bool region_del)
164{
165}
166
167static inline struct hugetlb_cgroup *hugetlb_cgroup_from_folio(struct folio *folio)
168{
169	return NULL;
170}
171
172static inline struct hugetlb_cgroup *
173hugetlb_cgroup_from_folio_rsvd(struct folio *folio)
174{
175	return NULL;
176}
177
178static inline void set_hugetlb_cgroup(struct folio *folio,
179				     struct hugetlb_cgroup *h_cg)
180{
181}
182
183static inline void set_hugetlb_cgroup_rsvd(struct folio *folio,
184					  struct hugetlb_cgroup *h_cg)
185{
186}
187
188static inline bool hugetlb_cgroup_disabled(void)
189{
190	return true;
191}
192
193static inline void hugetlb_cgroup_put_rsvd_cgroup(struct hugetlb_cgroup *h_cg)
194{
195}
196
197static inline void resv_map_dup_hugetlb_cgroup_uncharge_info(
198						struct resv_map *resv_map)
199{
200}
201
202static inline void resv_map_put_hugetlb_cgroup_uncharge_info(
203						struct resv_map *resv_map)
204{
205}
206
207static inline int hugetlb_cgroup_charge_cgroup(int idx, unsigned long nr_pages,
208					       struct hugetlb_cgroup **ptr)
209{
210	return 0;
211}
212
213static inline int hugetlb_cgroup_charge_cgroup_rsvd(int idx,
214						    unsigned long nr_pages,
215						    struct hugetlb_cgroup **ptr)
216{
217	return 0;
218}
219
220static inline void hugetlb_cgroup_commit_charge(int idx, unsigned long nr_pages,
221						struct hugetlb_cgroup *h_cg,
222						struct folio *folio)
223{
224}
225
226static inline void
227hugetlb_cgroup_commit_charge_rsvd(int idx, unsigned long nr_pages,
228				  struct hugetlb_cgroup *h_cg,
229				  struct folio *folio)
230{
231}
232
233static inline void hugetlb_cgroup_uncharge_folio(int idx, unsigned long nr_pages,
234						struct folio *folio)
235{
236}
237
238static inline void hugetlb_cgroup_uncharge_folio_rsvd(int idx,
239						     unsigned long nr_pages,
240						     struct folio *folio)
241{
242}
243static inline void hugetlb_cgroup_uncharge_cgroup(int idx,
244						  unsigned long nr_pages,
245						  struct hugetlb_cgroup *h_cg)
246{
247}
248
249static inline void
250hugetlb_cgroup_uncharge_cgroup_rsvd(int idx, unsigned long nr_pages,
251				    struct hugetlb_cgroup *h_cg)
252{
253}
254
255static inline void hugetlb_cgroup_uncharge_counter(struct resv_map *resv,
256						   unsigned long start,
257						   unsigned long end)
258{
259}
260
261static inline void hugetlb_cgroup_file_init(void)
262{
263}
264
265static inline void hugetlb_cgroup_migrate(struct folio *old_folio,
266					  struct folio *new_folio)
267{
268}
269
270#endif  /* CONFIG_MEM_RES_CTLR_HUGETLB */
271#endif
272