| 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 inc_dl_tasks_cs(struct task_struct *task); | 
|---|
| 74 | extern void dec_dl_tasks_cs(struct task_struct *task); | 
|---|
| 75 | extern void cpuset_lock(void); | 
|---|
| 76 | extern void cpuset_unlock(void); | 
|---|
| 77 | extern void cpuset_cpus_allowed(struct task_struct *p, struct cpumask *mask); | 
|---|
| 78 | extern bool cpuset_cpus_allowed_fallback(struct task_struct *p); | 
|---|
| 79 | extern bool cpuset_cpu_is_isolated(int cpu); | 
|---|
| 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_current_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_current_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 | #ifdef CONFIG_CPUSETS_V1 | 
|---|
| 103 | #define cpuset_memory_pressure_bump() 				\ | 
|---|
| 104 | do {							\ | 
|---|
| 105 | if (cpuset_memory_pressure_enabled)		\ | 
|---|
| 106 | __cpuset_memory_pressure_bump();	\ | 
|---|
| 107 | } while (0) | 
|---|
| 108 | extern int cpuset_memory_pressure_enabled; | 
|---|
| 109 | extern void __cpuset_memory_pressure_bump(void); | 
|---|
| 110 | #else | 
|---|
| 111 | static inline void cpuset_memory_pressure_bump(void) { } | 
|---|
| 112 | #endif | 
|---|
| 113 |  | 
|---|
| 114 | extern void cpuset_task_status_allowed(struct seq_file *m, | 
|---|
| 115 | struct task_struct *task); | 
|---|
| 116 | extern int proc_cpuset_show(struct seq_file *m, struct pid_namespace *ns, | 
|---|
| 117 | struct pid *pid, struct task_struct *tsk); | 
|---|
| 118 |  | 
|---|
| 119 | extern int cpuset_mem_spread_node(void); | 
|---|
| 120 |  | 
|---|
| 121 | static inline int cpuset_do_page_mem_spread(void) | 
|---|
| 122 | { | 
|---|
| 123 | return task_spread_page(current); | 
|---|
| 124 | } | 
|---|
| 125 |  | 
|---|
| 126 | extern bool current_cpuset_is_being_rebound(void); | 
|---|
| 127 |  | 
|---|
| 128 | extern void dl_rebuild_rd_accounting(void); | 
|---|
| 129 | extern void rebuild_sched_domains(void); | 
|---|
| 130 |  | 
|---|
| 131 | extern void cpuset_print_current_mems_allowed(void); | 
|---|
| 132 | extern void cpuset_reset_sched_domains(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 | extern bool cpuset_node_allowed(struct cgroup *cgroup, int nid); | 
|---|
| 177 | #else /* !CONFIG_CPUSETS */ | 
|---|
| 178 |  | 
|---|
| 179 | static inline bool cpusets_enabled(void) { return false; } | 
|---|
| 180 |  | 
|---|
| 181 | static inline bool cpusets_insane_config(void) { return false; } | 
|---|
| 182 |  | 
|---|
| 183 | static inline int cpuset_init(void) { return 0; } | 
|---|
| 184 | static inline void cpuset_init_smp(void) {} | 
|---|
| 185 |  | 
|---|
| 186 | static inline void cpuset_force_rebuild(void) { } | 
|---|
| 187 |  | 
|---|
| 188 | static inline void cpuset_update_active_cpus(void) | 
|---|
| 189 | { | 
|---|
| 190 | partition_sched_domains(1, NULL, NULL); | 
|---|
| 191 | } | 
|---|
| 192 |  | 
|---|
| 193 | static inline void inc_dl_tasks_cs(struct task_struct *task) { } | 
|---|
| 194 | static inline void dec_dl_tasks_cs(struct task_struct *task) { } | 
|---|
| 195 | static inline void cpuset_lock(void) { } | 
|---|
| 196 | static inline void cpuset_unlock(void) { } | 
|---|
| 197 |  | 
|---|
| 198 | static inline void cpuset_cpus_allowed(struct task_struct *p, | 
|---|
| 199 | struct cpumask *mask) | 
|---|
| 200 | { | 
|---|
| 201 | cpumask_copy(mask, task_cpu_possible_mask(p)); | 
|---|
| 202 | } | 
|---|
| 203 |  | 
|---|
| 204 | static inline bool cpuset_cpus_allowed_fallback(struct task_struct *p) | 
|---|
| 205 | { | 
|---|
| 206 | return false; | 
|---|
| 207 | } | 
|---|
| 208 |  | 
|---|
| 209 | static inline bool cpuset_cpu_is_isolated(int cpu) | 
|---|
| 210 | { | 
|---|
| 211 | return false; | 
|---|
| 212 | } | 
|---|
| 213 |  | 
|---|
| 214 | static inline nodemask_t cpuset_mems_allowed(struct task_struct *p) | 
|---|
| 215 | { | 
|---|
| 216 | return node_possible_map; | 
|---|
| 217 | } | 
|---|
| 218 |  | 
|---|
| 219 | #define cpuset_current_mems_allowed (node_states[N_MEMORY]) | 
|---|
| 220 | static inline void cpuset_init_current_mems_allowed(void) {} | 
|---|
| 221 |  | 
|---|
| 222 | static inline int cpuset_nodemask_valid_mems_allowed(nodemask_t *nodemask) | 
|---|
| 223 | { | 
|---|
| 224 | return 1; | 
|---|
| 225 | } | 
|---|
| 226 |  | 
|---|
| 227 | static inline bool __cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask) | 
|---|
| 228 | { | 
|---|
| 229 | return true; | 
|---|
| 230 | } | 
|---|
| 231 |  | 
|---|
| 232 | static inline bool cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask) | 
|---|
| 233 | { | 
|---|
| 234 | return true; | 
|---|
| 235 | } | 
|---|
| 236 |  | 
|---|
| 237 | static inline int cpuset_mems_allowed_intersects(const struct task_struct *tsk1, | 
|---|
| 238 | const struct task_struct *tsk2) | 
|---|
| 239 | { | 
|---|
| 240 | return 1; | 
|---|
| 241 | } | 
|---|
| 242 |  | 
|---|
| 243 | static inline void cpuset_memory_pressure_bump(void) {} | 
|---|
| 244 |  | 
|---|
| 245 | static inline void cpuset_task_status_allowed(struct seq_file *m, | 
|---|
| 246 | struct task_struct *task) | 
|---|
| 247 | { | 
|---|
| 248 | } | 
|---|
| 249 |  | 
|---|
| 250 | static inline int cpuset_mem_spread_node(void) | 
|---|
| 251 | { | 
|---|
| 252 | return 0; | 
|---|
| 253 | } | 
|---|
| 254 |  | 
|---|
| 255 | static inline int cpuset_do_page_mem_spread(void) | 
|---|
| 256 | { | 
|---|
| 257 | return 0; | 
|---|
| 258 | } | 
|---|
| 259 |  | 
|---|
| 260 | static inline bool current_cpuset_is_being_rebound(void) | 
|---|
| 261 | { | 
|---|
| 262 | return false; | 
|---|
| 263 | } | 
|---|
| 264 |  | 
|---|
| 265 | static inline void dl_rebuild_rd_accounting(void) | 
|---|
| 266 | { | 
|---|
| 267 | } | 
|---|
| 268 |  | 
|---|
| 269 | static inline void rebuild_sched_domains(void) | 
|---|
| 270 | { | 
|---|
| 271 | partition_sched_domains(1, NULL, NULL); | 
|---|
| 272 | } | 
|---|
| 273 |  | 
|---|
| 274 | static inline void cpuset_reset_sched_domains(void) | 
|---|
| 275 | { | 
|---|
| 276 | partition_sched_domains(1, NULL, NULL); | 
|---|
| 277 | } | 
|---|
| 278 |  | 
|---|
| 279 | static inline void cpuset_print_current_mems_allowed(void) | 
|---|
| 280 | { | 
|---|
| 281 | } | 
|---|
| 282 |  | 
|---|
| 283 | static inline void set_mems_allowed(nodemask_t nodemask) | 
|---|
| 284 | { | 
|---|
| 285 | } | 
|---|
| 286 |  | 
|---|
| 287 | static inline unsigned int read_mems_allowed_begin(void) | 
|---|
| 288 | { | 
|---|
| 289 | return 0; | 
|---|
| 290 | } | 
|---|
| 291 |  | 
|---|
| 292 | static inline bool read_mems_allowed_retry(unsigned int seq) | 
|---|
| 293 | { | 
|---|
| 294 | return false; | 
|---|
| 295 | } | 
|---|
| 296 |  | 
|---|
| 297 | static inline bool cpuset_node_allowed(struct cgroup *cgroup, int nid) | 
|---|
| 298 | { | 
|---|
| 299 | return true; | 
|---|
| 300 | } | 
|---|
| 301 | #endif /* !CONFIG_CPUSETS */ | 
|---|
| 302 |  | 
|---|
| 303 | #endif /* _LINUX_CPUSET_H */ | 
|---|
| 304 |  | 
|---|