1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | #ifndef _LINUX_CPUSET_H |
3 | #define _LINUX_CPUSET_H |
4 | /* |
5 | * cpuset interface |
6 | * |
7 | * Copyright (C) 2003 BULL SA |
8 | * Copyright (C) 2004-2006 Silicon Graphics, Inc. |
9 | * |
10 | */ |
11 | |
12 | #include <linux/sched.h> |
13 | #include <linux/sched/topology.h> |
14 | #include <linux/sched/task.h> |
15 | #include <linux/cpumask.h> |
16 | #include <linux/nodemask.h> |
17 | #include <linux/mm.h> |
18 | #include <linux/mmu_context.h> |
19 | #include <linux/jump_label.h> |
20 | |
21 | #ifdef CONFIG_CPUSETS |
22 | |
23 | /* |
24 | * Static branch rewrites can happen in an arbitrary order for a given |
25 | * key. In code paths where we need to loop with read_mems_allowed_begin() and |
26 | * read_mems_allowed_retry() to get a consistent view of mems_allowed, we need |
27 | * to ensure that begin() always gets rewritten before retry() in the |
28 | * disabled -> enabled transition. If not, then if local irqs are disabled |
29 | * around the loop, we can deadlock since retry() would always be |
30 | * comparing the latest value of the mems_allowed seqcount against 0 as |
31 | * begin() still would see cpusets_enabled() as false. The enabled -> disabled |
32 | * transition should happen in reverse order for the same reasons (want to stop |
33 | * looking at real value of mems_allowed.sequence in retry() first). |
34 | */ |
35 | extern struct static_key_false cpusets_pre_enable_key; |
36 | extern struct static_key_false cpusets_enabled_key; |
37 | extern struct static_key_false cpusets_insane_config_key; |
38 | |
39 | static inline bool cpusets_enabled(void) |
40 | { |
41 | return static_branch_unlikely(&cpusets_enabled_key); |
42 | } |
43 | |
44 | static inline void cpuset_inc(void) |
45 | { |
46 | static_branch_inc_cpuslocked(&cpusets_pre_enable_key); |
47 | static_branch_inc_cpuslocked(&cpusets_enabled_key); |
48 | } |
49 | |
50 | static inline void cpuset_dec(void) |
51 | { |
52 | static_branch_dec_cpuslocked(&cpusets_enabled_key); |
53 | static_branch_dec_cpuslocked(&cpusets_pre_enable_key); |
54 | } |
55 | |
56 | /* |
57 | * This will get enabled whenever a cpuset configuration is considered |
58 | * unsupportable in general. E.g. movable only node which cannot satisfy |
59 | * any non movable allocations (see update_nodemask). Page allocator |
60 | * needs to make additional checks for those configurations and this |
61 | * check is meant to guard those checks without any overhead for sane |
62 | * configurations. |
63 | */ |
64 | static inline bool cpusets_insane_config(void) |
65 | { |
66 | return static_branch_unlikely(&cpusets_insane_config_key); |
67 | } |
68 | |
69 | extern int cpuset_init(void); |
70 | extern void cpuset_init_smp(void); |
71 | extern void cpuset_force_rebuild(void); |
72 | extern void cpuset_update_active_cpus(void); |
73 | extern void cpuset_wait_for_hotplug(void); |
74 | extern void inc_dl_tasks_cs(struct task_struct *task); |
75 | extern void dec_dl_tasks_cs(struct task_struct *task); |
76 | extern void cpuset_lock(void); |
77 | extern void cpuset_unlock(void); |
78 | extern void cpuset_cpus_allowed(struct task_struct *p, struct cpumask *mask); |
79 | extern bool cpuset_cpus_allowed_fallback(struct task_struct *p); |
80 | extern nodemask_t cpuset_mems_allowed(struct task_struct *p); |
81 | #define cpuset_current_mems_allowed (current->mems_allowed) |
82 | void cpuset_init_current_mems_allowed(void); |
83 | int cpuset_nodemask_valid_mems_allowed(nodemask_t *nodemask); |
84 | |
85 | extern bool cpuset_node_allowed(int node, gfp_t gfp_mask); |
86 | |
87 | static inline bool __cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask) |
88 | { |
89 | return cpuset_node_allowed(node: zone_to_nid(zone: z), gfp_mask); |
90 | } |
91 | |
92 | static inline bool cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask) |
93 | { |
94 | if (cpusets_enabled()) |
95 | return __cpuset_zone_allowed(z, gfp_mask); |
96 | return true; |
97 | } |
98 | |
99 | extern int cpuset_mems_allowed_intersects(const struct task_struct *tsk1, |
100 | const struct task_struct *tsk2); |
101 | |
102 | #define cpuset_memory_pressure_bump() \ |
103 | do { \ |
104 | if (cpuset_memory_pressure_enabled) \ |
105 | __cpuset_memory_pressure_bump(); \ |
106 | } while (0) |
107 | extern int cpuset_memory_pressure_enabled; |
108 | extern void __cpuset_memory_pressure_bump(void); |
109 | |
110 | extern void cpuset_task_status_allowed(struct seq_file *m, |
111 | struct task_struct *task); |
112 | extern int proc_cpuset_show(struct seq_file *m, struct pid_namespace *ns, |
113 | struct pid *pid, struct task_struct *tsk); |
114 | |
115 | extern int cpuset_mem_spread_node(void); |
116 | extern int cpuset_slab_spread_node(void); |
117 | |
118 | static inline int cpuset_do_page_mem_spread(void) |
119 | { |
120 | return task_spread_page(current); |
121 | } |
122 | |
123 | static inline int cpuset_do_slab_mem_spread(void) |
124 | { |
125 | return task_spread_slab(current); |
126 | } |
127 | |
128 | extern bool current_cpuset_is_being_rebound(void); |
129 | |
130 | extern void rebuild_sched_domains(void); |
131 | |
132 | extern void cpuset_print_current_mems_allowed(void); |
133 | |
134 | /* |
135 | * read_mems_allowed_begin is required when making decisions involving |
136 | * mems_allowed such as during page allocation. mems_allowed can be updated in |
137 | * parallel and depending on the new value an operation can fail potentially |
138 | * causing process failure. A retry loop with read_mems_allowed_begin and |
139 | * read_mems_allowed_retry prevents these artificial failures. |
140 | */ |
141 | static inline unsigned int read_mems_allowed_begin(void) |
142 | { |
143 | if (!static_branch_unlikely(&cpusets_pre_enable_key)) |
144 | return 0; |
145 | |
146 | return read_seqcount_begin(¤t->mems_allowed_seq); |
147 | } |
148 | |
149 | /* |
150 | * If this returns true, the operation that took place after |
151 | * read_mems_allowed_begin may have failed artificially due to a concurrent |
152 | * update of mems_allowed. It is up to the caller to retry the operation if |
153 | * appropriate. |
154 | */ |
155 | static inline bool read_mems_allowed_retry(unsigned int seq) |
156 | { |
157 | if (!static_branch_unlikely(&cpusets_enabled_key)) |
158 | return false; |
159 | |
160 | return read_seqcount_retry(¤t->mems_allowed_seq, seq); |
161 | } |
162 | |
163 | static inline void set_mems_allowed(nodemask_t nodemask) |
164 | { |
165 | unsigned long flags; |
166 | |
167 | task_lock(current); |
168 | local_irq_save(flags); |
169 | write_seqcount_begin(¤t->mems_allowed_seq); |
170 | current->mems_allowed = nodemask; |
171 | write_seqcount_end(¤t->mems_allowed_seq); |
172 | local_irq_restore(flags); |
173 | task_unlock(current); |
174 | } |
175 | |
176 | #else /* !CONFIG_CPUSETS */ |
177 | |
178 | static inline bool cpusets_enabled(void) { return false; } |
179 | |
180 | static inline bool cpusets_insane_config(void) { return false; } |
181 | |
182 | static inline int cpuset_init(void) { return 0; } |
183 | static inline void cpuset_init_smp(void) {} |
184 | |
185 | static inline void cpuset_force_rebuild(void) { } |
186 | |
187 | static inline void cpuset_update_active_cpus(void) |
188 | { |
189 | partition_sched_domains(1, NULL, NULL); |
190 | } |
191 | |
192 | static inline void cpuset_wait_for_hotplug(void) { } |
193 | |
194 | static inline void inc_dl_tasks_cs(struct task_struct *task) { } |
195 | static inline void dec_dl_tasks_cs(struct task_struct *task) { } |
196 | static inline void cpuset_lock(void) { } |
197 | static inline void cpuset_unlock(void) { } |
198 | |
199 | static inline void cpuset_cpus_allowed(struct task_struct *p, |
200 | struct cpumask *mask) |
201 | { |
202 | cpumask_copy(mask, task_cpu_possible_mask(p)); |
203 | } |
204 | |
205 | static inline bool cpuset_cpus_allowed_fallback(struct task_struct *p) |
206 | { |
207 | return false; |
208 | } |
209 | |
210 | static inline nodemask_t cpuset_mems_allowed(struct task_struct *p) |
211 | { |
212 | return node_possible_map; |
213 | } |
214 | |
215 | #define cpuset_current_mems_allowed (node_states[N_MEMORY]) |
216 | static inline void cpuset_init_current_mems_allowed(void) {} |
217 | |
218 | static inline int cpuset_nodemask_valid_mems_allowed(nodemask_t *nodemask) |
219 | { |
220 | return 1; |
221 | } |
222 | |
223 | static inline bool __cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask) |
224 | { |
225 | return true; |
226 | } |
227 | |
228 | static inline bool cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask) |
229 | { |
230 | return true; |
231 | } |
232 | |
233 | static inline int cpuset_mems_allowed_intersects(const struct task_struct *tsk1, |
234 | const struct task_struct *tsk2) |
235 | { |
236 | return 1; |
237 | } |
238 | |
239 | static inline void cpuset_memory_pressure_bump(void) {} |
240 | |
241 | static inline void cpuset_task_status_allowed(struct seq_file *m, |
242 | struct task_struct *task) |
243 | { |
244 | } |
245 | |
246 | static inline int cpuset_mem_spread_node(void) |
247 | { |
248 | return 0; |
249 | } |
250 | |
251 | static inline int cpuset_slab_spread_node(void) |
252 | { |
253 | return 0; |
254 | } |
255 | |
256 | static inline int cpuset_do_page_mem_spread(void) |
257 | { |
258 | return 0; |
259 | } |
260 | |
261 | static inline int cpuset_do_slab_mem_spread(void) |
262 | { |
263 | return 0; |
264 | } |
265 | |
266 | static inline bool current_cpuset_is_being_rebound(void) |
267 | { |
268 | return false; |
269 | } |
270 | |
271 | static inline void rebuild_sched_domains(void) |
272 | { |
273 | partition_sched_domains(1, NULL, NULL); |
274 | } |
275 | |
276 | static inline void cpuset_print_current_mems_allowed(void) |
277 | { |
278 | } |
279 | |
280 | static inline void set_mems_allowed(nodemask_t nodemask) |
281 | { |
282 | } |
283 | |
284 | static inline unsigned int read_mems_allowed_begin(void) |
285 | { |
286 | return 0; |
287 | } |
288 | |
289 | static inline bool read_mems_allowed_retry(unsigned int seq) |
290 | { |
291 | return false; |
292 | } |
293 | |
294 | #endif /* !CONFIG_CPUSETS */ |
295 | |
296 | #endif /* _LINUX_CPUSET_H */ |
297 | |