1 /*****************************************************************************\
2 * node_conf.c - partially manage the node records of slurm
3 * (see src/slurmctld/node_mgr.c for the set of functionalities
4 * related to slurmctld usage of nodes)
5 * Note: there is a global node table (node_record_table_ptr), its
6 * hash table (node_hash_table), time stamp (last_node_update) and
7 * configuration list (config_list)
8 *****************************************************************************
9 * Copyright (C) 2002-2007 The Regents of the University of California.
10 * Copyright (C) 2008-2010 Lawrence Livermore National Security.
11 * Copyright (C) 2010-2017 SchedMD LLC.
12 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
13 * Written by Morris Jette <jette1@llnl.gov> et. al.
14 * CODE-OCEC-09-009. All rights reserved.
15 *
16 * This file is part of Slurm, a resource management program.
17 * For details, see <https://slurm.schedmd.com/>.
18 * Please also read the included file: DISCLAIMER.
19 *
20 * Slurm is free software; you can redistribute it and/or modify it under
21 * the terms of the GNU General Public License as published by the Free
22 * Software Foundation; either version 2 of the License, or (at your option)
23 * any later version.
24 *
25 * In addition, as a special exception, the copyright holders give permission
26 * to link the code of portions of this program with the OpenSSL library under
27 * certain conditions as described in each individual source file, and
28 * distribute linked combinations including the two. You must obey the GNU
29 * General Public License in all respects for all of the code used other than
30 * OpenSSL. If you modify file(s) with this exception, you may extend this
31 * exception to your version of the file(s), but you are not obligated to do
32 * so. If you do not wish to do so, delete this exception statement from your
33 * version. If you delete this exception statement from all source files in
34 * the program, then also delete it here.
35 *
36 * Slurm is distributed in the hope that it will be useful, but WITHOUT ANY
37 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
38 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
39 * details.
40 *
41 * You should have received a copy of the GNU General Public License along
42 * with Slurm; if not, write to the Free Software Foundation, Inc.,
43 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
44 \*****************************************************************************/
45
46 #include "config.h"
47
48 #include <ctype.h>
49 #include <errno.h>
50 #include <fcntl.h>
51 #include <inttypes.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <sys/types.h>
56 #include <sys/stat.h>
57 #include <time.h>
58
59 #include "src/common/assoc_mgr.h"
60 #include "src/common/gres.h"
61 #include "src/common/hostlist.h"
62 #include "src/common/macros.h"
63 #include "src/common/node_select.h"
64 #include "src/common/pack.h"
65 #include "src/common/parse_time.h"
66 #include "src/common/read_config.h"
67 #include "src/common/slurm_accounting_storage.h"
68 #include "src/common/slurm_acct_gather_energy.h"
69 #include "src/common/slurm_ext_sensors.h"
70 #include "src/common/slurm_topology.h"
71 #include "src/common/xassert.h"
72 #include "src/common/xmalloc.h"
73 #include "src/common/xstring.h"
74
75 #define _DEBUG 0
76
77 strong_alias(init_node_conf, slurm_init_node_conf);
78 strong_alias(build_all_nodeline_info, slurm_build_all_nodeline_info);
79 strong_alias(rehash_node, slurm_rehash_node);
80 strong_alias(hostlist2bitmap, slurm_hostlist2bitmap);
81
82 /* Global variables */
83 List config_list = NULL; /* list of config_record entries */
84 List front_end_list = NULL; /* list of slurm_conf_frontend_t entries */
85 time_t last_node_update = (time_t) 0; /* time of last update */
86 node_record_t *node_record_table_ptr = NULL; /* node records */
87 xhash_t* node_hash_table = NULL;
88 int node_record_count = 0; /* count in node_record_table_ptr */
89 uint16_t *cr_node_num_cores = NULL;
90 uint32_t *cr_node_cores_offset = NULL;
91
92 /* Local function definitions */
93 static int _delete_config_record (void);
94 #if _DEBUG
95 static void _dump_hash (void);
96 #endif
97 static node_record_t *_find_node_record(char *name, bool test_alias,
98 bool log_missing);
99 static void _list_delete_config (void *config_entry);
100 static void _node_record_hash_identity (void* item, const char** key,
101 uint32_t* key_len);
102
103 /*
104 * _delete_config_record - delete all configuration records
105 * RET 0 if no error, errno otherwise
106 * global: config_list - list of all configuration records
107 */
_delete_config_record(void)108 static int _delete_config_record (void)
109 {
110 last_node_update = time (NULL);
111 list_flush(config_list);
112 list_flush(front_end_list);
113
114 return SLURM_SUCCESS;
115 }
116
117
118 #if _DEBUG
119 /*
120 * helper function used by _dump_hash to print the hash table elements
121 */
xhash_walk_helper_cbk(void * item,void * arg)122 static void xhash_walk_helper_cbk (void* item, void* arg)
123 {
124 static int i = 0; /* sequential walk, so just update a static i */
125 int inx;
126 node_record_t *node_ptr = (node_record_t *) item;
127
128 inx = node_ptr - node_record_table_ptr;
129 debug3("node_hash[%d]:%d(%s)", i++, inx, node_ptr->name);
130 }
131 /*
132 * _dump_hash - print the node_hash_table contents, used for debugging
133 * or analysis of hash technique
134 * global: node_record_table_ptr - pointer to global node table
135 * node_hash_table - table of hash indexes
136 */
_dump_hash(void)137 static void _dump_hash (void)
138 {
139 if (node_hash_table == NULL)
140 return;
141 debug2("node_hash: indexing %ld elements",
142 xhash_count(node_hash_table));
143 xhash_walk(node_hash_table, xhash_walk_helper_cbk, NULL);
144 }
145 #endif
146
147 /* _list_delete_config - delete an entry from the config list,
148 * see list.h for documentation */
_list_delete_config(void * config_entry)149 static void _list_delete_config (void *config_entry)
150 {
151 config_record_t *config_ptr = (config_record_t *) config_entry;
152
153 xassert(config_ptr);
154 xassert(config_ptr->magic == CONFIG_MAGIC);
155 xfree(config_ptr->cpu_spec_list);
156 xfree(config_ptr->feature);
157 xfree(config_ptr->gres);
158 xfree (config_ptr->nodes);
159 FREE_NULL_BITMAP (config_ptr->node_bitmap);
160 xfree(config_ptr->tres_weights);
161 xfree(config_ptr->tres_weights_str);
162 xfree (config_ptr);
163 }
164
165 /*
166 * xhash helper function to index node_record per name field
167 * in node_hash_table
168 */
_node_record_hash_identity(void * item,const char ** key,uint32_t * key_len)169 static void _node_record_hash_identity (void* item, const char** key,
170 uint32_t* key_len)
171 {
172 node_record_t *node_ptr = (node_record_t *) item;
173 *key = node_ptr->name;
174 *key_len = strlen(node_ptr->name);
175 }
176
177 /*
178 * bitmap2hostlist - given a bitmap, build a hostlist
179 * IN bitmap - bitmap pointer
180 * RET pointer to hostlist or NULL on error
181 * globals: node_record_table_ptr - pointer to node table
182 * NOTE: the caller must xfree the memory at node_list when no longer required
183 */
bitmap2hostlist(bitstr_t * bitmap)184 hostlist_t bitmap2hostlist (bitstr_t *bitmap)
185 {
186 int i, first, last;
187 hostlist_t hl;
188
189 if (bitmap == NULL)
190 return NULL;
191
192 first = bit_ffs(bitmap);
193 if (first == -1)
194 return NULL;
195
196 last = bit_fls(bitmap);
197 hl = hostlist_create(NULL);
198 for (i = first; i <= last; i++) {
199 if (bit_test(bitmap, i) == 0)
200 continue;
201 hostlist_push_host(hl, node_record_table_ptr[i].name);
202 }
203 return hl;
204
205 }
206
207 /*
208 * bitmap2node_name_sortable - given a bitmap, build a list of comma
209 * separated node names. names may include regular expressions
210 * (e.g. "lx[01-10]")
211 * IN bitmap - bitmap pointer
212 * IN sort - returned sorted list or not
213 * RET pointer to node list or NULL on error
214 * globals: node_record_table_ptr - pointer to node table
215 * NOTE: the caller must xfree the memory at node_list when no longer required
216 */
bitmap2node_name_sortable(bitstr_t * bitmap,bool sort)217 char * bitmap2node_name_sortable (bitstr_t *bitmap, bool sort)
218 {
219 hostlist_t hl;
220 char *buf;
221
222 hl = bitmap2hostlist (bitmap);
223 if (hl == NULL)
224 return xstrdup("");
225 if (sort)
226 hostlist_sort(hl);
227 buf = hostlist_ranged_string_xmalloc(hl);
228 hostlist_destroy(hl);
229 return buf;
230 }
231
232 /*
233 * bitmap2node_name - given a bitmap, build a list of sorted, comma
234 * separated node names. names may include regular expressions
235 * (e.g. "lx[01-10]")
236 * IN bitmap - bitmap pointer
237 * RET pointer to node list or NULL on error
238 * globals: node_record_table_ptr - pointer to node table
239 * NOTE: the caller must xfree the memory at node_list when no longer required
240 */
bitmap2node_name(bitstr_t * bitmap)241 char * bitmap2node_name (bitstr_t *bitmap)
242 {
243 return bitmap2node_name_sortable(bitmap, 1);
244 }
245
246 #ifdef HAVE_FRONT_END
247 /* Log the contents of a frontend record */
_dump_front_end(slurm_conf_frontend_t * fe_ptr)248 static void _dump_front_end(slurm_conf_frontend_t *fe_ptr)
249 {
250 info("fe name:%s addr:%s port:%u state:%u reason:%s "
251 "allow_groups:%s allow_users:%s "
252 "deny_groups:%s deny_users:%s",
253 fe_ptr->frontends, fe_ptr->addresses,
254 fe_ptr->port, fe_ptr->node_state, fe_ptr->reason,
255 fe_ptr->allow_groups, fe_ptr->allow_users,
256 fe_ptr->deny_groups, fe_ptr->deny_users);
257 }
258 #endif
259
260 /*
261 * build_all_frontend_info - get a array of slurm_conf_frontend_t structures
262 * from the slurm.conf reader, build table, and set values
263 * is_slurmd_context: set to true if run from slurmd
264 * RET 0 if no error, error code otherwise
265 */
build_all_frontend_info(bool is_slurmd_context)266 extern int build_all_frontend_info (bool is_slurmd_context)
267 {
268 slurm_conf_frontend_t **ptr_array;
269 #ifdef HAVE_FRONT_END
270 slurm_conf_frontend_t *fe_single, *fe_line;
271 int i, count, max_rc = SLURM_SUCCESS;
272 bool front_end_debug;
273
274 if (slurm_get_debug_flags() & DEBUG_FLAG_FRONT_END)
275 front_end_debug = true;
276 else
277 front_end_debug = false;
278 count = slurm_conf_frontend_array(&ptr_array);
279 if (count == 0)
280 fatal("No FrontendName information available!");
281
282 for (i = 0; i < count; i++) {
283 hostlist_t hl_name, hl_addr;
284 char *fe_name, *fe_addr;
285
286 fe_line = ptr_array[i];
287 hl_name = hostlist_create(fe_line->frontends);
288 if (hl_name == NULL)
289 fatal("Invalid FrontendName:%s", fe_line->frontends);
290 hl_addr = hostlist_create(fe_line->addresses);
291 if (hl_addr == NULL)
292 fatal("Invalid FrontendAddr:%s", fe_line->addresses);
293 if (hostlist_count(hl_name) != hostlist_count(hl_addr)) {
294 fatal("Inconsistent node count between "
295 "FrontendName(%s) and FrontendAddr(%s)",
296 fe_line->frontends, fe_line->addresses);
297 }
298 while ((fe_name = hostlist_shift(hl_name))) {
299 fe_addr = hostlist_shift(hl_addr);
300 fe_single = xmalloc(sizeof(slurm_conf_frontend_t));
301 list_append(front_end_list, fe_single);
302 fe_single->frontends = xstrdup(fe_name);
303 fe_single->addresses = xstrdup(fe_addr);
304 free(fe_name);
305 free(fe_addr);
306 if (fe_line->allow_groups && fe_line->allow_groups[0]) {
307 fe_single->allow_groups =
308 xstrdup(fe_line->allow_groups);
309 }
310 if (fe_line->allow_users && fe_line->allow_users[0]) {
311 fe_single->allow_users =
312 xstrdup(fe_line->allow_users);
313 }
314 if (fe_line->deny_groups && fe_line->deny_groups[0]) {
315 fe_single->deny_groups =
316 xstrdup(fe_line->deny_groups);
317 }
318 if (fe_line->deny_users && fe_line->deny_users[0]) {
319 fe_single->deny_users =
320 xstrdup(fe_line->deny_users);
321 }
322 fe_single->port = fe_line->port;
323 if (fe_line->reason && fe_line->reason[0])
324 fe_single->reason = xstrdup(fe_line->reason);
325 fe_single->node_state = fe_line->node_state;
326 if (front_end_debug && !is_slurmd_context)
327 _dump_front_end(fe_single);
328 }
329 hostlist_destroy(hl_addr);
330 hostlist_destroy(hl_name);
331 }
332 return max_rc;
333 #else
334 if (slurm_conf_frontend_array(&ptr_array) != 0)
335 fatal("FrontendName information configured!");
336 return SLURM_SUCCESS;
337 #endif
338 }
339
_check_callback(char * alias,char * hostname,char * address,char * bcast_address,uint16_t port,int state_val,slurm_conf_node_t * node_ptr,config_record_t * config_ptr)340 static void _check_callback(char *alias, char *hostname,
341 char *address, char *bcast_address,
342 uint16_t port, int state_val,
343 slurm_conf_node_t *node_ptr,
344 config_record_t *config_ptr)
345 {
346 node_record_t *node_rec;
347
348 if ((node_rec = find_node_record2(alias)))
349 fatal("Duplicated NodeHostName %s in config file", alias);
350
351 node_rec = create_node_record(config_ptr, alias);
352 if ((state_val != NO_VAL) &&
353 (state_val != NODE_STATE_UNKNOWN))
354 node_rec->node_state = state_val;
355 node_rec->last_response = (time_t) 0;
356 node_rec->comm_name = xstrdup(address);
357 node_rec->cpu_bind = node_ptr->cpu_bind;
358 node_rec->node_hostname = xstrdup(hostname);
359 node_rec->bcast_address = xstrdup(bcast_address);
360 node_rec->port = port;
361 node_rec->weight = node_ptr->weight;
362 node_rec->features = xstrdup(node_ptr->feature);
363 node_rec->reason = xstrdup(node_ptr->reason);
364 }
365
366 /*
367 * build_all_nodeline_info - get a array of slurm_conf_node_t structures
368 * from the slurm.conf reader, build table, and set values
369 * IN set_bitmap - if true then set node_bitmap in config record (used by
370 * slurmd), false is used by slurmctld and testsuite
371 * IN tres_cnt - number of TRES configured on system (used on controller side)
372 * RET 0 if no error, error code otherwise
373 */
build_all_nodeline_info(bool set_bitmap,int tres_cnt)374 extern int build_all_nodeline_info(bool set_bitmap, int tres_cnt)
375 {
376 slurm_conf_node_t *node, **ptr_array;
377 config_record_t *config_ptr = NULL;
378 int count;
379 int i, rc, max_rc = SLURM_SUCCESS;
380 bool in_daemon;
381 static bool daemon_run = false, daemon_set = false;
382
383 in_daemon = run_in_daemon(&daemon_run, &daemon_set, "slurmctld,slurmd");
384
385 count = slurm_conf_nodename_array(&ptr_array);
386 if (count == 0)
387 fatal("No NodeName information available!");
388
389 for (i = 0; i < count; i++) {
390 node = ptr_array[i];
391
392 config_ptr = create_config_record();
393 config_ptr->nodes = xstrdup(node->nodenames);
394 config_ptr->cpu_bind = node->cpu_bind;
395 config_ptr->cpus = node->cpus;
396 config_ptr->boards = node->boards;
397 config_ptr->sockets = node->sockets;
398 config_ptr->cores = node->cores;
399 config_ptr->core_spec_cnt = node->core_spec_cnt;
400 config_ptr->cpu_spec_list = xstrdup(node->cpu_spec_list);
401 config_ptr->threads = node->threads;
402 config_ptr->real_memory = node->real_memory;
403 config_ptr->mem_spec_limit = node->mem_spec_limit;
404 config_ptr->tmp_disk = node->tmp_disk;
405
406 if (tres_cnt) {
407 config_ptr->tres_weights_str =
408 xstrdup(node->tres_weights_str);
409 config_ptr->tres_weights =
410 slurm_get_tres_weight_array(
411 node->tres_weights_str,
412 tres_cnt, true);
413 }
414
415 config_ptr->weight = node->weight;
416 if (node->feature && node->feature[0])
417 config_ptr->feature = xstrdup(node->feature);
418 if (in_daemon) {
419 config_ptr->gres = gres_plugin_name_filter(node->gres,
420 node->nodenames);
421 }
422
423 rc = check_nodeline_info(node, config_ptr, LOG_LEVEL_FATAL,
424 _check_callback);
425 max_rc = MAX(max_rc, rc);
426 }
427
428 if (set_bitmap) {
429 ListIterator config_iterator;
430 config_iterator = list_iterator_create(config_list);
431 while ((config_ptr = list_next(config_iterator))) {
432 node_name2bitmap(config_ptr->nodes, true,
433 &config_ptr->node_bitmap);
434 }
435 list_iterator_destroy(config_iterator);
436 }
437
438 return max_rc;
439 }
440
441 /*
442 * check_nodeline_info - From the slurm.conf reader, build table,
443 * and set values
444 * RET 0 if no error, error code otherwise
445 * Note: Operates on common variables
446 * default_node_record - default node configuration values
447 */
check_nodeline_info(slurm_conf_node_t * node_ptr,config_record_t * config_ptr,log_level_t lvl,void (* _callback)(char * alias,char * hostname,char * address,char * bcast_address,uint16_t port,int state_val,slurm_conf_node_t * node_ptr,config_record_t * config_ptr))448 extern int check_nodeline_info(slurm_conf_node_t *node_ptr,
449 config_record_t *config_ptr,
450 log_level_t lvl,
451 void (*_callback) (
452 char *alias, char *hostname,
453 char *address, char *bcast_address,
454 uint16_t port, int state_val,
455 slurm_conf_node_t *node_ptr,
456 config_record_t *config_ptr))
457 {
458 int error_code = SLURM_SUCCESS;
459 hostlist_t address_list = NULL;
460 hostlist_t alias_list = NULL;
461 hostlist_t bcast_list = NULL;
462 hostlist_t hostname_list = NULL;
463 hostlist_t port_list = NULL;
464 char *address = NULL;
465 char *alias = NULL;
466 char *bcast_address = NULL;
467 char *hostname = NULL;
468 char *port_str = NULL;
469 int state_val = NODE_STATE_UNKNOWN;
470 int address_count, alias_count, bcast_count, hostname_count, port_count;
471 uint16_t port = 0;
472
473 if ((node_ptr->nodenames == NULL) || (node_ptr->nodenames[0] == '\0'))
474 return -1;
475
476 if (node_ptr->state != NULL) {
477 state_val = state_str2int(node_ptr->state, node_ptr->nodenames);
478 if (state_val == NO_VAL)
479 fatal("Invalid state %s from %s",
480 node_ptr->state, node_ptr->nodenames);
481 }
482
483 if (!(address_list = hostlist_create(node_ptr->addresses)))
484 fatal("Unable to create NodeAddr list from %s",
485 node_ptr->addresses);
486
487 if (!(alias_list = hostlist_create(node_ptr->nodenames)))
488 fatal("Unable to create NodeName list from %s",
489 node_ptr->nodenames);
490
491 if (!(bcast_list = hostlist_create(node_ptr->bcast_addresses)))
492 fatal("Unable to create BcastAddr list from %s",
493 node_ptr->bcast_addresses);
494
495 if (!(hostname_list = hostlist_create(node_ptr->hostnames)))
496 fatal("Unable to create NodeHostname list from %s",
497 node_ptr->hostnames);
498
499 if (node_ptr->port_str && node_ptr->port_str[0] &&
500 (node_ptr->port_str[0] != '[') &&
501 (strchr(node_ptr->port_str, '-') ||
502 strchr(node_ptr->port_str, ','))) {
503 xstrfmtcat(port_str, "[%s]", node_ptr->port_str);
504 port_list = hostlist_create(port_str);
505 xfree(port_str);
506 } else
507 port_list = hostlist_create(node_ptr->port_str);
508
509 if (!port_list)
510 fatal("Unable to create Port list from %s",
511 node_ptr->port_str);
512
513 /* some sanity checks */
514 address_count = hostlist_count(address_list);
515 bcast_count = hostlist_count(bcast_list);
516 alias_count = hostlist_count(alias_list);
517 hostname_count = hostlist_count(hostname_list);
518 port_count = hostlist_count(port_list);
519 #ifdef HAVE_FRONT_END
520 if ((hostname_count != alias_count) && (hostname_count != 1))
521 fatal("NodeHostname count must equal that of NodeName records of there must be no more than one");
522
523 if ((address_count != alias_count) && (address_count != 1))
524 fatal("NodeAddr count must equal that of NodeName records of there must be no more than one");
525 #else
526 #ifdef MULTIPLE_SLURMD
527 if ((address_count != alias_count) && (address_count != 1))
528 fatal("NodeAddr count must equal that of NodeName records of there must be no more than one");
529 if (bcast_count && (bcast_count != alias_count) && (bcast_count != 1))
530 fatal("BcastAddr count must equal that of NodeName records, or there must be no more than one");
531 #else
532 if (address_count < alias_count)
533 fatal("At least as many NodeAddr are required as NodeName");
534
535 if (bcast_count && (bcast_count < alias_count))
536 fatal("At least as many BcastAddr are required as NodeName");
537
538 if (hostname_count < alias_count)
539 fatal("At least as many NodeHostname are required as NodeName");
540 #endif /* MULTIPLE_SLURMD */
541 #endif /* HAVE_FRONT_END */
542 if ((port_count != alias_count) && (port_count > 1))
543 fatal("Port count must equal that of NodeName records or there must be no more than one (%u != %u)",
544 port_count, alias_count);
545
546 /* now build the individual node structures */
547 while ((alias = hostlist_shift(alias_list))) {
548 if (address_count > 0) {
549 address_count--;
550 if (address)
551 free(address);
552 address = hostlist_shift(address_list);
553 }
554 if (bcast_count > 0) {
555 bcast_count--;
556 if (bcast_address)
557 free(bcast_address);
558 bcast_address = hostlist_shift(bcast_list);
559 }
560 if (hostname_count > 0) {
561 hostname_count--;
562 if (hostname)
563 free(hostname);
564 hostname = hostlist_shift(hostname_list);
565 }
566 if (port_count > 0) {
567 int port_int;
568 port_count--;
569 if (port_str)
570 free(port_str);
571 port_str = hostlist_shift(port_list);
572 port_int = atoi(port_str);
573 if ((port_int <= 0) || (port_int > 0xffff)) {
574 log_var(lvl, "Invalid Port %s",
575 node_ptr->port_str);
576 }
577 port = port_int;
578 }
579
580 (*_callback)(alias, hostname, address, bcast_address,
581 port, state_val, node_ptr, config_ptr);
582
583 free(alias);
584 }
585 /* free allocated storage */
586 if (address)
587 free(address);
588 if (bcast_address)
589 free(bcast_address);
590 if (hostname)
591 free(hostname);
592 if (port_str)
593 free(port_str);
594 if (address_list)
595 hostlist_destroy(address_list);
596 if (alias_list)
597 hostlist_destroy(alias_list);
598 if (bcast_list)
599 hostlist_destroy(bcast_list);
600 if (hostname_list)
601 hostlist_destroy(hostname_list);
602 if (port_list)
603 hostlist_destroy(port_list);
604 return error_code;
605 }
606
607 /*
608 * create_config_record - create a config_record entry and set is values to
609 * the defaults. each config record corresponds to a line in the
610 * slurm.conf file and typically describes the configuration of a
611 * large number of nodes
612 * RET pointer to the config_record
613 * NOTE: memory allocated will remain in existence until
614 * _delete_config_record() is called to delete all configuration records
615 */
create_config_record(void)616 extern config_record_t *create_config_record(void)
617 {
618 config_record_t *config_ptr = xmalloc(sizeof(*config_ptr));
619
620 last_node_update = time (NULL);
621
622 config_ptr->nodes = NULL;
623 config_ptr->node_bitmap = NULL;
624 xassert (config_ptr->magic = CONFIG_MAGIC); /* set value */
625
626 list_append(config_list, config_ptr);
627
628 return config_ptr;
629 }
630
631 /*
632 * create_node_record - create a node record and set its values to defaults
633 * IN config_ptr - pointer to node's configuration information
634 * IN node_name - name of the node
635 * RET pointer to the record or NULL if error
636 * NOTE: allocates memory at node_record_table_ptr that must be xfreed when
637 * the global node table is no longer required
638 */
create_node_record(config_record_t * config_ptr,char * node_name)639 extern node_record_t *create_node_record(config_record_t *config_ptr,
640 char *node_name)
641 {
642 node_record_t *node_ptr;
643 int old_buffer_size, new_buffer_size;
644
645 last_node_update = time (NULL);
646 xassert(config_ptr);
647 xassert(node_name);
648
649 /* round up the buffer size to reduce overhead of xrealloc */
650 old_buffer_size = (node_record_count) * sizeof(node_record_t);
651 old_buffer_size =
652 ((int) ((old_buffer_size / BUF_SIZE) + 1)) * BUF_SIZE;
653 new_buffer_size =
654 (node_record_count + 1) * sizeof(node_record_t);
655 new_buffer_size =
656 ((int) ((new_buffer_size / BUF_SIZE) + 1)) * BUF_SIZE;
657 if (!node_record_table_ptr) {
658 node_record_table_ptr = xmalloc(new_buffer_size);
659 } else if (old_buffer_size != new_buffer_size) {
660 xrealloc (node_record_table_ptr, new_buffer_size);
661 /*
662 * You need to rehash the hash after we realloc or we will have
663 * only bad memory references in the hash.
664 */
665 rehash_node();
666 }
667 node_ptr = node_record_table_ptr + (node_record_count++);
668 node_ptr->name = xstrdup(node_name);
669 if (!node_hash_table)
670 node_hash_table = xhash_init(_node_record_hash_identity, NULL);
671 xhash_add(node_hash_table, node_ptr);
672
673 node_ptr->config_ptr = config_ptr;
674 /* these values will be overwritten when the node actually registers */
675 node_ptr->cpus = config_ptr->cpus;
676 node_ptr->cpu_load = NO_VAL;
677 node_ptr->free_mem = NO_VAL64;
678 node_ptr->cpu_spec_list = xstrdup(config_ptr->cpu_spec_list);
679 node_ptr->boards = config_ptr->boards;
680 node_ptr->sockets = config_ptr->sockets;
681 node_ptr->cores = config_ptr->cores;
682 node_ptr->core_spec_cnt = config_ptr->core_spec_cnt;
683 node_ptr->threads = config_ptr->threads;
684 node_ptr->mem_spec_limit = config_ptr->mem_spec_limit;
685 node_ptr->real_memory = config_ptr->real_memory;
686 node_ptr->node_spec_bitmap = NULL;
687 node_ptr->tmp_disk = config_ptr->tmp_disk;
688 node_ptr->select_nodeinfo = select_g_select_nodeinfo_alloc();
689 node_ptr->energy = acct_gather_energy_alloc(1);
690 node_ptr->ext_sensors = ext_sensors_alloc();
691 node_ptr->owner = NO_VAL;
692 node_ptr->mcs_label = NULL;
693 node_ptr->next_state = NO_VAL;
694 node_ptr->protocol_version = SLURM_MIN_PROTOCOL_VERSION;
695 xassert (node_ptr->magic = NODE_MAGIC) /* set value */;
696 return node_ptr;
697 }
698
699 /*
700 * find_node_record - find a record for node with specified name
701 * IN: name - name of the desired node
702 * RET: pointer to node record or NULL if not found
703 * NOTE: Logs an error if the node name is NOT found
704 */
find_node_record(char * name)705 extern node_record_t *find_node_record(char *name)
706 {
707 return _find_node_record(name, true, true);
708 }
709
710 /*
711 * find_node_record2 - find a record for node with specified name
712 * IN: name - name of the desired node
713 * RET: pointer to node record or NULL if not found
714 * NOTE: Does not log an error if the node name is NOT found
715 */
find_node_record2(char * name)716 extern node_record_t *find_node_record2(char *name)
717 {
718 return _find_node_record(name, true, false);
719 }
720
721 /*
722 * find_node_record_no_alias - find a record for node with specified name
723 * without looking at the node's alias (NodeHostName).
724 * IN: name - name of the desired node
725 * RET: pointer to node record or NULL if not found
726 * NOTE: Logs an error if the node name is NOT found
727 */
find_node_record_no_alias(char * name)728 extern node_record_t *find_node_record_no_alias(char *name)
729 {
730 return _find_node_record(name, false, true);
731 }
732
733 /*
734 * _find_node_record - find a record for node with specified name
735 * IN: name - name of the desired node
736 * IN: test_alias - if set, also test NodeHostName value
737 * IN: log_missing - if set, then print an error message if the node is not found
738 * RET: pointer to node record or NULL if not found
739 */
_find_node_record(char * name,bool test_alias,bool log_missing)740 static node_record_t *_find_node_record(char *name, bool test_alias,
741 bool log_missing)
742 {
743 node_record_t *node_ptr;
744
745 if ((name == NULL) || (name[0] == '\0')) {
746 info("%s: passed NULL node name", __func__);
747 return NULL;
748 }
749
750 /* nothing added yet */
751 if (!node_hash_table)
752 return NULL;
753
754 /* try to find via hash table, if it exists */
755 if ((node_ptr = xhash_get_str(node_hash_table, name))) {
756 xassert(node_ptr->magic == NODE_MAGIC);
757 return node_ptr;
758 }
759
760 if ((node_record_count == 1) &&
761 (xstrcmp(node_record_table_ptr[0].name, "localhost") == 0))
762 return (&node_record_table_ptr[0]);
763
764 if (log_missing)
765 error("%s(%d): lookup failure for %s",
766 __func__, __LINE__, name);
767
768 if (test_alias) {
769 char *alias = slurm_conf_get_nodename(name);
770 /* look for the alias node record if the user put this in
771 * instead of what slurm sees the node name as */
772 if (!alias)
773 return NULL;
774
775 node_ptr = xhash_get_str(node_hash_table, alias);
776 if (log_missing)
777 error("%s(%d): lookup failure for %s alias %s",
778 __func__, __LINE__, name, alias);
779 xfree(alias);
780 return node_ptr;
781 }
782
783 return NULL;
784 }
785
786 /*
787 * init_node_conf - initialize the node configuration tables and values.
788 * this should be called before creating any node or configuration
789 * entries.
790 * RET 0 if no error, otherwise an error code
791 */
init_node_conf(void)792 extern int init_node_conf (void)
793 {
794 last_node_update = time (NULL);
795 int i;
796 node_record_t *node_ptr;
797
798 node_ptr = node_record_table_ptr;
799 for (i = 0; i < node_record_count; i++, node_ptr++)
800 purge_node_rec(node_ptr);
801
802 node_record_count = 0;
803 xfree(node_record_table_ptr);
804 xhash_free(node_hash_table);
805
806 if (config_list) /* delete defunct configuration entries */
807 (void) _delete_config_record ();
808 else {
809 config_list = list_create (_list_delete_config);
810 front_end_list = list_create (destroy_frontend);
811 }
812
813 return SLURM_SUCCESS;
814 }
815
816
817 /* node_fini2 - free memory associated with node records (except bitmaps) */
node_fini2(void)818 extern void node_fini2 (void)
819 {
820 int i;
821 node_record_t *node_ptr;
822
823 if (config_list) {
824 FREE_NULL_LIST(config_list);
825 FREE_NULL_LIST(front_end_list);
826 }
827
828 xhash_free(node_hash_table);
829 node_ptr = node_record_table_ptr;
830 for (i = 0; i < node_record_count; i++, node_ptr++)
831 purge_node_rec(node_ptr);
832
833 xfree(node_record_table_ptr);
834 node_record_count = 0;
835 }
836
837
838 /*
839 * node_name2bitmap - given a node name regular expression, build a bitmap
840 * representation
841 * IN node_names - list of nodes
842 * IN best_effort - if set don't return an error on invalid node name entries
843 * OUT bitmap - set to bitmap, may not have all bits set on error
844 * RET 0 if no error, otherwise EINVAL
845 * NOTE: call FREE_NULL_BITMAP() to free bitmap memory when no longer required
846 */
node_name2bitmap(char * node_names,bool best_effort,bitstr_t ** bitmap)847 extern int node_name2bitmap (char *node_names, bool best_effort,
848 bitstr_t **bitmap)
849 {
850 int rc = SLURM_SUCCESS;
851 char *this_node_name;
852 bitstr_t *my_bitmap;
853 hostlist_t host_list;
854
855 my_bitmap = (bitstr_t *) bit_alloc (node_record_count);
856 *bitmap = my_bitmap;
857
858 if (node_names == NULL) {
859 info("node_name2bitmap: node_names is NULL");
860 return rc;
861 }
862
863 if ( (host_list = hostlist_create (node_names)) == NULL) {
864 /* likely a badly formatted hostlist */
865 error ("hostlist_create on %s error:", node_names);
866 if (!best_effort)
867 rc = EINVAL;
868 return rc;
869 }
870
871 while ( (this_node_name = hostlist_shift (host_list)) ) {
872 node_record_t *node_ptr;
873 node_ptr = _find_node_record(this_node_name, best_effort, true);
874 if (node_ptr) {
875 bit_set (my_bitmap, (bitoff_t) (node_ptr -
876 node_record_table_ptr));
877 } else {
878 error ("node_name2bitmap: invalid node specified %s",
879 this_node_name);
880 if (!best_effort)
881 rc = EINVAL;
882 }
883 free (this_node_name);
884 }
885 hostlist_destroy (host_list);
886
887 return rc;
888 }
889
890 /*
891 * hostlist2bitmap - given a hostlist, build a bitmap representation
892 * IN hl - hostlist
893 * IN best_effort - if set don't return an error on invalid node name entries
894 * OUT bitmap - set to bitmap, may not have all bits set on error
895 * RET 0 if no error, otherwise EINVAL
896 */
hostlist2bitmap(hostlist_t hl,bool best_effort,bitstr_t ** bitmap)897 extern int hostlist2bitmap (hostlist_t hl, bool best_effort, bitstr_t **bitmap)
898 {
899 int rc = SLURM_SUCCESS;
900 bitstr_t *my_bitmap;
901 char *name;
902 hostlist_iterator_t hi;
903
904 FREE_NULL_BITMAP(*bitmap);
905 my_bitmap = (bitstr_t *) bit_alloc (node_record_count);
906 *bitmap = my_bitmap;
907
908 hi = hostlist_iterator_create(hl);
909 while ((name = hostlist_next(hi))) {
910 node_record_t *node_ptr;
911 node_ptr = _find_node_record(name, best_effort, true);
912 if (node_ptr) {
913 bit_set (my_bitmap, (bitoff_t) (node_ptr -
914 node_record_table_ptr));
915 } else {
916 error ("hostlist2bitmap: invalid node specified %s",
917 name);
918 if (!best_effort)
919 rc = EINVAL;
920 }
921 free (name);
922 }
923
924 hostlist_iterator_destroy(hi);
925 return rc;
926
927 }
928
929 /* Purge the contents of a node record */
purge_node_rec(node_record_t * node_ptr)930 extern void purge_node_rec(node_record_t *node_ptr)
931 {
932 xfree(node_ptr->arch);
933 xfree(node_ptr->comm_name);
934 xfree(node_ptr->cpu_spec_list);
935 xfree(node_ptr->features);
936 xfree(node_ptr->features_act);
937 xfree(node_ptr->gres);
938 FREE_NULL_LIST(node_ptr->gres_list);
939 xfree(node_ptr->name);
940 xfree(node_ptr->node_hostname);
941 FREE_NULL_BITMAP(node_ptr->node_spec_bitmap);
942 xfree(node_ptr->os);
943 xfree(node_ptr->part_pptr);
944 xfree(node_ptr->power);
945 xfree(node_ptr->reason);
946 xfree(node_ptr->version);
947 acct_gather_energy_destroy(node_ptr->energy);
948 ext_sensors_destroy(node_ptr->ext_sensors);
949 select_g_select_nodeinfo_free(node_ptr->select_nodeinfo);
950 xfree(node_ptr->tres_str);
951 xfree(node_ptr->tres_fmt_str);
952 xfree(node_ptr->tres_cnt);
953 }
954
955 /*
956 * rehash_node - build a hash table of the node_record entries.
957 * NOTE: using xhash implementation
958 */
rehash_node(void)959 extern void rehash_node (void)
960 {
961 int i;
962 node_record_t *node_ptr = node_record_table_ptr;
963
964 xhash_free (node_hash_table);
965 node_hash_table = xhash_init(_node_record_hash_identity, NULL);
966 for (i = 0; i < node_record_count; i++, node_ptr++) {
967 if ((node_ptr->name == NULL) ||
968 (node_ptr->name[0] == '\0'))
969 continue; /* vestigial record */
970 xhash_add(node_hash_table, node_ptr);
971 }
972
973 #if _DEBUG
974 _dump_hash();
975 #endif
976 return;
977 }
978
979 /* Convert a node state string to it's equivalent enum value */
state_str2int(const char * state_str,char * node_name)980 extern int state_str2int(const char *state_str, char *node_name)
981 {
982 int state_val = NO_VAL;
983 int i;
984
985 for (i = 0; i <= NODE_STATE_END; i++) {
986 if (xstrcasecmp(node_state_string(i), "END") == 0)
987 break;
988 if (xstrcasecmp(node_state_string(i), state_str) == 0) {
989 state_val = i;
990 break;
991 }
992 }
993 if (i >= NODE_STATE_END) {
994 if (xstrncasecmp("CLOUD", state_str, 5) == 0)
995 state_val = NODE_STATE_IDLE | NODE_STATE_CLOUD |
996 NODE_STATE_POWER_SAVE;
997 else if (xstrncasecmp("DRAIN", state_str, 5) == 0)
998 state_val = NODE_STATE_UNKNOWN | NODE_STATE_DRAIN;
999 else if (xstrncasecmp("FAIL", state_str, 4) == 0)
1000 state_val = NODE_STATE_IDLE | NODE_STATE_FAIL;
1001 }
1002 if (state_val == NO_VAL) {
1003 error("node %s has invalid state %s", node_name, state_str);
1004 errno = EINVAL;
1005 }
1006 return state_val;
1007 }
1008
1009 /* (re)set cr_node_num_cores arrays */
cr_init_global_core_data(node_record_t * node_ptr,int node_cnt)1010 extern void cr_init_global_core_data(node_record_t *node_ptr, int node_cnt)
1011 {
1012 uint32_t n;
1013
1014 cr_fini_global_core_data();
1015
1016 cr_node_num_cores = xmalloc(node_cnt * sizeof(uint16_t));
1017 cr_node_cores_offset = xmalloc((node_cnt+1) * sizeof(uint32_t));
1018
1019 for (n = 0; n < node_cnt; n++) {
1020 uint16_t cores = node_ptr[n].config_ptr->cores;
1021 cores *= node_ptr[n].config_ptr->sockets;
1022
1023 cr_node_num_cores[n] = cores;
1024 if (n > 0) {
1025 cr_node_cores_offset[n] = cr_node_cores_offset[n-1] +
1026 cr_node_num_cores[n-1] ;
1027 } else
1028 cr_node_cores_offset[0] = 0;
1029 }
1030
1031 /* an extra value is added to get the total number of cores */
1032 /* as cr_get_coremap_offset is sometimes used to get the total */
1033 /* number of cores in the cluster */
1034 cr_node_cores_offset[node_cnt] = cr_node_cores_offset[node_cnt-1] +
1035 cr_node_num_cores[node_cnt-1] ;
1036
1037 }
1038
cr_fini_global_core_data(void)1039 extern void cr_fini_global_core_data(void)
1040 {
1041 xfree(cr_node_num_cores);
1042 xfree(cr_node_cores_offset);
1043 }
1044
1045 /* return the coremap index to the first core of the given node */
1046
cr_get_coremap_offset(uint32_t node_index)1047 extern uint32_t cr_get_coremap_offset(uint32_t node_index)
1048 {
1049 xassert(cr_node_cores_offset);
1050 return cr_node_cores_offset[node_index];
1051 }
1052
1053 /* Return a bitmap the size of the machine in cores. On a Bluegene
1054 * system it will return a bitmap in cnodes. */
cr_create_cluster_core_bitmap(int core_mult)1055 extern bitstr_t *cr_create_cluster_core_bitmap(int core_mult)
1056 {
1057 /* DEF_TIMERS; */
1058 /* START_TIMER; */
1059 bitstr_t *core_bitmap;
1060 static int cnt = 0;
1061
1062 if (!cnt) {
1063 cnt = cr_get_coremap_offset(node_record_count);
1064 if (core_mult)
1065 cnt *= core_mult;
1066 }
1067 core_bitmap = bit_alloc(cnt);
1068 /* END_TIMER; */
1069 /* info("creating of core bitmap of %d took %s", cnt, TIME_STR); */
1070 return core_bitmap;
1071 }
1072
1073 /*
1074 * Determine maximum number of CPUs on this node usable by a job
1075 * ntasks_per_core IN - tasks-per-core to be launched by this job
1076 * cpus_per_task IN - number of required CPUs per task for this job
1077 * total_cores IN - total number of cores on this node
1078 * total_cpus IN - total number of CPUs on this node
1079 * RET count of usable CPUs on this node usable by this job
1080 */
adjust_cpus_nppcu(uint16_t ntasks_per_core,int cpus_per_task,int total_cores,int total_cpus)1081 extern int adjust_cpus_nppcu(uint16_t ntasks_per_core, int cpus_per_task,
1082 int total_cores, int total_cpus)
1083 {
1084 int cpus = total_cpus;
1085
1086 //FIXME: This function ignores tasks-per-socket and tasks-per-node checks.
1087 // Those parameters are tested later
1088 if ((ntasks_per_core != 0) && (ntasks_per_core != 0xffff) &&
1089 (cpus_per_task != 0)) {
1090 cpus = MAX((total_cores * ntasks_per_core * cpus_per_task),
1091 total_cpus);
1092 }
1093
1094 return cpus;
1095 }
1096
find_hostname(uint32_t pos,char * hosts)1097 extern char *find_hostname(uint32_t pos, char *hosts)
1098 {
1099 hostlist_t hostlist = NULL;
1100 char *temp = NULL, *host = NULL;
1101
1102 if (!hosts || (pos == NO_VAL) || (pos == INFINITE))
1103 return NULL;
1104
1105 hostlist = hostlist_create(hosts);
1106 temp = hostlist_nth(hostlist, pos);
1107 if (temp) {
1108 host = xstrdup(temp);
1109 free(temp);
1110 }
1111 hostlist_destroy(hostlist);
1112 return host;
1113 }
1114