| File: | build-scan/../src/basic/cpu-set-util.c |
| Warning: | line 208, column 32 Potential leak of memory pointed to by 'c.set' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | ||||
| 2 | /*** | ||||
| 3 | Copyright © 2015 Filipe Brandenburger | ||||
| 4 | ***/ | ||||
| 5 | |||||
| 6 | #include <errno(*__errno_location ()).h> | ||||
| 7 | #include <stddef.h> | ||||
| 8 | #include <stdio.h> | ||||
| 9 | #include <syslog.h> | ||||
| 10 | |||||
| 11 | #include "alloc-util.h" | ||||
| 12 | #include "cpu-set-util.h" | ||||
| 13 | #include "dirent-util.h" | ||||
| 14 | #include "extract-word.h" | ||||
| 15 | #include "fileio.h" | ||||
| 16 | #include "fd-util.h" | ||||
| 17 | #include "log.h" | ||||
| 18 | #include "macro.h" | ||||
| 19 | #include "missing.h" | ||||
| 20 | #include "parse-util.h" | ||||
| 21 | #include "stat-util.h" | ||||
| 22 | #include "stdio-util.h" | ||||
| 23 | #include "string-util.h" | ||||
| 24 | #include "string-table.h" | ||||
| 25 | #include "strv.h" | ||||
| 26 | #include "util.h" | ||||
| 27 | |||||
| 28 | char* cpu_set_to_string(const CPUSet *a) { | ||||
| 29 | _cleanup_free___attribute__((cleanup(freep))) char *str = NULL((void*)0); | ||||
| 30 | size_t allocated = 0, len = 0; | ||||
| 31 | int i, r; | ||||
| 32 | |||||
| 33 | for (i = 0; (size_t) i < a->allocated * 8; i++) { | ||||
| 34 | if (!CPU_ISSET_S(i, a->allocated, a->set)(__extension__ ({ size_t __cpu = (i); __cpu / 8 < (a->allocated ) ? ((((const __cpu_mask *) ((a->set)->__bits))[((__cpu ) / (8 * sizeof (__cpu_mask)))] & ((__cpu_mask) 1 << ((__cpu) % (8 * sizeof (__cpu_mask)))))) != 0 : 0; }))) | ||||
| 35 | continue; | ||||
| 36 | |||||
| 37 | if (!GREEDY_REALLOC(str, allocated, len + 1 + DECIMAL_STR_MAX(int))greedy_realloc((void**) &(str), &(allocated), (len + 1 + (2+(sizeof(int) <= 1 ? 3 : sizeof(int) <= 2 ? 5 : sizeof (int) <= 4 ? 10 : sizeof(int) <= 8 ? 20 : sizeof(int[-2 *(sizeof(int) > 8)])))), sizeof((str)[0]))) | ||||
| 38 | return NULL((void*)0); | ||||
| 39 | |||||
| 40 | r = sprintf(str + len, len > 0 ? " %d" : "%d", i); | ||||
| 41 | assert_se(r > 0)do { if ((__builtin_expect(!!(!(r > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("r > 0"), "../src/basic/cpu-set-util.c" , 41, __PRETTY_FUNCTION__); } while (0); | ||||
| 42 | len += r; | ||||
| 43 | } | ||||
| 44 | |||||
| 45 | return TAKE_PTR(str)({ typeof(str) _ptr_ = (str); (str) = ((void*)0); _ptr_; }) ?: strdup(""); | ||||
| 46 | } | ||||
| 47 | |||||
| 48 | char *cpu_set_to_range_string(const CPUSet *set) { | ||||
| 49 | unsigned range_start = 0, range_end; | ||||
| 50 | _cleanup_free___attribute__((cleanup(freep))) char *str = NULL((void*)0); | ||||
| 51 | size_t allocated = 0, len = 0; | ||||
| 52 | bool_Bool in_range = false0; | ||||
| 53 | int r; | ||||
| 54 | |||||
| 55 | for (unsigned i = 0; i < set->allocated * 8; i++) | ||||
| 56 | if (CPU_ISSET_S(i, set->allocated, set->set)(__extension__ ({ size_t __cpu = (i); __cpu / 8 < (set-> allocated) ? ((((const __cpu_mask *) ((set->set)->__bits ))[((__cpu) / (8 * sizeof (__cpu_mask)))] & ((__cpu_mask) 1 << ((__cpu) % (8 * sizeof (__cpu_mask)))))) != 0 : 0 ; }))) { | ||||
| 57 | if (in_range) | ||||
| 58 | range_end++; | ||||
| 59 | else { | ||||
| 60 | range_start = range_end = i; | ||||
| 61 | in_range = true1; | ||||
| 62 | } | ||||
| 63 | } else if (in_range) { | ||||
| 64 | in_range = false0; | ||||
| 65 | |||||
| 66 | if (!GREEDY_REALLOC(str, allocated, len + 2 + 2 * DECIMAL_STR_MAX(unsigned))greedy_realloc((void**) &(str), &(allocated), (len + 2 + 2 * (2+(sizeof(unsigned) <= 1 ? 3 : sizeof(unsigned) <= 2 ? 5 : sizeof(unsigned) <= 4 ? 10 : sizeof(unsigned) <= 8 ? 20 : sizeof(int[-2*(sizeof(unsigned) > 8)])))), sizeof ((str)[0]))) | ||||
| 67 | return NULL((void*)0); | ||||
| 68 | |||||
| 69 | if (range_end > range_start) | ||||
| 70 | r = sprintf(str + len, len > 0 ? " %d-%d" : "%d-%d", range_start, range_end); | ||||
| 71 | else | ||||
| 72 | r = sprintf(str + len, len > 0 ? " %d" : "%d", range_start); | ||||
| 73 | assert_se(r > 0)do { if ((__builtin_expect(!!(!(r > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("r > 0"), "../src/basic/cpu-set-util.c" , 73, __PRETTY_FUNCTION__); } while (0); | ||||
| 74 | len += r; | ||||
| 75 | } | ||||
| 76 | |||||
| 77 | if (in_range) { | ||||
| 78 | if (!GREEDY_REALLOC(str, allocated, len + 2 + 2 * DECIMAL_STR_MAX(int))greedy_realloc((void**) &(str), &(allocated), (len + 2 + 2 * (2+(sizeof(int) <= 1 ? 3 : sizeof(int) <= 2 ? 5 : sizeof(int) <= 4 ? 10 : sizeof(int) <= 8 ? 20 : sizeof (int[-2*(sizeof(int) > 8)])))), sizeof((str)[0]))) | ||||
| 79 | return NULL((void*)0); | ||||
| 80 | |||||
| 81 | if (range_end > range_start) | ||||
| 82 | r = sprintf(str + len, len > 0 ? " %d-%d" : "%d-%d", range_start, range_end); | ||||
| 83 | else | ||||
| 84 | r = sprintf(str + len, len > 0 ? " %d" : "%d", range_start); | ||||
| 85 | assert_se(r > 0)do { if ((__builtin_expect(!!(!(r > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("r > 0"), "../src/basic/cpu-set-util.c" , 85, __PRETTY_FUNCTION__); } while (0); | ||||
| 86 | } | ||||
| 87 | |||||
| 88 | return TAKE_PTR(str)({ typeof(str) _ptr_ = (str); (str) = ((void*)0); _ptr_; }) ?: strdup(""); | ||||
| 89 | } | ||||
| 90 | |||||
| 91 | /* XXX(msekleta): this is the workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1819152, remove in 8.3 */ | ||||
| 92 | char *cpu_set_to_range_string_kernel(const CPUSet *set) { | ||||
| 93 | unsigned range_start = 0, range_end; | ||||
| 94 | _cleanup_free___attribute__((cleanup(freep))) char *str = NULL((void*)0); | ||||
| 95 | size_t allocated = 0, len = 0; | ||||
| 96 | bool_Bool in_range = false0; | ||||
| 97 | int r; | ||||
| 98 | |||||
| 99 | for (unsigned i = 0; i < set->allocated * 8; i++) | ||||
| 100 | if (CPU_ISSET_S(i, set->allocated, set->set)(__extension__ ({ size_t __cpu = (i); __cpu / 8 < (set-> allocated) ? ((((const __cpu_mask *) ((set->set)->__bits ))[((__cpu) / (8 * sizeof (__cpu_mask)))] & ((__cpu_mask) 1 << ((__cpu) % (8 * sizeof (__cpu_mask)))))) != 0 : 0 ; }))) { | ||||
| 101 | if (in_range) | ||||
| 102 | range_end++; | ||||
| 103 | else { | ||||
| 104 | range_start = range_end = i; | ||||
| 105 | in_range = true1; | ||||
| 106 | } | ||||
| 107 | } else if (in_range) { | ||||
| 108 | in_range = false0; | ||||
| 109 | |||||
| 110 | if (!GREEDY_REALLOC(str, allocated, len + 2 + 2 * DECIMAL_STR_MAX(unsigned))greedy_realloc((void**) &(str), &(allocated), (len + 2 + 2 * (2+(sizeof(unsigned) <= 1 ? 3 : sizeof(unsigned) <= 2 ? 5 : sizeof(unsigned) <= 4 ? 10 : sizeof(unsigned) <= 8 ? 20 : sizeof(int[-2*(sizeof(unsigned) > 8)])))), sizeof ((str)[0]))) | ||||
| 111 | return NULL((void*)0); | ||||
| 112 | |||||
| 113 | if (range_end > range_start) | ||||
| 114 | r = sprintf(str + len, len > 0 ? ",%d-%d" : "%d-%d", range_start, range_end); | ||||
| 115 | else | ||||
| 116 | r = sprintf(str + len, len > 0 ? ",%d" : "%d", range_start); | ||||
| 117 | assert_se(r > 0)do { if ((__builtin_expect(!!(!(r > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("r > 0"), "../src/basic/cpu-set-util.c" , 117, __PRETTY_FUNCTION__); } while (0); | ||||
| 118 | len += r; | ||||
| 119 | } | ||||
| 120 | |||||
| 121 | if (in_range) { | ||||
| 122 | if (!GREEDY_REALLOC(str, allocated, len + 2 + 2 * DECIMAL_STR_MAX(int))greedy_realloc((void**) &(str), &(allocated), (len + 2 + 2 * (2+(sizeof(int) <= 1 ? 3 : sizeof(int) <= 2 ? 5 : sizeof(int) <= 4 ? 10 : sizeof(int) <= 8 ? 20 : sizeof (int[-2*(sizeof(int) > 8)])))), sizeof((str)[0]))) | ||||
| 123 | return NULL((void*)0); | ||||
| 124 | |||||
| 125 | if (range_end > range_start) | ||||
| 126 | r = sprintf(str + len, len > 0 ? ",%d-%d" : "%d-%d", range_start, range_end); | ||||
| 127 | else | ||||
| 128 | r = sprintf(str + len, len > 0 ? ",%d" : "%d", range_start); | ||||
| 129 | assert_se(r > 0)do { if ((__builtin_expect(!!(!(r > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("r > 0"), "../src/basic/cpu-set-util.c" , 129, __PRETTY_FUNCTION__); } while (0); | ||||
| 130 | } | ||||
| 131 | |||||
| 132 | return TAKE_PTR(str)({ typeof(str) _ptr_ = (str); (str) = ((void*)0); _ptr_; }) ?: strdup(""); | ||||
| 133 | } | ||||
| 134 | |||||
| 135 | |||||
| 136 | int cpu_set_realloc(CPUSet *cpu_set, unsigned ncpus) { | ||||
| 137 | size_t need; | ||||
| 138 | |||||
| 139 | assert(cpu_set)do { if ((__builtin_expect(!!(!(cpu_set)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("cpu_set"), "../src/basic/cpu-set-util.c" , 139, __PRETTY_FUNCTION__); } while (0); | ||||
| 140 | |||||
| 141 | need = CPU_ALLOC_SIZE(ncpus)((((ncpus) + (8 * sizeof (__cpu_mask)) - 1) / (8 * sizeof (__cpu_mask ))) * sizeof (__cpu_mask)); | ||||
| 142 | if (need
| ||||
| 143 | cpu_set_t *t; | ||||
| 144 | |||||
| 145 | t = realloc(cpu_set->set, need); | ||||
| 146 | if (!t) | ||||
| 147 | return -ENOMEM12; | ||||
| 148 | |||||
| 149 | memzero((uint8_t*) t + cpu_set->allocated, need - cpu_set->allocated)({ size_t _l_ = (need - cpu_set->allocated); void *_x_ = ( (uint8_t*) t + cpu_set->allocated); _l_ == 0 ? _x_ : memset (_x_, 0, _l_); }); | ||||
| 150 | |||||
| 151 | cpu_set->set = t; | ||||
| 152 | cpu_set->allocated = need; | ||||
| 153 | } | ||||
| 154 | |||||
| 155 | return 0; | ||||
| 156 | } | ||||
| 157 | |||||
| 158 | static int cpu_set_add(CPUSet *cpu_set, unsigned cpu) { | ||||
| 159 | int r; | ||||
| 160 | |||||
| 161 | if (cpu >= 8192) | ||||
| 162 | /* As of kernel 5.1, CONFIG_NR_CPUS can be set to 8192 on PowerPC */ | ||||
| 163 | return -ERANGE34; | ||||
| 164 | |||||
| 165 | r = cpu_set_realloc(cpu_set, cpu + 1); | ||||
| 166 | if (r < 0) | ||||
| 167 | return r; | ||||
| 168 | |||||
| 169 | CPU_SET_S(cpu, cpu_set->allocated, cpu_set->set)(__extension__ ({ size_t __cpu = (cpu); __cpu / 8 < (cpu_set ->allocated) ? (((__cpu_mask *) ((cpu_set->set)->__bits ))[((__cpu) / (8 * sizeof (__cpu_mask)))] |= ((__cpu_mask) 1 << ((__cpu) % (8 * sizeof (__cpu_mask))))) : 0; })); | ||||
| 170 | return 0; | ||||
| 171 | } | ||||
| 172 | |||||
| 173 | int cpu_set_add_all(CPUSet *a, const CPUSet *b) { | ||||
| 174 | int r; | ||||
| 175 | |||||
| 176 | /* Do this backwards, so if we fail, we fail before changing anything. */ | ||||
| 177 | for (unsigned cpu_p1 = b->allocated * 8; cpu_p1 > 0; cpu_p1--) | ||||
| 178 | if (CPU_ISSET_S(cpu_p1 - 1, b->allocated, b->set)(__extension__ ({ size_t __cpu = (cpu_p1 - 1); __cpu / 8 < (b->allocated) ? ((((const __cpu_mask *) ((b->set)-> __bits))[((__cpu) / (8 * sizeof (__cpu_mask)))] & ((__cpu_mask ) 1 << ((__cpu) % (8 * sizeof (__cpu_mask)))))) != 0 : 0 ; }))) { | ||||
| 179 | r = cpu_set_add(a, cpu_p1 - 1); | ||||
| 180 | if (r < 0) | ||||
| 181 | return r; | ||||
| 182 | } | ||||
| 183 | |||||
| 184 | return 1; | ||||
| 185 | } | ||||
| 186 | |||||
| 187 | int parse_cpu_set_full( | ||||
| 188 | const char *rvalue, | ||||
| 189 | CPUSet *cpu_set, | ||||
| 190 | bool_Bool warn, | ||||
| 191 | const char *unit, | ||||
| 192 | const char *filename, | ||||
| 193 | unsigned line, | ||||
| 194 | const char *lvalue) { | ||||
| 195 | |||||
| 196 | _cleanup_(cpu_set_reset)__attribute__((cleanup(cpu_set_reset))) CPUSet c = {}; | ||||
| 197 | const char *p = rvalue; | ||||
| 198 | |||||
| 199 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/basic/cpu-set-util.c", 199 , __PRETTY_FUNCTION__); } while (0); | ||||
| 200 | |||||
| 201 | for (;;) { | ||||
| 202 | _cleanup_free___attribute__((cleanup(freep))) char *word = NULL((void*)0); | ||||
| 203 | unsigned cpu_lower, cpu_upper; | ||||
| 204 | int r; | ||||
| 205 | |||||
| 206 | r = extract_first_word(&p, &word, WHITESPACE" \t\n\r" ",", EXTRACT_QUOTES); | ||||
| 207 | if (r == -ENOMEM12) | ||||
| 208 | return warn ? log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/basic/cpu-set-util.c" , 208, __func__) : -ENOMEM12; | ||||
| |||||
| 209 | if (r < 0) | ||||
| 210 | return warn ? log_syntax(unit, LOG_ERR, filename, line, r, "Invalid value for %s: %s", lvalue, rvalue)({ int _level = (3), _e = (r); (log_get_max_level_realm(LOG_REALM_SYSTEMD ) >= ((_level) & 0x07)) ? log_syntax_internal(unit, _level , filename, line, _e, "../src/basic/cpu-set-util.c", 210, __func__ , "Invalid value for %s: %s", lvalue, rvalue) : -abs(_e); }) : r; | ||||
| 211 | if (r == 0) | ||||
| 212 | break; | ||||
| 213 | |||||
| 214 | r = parse_range(word, &cpu_lower, &cpu_upper); | ||||
| 215 | if (r < 0) | ||||
| 216 | return warn ? log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU affinity '%s'", word)({ int _level = (3), _e = (r); (log_get_max_level_realm(LOG_REALM_SYSTEMD ) >= ((_level) & 0x07)) ? log_syntax_internal(unit, _level , filename, line, _e, "../src/basic/cpu-set-util.c", 216, __func__ , "Failed to parse CPU affinity '%s'", word) : -abs(_e); }) : r; | ||||
| 217 | |||||
| 218 | if (cpu_lower > cpu_upper) { | ||||
| 219 | if (warn
| ||||
| 220 | log_syntax(unit, LOG_WARNING, filename, line, 0, "Range '%s' is invalid, %u > %u, ignoring.",({ int _level = (4), _e = (0); (log_get_max_level_realm(LOG_REALM_SYSTEMD ) >= ((_level) & 0x07)) ? log_syntax_internal(unit, _level , filename, line, _e, "../src/basic/cpu-set-util.c", 221, __func__ , "Range '%s' is invalid, %u > %u, ignoring.", word, cpu_lower , cpu_upper) : -abs(_e); }) | ||||
| 221 | word, cpu_lower, cpu_upper)({ int _level = (4), _e = (0); (log_get_max_level_realm(LOG_REALM_SYSTEMD ) >= ((_level) & 0x07)) ? log_syntax_internal(unit, _level , filename, line, _e, "../src/basic/cpu-set-util.c", 221, __func__ , "Range '%s' is invalid, %u > %u, ignoring.", word, cpu_lower , cpu_upper) : -abs(_e); }); | ||||
| 222 | |||||
| 223 | /* Make sure something is allocated, to distinguish this from the empty case */ | ||||
| 224 | r = cpu_set_realloc(&c, 1); | ||||
| 225 | if (r
| ||||
| 226 | return r; | ||||
| 227 | } | ||||
| 228 | |||||
| 229 | for (unsigned cpu_p1 = MIN(cpu_upper, UINT_MAX-1)__extension__ ({ const typeof((cpu_upper)) __unique_prefix_A12 = ((cpu_upper)); const typeof(((2147483647 *2U +1U)-1)) __unique_prefix_B13 = (((2147483647 *2U +1U)-1)); __unique_prefix_A12 < __unique_prefix_B13 ? __unique_prefix_A12 : __unique_prefix_B13; }) + 1; cpu_p1 > cpu_lower; cpu_p1--) { | ||||
| 230 | r = cpu_set_add(&c, cpu_p1 - 1); | ||||
| 231 | if (r < 0) | ||||
| 232 | return warn ? log_syntax(unit, LOG_ERR, filename, line, r,({ int _level = (3), _e = (r); (log_get_max_level_realm(LOG_REALM_SYSTEMD ) >= ((_level) & 0x07)) ? log_syntax_internal(unit, _level , filename, line, _e, "../src/basic/cpu-set-util.c", 233, __func__ , "Cannot add CPU %u to set: %m", cpu_p1 - 1) : -abs(_e); }) | ||||
| 233 | "Cannot add CPU %u to set: %m", cpu_p1 - 1)({ int _level = (3), _e = (r); (log_get_max_level_realm(LOG_REALM_SYSTEMD ) >= ((_level) & 0x07)) ? log_syntax_internal(unit, _level , filename, line, _e, "../src/basic/cpu-set-util.c", 233, __func__ , "Cannot add CPU %u to set: %m", cpu_p1 - 1) : -abs(_e); }) : r; | ||||
| 234 | } | ||||
| 235 | } | ||||
| 236 | |||||
| 237 | /* On success, transfer ownership to the output variable */ | ||||
| 238 | *cpu_set = c; | ||||
| 239 | c = (CPUSet) {}; | ||||
| 240 | |||||
| 241 | return 0; | ||||
| 242 | } | ||||
| 243 | |||||
| 244 | int parse_cpu_set_extend( | ||||
| 245 | const char *rvalue, | ||||
| 246 | CPUSet *old, | ||||
| 247 | bool_Bool warn, | ||||
| 248 | const char *unit, | ||||
| 249 | const char *filename, | ||||
| 250 | unsigned line, | ||||
| 251 | const char *lvalue) { | ||||
| 252 | |||||
| 253 | _cleanup_(cpu_set_reset)__attribute__((cleanup(cpu_set_reset))) CPUSet cpuset = {}; | ||||
| 254 | int r; | ||||
| 255 | |||||
| 256 | r = parse_cpu_set_full(rvalue, &cpuset, true1, unit, filename, line, lvalue); | ||||
| 257 | if (r < 0) | ||||
| 258 | return r; | ||||
| 259 | |||||
| 260 | if (!cpuset.set) { | ||||
| 261 | /* An empty assignment resets the CPU list */ | ||||
| 262 | cpu_set_reset(old); | ||||
| 263 | return 0; | ||||
| 264 | } | ||||
| 265 | |||||
| 266 | if (!old->set) { | ||||
| 267 | *old = cpuset; | ||||
| 268 | cpuset = (CPUSet) {}; | ||||
| 269 | return 1; | ||||
| 270 | } | ||||
| 271 | |||||
| 272 | return cpu_set_add_all(old, &cpuset); | ||||
| 273 | } | ||||
| 274 | |||||
| 275 | int cpus_in_affinity_mask(void) { | ||||
| 276 | size_t n = 16; | ||||
| 277 | int r; | ||||
| 278 | |||||
| 279 | for (;;) { | ||||
| 280 | cpu_set_t *c; | ||||
| 281 | |||||
| 282 | c = CPU_ALLOC(n)__sched_cpualloc (n); | ||||
| 283 | if (!c) | ||||
| 284 | return -ENOMEM12; | ||||
| 285 | |||||
| 286 | if (sched_getaffinity(0, CPU_ALLOC_SIZE(n)((((n) + (8 * sizeof (__cpu_mask)) - 1) / (8 * sizeof (__cpu_mask ))) * sizeof (__cpu_mask)), c) >= 0) { | ||||
| 287 | int k; | ||||
| 288 | |||||
| 289 | k = CPU_COUNT_S(CPU_ALLOC_SIZE(n), c)__sched_cpucount (((((n) + (8 * sizeof (__cpu_mask)) - 1) / ( 8 * sizeof (__cpu_mask))) * sizeof (__cpu_mask)), c); | ||||
| 290 | CPU_FREE(c)__sched_cpufree (c); | ||||
| 291 | |||||
| 292 | if (k <= 0) | ||||
| 293 | return -EINVAL22; | ||||
| 294 | |||||
| 295 | return k; | ||||
| 296 | } | ||||
| 297 | |||||
| 298 | r = -errno(*__errno_location ()); | ||||
| 299 | CPU_FREE(c)__sched_cpufree (c); | ||||
| 300 | |||||
| 301 | if (r != -EINVAL22) | ||||
| 302 | return r; | ||||
| 303 | if (n > SIZE_MAX(18446744073709551615UL)/2) | ||||
| 304 | return -ENOMEM12; | ||||
| 305 | n *= 2; | ||||
| 306 | } | ||||
| 307 | } | ||||
| 308 | |||||
| 309 | int cpu_set_to_dbus(const CPUSet *set, uint8_t **ret, size_t *allocated) { | ||||
| 310 | uint8_t *out; | ||||
| 311 | |||||
| 312 | assert(set)do { if ((__builtin_expect(!!(!(set)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("set"), "../src/basic/cpu-set-util.c", 312 , __PRETTY_FUNCTION__); } while (0); | ||||
| 313 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/basic/cpu-set-util.c", 313 , __PRETTY_FUNCTION__); } while (0); | ||||
| 314 | |||||
| 315 | out = new0(uint8_t, set->allocated)((uint8_t*) calloc((set->allocated), sizeof(uint8_t))); | ||||
| 316 | if (!out) | ||||
| 317 | return -ENOMEM12; | ||||
| 318 | |||||
| 319 | for (unsigned cpu = 0; cpu < set->allocated * 8; cpu++) | ||||
| 320 | if (CPU_ISSET_S(cpu, set->allocated, set->set)(__extension__ ({ size_t __cpu = (cpu); __cpu / 8 < (set-> allocated) ? ((((const __cpu_mask *) ((set->set)->__bits ))[((__cpu) / (8 * sizeof (__cpu_mask)))] & ((__cpu_mask) 1 << ((__cpu) % (8 * sizeof (__cpu_mask)))))) != 0 : 0 ; }))) | ||||
| 321 | out[cpu / 8] |= 1u << (cpu % 8); | ||||
| 322 | |||||
| 323 | *ret = out; | ||||
| 324 | *allocated = set->allocated; | ||||
| 325 | return 0; | ||||
| 326 | } | ||||
| 327 | |||||
| 328 | int cpu_set_from_dbus(const uint8_t *bits, size_t size, CPUSet *set) { | ||||
| 329 | _cleanup_(cpu_set_reset)__attribute__((cleanup(cpu_set_reset))) CPUSet s = {}; | ||||
| 330 | int r; | ||||
| 331 | |||||
| 332 | assert(bits)do { if ((__builtin_expect(!!(!(bits)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("bits"), "../src/basic/cpu-set-util.c", 332 , __PRETTY_FUNCTION__); } while (0); | ||||
| 333 | assert(set)do { if ((__builtin_expect(!!(!(set)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("set"), "../src/basic/cpu-set-util.c", 333 , __PRETTY_FUNCTION__); } while (0); | ||||
| 334 | |||||
| 335 | for (unsigned cpu = size * 8; cpu > 0; cpu--) | ||||
| 336 | if (bits[(cpu - 1) / 8] & (1u << ((cpu - 1) % 8))) { | ||||
| 337 | r = cpu_set_add(&s, cpu - 1); | ||||
| 338 | if (r < 0) | ||||
| 339 | return r; | ||||
| 340 | } | ||||
| 341 | |||||
| 342 | *set = s; | ||||
| 343 | s = (CPUSet) {}; | ||||
| 344 | return 0; | ||||
| 345 | } | ||||
| 346 | |||||
| 347 | bool_Bool numa_policy_is_valid(const NUMAPolicy *policy) { | ||||
| 348 | assert(policy)do { if ((__builtin_expect(!!(!(policy)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("policy"), "../src/basic/cpu-set-util.c" , 348, __PRETTY_FUNCTION__); } while (0); | ||||
| 349 | |||||
| 350 | if (!mpol_is_valid(numa_policy_get_type(policy))) | ||||
| 351 | return false0; | ||||
| 352 | |||||
| 353 | if (!policy->nodes.set && | ||||
| 354 | !IN_SET(numa_policy_get_type(policy), MPOL_DEFAULT, MPOL_LOCAL, MPOL_PREFERRED)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){MPOL_DEFAULT, MPOL_LOCAL, MPOL_PREFERRED })/sizeof(int)]; switch(numa_policy_get_type(policy)) { case MPOL_DEFAULT : case MPOL_LOCAL: case MPOL_PREFERRED: _found = 1; break; default : break; } _found; })) | ||||
| 355 | return false0; | ||||
| 356 | |||||
| 357 | if (policy->nodes.set && | ||||
| 358 | numa_policy_get_type(policy) == MPOL_PREFERRED && | ||||
| 359 | CPU_COUNT_S(policy->nodes.allocated, policy->nodes.set)__sched_cpucount (policy->nodes.allocated, policy->nodes .set) != 1) | ||||
| 360 | return false0; | ||||
| 361 | |||||
| 362 | return true1; | ||||
| 363 | } | ||||
| 364 | |||||
| 365 | static int numa_policy_to_mempolicy(const NUMAPolicy *policy, unsigned long *ret_maxnode, unsigned long **ret_nodes) { | ||||
| 366 | unsigned node, bits = 0, ulong_bits; | ||||
| 367 | _cleanup_free___attribute__((cleanup(freep))) unsigned long *out = NULL((void*)0); | ||||
| 368 | |||||
| 369 | assert(policy)do { if ((__builtin_expect(!!(!(policy)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("policy"), "../src/basic/cpu-set-util.c" , 369, __PRETTY_FUNCTION__); } while (0); | ||||
| 370 | assert(ret_maxnode)do { if ((__builtin_expect(!!(!(ret_maxnode)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret_maxnode"), "../src/basic/cpu-set-util.c" , 370, __PRETTY_FUNCTION__); } while (0); | ||||
| 371 | assert(ret_nodes)do { if ((__builtin_expect(!!(!(ret_nodes)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret_nodes"), "../src/basic/cpu-set-util.c" , 371, __PRETTY_FUNCTION__); } while (0); | ||||
| 372 | |||||
| 373 | if (IN_SET(numa_policy_get_type(policy), MPOL_DEFAULT, MPOL_LOCAL)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){MPOL_DEFAULT, MPOL_LOCAL})/sizeof(int)]; switch(numa_policy_get_type(policy)) { case MPOL_DEFAULT: case MPOL_LOCAL: _found = 1; break; default: break; } _found; }) || | ||||
| 374 | (numa_policy_get_type(policy) == MPOL_PREFERRED && !policy->nodes.set)) { | ||||
| 375 | *ret_nodes = NULL((void*)0); | ||||
| 376 | *ret_maxnode = 0; | ||||
| 377 | return 0; | ||||
| 378 | } | ||||
| 379 | |||||
| 380 | bits = policy->nodes.allocated * 8; | ||||
| 381 | ulong_bits = sizeof(unsigned long) * 8; | ||||
| 382 | |||||
| 383 | out = new0(unsigned long, DIV_ROUND_UP(policy->nodes.allocated, sizeof(unsigned long)))((unsigned long*) calloc((({ const typeof((policy->nodes.allocated )) __unique_prefix_X14 = ((policy->nodes.allocated)); const typeof((sizeof(unsigned long))) __unique_prefix_Y15 = ((sizeof (unsigned long))); (__unique_prefix_X14 / __unique_prefix_Y15 + !!(__unique_prefix_X14 % __unique_prefix_Y15)); })), sizeof (unsigned long))); | ||||
| 384 | if (!out) | ||||
| 385 | return -ENOMEM12; | ||||
| 386 | |||||
| 387 | /* We don't make any assumptions about internal type libc is using to store NUMA node mask. | ||||
| 388 | Hence we need to convert the node mask to the representation expected by set_mempolicy() */ | ||||
| 389 | for (node = 0; node < bits; node++) | ||||
| 390 | if (CPU_ISSET_S(node, policy->nodes.allocated, policy->nodes.set)(__extension__ ({ size_t __cpu = (node); __cpu / 8 < (policy ->nodes.allocated) ? ((((const __cpu_mask *) ((policy-> nodes.set)->__bits))[((__cpu) / (8 * sizeof (__cpu_mask))) ] & ((__cpu_mask) 1 << ((__cpu) % (8 * sizeof (__cpu_mask )))))) != 0 : 0; }))) | ||||
| 391 | out[node / ulong_bits] |= 1ul << (node % ulong_bits); | ||||
| 392 | |||||
| 393 | *ret_nodes = TAKE_PTR(out)({ typeof(out) _ptr_ = (out); (out) = ((void*)0); _ptr_; }); | ||||
| 394 | *ret_maxnode = bits + 1; | ||||
| 395 | return 0; | ||||
| 396 | } | ||||
| 397 | |||||
| 398 | int apply_numa_policy(const NUMAPolicy *policy) { | ||||
| 399 | int r; | ||||
| 400 | _cleanup_free___attribute__((cleanup(freep))) unsigned long *nodes = NULL((void*)0); | ||||
| 401 | unsigned long maxnode; | ||||
| 402 | |||||
| 403 | assert(policy)do { if ((__builtin_expect(!!(!(policy)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("policy"), "../src/basic/cpu-set-util.c" , 403, __PRETTY_FUNCTION__); } while (0); | ||||
| 404 | |||||
| 405 | if (get_mempolicymissing_get_mempolicy(NULL((void*)0), NULL((void*)0), 0, 0, 0) < 0 && errno(*__errno_location ()) == ENOSYS38) | ||||
| 406 | return -EOPNOTSUPP95; | ||||
| 407 | |||||
| 408 | if (!numa_policy_is_valid(policy)) | ||||
| 409 | return -EINVAL22; | ||||
| 410 | |||||
| 411 | r = numa_policy_to_mempolicy(policy, &maxnode, &nodes); | ||||
| 412 | if (r < 0) | ||||
| 413 | return r; | ||||
| 414 | |||||
| 415 | r = set_mempolicymissing_set_mempolicy(numa_policy_get_type(policy), nodes, maxnode); | ||||
| 416 | if (r < 0) | ||||
| 417 | return -errno(*__errno_location ()); | ||||
| 418 | |||||
| 419 | return 0; | ||||
| 420 | } | ||||
| 421 | |||||
| 422 | int numa_to_cpu_set(const NUMAPolicy *policy, CPUSet *ret) { | ||||
| 423 | int r; | ||||
| 424 | size_t i; | ||||
| 425 | _cleanup_(cpu_set_reset)__attribute__((cleanup(cpu_set_reset))) CPUSet s = {}; | ||||
| 426 | |||||
| 427 | assert(policy)do { if ((__builtin_expect(!!(!(policy)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("policy"), "../src/basic/cpu-set-util.c" , 427, __PRETTY_FUNCTION__); } while (0); | ||||
| |||||
| 428 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/basic/cpu-set-util.c", 428 , __PRETTY_FUNCTION__); } while (0); | ||||
| 429 | |||||
| 430 | for (i = 0; i < policy->nodes.allocated * 8; i++) { | ||||
| 431 | _cleanup_free___attribute__((cleanup(freep))) char *l = NULL((void*)0); | ||||
| 432 | char p[STRLEN("/sys/devices/system/node/node//cpulist")(sizeof("""/sys/devices/system/node/node//cpulist""") - 1) + DECIMAL_STR_MAX(size_t)(2+(sizeof(size_t) <= 1 ? 3 : sizeof(size_t) <= 2 ? 5 : sizeof(size_t) <= 4 ? 10 : sizeof(size_t) <= 8 ? 20 : sizeof (int[-2*(sizeof(size_t) > 8)]))) + 1]; | ||||
| 433 | _cleanup_(cpu_set_reset)__attribute__((cleanup(cpu_set_reset))) CPUSet part = {}; | ||||
| 434 | |||||
| 435 | if (!CPU_ISSET_S(i, policy->nodes.allocated, policy->nodes.set)(__extension__ ({ size_t __cpu = (i); __cpu / 8 < (policy-> nodes.allocated) ? ((((const __cpu_mask *) ((policy->nodes .set)->__bits))[((__cpu) / (8 * sizeof (__cpu_mask)))] & ((__cpu_mask) 1 << ((__cpu) % (8 * sizeof (__cpu_mask) ))))) != 0 : 0; }))) | ||||
| 436 | continue; | ||||
| 437 | |||||
| 438 | xsprintf(p, "/sys/devices/system/node/node%zu/cpulist", i)do { if ((__builtin_expect(!!(!(((size_t) snprintf(p, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (p), typeof(&*(p))), sizeof(p)/sizeof((p)[0]), ((void)0)) ), "/sys/devices/system/node/node%zu/cpulist", i) < (__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (p), typeof(&*(p))), sizeof(p)/sizeof((p)[0]), ((void)0)) ))))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("xsprintf: " "p" "[] must be big enough"), "../src/basic/cpu-set-util.c", 438, __PRETTY_FUNCTION__); } while (0); | ||||
| 439 | |||||
| 440 | r = read_one_line_file(p, &l); | ||||
| 441 | if (r < 0) | ||||
| 442 | return r; | ||||
| 443 | |||||
| 444 | r = parse_cpu_set(l, &part); | ||||
| 445 | if (r < 0) | ||||
| 446 | return r; | ||||
| 447 | |||||
| 448 | r = cpu_set_add_all(&s, &part); | ||||
| 449 | if (r < 0) | ||||
| 450 | return r; | ||||
| 451 | } | ||||
| 452 | |||||
| 453 | *ret = s; | ||||
| 454 | s = (CPUSet) {}; | ||||
| 455 | |||||
| 456 | return 0; | ||||
| 457 | } | ||||
| 458 | |||||
| 459 | static const char* const mpol_table[] = { | ||||
| 460 | [MPOL_DEFAULT] = "default", | ||||
| 461 | [MPOL_PREFERRED] = "preferred", | ||||
| 462 | [MPOL_BIND] = "bind", | ||||
| 463 | [MPOL_INTERLEAVE] = "interleave", | ||||
| 464 | [MPOL_LOCAL] = "local", | ||||
| 465 | }; | ||||
| 466 | |||||
| 467 | DEFINE_STRING_TABLE_LOOKUP(mpol, int)const char *mpol_to_string(int i) { if (i < 0 || i >= ( int) __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(mpol_table), typeof(&*(mpol_table))), sizeof(mpol_table )/sizeof((mpol_table)[0]), ((void)0)))) return ((void*)0); return mpol_table[i]; } int mpol_from_string(const char *s) { return (int) string_table_lookup(mpol_table, __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(mpol_table), typeof(& *(mpol_table))), sizeof(mpol_table)/sizeof((mpol_table)[0]), ( (void)0))), s); }; |
| 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
| 2 | #pragma once |
| 3 | |
| 4 | /*** |
| 5 | Copyright © 2015 Filipe Brandenburger |
| 6 | ***/ |
| 7 | |
| 8 | #include <sched.h> |
| 9 | |
| 10 | #include "macro.h" |
| 11 | #include "missing.h" |
| 12 | |
| 13 | /* This wraps the libc interface with a variable to keep the allocated size. */ |
| 14 | typedef struct CPUSet { |
| 15 | cpu_set_t *set; |
| 16 | size_t allocated; /* in bytes */ |
| 17 | } CPUSet; |
| 18 | |
| 19 | static inline void cpu_set_reset(CPUSet *a) { |
| 20 | assert((a->allocated > 0) == !!a->set)do { if ((__builtin_expect(!!(!((a->allocated > 0) == ! !a->set)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ( "(a->allocated > 0) == !!a->set"), "../src/basic/cpu-set-util.h" , 20, __PRETTY_FUNCTION__); } while (0); |
| 21 | if (a->set) |
| 22 | CPU_FREE(a->set)__sched_cpufree (a->set); |
| 23 | *a = (CPUSet) {}; |
| 24 | } |
| 25 | |
| 26 | int cpu_set_add_all(CPUSet *a, const CPUSet *b); |
| 27 | |
| 28 | char* cpu_set_to_string(const CPUSet *a); |
| 29 | char *cpu_set_to_range_string(const CPUSet *a); |
| 30 | char *cpu_set_to_range_string_kernel(const CPUSet *a); |
| 31 | int cpu_set_realloc(CPUSet *cpu_set, unsigned ncpus); |
| 32 | |
| 33 | int parse_cpu_set_full( |
| 34 | const char *rvalue, |
| 35 | CPUSet *cpu_set, |
| 36 | bool_Bool warn, |
| 37 | const char *unit, |
| 38 | const char *filename, unsigned line, |
| 39 | const char *lvalue); |
| 40 | int parse_cpu_set_extend( |
| 41 | const char *rvalue, |
| 42 | CPUSet *old, |
| 43 | bool_Bool warn, |
| 44 | const char *unit, |
| 45 | const char *filename, |
| 46 | unsigned line, |
| 47 | const char *lvalue); |
| 48 | |
| 49 | static inline int parse_cpu_set(const char *rvalue, CPUSet *cpu_set){ |
| 50 | return parse_cpu_set_full(rvalue, cpu_set, false0, NULL((void*)0), NULL((void*)0), 0, NULL((void*)0)); |
| 51 | } |
| 52 | |
| 53 | int cpu_set_to_dbus(const CPUSet *set, uint8_t **ret, size_t *allocated); |
| 54 | int cpu_set_from_dbus(const uint8_t *bits, size_t size, CPUSet *set); |
| 55 | |
| 56 | int cpus_in_affinity_mask(void); |
| 57 | |
| 58 | static inline bool_Bool mpol_is_valid(int t) { |
| 59 | return t >= MPOL_DEFAULT && t <= MPOL_LOCAL; |
| 60 | } |
| 61 | |
| 62 | typedef struct NUMAPolicy { |
| 63 | /* Always use numa_policy_get_type() to read the value */ |
| 64 | int type; |
| 65 | CPUSet nodes; |
| 66 | } NUMAPolicy; |
| 67 | |
| 68 | bool_Bool numa_policy_is_valid(const NUMAPolicy *p); |
| 69 | |
| 70 | static inline int numa_policy_get_type(const NUMAPolicy *p) { |
| 71 | return p->type < 0 ? (p->nodes.set ? MPOL_PREFERRED : -1) : p->type; |
| 72 | } |
| 73 | |
| 74 | static inline void numa_policy_reset(NUMAPolicy *p) { |
| 75 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/basic/cpu-set-util.h", 75, __PRETTY_FUNCTION__); } while (0); |
| 76 | cpu_set_reset(&p->nodes); |
| 77 | p->type = -1; |
| 78 | } |
| 79 | |
| 80 | int apply_numa_policy(const NUMAPolicy *policy); |
| 81 | int numa_to_cpu_set(const NUMAPolicy *policy, CPUSet *ret); |
| 82 | |
| 83 | const char* mpol_to_string(int i) _const___attribute__ ((const)); |
| 84 | int mpol_from_string(const char *s) _pure___attribute__ ((pure)); |