1 /*****************************************************************************\
2  *  assoc_mgr.c - File to keep track of associations/QOS used by the daemons
3  *****************************************************************************
4  *  Copyright (C) 2004-2007 The Regents of the University of California.
5  *  Copyright (C) 2008-2009 Lawrence Livermore National Security.
6  *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
7  *  Written by Danny Auble <da@llnl.gov>
8  *
9  *  This file is part of Slurm, a resource management program.
10  *  For details, see <https://slurm.schedmd.com/>.
11  *  Please also read the included file: DISCLAIMER.
12  *
13  *  Slurm is free software; you can redistribute it and/or modify it under
14  *  the terms of the GNU General Public License as published by the Free
15  *  Software Foundation; either version 2 of the License, or (at your option)
16  *  any later version.
17  *
18  *  In addition, as a special exception, the copyright holders give permission
19  *  to link the code of portions of this program with the OpenSSL library under
20  *  certain conditions as described in each individual source file, and
21  *  distribute linked combinations including the two. You must obey the GNU
22  *  General Public License in all respects for all of the code used other than
23  *  OpenSSL. If you modify file(s) with this exception, you may extend this
24  *  exception to your version of the file(s), but you are not obligated to do
25  *  so. If you do not wish to do so, delete this exception statement from your
26  *  version.  If you delete this exception statement from all source files in
27  *  the program, then also delete it here.
28  *
29  *  Slurm is distributed in the hope that it will be useful, but WITHOUT ANY
30  *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
31  *  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
32  *  details.
33  *
34  *  You should have received a copy of the GNU General Public License along
35  *  with Slurm; if not, write to the Free Software Foundation, Inc.,
36  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA.
37 \*****************************************************************************/
38 
39 #include "assoc_mgr.h"
40 
41 #include <sys/types.h>
42 #include <pwd.h>
43 #include <fcntl.h>
44 #include <stdlib.h>
45 #include <ctype.h>
46 
47 #include "src/common/uid.h"
48 #include "src/common/xstring.h"
49 #include "src/common/slurm_priority.h"
50 #include "src/common/slurmdbd_pack.h"
51 #include "src/slurmdbd/read_config.h"
52 
53 #define ASSOC_HASH_SIZE 1000
54 #define ASSOC_HASH_ID_INX(_assoc_id)	(_assoc_id % ASSOC_HASH_SIZE)
55 
56 slurmdb_assoc_rec_t *assoc_mgr_root_assoc = NULL;
57 uint32_t g_qos_max_priority = 0;
58 uint32_t g_assoc_max_priority = 0;
59 uint32_t g_qos_count = 0;
60 uint32_t g_user_assoc_count = 0;
61 uint32_t g_tres_count = 0;
62 
63 List assoc_mgr_tres_list = NULL;
64 slurmdb_tres_rec_t **assoc_mgr_tres_array = NULL;
65 char **assoc_mgr_tres_name_array = NULL;
66 List assoc_mgr_assoc_list = NULL;
67 List assoc_mgr_res_list = NULL;
68 List assoc_mgr_qos_list = NULL;
69 List assoc_mgr_user_list = NULL;
70 List assoc_mgr_wckey_list = NULL;
71 
72 static char *assoc_mgr_cluster_name = NULL;
73 static int setup_children = 0;
74 static pthread_rwlock_t assoc_mgr_locks[ASSOC_MGR_ENTITY_COUNT];
75 static pthread_mutex_t assoc_lock_init = PTHREAD_MUTEX_INITIALIZER;
76 
77 static assoc_init_args_t init_setup;
78 static slurmdb_assoc_rec_t **assoc_hash_id = NULL;
79 static slurmdb_assoc_rec_t **assoc_hash = NULL;
80 static int *assoc_mgr_tres_old_pos = NULL;
81 
_running_cache(void)82 static bool _running_cache(void)
83 {
84 	if (init_setup.running_cache && *init_setup.running_cache)
85 		return true;
86 
87 	return false;
88 }
89 
_get_str_inx(char * name)90 static int _get_str_inx(char *name)
91 {
92 	int j, index = 0;
93 
94 	if (!name)
95 		return 0;
96 
97 	for (j = 1; *name; name++, j++)
98 		index += (int)tolower(*name) * j;
99 
100 	return index;
101 }
102 
_assoc_hash_index(slurmdb_assoc_rec_t * assoc)103 static int _assoc_hash_index(slurmdb_assoc_rec_t *assoc)
104 {
105 	int index;
106 
107 	xassert(assoc);
108 
109 	/* Multiply each character by its numerical position in the
110 	 * name string to add a bit of entropy.
111 	 */
112 
113 	index = assoc->uid;
114 
115 	/* only set on the slurmdbd */
116 	if (!assoc_mgr_cluster_name && assoc->cluster)
117 		index += _get_str_inx(assoc->cluster);
118 
119 	if (assoc->acct)
120 		index += _get_str_inx(assoc->acct);
121 
122 	if (assoc->partition)
123 		index += _get_str_inx(assoc->partition);
124 
125 	index %= ASSOC_HASH_SIZE;
126 	if (index < 0)
127 		index += ASSOC_HASH_SIZE;
128 
129 	return index;
130 
131 }
132 
_add_assoc_hash(slurmdb_assoc_rec_t * assoc)133 static void _add_assoc_hash(slurmdb_assoc_rec_t *assoc)
134 {
135 	int inx = ASSOC_HASH_ID_INX(assoc->id);
136 
137 	if (!assoc_hash_id)
138 		assoc_hash_id = xcalloc(ASSOC_HASH_SIZE,
139 					sizeof(slurmdb_assoc_rec_t *));
140 	if (!assoc_hash)
141 		assoc_hash = xcalloc(ASSOC_HASH_SIZE,
142 				     sizeof(slurmdb_assoc_rec_t *));
143 
144 	assoc->assoc_next_id = assoc_hash_id[inx];
145 	assoc_hash_id[inx] = assoc;
146 
147 	inx = _assoc_hash_index(assoc);
148 	assoc->assoc_next = assoc_hash[inx];
149 	assoc_hash[inx] = assoc;
150 }
151 
_remove_from_assoc_list(slurmdb_assoc_rec_t * assoc)152 static bool _remove_from_assoc_list(slurmdb_assoc_rec_t *assoc)
153 {
154 	slurmdb_assoc_rec_t *assoc_ptr;
155 	ListIterator itr = list_iterator_create(assoc_mgr_assoc_list);
156 
157 	while ((assoc_ptr = list_next(itr))) {
158 		if (assoc_ptr == assoc) {
159 			list_remove(itr);
160 			break;
161 		}
162 	}
163 
164 	list_iterator_destroy(itr);
165 
166 	return assoc_ptr ? 1 : 0;
167 }
168 
_find_assoc_rec_id(uint32_t assoc_id)169 static slurmdb_assoc_rec_t *_find_assoc_rec_id(uint32_t assoc_id)
170 {
171 	slurmdb_assoc_rec_t *assoc;
172 
173 	if (!assoc_hash_id) {
174 		debug2("_find_assoc_rec_id: no associations added yet");
175 		return NULL;
176 	}
177 
178 	assoc =	assoc_hash_id[ASSOC_HASH_ID_INX(assoc_id)];
179 
180 	while (assoc) {
181 		if (assoc->id == assoc_id)
182 			return assoc;
183 		assoc = assoc->assoc_next_id;
184 	}
185 
186 	return NULL;
187 }
188 
189 /*
190  * _find_assoc_rec - return a pointer to the assoc_ptr with the given
191  * contents of assoc.
192  * IN assoc - requested association info
193  * RET pointer to the assoc_ptr's record, NULL on error
194  */
_find_assoc_rec(slurmdb_assoc_rec_t * assoc)195 static slurmdb_assoc_rec_t *_find_assoc_rec(
196 	slurmdb_assoc_rec_t *assoc)
197 {
198 	slurmdb_assoc_rec_t *assoc_ptr;
199 	int inx;
200 
201 	/* We can only use _find_assoc_rec_id if we are not on the slurmdbd */
202 	if (assoc->id && assoc_mgr_cluster_name)
203 		return _find_assoc_rec_id(assoc->id);
204 
205 	if (!assoc_hash) {
206 		debug2("_find_assoc_rec: no associations added yet");
207 		return NULL;
208 	}
209 
210 
211 	inx = _assoc_hash_index(assoc);
212 	assoc_ptr = assoc_hash[inx];
213 
214 	while (assoc_ptr) {
215 		if ((!assoc->user && (assoc->uid == NO_VAL))
216 		    && (assoc_ptr->user || (assoc_ptr->uid != NO_VAL))) {
217 			debug3("%s: we are looking for a nonuser association",
218 				__func__);
219 			goto next;
220 		} else if ((!assoc_ptr->user && (assoc_ptr->uid == NO_VAL))
221 			   && (assoc->user || (assoc->uid != NO_VAL))) {
222 			debug3("%s: we are looking for a user association",
223 				__func__);
224 			goto next;
225 		} else if (assoc->user && assoc_ptr->user
226 			   && ((assoc->uid == NO_VAL) ||
227 			       (assoc_ptr->uid == NO_VAL))) {
228 			/* This means the uid isn't set in one of the
229 			 * associations, so use the name instead
230 			 */
231 			if (xstrcasecmp(assoc->user, assoc_ptr->user)) {
232 				debug3("%s: 2 not the right user %u != %u",
233 				       __func__, assoc->uid, assoc_ptr->uid);
234 				goto next;
235 			}
236 		} else if (assoc->uid != assoc_ptr->uid) {
237 			debug3("%s: not the right user %u != %u",
238 			       __func__, assoc->uid, assoc_ptr->uid);
239 			goto next;
240 		}
241 
242 		if (assoc->acct &&
243 		    (!assoc_ptr->acct
244 		     || xstrcasecmp(assoc->acct, assoc_ptr->acct))) {
245 			debug3("%s: not the right account %s != %s",
246 			       __func__, assoc->acct, assoc_ptr->acct);
247 			goto next;
248 		}
249 
250 		/* only check for on the slurmdbd */
251 		if (!assoc_mgr_cluster_name && assoc->cluster
252 		    && (!assoc_ptr->cluster
253 			|| xstrcasecmp(assoc->cluster, assoc_ptr->cluster))) {
254 			debug3("%s: not the right cluster", __func__);
255 			goto next;
256 		}
257 
258 		if (assoc->partition
259 		    && (!assoc_ptr->partition
260 			|| xstrcasecmp(assoc->partition,
261 				       assoc_ptr->partition))) {
262 			debug3("%s: not the right partition", __func__);
263 			goto next;
264 		}
265 
266 		break;
267 	next:
268 		assoc_ptr = assoc_ptr->assoc_next;
269 	}
270 
271 	return assoc_ptr;
272 }
273 
274 /*
275  * _list_delete_assoc - delete a assoc record
276  * IN assoc_entry - pointer to assoc_record to delete
277  * global: assoc_list - pointer to global assoc list
278  *	assoc_count - count of assoc list entries
279  *	assoc_hash - hash table into assoc records
280  */
_delete_assoc_hash(slurmdb_assoc_rec_t * assoc)281 static void _delete_assoc_hash(slurmdb_assoc_rec_t *assoc)
282 {
283 	slurmdb_assoc_rec_t *assoc_ptr = assoc;
284 	slurmdb_assoc_rec_t **assoc_pptr;
285 
286 	xassert(assoc);
287 
288 	/* Remove the record from assoc hash table */
289 	assoc_pptr = &assoc_hash_id[ASSOC_HASH_ID_INX(assoc_ptr->id)];
290 	while (assoc_pptr && ((assoc_ptr = *assoc_pptr) != assoc)) {
291 		if (!assoc_ptr->assoc_next_id)
292 			assoc_pptr = NULL;
293 		else
294 			assoc_pptr = &assoc_ptr->assoc_next_id;
295 	}
296 
297 	if (!assoc_pptr) {
298 		fatal("assoc id hash error");
299 		return;	/* Fix CLANG false positive error */
300 	} else
301 		*assoc_pptr = assoc_ptr->assoc_next_id;
302 
303 	assoc_ptr = assoc;
304 	assoc_pptr = &assoc_hash[_assoc_hash_index(assoc_ptr)];
305 	while (assoc_pptr && ((assoc_ptr = *assoc_pptr) != assoc)) {
306 		if (!assoc_ptr->assoc_next)
307 			assoc_pptr = NULL;
308 		else
309 			assoc_pptr = &assoc_ptr->assoc_next;
310 	}
311 
312 	if (!assoc_pptr) {
313 		fatal("assoc hash error");
314 		return;	/* Fix CLANG false positive error */
315 	} else
316 		*assoc_pptr = assoc_ptr->assoc_next;
317 }
318 
319 
_normalize_assoc_shares_fair_tree(slurmdb_assoc_rec_t * assoc)320 static void _normalize_assoc_shares_fair_tree(
321 	slurmdb_assoc_rec_t *assoc)
322 {
323 	slurmdb_assoc_rec_t *fs_assoc = assoc;
324 	double shares_norm = 0.0;
325 
326 	if ((assoc->shares_raw == SLURMDB_FS_USE_PARENT)
327 	    && assoc->usage->fs_assoc_ptr)
328 		fs_assoc = assoc->usage->fs_assoc_ptr;
329 
330 	if (fs_assoc->usage->level_shares)
331 		shares_norm =
332 			(double)fs_assoc->shares_raw /
333 			(double)fs_assoc->usage->level_shares;
334 	assoc->usage->shares_norm = shares_norm;
335 }
336 
337 
338 /* you should check for assoc == NULL before this function */
_normalize_assoc_shares_traditional(slurmdb_assoc_rec_t * assoc)339 static void _normalize_assoc_shares_traditional(
340 		slurmdb_assoc_rec_t *assoc)
341 {
342 	slurmdb_assoc_rec_t *assoc2 = assoc;
343 	xassert(assoc);
344 
345 	if ((assoc->shares_raw == SLURMDB_FS_USE_PARENT)
346 	    && assoc->usage->fs_assoc_ptr) {
347 		debug3("assoc %u(%s %s) normalize = %f from parent %u(%s %s)",
348 		       assoc->id, assoc->acct, assoc->user,
349 		       assoc->usage->fs_assoc_ptr->usage->shares_norm,
350 		       assoc->usage->fs_assoc_ptr->id,
351 		       assoc->usage->fs_assoc_ptr->acct,
352 		       assoc->usage->fs_assoc_ptr->user);
353 		assoc->usage->shares_norm =
354 			assoc->usage->fs_assoc_ptr->usage->shares_norm;
355 		return;
356 	}
357 
358 	assoc2->usage->shares_norm = 1.0;
359 	while (assoc->usage->parent_assoc_ptr) {
360 		if (assoc->shares_raw != SLURMDB_FS_USE_PARENT) {
361 			if (!assoc->usage->level_shares)
362 				assoc2->usage->shares_norm = 0;
363 			else
364 				assoc2->usage->shares_norm *=
365 					(double)assoc->shares_raw /
366 					(double)assoc->usage->level_shares;
367 			debug3("assoc %u(%s %s) normalize = %f "
368 			       "from %u(%s %s) %u / %u = %f",
369 			       assoc2->id, assoc2->acct, assoc2->user,
370 			       assoc2->usage->shares_norm,
371 			       assoc->id, assoc->acct, assoc->user,
372 			       assoc->shares_raw,
373 			       assoc->usage->level_shares,
374 			       assoc->usage->level_shares ?
375 			       (double)assoc->shares_raw /
376 			       (double)assoc->usage->level_shares :
377 			       0);
378 		}
379 
380 		assoc = assoc->usage->parent_assoc_ptr;
381 	}
382 }
383 
384 
_addto_used_info(slurmdb_assoc_rec_t * assoc1,slurmdb_assoc_rec_t * assoc2)385 static int _addto_used_info(slurmdb_assoc_rec_t *assoc1,
386 			    slurmdb_assoc_rec_t *assoc2)
387 {
388 	int i;
389 
390 	if (!assoc1 || !assoc2)
391 		return SLURM_ERROR;
392 
393 	for (i=0; i < assoc1->usage->tres_cnt; i++) {
394 		assoc1->usage->grp_used_tres[i] +=
395 			assoc2->usage->grp_used_tres[i];
396 		assoc1->usage->grp_used_tres_run_secs[i] +=
397 			assoc2->usage->grp_used_tres_run_secs[i];
398 		assoc1->usage->usage_tres_raw[i] +=
399 			assoc2->usage->usage_tres_raw[i];
400 	}
401 
402 	assoc1->usage->accrue_cnt += assoc2->usage->accrue_cnt;
403 
404 	assoc1->usage->grp_used_wall += assoc2->usage->grp_used_wall;
405 
406 	assoc1->usage->used_jobs += assoc2->usage->used_jobs;
407 	assoc1->usage->used_submit_jobs += assoc2->usage->used_submit_jobs;
408 	assoc1->usage->usage_raw += assoc2->usage->usage_raw;
409 
410 	/*
411 	 * Basically copied from src/slurmctld/acct_policy.c
412 	 * _add_usage_node_bitmap().
413 	 */
414 	if (assoc2->usage->grp_node_bitmap) {
415 		int i_first, i_last;
416 		if (assoc1->usage->grp_node_bitmap)
417 			bit_or(assoc1->usage->grp_node_bitmap,
418 			       assoc2->usage->grp_node_bitmap);
419 		else
420 			assoc1->usage->grp_node_bitmap =
421 				bit_copy(assoc2->usage->grp_node_bitmap);
422 
423 		if (!assoc1->usage->grp_node_job_cnt)
424 			assoc1->usage->grp_node_job_cnt = xcalloc(
425 				bit_size(assoc1->usage->grp_node_bitmap),
426 				sizeof(uint16_t));
427 
428 		i_first = bit_ffs(assoc2->usage->grp_node_bitmap);
429 		if (i_first != -1) {
430 			i_last = bit_fls(assoc2->usage->grp_node_bitmap);
431 			for (int i = i_first; i <= i_last; i++) {
432 				if (!bit_test(assoc2->usage->grp_node_bitmap,
433 					      i))
434 					continue;
435 				assoc1->usage->grp_node_job_cnt[i] +=
436 					assoc2->usage->grp_node_job_cnt[i];
437 			}
438 		}
439 	}
440 	return SLURM_SUCCESS;
441 }
442 
_clear_used_assoc_info(slurmdb_assoc_rec_t * assoc)443 static int _clear_used_assoc_info(slurmdb_assoc_rec_t *assoc)
444 {
445 	int i;
446 
447 	if (!assoc || !assoc->usage)
448 		return SLURM_ERROR;
449 
450 	for (i=0; i<assoc->usage->tres_cnt; i++) {
451 		assoc->usage->grp_used_tres[i] = 0;
452 		assoc->usage->grp_used_tres_run_secs[i] = 0;
453 	}
454 
455 	assoc->usage->accrue_cnt = 0;
456 	assoc->usage->used_jobs  = 0;
457 	assoc->usage->used_submit_jobs = 0;
458 
459 	if (assoc->usage->grp_node_bitmap)
460 		bit_clear_all(assoc->usage->grp_node_bitmap);
461 	if (assoc->usage->grp_node_job_cnt)
462 		memset(assoc->usage->grp_node_job_cnt, 0,
463 		       sizeof(uint16_t) * node_record_count);
464 
465 	/* do not reset usage_raw or grp_used_wall.
466 	 * if you need to reset it do it
467 	 * else where since sometimes we call this and do not want
468 	 * shares reset */
469 
470 	return SLURM_SUCCESS;
471 }
472 
_clear_qos_used_limit_list(List used_limit_list,uint32_t tres_cnt)473 static void _clear_qos_used_limit_list(List used_limit_list, uint32_t tres_cnt)
474 {
475 	slurmdb_used_limits_t *used_limits = NULL;
476 	ListIterator itr = NULL;
477 	int i;
478 
479 	if (!used_limit_list || !list_count(used_limit_list))
480 		return;
481 
482 	itr = list_iterator_create(used_limit_list);
483 	while ((used_limits = list_next(itr))) {
484 		used_limits->accrue_cnt = 0;
485 		used_limits->jobs = 0;
486 		if (used_limits->node_bitmap)
487 			bit_nclear(used_limits->node_bitmap, 0,
488 			         (node_record_count - 1));
489 		if (used_limits->node_job_cnt) {
490 			memset(used_limits->node_job_cnt, 0,
491 			       sizeof(uint16_t) * node_record_count);
492 		}
493 		used_limits->submit_jobs = 0;
494 		for (i=0; i<tres_cnt; i++) {
495 			used_limits->tres[i] = 0;
496 			used_limits->tres_run_mins[i] = 0;
497 		}
498 	}
499 	list_iterator_destroy(itr);
500 
501 	return;
502 }
503 
_clear_qos_acct_limit_info(slurmdb_qos_rec_t * qos_ptr)504 static void _clear_qos_acct_limit_info(slurmdb_qos_rec_t *qos_ptr)
505 {
506 	_clear_qos_used_limit_list(qos_ptr->usage->acct_limit_list,
507 				   qos_ptr->usage->tres_cnt);
508 }
509 
_clear_qos_user_limit_info(slurmdb_qos_rec_t * qos_ptr)510 static void _clear_qos_user_limit_info(slurmdb_qos_rec_t *qos_ptr)
511 {
512 	_clear_qos_used_limit_list(qos_ptr->usage->user_limit_list,
513 				   qos_ptr->usage->tres_cnt);
514 }
515 
_clear_used_qos_info(slurmdb_qos_rec_t * qos)516 static int _clear_used_qos_info(slurmdb_qos_rec_t *qos)
517 {
518 	int i;
519 
520 	if (!qos || !qos->usage)
521 		return SLURM_ERROR;
522 
523 	qos->usage->accrue_cnt = 0;
524 	qos->usage->grp_used_jobs  = 0;
525 	qos->usage->grp_used_submit_jobs = 0;
526 	if (qos->usage->grp_node_bitmap)
527 		bit_nclear(qos->usage->grp_node_bitmap, 0,
528 		         (node_record_count - 1));
529 	if (qos->usage->grp_node_job_cnt) {
530 		memset(qos->usage->grp_node_job_cnt, 0,
531 		       sizeof(uint16_t) * node_record_count);
532 	}
533 	for (i=0; i<qos->usage->tres_cnt; i++) {
534 		qos->usage->grp_used_tres[i] = 0;
535 		qos->usage->grp_used_tres_run_secs[i] = 0;
536 	}
537 	/* do not reset usage_raw or grp_used_wall.
538 	 * if you need to reset it do it
539 	 * else where since sometimes we call this and do not want
540 	 * shares reset */
541 
542 	_clear_qos_acct_limit_info(qos);
543 	_clear_qos_user_limit_info(qos);
544 
545 	return SLURM_SUCCESS;
546 }
547 
548 /* Locks should be in place before calling this. */
_change_user_name(slurmdb_user_rec_t * user)549 static int _change_user_name(slurmdb_user_rec_t *user)
550 {
551 	int rc = SLURM_SUCCESS;
552 	ListIterator itr = NULL;
553 	slurmdb_assoc_rec_t *assoc = NULL;
554 	slurmdb_wckey_rec_t *wckey = NULL;
555 	uid_t pw_uid;
556 
557 	xassert(user->name);
558 	xassert(user->old_name);
559 
560 	if (uid_from_string(user->name, &pw_uid) < 0) {
561 		debug("_change_user_name: couldn't get new uid for user %s",
562 		      user->name);
563 		user->uid = NO_VAL;
564 	} else
565 		user->uid = pw_uid;
566 
567 	if (assoc_mgr_assoc_list) {
568 		itr = list_iterator_create(assoc_mgr_assoc_list);
569 		while ((assoc = list_next(itr))) {
570 			if (!assoc->user)
571 				continue;
572 			if (!xstrcmp(user->old_name, assoc->user)) {
573 				/* Since the uid changed the
574 				   hash as well will change.  Remove
575 				   the assoc from the hash before the
576 				   change or you won't find it.
577 				*/
578 				_delete_assoc_hash(assoc);
579 
580 				xfree(assoc->user);
581 				assoc->user = xstrdup(user->name);
582 				assoc->uid = user->uid;
583 				_add_assoc_hash(assoc);
584 				debug3("changing assoc %d", assoc->id);
585 			}
586 		}
587 		list_iterator_destroy(itr);
588 	}
589 
590 	if (assoc_mgr_wckey_list) {
591 		itr = list_iterator_create(assoc_mgr_wckey_list);
592 		while ((wckey = list_next(itr))) {
593 			if (!xstrcmp(user->old_name, wckey->user)) {
594 				xfree(wckey->user);
595 				wckey->user = xstrdup(user->name);
596 				wckey->uid = user->uid;
597 				debug3("changing wckey %d", wckey->id);
598 			}
599 		}
600 		list_iterator_destroy(itr);
601 	}
602 
603 	return rc;
604 }
605 
_grab_parents_qos(slurmdb_assoc_rec_t * assoc)606 static int _grab_parents_qos(slurmdb_assoc_rec_t *assoc)
607 {
608 	slurmdb_assoc_rec_t *parent_assoc = NULL;
609 	char *qos_char = NULL;
610 	ListIterator itr = NULL;
611 
612 	if (!assoc)
613 		return SLURM_ERROR;
614 
615 	if (assoc->qos_list)
616 		list_flush(assoc->qos_list);
617 	else
618 		assoc->qos_list = list_create(xfree_ptr);
619 
620 	parent_assoc = assoc->usage->parent_assoc_ptr;
621 
622 	if (!parent_assoc || !parent_assoc->qos_list
623 	    || !list_count(parent_assoc->qos_list))
624 		return SLURM_SUCCESS;
625 
626 	itr = list_iterator_create(parent_assoc->qos_list);
627 	while ((qos_char = list_next(itr)))
628 		list_append(assoc->qos_list, xstrdup(qos_char));
629 	list_iterator_destroy(itr);
630 
631 	return SLURM_SUCCESS;
632 }
633 
_local_update_assoc_qos_list(slurmdb_assoc_rec_t * assoc,List new_qos_list)634 static int _local_update_assoc_qos_list(slurmdb_assoc_rec_t *assoc,
635 					List new_qos_list)
636 {
637 	ListIterator new_qos_itr = NULL, curr_qos_itr = NULL;
638 	char *new_qos = NULL, *curr_qos = NULL;
639 	int flushed = 0;
640 
641 	if (!assoc || !new_qos_list) {
642 		error("need both new qos_list and an association to update");
643 		return SLURM_ERROR;
644 	}
645 
646 	if (!list_count(new_qos_list)) {
647 		_grab_parents_qos(assoc);
648 		return SLURM_SUCCESS;
649 	}
650 
651 	/* Even though we only use the valid_qos bitstr for things we
652 	   need to keep the list around for now since we don't pack the
653 	   bitstr for state save.
654 	*/
655 	new_qos_itr = list_iterator_create(new_qos_list);
656 	curr_qos_itr = list_iterator_create(assoc->qos_list);
657 
658 	while ((new_qos = list_next(new_qos_itr))) {
659 		if (new_qos[0] == '-') {
660 			while ((curr_qos = list_next(curr_qos_itr))) {
661 				if (!xstrcmp(curr_qos, new_qos+1)) {
662 					list_delete_item(curr_qos_itr);
663 					break;
664 				}
665 			}
666 
667 			list_iterator_reset(curr_qos_itr);
668 		} else if (new_qos[0] == '+') {
669 			while ((curr_qos = list_next(curr_qos_itr)))
670 				if (!xstrcmp(curr_qos, new_qos+1))
671 					break;
672 
673 			if (!curr_qos) {
674 				list_append(assoc->qos_list,
675 					    xstrdup(new_qos+1));
676 				list_iterator_reset(curr_qos_itr);
677 			}
678 		} else if (new_qos[0] == '=') {
679 			if (!flushed)
680 				list_flush(assoc->qos_list);
681 			list_append(assoc->qos_list, xstrdup(new_qos+1));
682 			flushed = 1;
683 		} else if (new_qos[0]) {
684 			if (!flushed)
685 				list_flush(assoc->qos_list);
686 			list_append(assoc->qos_list, xstrdup(new_qos));
687 			flushed = 1;
688 		}
689 	}
690 	list_iterator_destroy(curr_qos_itr);
691 	list_iterator_destroy(new_qos_itr);
692 
693 	return SLURM_SUCCESS;
694 }
695 
696 /* locks should be put in place before calling this function USER_WRITE */
_set_user_default_acct(slurmdb_assoc_rec_t * assoc)697 static void _set_user_default_acct(slurmdb_assoc_rec_t *assoc)
698 {
699 	xassert(assoc);
700 	xassert(assoc->acct);
701 	xassert(assoc_mgr_user_list);
702 
703 	/* set up the default if this is it */
704 	if ((assoc->is_def == 1) && (assoc->uid != NO_VAL)) {
705 		slurmdb_user_rec_t *user = NULL;
706 		ListIterator user_itr =
707 			list_iterator_create(assoc_mgr_user_list);
708 		while ((user = list_next(user_itr))) {
709 			if (user->uid != assoc->uid)
710 				continue;
711 			if (!user->default_acct
712 			    || xstrcmp(user->default_acct, assoc->acct)) {
713 				xfree(user->default_acct);
714 				user->default_acct = xstrdup(assoc->acct);
715 				debug2("user %s default acct is %s",
716 				       user->name, user->default_acct);
717 			}
718 			/* cache user rec reference for backfill*/
719 			assoc->user_rec = user;
720 			break;
721 		}
722 		list_iterator_destroy(user_itr);
723 	}
724 }
725 
726 /* locks should be put in place before calling this function USER_WRITE */
_set_user_default_wckey(slurmdb_wckey_rec_t * wckey)727 static void _set_user_default_wckey(slurmdb_wckey_rec_t *wckey)
728 {
729 	xassert(wckey);
730 	xassert(wckey->name);
731 	xassert(assoc_mgr_user_list);
732 
733 	/* set up the default if this is it */
734 	if ((wckey->is_def == 1) && (wckey->uid != NO_VAL)) {
735 		slurmdb_user_rec_t *user = NULL;
736 		ListIterator user_itr =
737 			list_iterator_create(assoc_mgr_user_list);
738 		while ((user = list_next(user_itr))) {
739 			if (user->uid != wckey->uid)
740 				continue;
741 			if (!user->default_wckey
742 			    || xstrcmp(user->default_wckey, wckey->name)) {
743 				xfree(user->default_wckey);
744 				user->default_wckey = xstrdup(wckey->name);
745 				debug2("user %s default wckey is %s",
746 				       user->name, user->default_wckey);
747 			}
748 			break;
749 		}
750 		list_iterator_destroy(user_itr);
751 	}
752 }
753 
754 /* Return first parent that is not SLURMDB_FS_USE_PARENT unless
755  * direct is set */
_find_assoc_parent(slurmdb_assoc_rec_t * assoc,bool direct)756 static slurmdb_assoc_rec_t* _find_assoc_parent(
757 	slurmdb_assoc_rec_t *assoc, bool direct)
758 {
759 	slurmdb_assoc_rec_t *parent = NULL, *prev_parent;
760 	xassert(assoc);
761 
762 	parent = assoc;
763 
764 	while (parent) {
765 		if (!parent->parent_id)
766 			break;
767 
768 		prev_parent = parent;
769 		if (!(parent = _find_assoc_rec_id(prev_parent->parent_id))) {
770 			error("Can't find parent id %u for assoc %u, "
771 			      "this should never happen.",
772 			      prev_parent->parent_id, prev_parent->id);
773 			break;
774 		}
775 		/* See if we need to look for the next parent up the tree */
776 		if (direct || (assoc->shares_raw != SLURMDB_FS_USE_PARENT) ||
777 		    (parent->shares_raw != SLURMDB_FS_USE_PARENT))
778 			break;
779 	}
780 
781 	if (parent)
782 		debug2("assoc %u(%s, %s) has %s parent of %u(%s, %s)",
783 		       assoc->id, assoc->acct, assoc->user,
784 		       direct ? "direct" : "fs",
785 		       parent->id, parent->acct, parent->user);
786 	else
787 		debug2("assoc %u(%s, %s) doesn't have a %s "
788 		       "parent (probably root)",
789 		       assoc->id, assoc->acct, assoc->user,
790 		       direct ? "direct" : "fs");
791 
792 	return parent;
793 }
794 
_set_assoc_parent_and_user(slurmdb_assoc_rec_t * assoc,int reset)795 static int _set_assoc_parent_and_user(slurmdb_assoc_rec_t *assoc,
796 				      int reset)
797 {
798 	xassert(verify_assoc_lock(ASSOC_LOCK, WRITE_LOCK));
799 	xassert(verify_assoc_lock(QOS_LOCK, READ_LOCK));
800 	xassert(verify_assoc_lock(TRES_LOCK, READ_LOCK));
801 	xassert(verify_assoc_lock(USER_LOCK, WRITE_LOCK));
802 
803 	xassert(assoc_mgr_user_list);
804 
805 	if (!assoc || !assoc_mgr_assoc_list) {
806 		error("you didn't give me an association");
807 		return SLURM_ERROR;
808 	}
809 
810 	if (!assoc->usage)
811 		assoc->usage = slurmdb_create_assoc_usage(g_tres_count);
812 
813 	if (assoc->parent_id) {
814 		/* Here we need the direct parent (parent_assoc_ptr)
815 		 * and also the first parent that doesn't have
816 		 * shares_raw == SLURMDB_FS_USE_PARENT (fs_assoc_ptr).
817 		 */
818 		assoc->usage->parent_assoc_ptr =
819 			_find_assoc_parent(assoc, true);
820 		if (!assoc->usage->parent_assoc_ptr) {
821 			error("Can't find parent id %u for assoc %u, "
822 			      "this should never happen.",
823 			      assoc->parent_id, assoc->id);
824 			assoc->usage->fs_assoc_ptr = NULL;
825 		} else if (assoc->shares_raw == SLURMDB_FS_USE_PARENT)
826 			assoc->usage->fs_assoc_ptr =
827 				_find_assoc_parent(assoc, false);
828 		else if (assoc->usage->parent_assoc_ptr->shares_raw
829 			 == SLURMDB_FS_USE_PARENT)
830 			assoc->usage->fs_assoc_ptr = _find_assoc_parent(
831 				assoc->usage->parent_assoc_ptr, false);
832 		else
833 			assoc->usage->fs_assoc_ptr =
834 				assoc->usage->parent_assoc_ptr;
835 
836 		if (assoc->usage->fs_assoc_ptr && setup_children) {
837 			if (!assoc->usage->fs_assoc_ptr->usage)
838 				assoc->usage->fs_assoc_ptr->usage =
839 					slurmdb_create_assoc_usage(
840 						g_tres_count);
841 			if (!assoc->usage->
842 			    fs_assoc_ptr->usage->children_list)
843 				assoc->usage->
844 					fs_assoc_ptr->usage->children_list =
845 					list_create(NULL);
846 			list_append(assoc->usage->
847 				    fs_assoc_ptr->usage->children_list,
848 				    assoc);
849 		}
850 
851 		if (assoc == assoc->usage->parent_assoc_ptr) {
852 			assoc->usage->parent_assoc_ptr = NULL;
853 			assoc->usage->fs_assoc_ptr = NULL;
854 			error("association %u was pointing to "
855 			      "itself as it's parent",
856 			      assoc->id);
857 		}
858 	} else if (assoc_mgr_root_assoc != assoc) {
859 		slurmdb_assoc_rec_t *last_root = assoc_mgr_root_assoc;
860 
861 		assoc_mgr_root_assoc = assoc;
862 		/* set up new root since if running off cache the
863 		   total usage for the cluster doesn't get set up again */
864 		if (last_root) {
865 			assoc_mgr_root_assoc->usage->usage_raw =
866 				last_root->usage->usage_raw;
867 			assoc_mgr_root_assoc->usage->usage_norm =
868 				last_root->usage->usage_norm;
869 			memcpy(assoc_mgr_root_assoc->usage->usage_tres_raw,
870 			       last_root->usage->usage_tres_raw,
871 			       sizeof(long double) * g_tres_count);
872 		}
873 	}
874 
875 	if (assoc->user) {
876 		uid_t pw_uid;
877 
878 		g_user_assoc_count++;
879 		if (assoc->uid == NO_VAL || assoc->uid == INFINITE ||
880 				assoc->uid == 0) {
881 			if (uid_from_string(assoc->user, &pw_uid) < 0)
882 				assoc->uid = NO_VAL;
883 			else
884 				assoc->uid = pw_uid;
885 		}
886 		_set_user_default_acct(assoc);
887 
888 		/* get the qos bitmap here */
889 		if (g_qos_count > 0) {
890 			if (!assoc->usage->valid_qos
891 			    || (bit_size(assoc->usage->valid_qos)
892 				!= g_qos_count)) {
893 				FREE_NULL_BITMAP(assoc->usage->valid_qos);
894 				assoc->usage->valid_qos =
895 					bit_alloc(g_qos_count);
896 			} else
897 				bit_nclear(assoc->usage->valid_qos, 0,
898 					   (bit_size(assoc->usage->valid_qos)
899 					    - 1));
900 			set_qos_bitstr_from_list(assoc->usage->valid_qos,
901 						 assoc->qos_list);
902 			if (((int32_t)assoc->def_qos_id > 0)
903 			    && !bit_test(assoc->usage->valid_qos,
904 					 assoc->def_qos_id)) {
905 				error("assoc %u doesn't have access "
906 				      "to it's default qos '%s'",
907 				      assoc->id,
908 				      slurmdb_qos_str(assoc_mgr_qos_list,
909 						      assoc->def_qos_id));
910 				assoc->def_qos_id = 0;
911 			}
912 		} else
913 			assoc->def_qos_id = 0;
914 	} else {
915 		assoc->uid = NO_VAL;
916 	}
917 	/* If you uncomment this below make sure you put READ_LOCK on
918 	 * the qos_list (the third lock) on calling functions.
919 	 */
920 	//log_assoc_rec(assoc);
921 
922 	return SLURM_SUCCESS;
923 }
924 
_set_assoc_norm_priority(slurmdb_assoc_rec_t * assoc)925 static void _set_assoc_norm_priority(slurmdb_assoc_rec_t *assoc)
926 {
927 	if (!assoc)
928 		return;
929 
930 	if (assoc->priority == INFINITE)
931 		assoc->priority = 0;
932 
933 	if (!g_assoc_max_priority)
934 		return;
935 
936 	if (!assoc->usage)
937 		assoc->usage = slurmdb_create_assoc_usage(g_tres_count);
938 	assoc->usage->priority_norm =
939 		(double)assoc->priority / (double)g_assoc_max_priority;
940 }
941 
_calculate_assoc_norm_priorities(bool new_max)942 static void _calculate_assoc_norm_priorities(bool new_max)
943 {
944 	ListIterator itr = NULL;
945 	slurmdb_assoc_rec_t *assoc;
946 
947 	xassert(verify_assoc_lock(ASSOC_LOCK, WRITE_LOCK));
948 	xassert(verify_assoc_lock(QOS_LOCK, READ_LOCK));
949 	xassert(verify_assoc_lock(TRES_LOCK, READ_LOCK));
950 	xassert(verify_assoc_lock(USER_LOCK, WRITE_LOCK));
951 
952 	itr = list_iterator_create(assoc_mgr_assoc_list);
953 
954 	if (new_max) {
955 		g_assoc_max_priority = 0;
956 		while ((assoc = list_next(itr))) {
957 			if ((assoc->priority != INFINITE) &&
958 			    assoc->priority > g_assoc_max_priority)
959 				g_assoc_max_priority = assoc->priority;
960 		}
961 	}
962 
963 	list_iterator_reset(itr);
964 	while ((assoc = list_next(itr)))
965 		_set_assoc_norm_priority(assoc);
966 
967 	list_iterator_destroy(itr);
968 }
969 
_set_qos_norm_priority(slurmdb_qos_rec_t * qos)970 static void _set_qos_norm_priority(slurmdb_qos_rec_t *qos)
971 {
972 	if (!qos || !g_qos_max_priority)
973 		return;
974 
975 	if (!qos->usage)
976 		qos->usage = slurmdb_create_qos_usage(g_tres_count);
977 	qos->usage->norm_priority =
978 		(double)qos->priority / (double)g_qos_max_priority;
979 }
980 
_get_children_level_shares(slurmdb_assoc_rec_t * assoc)981 static uint32_t _get_children_level_shares(slurmdb_assoc_rec_t *assoc)
982 {
983 	List children = assoc->usage->children_list;
984 	ListIterator itr = NULL;
985 	slurmdb_assoc_rec_t *child;
986 	uint32_t sum = 0;
987 
988 	if (!children || list_is_empty(children))
989 		return 0;
990 
991 	itr = list_iterator_create(children);
992 	while ((child = list_next(itr))) {
993 		if (child->shares_raw == SLURMDB_FS_USE_PARENT)
994 			sum += _get_children_level_shares(child);
995 		else
996 			sum += child->shares_raw;
997 	}
998 	list_iterator_destroy(itr);
999 
1000 	return sum;
1001 }
1002 
1003 
_set_children_level_shares(slurmdb_assoc_rec_t * assoc,uint32_t level_shares)1004 static void _set_children_level_shares(slurmdb_assoc_rec_t *assoc,
1005 				       uint32_t level_shares)
1006 {
1007 	List children = assoc->usage->children_list;
1008 	ListIterator itr = NULL;
1009 	slurmdb_assoc_rec_t *child;
1010 
1011 	if (!children || list_is_empty(children))
1012 		return;
1013 	//info("parent %d %s %s", assoc->id, assoc->acct, assoc->user);
1014 	itr = list_iterator_create(children);
1015 	while ((child = list_next(itr))) {
1016 		/* info("%d %s %s has %d shares", */
1017 		/*      child->id, child->acct, child->user, level_shares); */
1018 		child->usage->level_shares = level_shares;
1019 	}
1020 	list_iterator_destroy(itr);
1021 }
1022 
1023 /* transfer slurmdb assoc list to be assoc_mgr assoc list */
_post_assoc_list(void)1024 static int _post_assoc_list(void)
1025 {
1026 	slurmdb_assoc_rec_t *assoc = NULL;
1027 	ListIterator itr = NULL;
1028 	int reset = 1;
1029 	g_assoc_max_priority = 0;
1030 	//DEF_TIMERS;
1031 
1032 	xassert(verify_assoc_lock(ASSOC_LOCK, WRITE_LOCK));
1033 	xassert(verify_assoc_lock(QOS_LOCK, READ_LOCK));
1034 	xassert(verify_assoc_lock(TRES_LOCK, READ_LOCK));
1035 	xassert(verify_assoc_lock(USER_LOCK, WRITE_LOCK));
1036 
1037 	if (!assoc_mgr_assoc_list)
1038 		return SLURM_ERROR;
1039 
1040 	xfree(assoc_hash_id);
1041 	xfree(assoc_hash);
1042 
1043 	itr = list_iterator_create(assoc_mgr_assoc_list);
1044 
1045 	//START_TIMER;
1046 	g_user_assoc_count = 0;
1047 	while ((assoc = list_next(itr))) {
1048 		_set_assoc_parent_and_user(assoc, reset);
1049 		_add_assoc_hash(assoc);
1050 		assoc_mgr_set_assoc_tres_cnt(assoc);
1051 		reset = 0;
1052 	}
1053 
1054 	if (setup_children) {
1055 		/* Now set the shares on each level */
1056 		list_iterator_reset(itr);
1057 		while ((assoc = list_next(itr))) {
1058 			if (!assoc->usage->children_list
1059 			    || list_is_empty(assoc->usage->children_list))
1060 				continue;
1061 
1062 			_set_children_level_shares(
1063 				assoc,
1064 				_get_children_level_shares(assoc));
1065 		}
1066 		/* Now normalize the static shares */
1067 		list_iterator_reset(itr);
1068 		while ((assoc = list_next(itr)))
1069 			assoc_mgr_normalize_assoc_shares(assoc);
1070 	}
1071 	list_iterator_destroy(itr);
1072 
1073 	_calculate_assoc_norm_priorities(true);
1074 
1075 	slurmdb_sort_hierarchical_assoc_list(assoc_mgr_assoc_list, true);
1076 
1077 	//END_TIMER2("load_associations");
1078 	return SLURM_SUCCESS;
1079 }
1080 
_post_user_list(List user_list)1081 static int _post_user_list(List user_list)
1082 {
1083 	slurmdb_user_rec_t *user = NULL;
1084 	ListIterator itr = list_iterator_create(user_list);
1085 	DEF_TIMERS;
1086 
1087 	START_TIMER;
1088 	while ((user = list_next(itr))) {
1089 		uid_t pw_uid;
1090 		/* Just to make sure we have a default_wckey since it
1091 		   might not be set up yet.
1092 		*/
1093 		if (!user->default_wckey)
1094 			user->default_wckey = xstrdup("");
1095 		if (uid_from_string (user->name, &pw_uid) < 0) {
1096 			debug("%s: couldn't get a uid for user: %s",
1097 			      __func__, user->name);
1098 			user->uid = NO_VAL;
1099 		} else
1100 			user->uid = pw_uid;
1101 	}
1102 	list_iterator_destroy(itr);
1103 	END_TIMER2(__func__);
1104 	return SLURM_SUCCESS;
1105 }
1106 
_post_wckey_list(List wckey_list)1107 static int _post_wckey_list(List wckey_list)
1108 {
1109 	slurmdb_wckey_rec_t *wckey = NULL;
1110 	ListIterator itr = list_iterator_create(wckey_list);
1111 	//START_TIMER;
1112 
1113 	xassert(assoc_mgr_user_list);
1114 
1115 	while ((wckey = list_next(itr))) {
1116 		uid_t pw_uid;
1117 		if (uid_from_string (wckey->user, &pw_uid) < 0) {
1118 			if (slurmdbd_conf)
1119 				debug("post wckey: couldn't get a uid "
1120 				      "for user %s",
1121 				      wckey->user);
1122 			wckey->uid = NO_VAL;
1123 		} else
1124 			wckey->uid = pw_uid;
1125 		_set_user_default_wckey(wckey);
1126 	}
1127 	list_iterator_destroy(itr);
1128 	return SLURM_SUCCESS;
1129 }
1130 
1131 /* NOTE QOS write lock needs to be set before calling this. */
_post_qos_list(List qos_list)1132 static int _post_qos_list(List qos_list)
1133 {
1134 	slurmdb_qos_rec_t *qos = NULL;
1135 	ListIterator itr = list_iterator_create(qos_list);
1136 
1137 	g_qos_count = 0;
1138 	g_qos_max_priority = 0;
1139 
1140 	while ((qos = list_next(itr))) {
1141 		if (qos->flags & QOS_FLAG_NOTSET)
1142 			qos->flags = 0;
1143 
1144 		if (!qos->usage)
1145 			qos->usage = slurmdb_create_qos_usage(g_tres_count);
1146 		/* get the highest qos value to create bitmaps from */
1147 		if (qos->id > g_qos_count)
1148 			g_qos_count = qos->id;
1149 
1150 		if (qos->priority > g_qos_max_priority)
1151 			g_qos_max_priority = qos->priority;
1152 
1153 		assoc_mgr_set_qos_tres_cnt(qos);
1154 	}
1155 	/* Since in the database id's don't start at 1
1156 	   instead of 0 we need to ignore the 0 bit and start
1157 	   with 1 so increase the count by 1.
1158 	*/
1159 	if (g_qos_count > 0)
1160 		g_qos_count++;
1161 
1162 	if (g_qos_max_priority) {
1163 		list_iterator_reset(itr);
1164 
1165 		while ((qos = list_next(itr)))
1166 			_set_qos_norm_priority(qos);
1167 	}
1168 	list_iterator_destroy(itr);
1169 
1170 	return SLURM_SUCCESS;
1171 }
1172 
_post_res_list(List res_list)1173 static int _post_res_list(List res_list)
1174 {
1175 	if (res_list && assoc_mgr_cluster_name) {
1176 		slurmdb_res_rec_t *object = NULL;
1177 		ListIterator itr = list_iterator_create(res_list);
1178 		while ((object = list_next(itr))) {
1179 			if (object->clus_res_list
1180 			    && list_count(object->clus_res_list)) {
1181 				xassert(!object->clus_res_rec);
1182 
1183 				while ((object->clus_res_rec =
1184 					list_pop(object->clus_res_list))) {
1185 					/* only update the local clusters
1186 					 * res, only one per res
1187 					 * record, so throw the others away. */
1188 					if (!xstrcasecmp(object->clus_res_rec->
1189 							cluster,
1190 							assoc_mgr_cluster_name))
1191 						break;
1192 					slurmdb_destroy_clus_res_rec(
1193 						object->clus_res_rec);
1194 				}
1195 				FREE_NULL_LIST(object->clus_res_list);
1196 			}
1197 
1198 			if (!object->clus_res_rec) {
1199 				error("Bad resource given %s@%s",
1200 				      object->name, object->server);
1201 				list_delete_item(itr);
1202 			}
1203 		}
1204 		list_iterator_destroy(itr);
1205 	}
1206 
1207 	if (init_setup.sync_license_notify)
1208 		init_setup.sync_license_notify(res_list);
1209 
1210 	return SLURM_SUCCESS;
1211 }
1212 
1213 /*
1214  * Given the cur_pos of a tres in new_array return the old position of
1215  * the same tres in the old_array.
1216  */
_get_old_tres_pos(slurmdb_tres_rec_t ** new_array,slurmdb_tres_rec_t ** old_array,int cur_pos,int old_cnt)1217 static int _get_old_tres_pos(slurmdb_tres_rec_t **new_array,
1218 			     slurmdb_tres_rec_t **old_array,
1219 			     int cur_pos, int old_cnt)
1220 {
1221 	int j, pos = NO_VAL;
1222 
1223 	/* This means the tres didn't change order */
1224 	if ((cur_pos < old_cnt) &&
1225 	    (new_array[cur_pos]->id == old_array[cur_pos]->id))
1226 		pos = cur_pos;
1227 	else {
1228 		/* This means we might of changed the location or it
1229 		 * wasn't there before so break
1230 		 */
1231 		for (j = 0; j < old_cnt; j++)
1232 			if (new_array[cur_pos]->id == old_array[j]->id) {
1233 				pos = j;
1234 				break;
1235 			}
1236 	}
1237 
1238 	return pos;
1239 }
1240 
1241 /* assoc, qos and tres write lock should be locked before calling this
1242  * return 1 if callback is needed */
assoc_mgr_post_tres_list(List new_list)1243 extern int assoc_mgr_post_tres_list(List new_list)
1244 {
1245 	ListIterator itr;
1246 	slurmdb_tres_rec_t *tres_rec, **new_array;
1247 	char **new_name_array;
1248 	bool changed_size = false, changed_pos = false;
1249 	int i;
1250 	int new_cnt;
1251 
1252 	xassert(new_list);
1253 
1254 	new_cnt = list_count(new_list);
1255 
1256 	xassert(new_cnt > 0);
1257 
1258 	new_array = xcalloc(new_cnt, sizeof(slurmdb_tres_rec_t *));
1259 	new_name_array = xcalloc(new_cnt, sizeof(char *));
1260 
1261 	list_sort(new_list, (ListCmpF)slurmdb_sort_tres_by_id_asc);
1262 
1263 	/* we don't care if it gets smaller */
1264 	if (new_cnt > g_tres_count)
1265 		changed_size = true;
1266 
1267 	/* Set up the new array to see if we need to update any other
1268 	   arrays with current values.
1269 	*/
1270 	i = 0;
1271 	itr = list_iterator_create(new_list);
1272 	while ((tres_rec = list_next(itr))) {
1273 
1274 		new_array[i] = tres_rec;
1275 
1276 		new_name_array[i] = xstrdup_printf(
1277 			"%s%s%s",
1278 			tres_rec->type,
1279 			tres_rec->name ? "/" : "",
1280 			tres_rec->name ? tres_rec->name : "");
1281 
1282 		/*
1283 		 * This can happen when a new static or dynamic TRES is added.
1284 		 */
1285 		if (assoc_mgr_tres_array && (i < g_tres_count) &&
1286 		    (new_array[i]->id != assoc_mgr_tres_array[i]->id))
1287 			changed_pos = true;
1288 		i++;
1289 	}
1290 	list_iterator_destroy(itr);
1291 
1292 	/* If for some reason the position changed
1293 	 * (new static) we need to move it to it's new place.
1294 	 */
1295 	xfree(assoc_mgr_tres_old_pos);
1296 	if (changed_pos) {
1297 		int pos;
1298 
1299 		assoc_mgr_tres_old_pos = xcalloc(new_cnt, sizeof(int));
1300 		for (i=0; i<new_cnt; i++) {
1301 			if (!new_array[i]) {
1302 				assoc_mgr_tres_old_pos[i] = -1;
1303 				continue;
1304 			}
1305 
1306 			pos = _get_old_tres_pos(new_array, assoc_mgr_tres_array,
1307 						i, g_tres_count);
1308 
1309 			if (pos == NO_VAL)
1310 				assoc_mgr_tres_old_pos[i] = -1;
1311 			else
1312 				assoc_mgr_tres_old_pos[i] = pos;
1313 		}
1314 	}
1315 
1316 
1317 	xfree(assoc_mgr_tres_array);
1318 	assoc_mgr_tres_array = new_array;
1319 	new_array = NULL;
1320 
1321 	if (assoc_mgr_tres_name_array) {
1322 		for (i=0; i<g_tres_count; i++)
1323 			xfree(assoc_mgr_tres_name_array[i]);
1324 		xfree(assoc_mgr_tres_name_array);
1325 	}
1326 	assoc_mgr_tres_name_array = new_name_array;
1327 	new_name_array = NULL;
1328 
1329 	FREE_NULL_LIST(assoc_mgr_tres_list);
1330 	assoc_mgr_tres_list = new_list;
1331 	new_list = NULL;
1332 
1333 	g_tres_count = new_cnt;
1334 
1335 	if ((changed_size || changed_pos) &&
1336 	    assoc_mgr_assoc_list && assoc_mgr_qos_list) {
1337 		uint64_t grp_used_tres[new_cnt],
1338 			grp_used_tres_run_secs[new_cnt];
1339 		long double usage_tres_raw[new_cnt];
1340 		slurmdb_assoc_rec_t *assoc_rec;
1341 		slurmdb_qos_rec_t *qos_rec;
1342 		int array_size = sizeof(uint64_t) * new_cnt;
1343 		int d_array_size = sizeof(long double) * new_cnt;
1344 		slurmdb_used_limits_t *used_limits;
1345 		ListIterator itr_user;
1346 
1347 		/* update the associations and such here */
1348 		itr = list_iterator_create(assoc_mgr_assoc_list);
1349 		while ((assoc_rec = list_next(itr))) {
1350 
1351 			assoc_mgr_set_assoc_tres_cnt(assoc_rec);
1352 
1353 			if (!assoc_rec->usage)
1354 				continue;
1355 
1356 			/* Need to increase the size of the usage counts. */
1357 			if (changed_size) {
1358 				assoc_rec->usage->tres_cnt = new_cnt;
1359 				xrealloc(assoc_rec->usage->grp_used_tres,
1360 					 array_size);
1361 				xrealloc(assoc_rec->usage->
1362 					 grp_used_tres_run_secs,
1363 					 array_size);
1364 				xrealloc(assoc_rec->usage->usage_tres_raw,
1365 					 d_array_size);
1366 			}
1367 
1368 
1369 			if (changed_pos) {
1370 				memset(grp_used_tres, 0, array_size);
1371 				memset(grp_used_tres_run_secs, 0, array_size);
1372 				memset(usage_tres_raw, 0, d_array_size);
1373 
1374 				for (i=0; i<new_cnt; i++) {
1375 					int old_pos = assoc_mgr_tres_old_pos[i];
1376 					if (old_pos == -1)
1377 						continue;
1378 
1379 					grp_used_tres[i] = assoc_rec->
1380 						usage->grp_used_tres[old_pos];
1381 					grp_used_tres_run_secs[i] = assoc_rec->
1382 						usage->grp_used_tres_run_secs
1383 						[old_pos];
1384 					usage_tres_raw[i] =
1385 						assoc_rec->usage->usage_tres_raw
1386 						[old_pos];
1387 				}
1388 				memcpy(assoc_rec->usage->grp_used_tres,
1389 				       grp_used_tres, array_size);
1390 				memcpy(assoc_rec->usage->grp_used_tres_run_secs,
1391 				       grp_used_tres_run_secs, array_size);
1392 				memcpy(assoc_rec->usage->usage_tres_raw,
1393 				       usage_tres_raw, d_array_size);
1394 			}
1395 		}
1396 		list_iterator_destroy(itr);
1397 
1398 		/* update the qos and such here */
1399 		itr = list_iterator_create(assoc_mgr_qos_list);
1400 		while ((qos_rec = list_next(itr))) {
1401 
1402 			assoc_mgr_set_qos_tres_cnt(qos_rec);
1403 
1404 			if (!qos_rec->usage)
1405 				continue;
1406 
1407 			/* Need to increase the size of the usage counts. */
1408 			if (changed_size) {
1409 				qos_rec->usage->tres_cnt = new_cnt;
1410 				xrealloc(qos_rec->usage->
1411 					 grp_used_tres,
1412 					 array_size);
1413 				xrealloc(qos_rec->usage->
1414 					 grp_used_tres_run_secs,
1415 					 array_size);
1416 				xrealloc(qos_rec->usage->
1417 					 usage_tres_raw,
1418 					 d_array_size);
1419 				if (qos_rec->usage->user_limit_list) {
1420 					itr_user = list_iterator_create(
1421 						qos_rec->usage->
1422 						user_limit_list);
1423 					while ((used_limits = list_next(
1424 							itr_user))) {
1425 						xrealloc(used_limits->
1426 							 tres,
1427 							 array_size);
1428 						xrealloc(used_limits->
1429 							 tres_run_mins,
1430 							 array_size);
1431 					}
1432 					list_iterator_destroy(itr_user);
1433 				}
1434 			}
1435 
1436 			/* If for some reason the position changed
1437 			 * (new static) we need to move it to it's new place.
1438 			 */
1439 			if (changed_pos) {
1440 				memset(grp_used_tres, 0, array_size);
1441 				memset(grp_used_tres_run_secs, 0, array_size);
1442 				memset(usage_tres_raw, 0, d_array_size);
1443 
1444 				for (i=0; i<new_cnt; i++) {
1445 					int old_pos = assoc_mgr_tres_old_pos[i];
1446 					if (old_pos == -1)
1447 						continue;
1448 
1449 					grp_used_tres[i] = qos_rec->
1450 						usage->grp_used_tres[old_pos];
1451 					grp_used_tres_run_secs[i] = qos_rec->
1452 						usage->grp_used_tres_run_secs
1453 						[old_pos];
1454 					usage_tres_raw[i] =
1455 						qos_rec->usage->usage_tres_raw
1456 						[old_pos];
1457 				}
1458 				memcpy(qos_rec->usage->grp_used_tres,
1459 				       grp_used_tres, array_size);
1460 				memcpy(qos_rec->usage->grp_used_tres_run_secs,
1461 				       grp_used_tres_run_secs, array_size);
1462 				memcpy(qos_rec->usage->usage_tres_raw,
1463 				       usage_tres_raw, d_array_size);
1464 				if (qos_rec->usage->user_limit_list) {
1465 					itr_user = list_iterator_create(
1466 						qos_rec->usage->
1467 						user_limit_list);
1468 					while ((used_limits = list_next(
1469 							itr_user))) {
1470 						memset(grp_used_tres, 0,
1471 						       array_size);
1472 						memset(grp_used_tres_run_secs,
1473 						       0, array_size);
1474 						for (i=0; i<new_cnt; i++) {
1475 							int old_pos =
1476 								assoc_mgr_tres_old_pos[i];
1477 							if (old_pos == -1)
1478 								continue;
1479 
1480 							grp_used_tres[i] =
1481 								used_limits->
1482 								tres[old_pos];
1483 							grp_used_tres_run_secs
1484 								[i] =
1485 								used_limits->
1486 								tres_run_mins
1487 								[old_pos];
1488 						}
1489 
1490 						memcpy(used_limits->tres,
1491 						       grp_used_tres,
1492 						       array_size);
1493 						memcpy(used_limits->
1494 						       tres_run_mins,
1495 						       grp_used_tres_run_secs,
1496 						       array_size);
1497 					}
1498 					list_iterator_destroy(itr_user);
1499 				}
1500 			}
1501 		}
1502 		list_iterator_destroy(itr);
1503 	}
1504 
1505 	return (changed_size || changed_pos) ? 1 : 0;
1506 }
1507 
_get_assoc_mgr_tres_list(void * db_conn,int enforce)1508 static int _get_assoc_mgr_tres_list(void *db_conn, int enforce)
1509 {
1510 	slurmdb_tres_cond_t tres_q;
1511 	uid_t uid = getuid();
1512 	List new_list = NULL;
1513 	char *tres_req_str;
1514 	int changed;
1515 	assoc_mgr_lock_t locks =
1516 		{ .assoc = WRITE_LOCK, .qos = WRITE_LOCK, .tres= WRITE_LOCK };
1517 
1518 	memset(&tres_q, 0, sizeof(slurmdb_tres_cond_t));
1519 
1520 	assoc_mgr_lock(&locks);
1521 
1522 	/* If this exists we only want/care about tracking/caching these TRES */
1523 	if ((tres_req_str = slurm_get_accounting_storage_tres())) {
1524 		tres_q.type_list = list_create(xfree_ptr);
1525 		slurm_addto_char_list(tres_q.type_list, tres_req_str);
1526 		xfree(tres_req_str);
1527 	}
1528 	new_list = acct_storage_g_get_tres(
1529 		db_conn, uid, &tres_q);
1530 
1531 	FREE_NULL_LIST(tres_q.type_list);
1532 
1533 	if (!new_list) {
1534 		assoc_mgr_unlock(&locks);
1535 		if (enforce & ACCOUNTING_ENFORCE_ASSOCS) {
1536 			error("_get_assoc_mgr_tres_list: "
1537 			      "no list was made.");
1538 			return SLURM_ERROR;
1539 		} else {
1540 			return SLURM_SUCCESS;
1541 		}
1542 	}
1543 
1544 	changed = assoc_mgr_post_tres_list(new_list);
1545 
1546 	assoc_mgr_unlock(&locks);
1547 
1548 	if (changed && !_running_cache() && init_setup.update_cluster_tres) {
1549 		/* update jobs here, this needs to be outside of the
1550 		 * assoc_mgr locks */
1551 		init_setup.update_cluster_tres();
1552 	}
1553 
1554 	return SLURM_SUCCESS;
1555 }
1556 
_get_assoc_mgr_assoc_list(void * db_conn,int enforce)1557 static int _get_assoc_mgr_assoc_list(void *db_conn, int enforce)
1558 {
1559 	slurmdb_assoc_cond_t assoc_q;
1560 	uid_t uid = getuid();
1561 	assoc_mgr_lock_t locks = { .assoc = WRITE_LOCK, .qos = READ_LOCK,
1562 				   .tres = READ_LOCK, .user = WRITE_LOCK };
1563 
1564 //	DEF_TIMERS;
1565 	assoc_mgr_lock(&locks);
1566 	FREE_NULL_LIST(assoc_mgr_assoc_list);
1567 
1568 	memset(&assoc_q, 0, sizeof(slurmdb_assoc_cond_t));
1569 	if (assoc_mgr_cluster_name) {
1570 		assoc_q.cluster_list = list_create(NULL);
1571 		list_append(assoc_q.cluster_list, assoc_mgr_cluster_name);
1572 	} else if ((enforce & ACCOUNTING_ENFORCE_ASSOCS) && !slurmdbd_conf) {
1573 		error("_get_assoc_mgr_assoc_list: "
1574 		      "no cluster name here going to get "
1575 		      "all associations.");
1576 	}
1577 
1578 //	START_TIMER;
1579 	assoc_mgr_assoc_list =
1580 		acct_storage_g_get_assocs(db_conn, uid, &assoc_q);
1581 //	END_TIMER2("get_assocs");
1582 
1583 	FREE_NULL_LIST(assoc_q.cluster_list);
1584 
1585 	if (!assoc_mgr_assoc_list) {
1586 		/* create list so we don't keep calling this if there
1587 		   isn't anything there */
1588 		assoc_mgr_assoc_list =
1589 			list_create(slurmdb_destroy_assoc_rec);
1590 		assoc_mgr_unlock(&locks);
1591 		if (enforce & ACCOUNTING_ENFORCE_ASSOCS) {
1592 			error("_get_assoc_mgr_assoc_list: "
1593 			      "no list was made.");
1594 			return SLURM_ERROR;
1595 		} else {
1596 			debug3("not enforcing associations and no "
1597 			       "list was given so we are giving a blank list");
1598 			return SLURM_SUCCESS;
1599 		}
1600 	}
1601 
1602 	_post_assoc_list();
1603 
1604 	assoc_mgr_unlock(&locks);
1605 
1606 	return SLURM_SUCCESS;
1607 }
1608 
_get_assoc_mgr_res_list(void * db_conn,int enforce)1609 static int _get_assoc_mgr_res_list(void *db_conn, int enforce)
1610 {
1611 	slurmdb_res_cond_t res_q;
1612 	uid_t uid = getuid();
1613 	assoc_mgr_lock_t locks = { .res = WRITE_LOCK };
1614 
1615 	assoc_mgr_lock(&locks);
1616 	FREE_NULL_LIST(assoc_mgr_res_list);
1617 
1618 	slurmdb_init_res_cond(&res_q, 0);
1619 	if (assoc_mgr_cluster_name) {
1620 		res_q.with_clusters = 1;
1621 		res_q.cluster_list = list_create(NULL);
1622 		list_append(res_q.cluster_list, assoc_mgr_cluster_name);
1623 	} else if ((enforce & ACCOUNTING_ENFORCE_ASSOCS) && !slurmdbd_conf) {
1624 		error("_get_assoc_mgr_res_list: "
1625 		      "no cluster name here going to get "
1626 		      "all associations.");
1627 	}
1628 
1629 	assoc_mgr_res_list = acct_storage_g_get_res(db_conn, uid, &res_q);
1630 
1631 	FREE_NULL_LIST(res_q.cluster_list);
1632 
1633 	if (!assoc_mgr_res_list) {
1634 		assoc_mgr_unlock(&locks);
1635 		if (enforce & ACCOUNTING_ENFORCE_ASSOCS) {
1636 			error("_get_assoc_mgr_res_list:"
1637 			      "no list was made.");
1638 			return SLURM_ERROR;
1639 		} else {
1640 			return SLURM_SUCCESS;
1641 		}
1642 	}
1643 
1644 	_post_res_list(assoc_mgr_res_list);
1645 
1646 	assoc_mgr_unlock(&locks);
1647 	return SLURM_SUCCESS;
1648 }
1649 
_get_assoc_mgr_qos_list(void * db_conn,int enforce)1650 static int _get_assoc_mgr_qos_list(void *db_conn, int enforce)
1651 {
1652 	uid_t uid = getuid();
1653 	List new_list = NULL;
1654 	assoc_mgr_lock_t locks = { .qos = WRITE_LOCK };
1655 
1656 	new_list = acct_storage_g_get_qos(db_conn, uid, NULL);
1657 
1658 	if (!new_list) {
1659 		if (enforce & ACCOUNTING_ENFORCE_ASSOCS) {
1660 			error("_get_assoc_mgr_qos_list: no list was made.");
1661 			return SLURM_ERROR;
1662 		} else {
1663 			return SLURM_SUCCESS;
1664 		}
1665 	}
1666 
1667 	assoc_mgr_lock(&locks);
1668 
1669 	FREE_NULL_LIST(assoc_mgr_qos_list);
1670 	assoc_mgr_qos_list = new_list;
1671 	new_list = NULL;
1672 
1673 	_post_qos_list(assoc_mgr_qos_list);
1674 
1675 	assoc_mgr_unlock(&locks);
1676 
1677 	return SLURM_SUCCESS;
1678 }
1679 
_get_assoc_mgr_user_list(void * db_conn,int enforce)1680 static int _get_assoc_mgr_user_list(void *db_conn, int enforce)
1681 {
1682 	slurmdb_user_cond_t user_q;
1683 	uid_t uid = getuid();
1684 	assoc_mgr_lock_t locks = { .user = WRITE_LOCK };
1685 
1686 	memset(&user_q, 0, sizeof(slurmdb_user_cond_t));
1687 	user_q.with_coords = 1;
1688 
1689 	assoc_mgr_lock(&locks);
1690 	FREE_NULL_LIST(assoc_mgr_user_list);
1691 	assoc_mgr_user_list = acct_storage_g_get_users(db_conn, uid, &user_q);
1692 
1693 	if (!assoc_mgr_user_list) {
1694 		assoc_mgr_unlock(&locks);
1695 		if (enforce & ACCOUNTING_ENFORCE_ASSOCS) {
1696 			error("_get_assoc_mgr_user_list: "
1697 			      "no list was made.");
1698 			return SLURM_ERROR;
1699 		} else {
1700 			return SLURM_SUCCESS;
1701 		}
1702 	}
1703 
1704 	_post_user_list(assoc_mgr_user_list);
1705 
1706 	assoc_mgr_unlock(&locks);
1707 	return SLURM_SUCCESS;
1708 }
1709 
1710 
_get_assoc_mgr_wckey_list(void * db_conn,int enforce)1711 static int _get_assoc_mgr_wckey_list(void *db_conn, int enforce)
1712 {
1713 	slurmdb_wckey_cond_t wckey_q;
1714 	uid_t uid = getuid();
1715 	assoc_mgr_lock_t locks = { .user = WRITE_LOCK, .wckey = WRITE_LOCK };
1716 
1717 //	DEF_TIMERS;
1718 	assoc_mgr_lock(&locks);
1719 	FREE_NULL_LIST(assoc_mgr_wckey_list);
1720 
1721 	memset(&wckey_q, 0, sizeof(slurmdb_wckey_cond_t));
1722 	if (assoc_mgr_cluster_name) {
1723 		wckey_q.cluster_list = list_create(NULL);
1724 		list_append(wckey_q.cluster_list, assoc_mgr_cluster_name);
1725 	} else if ((enforce & ACCOUNTING_ENFORCE_WCKEYS) && !slurmdbd_conf) {
1726 		error("_get_assoc_mgr_wckey_list: "
1727 		      "no cluster name here going to get "
1728 		      "all wckeys.");
1729 	}
1730 
1731 //	START_TIMER;
1732 	assoc_mgr_wckey_list =
1733 		acct_storage_g_get_wckeys(db_conn, uid, &wckey_q);
1734 //	END_TIMER2("get_wckeys");
1735 
1736 	FREE_NULL_LIST(wckey_q.cluster_list);
1737 
1738 	if (!assoc_mgr_wckey_list) {
1739 		/* create list so we don't keep calling this if there
1740 		   isn't anything there */
1741 		assoc_mgr_wckey_list = list_create(slurmdb_destroy_wckey_rec);
1742 		assoc_mgr_unlock(&locks);
1743 		if (enforce & ACCOUNTING_ENFORCE_WCKEYS) {
1744 			error("_get_assoc_mgr_wckey_list: "
1745 			      "no list was made.");
1746 			return SLURM_ERROR;
1747 		} else {
1748 			debug3("not enforcing wckeys and no "
1749 			       "list was given so we are giving a blank list");
1750 			return SLURM_SUCCESS;
1751 		}
1752 	}
1753 
1754 	_post_wckey_list(assoc_mgr_wckey_list);
1755 
1756 	assoc_mgr_unlock(&locks);
1757 
1758 	return SLURM_SUCCESS;
1759 }
1760 
1761 /* This only gets a new list if available dropping the old one if
1762  * needed
1763  */
_refresh_assoc_mgr_tres_list(void * db_conn,int enforce)1764 static int _refresh_assoc_mgr_tres_list(void *db_conn, int enforce)
1765 {
1766 	/* this function does both get and refresh */
1767 	_get_assoc_mgr_tres_list(db_conn, enforce);
1768 
1769 	return SLURM_SUCCESS;
1770 }
1771 
_refresh_assoc_mgr_assoc_list(void * db_conn,int enforce)1772 static int _refresh_assoc_mgr_assoc_list(void *db_conn, int enforce)
1773 {
1774 	slurmdb_assoc_cond_t assoc_q;
1775 	List current_assocs = NULL;
1776 	uid_t uid = getuid();
1777 	ListIterator curr_itr = NULL;
1778 	slurmdb_assoc_rec_t *curr_assoc = NULL, *assoc = NULL;
1779 	assoc_mgr_lock_t locks = { .assoc = WRITE_LOCK, .qos = READ_LOCK,
1780 				   .tres = READ_LOCK, .user = WRITE_LOCK };
1781 //	DEF_TIMERS;
1782 
1783 	memset(&assoc_q, 0, sizeof(slurmdb_assoc_cond_t));
1784 	if (assoc_mgr_cluster_name) {
1785 		assoc_q.cluster_list = list_create(NULL);
1786 		list_append(assoc_q.cluster_list, assoc_mgr_cluster_name);
1787 	} else if ((enforce & ACCOUNTING_ENFORCE_ASSOCS) && !slurmdbd_conf) {
1788 		error("_refresh_assoc_mgr_assoc_list: "
1789 		      "no cluster name here going to get "
1790 		      "all associations.");
1791 	}
1792 
1793 	assoc_mgr_lock(&locks);
1794 
1795 	current_assocs = assoc_mgr_assoc_list;
1796 
1797 //	START_TIMER;
1798 	assoc_mgr_assoc_list =
1799 		acct_storage_g_get_assocs(db_conn, uid, &assoc_q);
1800 //	END_TIMER2("get_assocs");
1801 
1802 	FREE_NULL_LIST(assoc_q.cluster_list);
1803 
1804 	if (!assoc_mgr_assoc_list) {
1805 		assoc_mgr_assoc_list = current_assocs;
1806 		assoc_mgr_unlock(&locks);
1807 
1808 		error("_refresh_assoc_mgr_assoc_list: "
1809 		      "no new list given back keeping cached one.");
1810 		return SLURM_ERROR;
1811 	}
1812 
1813 	_post_assoc_list();
1814 
1815 	if (!current_assocs) {
1816 		assoc_mgr_unlock(&locks);
1817 		return SLURM_SUCCESS;
1818 	}
1819 
1820 	curr_itr = list_iterator_create(current_assocs);
1821 
1822 	/* add used limits We only look for the user associations to
1823 	 * do the parents since a parent may have moved */
1824 	while ((curr_assoc = list_next(curr_itr))) {
1825 		if (!curr_assoc->user)
1826 			continue;
1827 
1828 		if (!(assoc = _find_assoc_rec_id(curr_assoc->id)))
1829 			continue;
1830 
1831 		while (assoc) {
1832 			_addto_used_info(assoc, curr_assoc);
1833 			/* get the parent last since this pointer is
1834 			   different than the one we are updating from */
1835 			assoc = assoc->usage->parent_assoc_ptr;
1836 		}
1837 	}
1838 
1839 	list_iterator_destroy(curr_itr);
1840 
1841 	assoc_mgr_unlock(&locks);
1842 
1843 	FREE_NULL_LIST(current_assocs);
1844 
1845 	return SLURM_SUCCESS;
1846 }
1847 
1848 /* This only gets a new list if available dropping the old one if
1849  * needed
1850  */
_refresh_assoc_mgr_res_list(void * db_conn,int enforce)1851 static int _refresh_assoc_mgr_res_list(void *db_conn, int enforce)
1852 {
1853 	slurmdb_res_cond_t res_q;
1854 	List current_res = NULL;
1855 	uid_t uid = getuid();
1856 	assoc_mgr_lock_t locks = { .res = WRITE_LOCK };
1857 
1858 	slurmdb_init_res_cond(&res_q, 0);
1859 	if (assoc_mgr_cluster_name) {
1860 		res_q.with_clusters = 1;
1861 		res_q.cluster_list = list_create(NULL);
1862 		list_append(res_q.cluster_list, assoc_mgr_cluster_name);
1863 	} else if ((enforce & ACCOUNTING_ENFORCE_ASSOCS) && !slurmdbd_conf) {
1864 		error("_refresh_assoc_mgr_res_list: "
1865 		      "no cluster name here going to get "
1866 		      "all associations.");
1867 	}
1868 
1869 	current_res = acct_storage_g_get_res(db_conn, uid, &res_q);
1870 
1871 	FREE_NULL_LIST(res_q.cluster_list);
1872 
1873 	if (!current_res) {
1874 		error("_refresh_assoc_mgr_res_list: "
1875 		      "no new list given back keeping cached one.");
1876 		return SLURM_ERROR;
1877 	}
1878 
1879 	assoc_mgr_lock(&locks);
1880 
1881 	_post_res_list(current_res);
1882 
1883 	FREE_NULL_LIST(assoc_mgr_res_list);
1884 
1885 	assoc_mgr_res_list = current_res;
1886 
1887 	assoc_mgr_unlock(&locks);
1888 
1889 	return SLURM_SUCCESS;
1890 }
1891 
1892 /* This only gets a new list if available dropping the old one if
1893  * needed
1894  */
_refresh_assoc_mgr_qos_list(void * db_conn,int enforce)1895 static int _refresh_assoc_mgr_qos_list(void *db_conn, int enforce)
1896 {
1897 	List current_qos = NULL;
1898 	uid_t uid = getuid();
1899 	assoc_mgr_lock_t locks = { .qos = WRITE_LOCK };
1900 
1901 	current_qos = acct_storage_g_get_qos(db_conn, uid, NULL);
1902 
1903 	if (!current_qos) {
1904 		error("_refresh_assoc_mgr_qos_list: "
1905 		      "no new list given back keeping cached one.");
1906 		return SLURM_ERROR;
1907 	}
1908 
1909 	assoc_mgr_lock(&locks);
1910 
1911 	_post_qos_list(current_qos);
1912 
1913 	/* move usage from old list over to the new one */
1914 	if (assoc_mgr_qos_list) {
1915 		slurmdb_qos_rec_t *curr_qos = NULL, *qos_rec = NULL;
1916 		ListIterator itr = list_iterator_create(current_qos);
1917 
1918 		while ((curr_qos = list_next(itr))) {
1919 			if (!(qos_rec = list_find_first(assoc_mgr_qos_list,
1920 							slurmdb_find_qos_in_list,
1921 							&curr_qos->id)))
1922 				continue;
1923 			slurmdb_destroy_qos_usage(curr_qos->usage);
1924 			curr_qos->usage = qos_rec->usage;
1925 			qos_rec->usage = NULL;
1926 		}
1927 		list_iterator_destroy(itr);
1928 		FREE_NULL_LIST(assoc_mgr_qos_list);
1929 	}
1930 
1931 	assoc_mgr_qos_list = current_qos;
1932 
1933 	assoc_mgr_unlock(&locks);
1934 
1935 	return SLURM_SUCCESS;
1936 }
1937 
1938 /* This only gets a new list if available dropping the old one if
1939  * needed
1940  */
_refresh_assoc_mgr_user_list(void * db_conn,int enforce)1941 static int _refresh_assoc_mgr_user_list(void *db_conn, int enforce)
1942 {
1943 	List current_users = NULL;
1944 	slurmdb_user_cond_t user_q;
1945 	uid_t uid = getuid();
1946 	assoc_mgr_lock_t locks = { .user = WRITE_LOCK };
1947 
1948 	memset(&user_q, 0, sizeof(slurmdb_user_cond_t));
1949 	user_q.with_coords = 1;
1950 
1951 	current_users = acct_storage_g_get_users(db_conn, uid, &user_q);
1952 
1953 	if (!current_users) {
1954 		error("_refresh_assoc_mgr_user_list: "
1955 		      "no new list given back keeping cached one.");
1956 		return SLURM_ERROR;
1957 	}
1958 	_post_user_list(current_users);
1959 
1960 	assoc_mgr_lock(&locks);
1961 
1962 	FREE_NULL_LIST(assoc_mgr_user_list);
1963 
1964 	assoc_mgr_user_list = current_users;
1965 
1966 	assoc_mgr_unlock(&locks);
1967 
1968 	return SLURM_SUCCESS;
1969 }
1970 
1971 /* This only gets a new list if available dropping the old one if
1972  * needed
1973  */
_refresh_assoc_wckey_list(void * db_conn,int enforce)1974 static int _refresh_assoc_wckey_list(void *db_conn, int enforce)
1975 {
1976 	slurmdb_wckey_cond_t wckey_q;
1977 	List current_wckeys = NULL;
1978 	uid_t uid = getuid();
1979 	assoc_mgr_lock_t locks = { .user = WRITE_LOCK, .wckey = WRITE_LOCK };
1980 
1981 	memset(&wckey_q, 0, sizeof(slurmdb_wckey_cond_t));
1982 	if (assoc_mgr_cluster_name) {
1983 		wckey_q.cluster_list = list_create(NULL);
1984 		list_append(wckey_q.cluster_list, assoc_mgr_cluster_name);
1985 	} else if ((enforce & ACCOUNTING_ENFORCE_WCKEYS) && !slurmdbd_conf) {
1986 		error("_refresh_assoc_wckey_list: "
1987 		      "no cluster name here going to get "
1988 		      "all wckeys.");
1989 	}
1990 
1991 	current_wckeys = acct_storage_g_get_wckeys(db_conn, uid, &wckey_q);
1992 
1993 	FREE_NULL_LIST(wckey_q.cluster_list);
1994 
1995 	if (!current_wckeys) {
1996 		error("_refresh_assoc_wckey_list: "
1997 		      "no new list given back keeping cached one.");
1998 		return SLURM_ERROR;
1999 	}
2000 
2001 	_post_wckey_list(current_wckeys);
2002 
2003 	assoc_mgr_lock(&locks);
2004 	FREE_NULL_LIST(assoc_mgr_wckey_list);
2005 
2006 	assoc_mgr_wckey_list = current_wckeys;
2007 	assoc_mgr_unlock(&locks);
2008 
2009 	return SLURM_SUCCESS;
2010 }
2011 
assoc_mgr_init(void * db_conn,assoc_init_args_t * args,int db_conn_errno)2012 extern int assoc_mgr_init(void *db_conn, assoc_init_args_t *args,
2013 			  int db_conn_errno)
2014 {
2015 	static uint16_t checked_prio = 0;
2016 
2017 	if (!checked_prio) {
2018 		char *prio = slurm_get_priority_type();
2019 		if (prio && xstrcmp(prio, "priority/basic"))
2020 			setup_children = 1;
2021 
2022 		xfree(prio);
2023 		checked_prio = 1;
2024 		memset(&init_setup, 0, sizeof(assoc_init_args_t));
2025 		init_setup.cache_level = ASSOC_MGR_CACHE_ALL;
2026 	}
2027 
2028 	if (args)
2029 		memcpy(&init_setup, args, sizeof(assoc_init_args_t));
2030 
2031 	if (_running_cache()) {
2032 		debug4("No need to run assoc_mgr_init, "
2033 		       "we probably don't have a connection.  "
2034 		       "If we do use assoc_mgr_refresh_lists instead.");
2035 		return SLURM_SUCCESS;
2036 	}
2037 
2038 	if ((!assoc_mgr_cluster_name) && !slurmdbd_conf) {
2039 		xfree(assoc_mgr_cluster_name);
2040 		assoc_mgr_cluster_name = slurm_get_cluster_name();
2041 	}
2042 
2043 	/* check if we can't talk to the db yet (Do this after all
2044 	 * the initialization above) */
2045 	if (db_conn_errno != SLURM_SUCCESS)
2046 		return SLURM_ERROR;
2047 
2048 	/* get tres before association and qos since it is used there */
2049 	if ((!assoc_mgr_tres_list)
2050 	    && (init_setup.cache_level & ASSOC_MGR_CACHE_TRES)) {
2051 		if (_get_assoc_mgr_tres_list(db_conn, init_setup.enforce)
2052 		    == SLURM_ERROR)
2053 			return SLURM_ERROR;
2054 	}
2055 
2056 	/* get qos before association since it is used there */
2057 	if ((!assoc_mgr_qos_list)
2058 	    && (init_setup.cache_level & ASSOC_MGR_CACHE_QOS))
2059 		if (_get_assoc_mgr_qos_list(db_conn, init_setup.enforce) ==
2060 		    SLURM_ERROR)
2061 			return SLURM_ERROR;
2062 
2063 	/* get user before association/wckey since it is used there */
2064 	if ((!assoc_mgr_user_list)
2065 	    && (init_setup.cache_level & ASSOC_MGR_CACHE_USER))
2066 		if (_get_assoc_mgr_user_list(db_conn, init_setup.enforce) ==
2067 		    SLURM_ERROR)
2068 			return SLURM_ERROR;
2069 
2070 	if ((!assoc_mgr_assoc_list)
2071 	    && (init_setup.cache_level & ASSOC_MGR_CACHE_ASSOC))
2072 		if (_get_assoc_mgr_assoc_list(db_conn, init_setup.enforce)
2073 		    == SLURM_ERROR)
2074 			return SLURM_ERROR;
2075 
2076 	if (assoc_mgr_assoc_list && !setup_children) {
2077 		slurmdb_assoc_rec_t *assoc = NULL;
2078 		ListIterator itr =
2079 			list_iterator_create(assoc_mgr_assoc_list);
2080 		while ((assoc = list_next(itr))) {
2081 			log_assoc_rec(assoc, assoc_mgr_qos_list);
2082 		}
2083 		list_iterator_destroy(itr);
2084 	}
2085 
2086 	if ((!assoc_mgr_wckey_list)
2087 	    && (init_setup.cache_level & ASSOC_MGR_CACHE_WCKEY))
2088 		if (_get_assoc_mgr_wckey_list(db_conn, init_setup.enforce) ==
2089 		    SLURM_ERROR)
2090 			return SLURM_ERROR;
2091 
2092 	if ((!assoc_mgr_res_list)
2093 	    && (init_setup.cache_level & ASSOC_MGR_CACHE_RES))
2094 		if (_get_assoc_mgr_res_list(db_conn, init_setup.enforce) ==
2095 		    SLURM_ERROR)
2096 			return SLURM_ERROR;
2097 
2098 	return SLURM_SUCCESS;
2099 }
2100 
assoc_mgr_fini(bool save_state)2101 extern int assoc_mgr_fini(bool save_state)
2102 {
2103 	assoc_mgr_lock_t locks = { .assoc = WRITE_LOCK, .qos = WRITE_LOCK,
2104 				   .res = WRITE_LOCK, .tres = WRITE_LOCK,
2105 				   .user = WRITE_LOCK, .wckey = WRITE_LOCK };
2106 
2107 	if (save_state)
2108 		dump_assoc_mgr_state();
2109 
2110 	assoc_mgr_lock(&locks);
2111 
2112 	FREE_NULL_LIST(assoc_mgr_assoc_list);
2113 	FREE_NULL_LIST(assoc_mgr_tres_list);
2114 	FREE_NULL_LIST(assoc_mgr_res_list);
2115 	FREE_NULL_LIST(assoc_mgr_qos_list);
2116 	FREE_NULL_LIST(assoc_mgr_user_list);
2117 	FREE_NULL_LIST(assoc_mgr_wckey_list);
2118 	if (assoc_mgr_tres_name_array) {
2119 		int i;
2120 		for (i=0; i<g_tres_count; i++)
2121 			xfree(assoc_mgr_tres_name_array[i]);
2122 		xfree(assoc_mgr_tres_name_array);
2123 	}
2124 	xfree(assoc_mgr_tres_array);
2125 	xfree(assoc_mgr_tres_old_pos);
2126 	xfree(assoc_mgr_cluster_name);
2127 	assoc_mgr_assoc_list = NULL;
2128 	assoc_mgr_res_list = NULL;
2129 	assoc_mgr_qos_list = NULL;
2130 	assoc_mgr_user_list = NULL;
2131 	assoc_mgr_wckey_list = NULL;
2132 
2133 	assoc_mgr_root_assoc = NULL;
2134 
2135 	if (_running_cache())
2136 		*init_setup.running_cache = 0;
2137 
2138 	xfree(assoc_hash_id);
2139 	xfree(assoc_hash);
2140 
2141 	assoc_mgr_unlock(&locks);
2142 
2143 	return SLURM_SUCCESS;
2144 }
2145 
2146 #ifndef NDEBUG
2147 /*
2148  * Used to protect against double-locking within a single thread. Calling
2149  * assoc_mgr_lock() while already holding locks will lead to deadlock;
2150  * this will force such instances to abort() in development builds.
2151  */
2152 /*
2153  * FIXME: __thread is non-standard, and may cause build failures on unusual
2154  * systems. Only used within development builds to mitigate possible problems
2155  * with production builds.
2156  */
2157 static __thread bool assoc_mgr_locked = false;
2158 
2159 /*
2160  * Used to detect any location where the acquired locks differ from the
2161  * release locks.
2162  */
2163 
2164 static __thread assoc_mgr_lock_t thread_locks;
2165 
_store_locks(assoc_mgr_lock_t * lock_levels)2166 static bool _store_locks(assoc_mgr_lock_t *lock_levels)
2167 {
2168 	if (assoc_mgr_locked)
2169 		return false;
2170 	assoc_mgr_locked = true;
2171 
2172         memcpy((void *) &thread_locks, (void *) lock_levels,
2173                sizeof(assoc_mgr_lock_t));
2174 
2175         return true;
2176 }
2177 
_clear_locks(assoc_mgr_lock_t * lock_levels)2178 static bool _clear_locks(assoc_mgr_lock_t *lock_levels)
2179 {
2180 	if (!assoc_mgr_locked)
2181 		return false;
2182 	assoc_mgr_locked = false;
2183 
2184 	if (memcmp((void *) &thread_locks, (void *) lock_levels,
2185 		       sizeof(assoc_mgr_lock_t)))
2186 		return false;
2187 
2188 	memset((void *) &thread_locks, 0, sizeof(assoc_mgr_lock_t));
2189 
2190 	return true;
2191 }
2192 
verify_assoc_lock(assoc_mgr_lock_datatype_t datatype,lock_level_t level)2193 bool verify_assoc_lock(assoc_mgr_lock_datatype_t datatype, lock_level_t level)
2194 {
2195 	return (((lock_level_t *) &thread_locks)[datatype] >= level);
2196 }
2197 #endif
2198 
assoc_mgr_lock(assoc_mgr_lock_t * locks)2199 extern void assoc_mgr_lock(assoc_mgr_lock_t *locks)
2200 {
2201 	static bool init_run = false;
2202 	xassert(_store_locks(locks));
2203 
2204 	slurm_mutex_lock(&assoc_lock_init);
2205 	if (!init_run) {
2206 		init_run = true;
2207 		for (int i = 0; i < ASSOC_MGR_ENTITY_COUNT; i++)
2208 			slurm_rwlock_init(&assoc_mgr_locks[i]);
2209 	}
2210 	slurm_mutex_unlock(&assoc_lock_init);
2211 
2212 	if (locks->assoc == READ_LOCK)
2213 		slurm_rwlock_rdlock(&assoc_mgr_locks[ASSOC_LOCK]);
2214 	else if (locks->assoc == WRITE_LOCK)
2215 		slurm_rwlock_wrlock(&assoc_mgr_locks[ASSOC_LOCK]);
2216 
2217 	if (locks->file == READ_LOCK)
2218 		slurm_rwlock_rdlock(&assoc_mgr_locks[FILE_LOCK]);
2219 	else if (locks->file == WRITE_LOCK)
2220 		slurm_rwlock_wrlock(&assoc_mgr_locks[FILE_LOCK]);
2221 
2222 	if (locks->qos == READ_LOCK)
2223 		slurm_rwlock_rdlock(&assoc_mgr_locks[QOS_LOCK]);
2224 	else if (locks->qos == WRITE_LOCK)
2225 		slurm_rwlock_wrlock(&assoc_mgr_locks[QOS_LOCK]);
2226 
2227 	if (locks->res == READ_LOCK)
2228 		slurm_rwlock_rdlock(&assoc_mgr_locks[RES_LOCK]);
2229 	else if (locks->res == WRITE_LOCK)
2230 		slurm_rwlock_wrlock(&assoc_mgr_locks[RES_LOCK]);
2231 
2232 	if (locks->tres == READ_LOCK)
2233 		slurm_rwlock_rdlock(&assoc_mgr_locks[TRES_LOCK]);
2234 	else if (locks->tres == WRITE_LOCK)
2235 		slurm_rwlock_wrlock(&assoc_mgr_locks[TRES_LOCK]);
2236 
2237 	if (locks->user == READ_LOCK)
2238 		slurm_rwlock_rdlock(&assoc_mgr_locks[USER_LOCK]);
2239 	else if (locks->user == WRITE_LOCK)
2240 		slurm_rwlock_wrlock(&assoc_mgr_locks[USER_LOCK]);
2241 
2242 	if (locks->wckey == READ_LOCK)
2243 		slurm_rwlock_rdlock(&assoc_mgr_locks[WCKEY_LOCK]);
2244 	else if (locks->wckey == WRITE_LOCK)
2245 		slurm_rwlock_wrlock(&assoc_mgr_locks[WCKEY_LOCK]);
2246 }
2247 
assoc_mgr_unlock(assoc_mgr_lock_t * locks)2248 extern void assoc_mgr_unlock(assoc_mgr_lock_t *locks)
2249 {
2250 	xassert(_clear_locks(locks));
2251 
2252 	if (locks->wckey)
2253 		slurm_rwlock_unlock(&assoc_mgr_locks[WCKEY_LOCK]);
2254 
2255 	if (locks->user)
2256 		slurm_rwlock_unlock(&assoc_mgr_locks[USER_LOCK]);
2257 
2258 	if (locks->tres)
2259 		slurm_rwlock_unlock(&assoc_mgr_locks[TRES_LOCK]);
2260 
2261 	if (locks->res)
2262 		slurm_rwlock_unlock(&assoc_mgr_locks[RES_LOCK]);
2263 
2264 	if (locks->qos)
2265 		slurm_rwlock_unlock(&assoc_mgr_locks[QOS_LOCK]);
2266 
2267 	if (locks->file)
2268 		slurm_rwlock_unlock(&assoc_mgr_locks[FILE_LOCK]);
2269 
2270 	if (locks->assoc)
2271 		slurm_rwlock_unlock(&assoc_mgr_locks[ASSOC_LOCK]);
2272 }
2273 
2274 /* Since the returned assoc_list is full of pointers from the
2275  * assoc_mgr_assoc_list assoc_mgr_lock_t READ_LOCK on
2276  * assocs must be set before calling this function and while
2277  * handling it after a return.
2278  */
assoc_mgr_get_user_assocs(void * db_conn,slurmdb_assoc_rec_t * assoc,int enforce,List assoc_list)2279 extern int assoc_mgr_get_user_assocs(void *db_conn,
2280 				     slurmdb_assoc_rec_t *assoc,
2281 				     int enforce,
2282 				     List assoc_list)
2283 {
2284 	ListIterator itr = NULL;
2285 	slurmdb_assoc_rec_t *found_assoc = NULL;
2286 	int set = 0;
2287 
2288 	xassert(verify_assoc_lock(ASSOC_LOCK, READ_LOCK));
2289 
2290 	xassert(assoc);
2291 	xassert(assoc->uid != NO_VAL);
2292 	xassert(assoc_list);
2293 
2294 	if ((!assoc_mgr_assoc_list
2295 	     || !list_count(assoc_mgr_assoc_list))
2296 	    && !(enforce & ACCOUNTING_ENFORCE_ASSOCS)) {
2297 		return SLURM_SUCCESS;
2298 	}
2299 
2300 	xassert(assoc_mgr_assoc_list);
2301 
2302 	itr = list_iterator_create(assoc_mgr_assoc_list);
2303 	while ((found_assoc = list_next(itr))) {
2304 		if (assoc->uid != found_assoc->uid) {
2305 			debug4("not the right user %u != %u",
2306 			       assoc->uid, found_assoc->uid);
2307 			continue;
2308 		}
2309 
2310 		list_append(assoc_list, found_assoc);
2311 		set = 1;
2312 	}
2313 	list_iterator_destroy(itr);
2314 
2315 	if (!set) {
2316 		debug("UID %u has no associations", assoc->uid);
2317 		if (enforce & ACCOUNTING_ENFORCE_ASSOCS)
2318 			return SLURM_ERROR;
2319 	}
2320 	return SLURM_SUCCESS;
2321 }
2322 
assoc_mgr_fill_in_tres(void * db_conn,slurmdb_tres_rec_t * tres,int enforce,slurmdb_tres_rec_t ** tres_pptr,bool locked)2323 extern int assoc_mgr_fill_in_tres(void *db_conn,
2324 				  slurmdb_tres_rec_t *tres,
2325 				  int enforce,
2326 				  slurmdb_tres_rec_t **tres_pptr,
2327 				  bool locked)
2328 {
2329 	ListIterator itr;
2330 	slurmdb_tres_rec_t *found_tres = NULL;
2331 	assoc_mgr_lock_t locks = { .tres = READ_LOCK };
2332 
2333 	if (tres_pptr)
2334 		*tres_pptr = NULL;
2335 
2336 	/* Since we might be locked we can't come in here and try to
2337 	 * get the list since we would need the WRITE_LOCK to do that,
2338 	 * so just return as this would only happen on a system not
2339 	 * talking to the database.
2340 	 */
2341 	if (!assoc_mgr_tres_list) {
2342 		int rc = SLURM_SUCCESS;
2343 
2344 		if (enforce & ACCOUNTING_ENFORCE_TRES) {
2345 			error("No TRES list available, this should never "
2346 			      "happen when running with the database, "
2347 			      "make sure it is configured.");
2348 			rc = SLURM_ERROR;
2349 		}
2350 		return rc;
2351 	}
2352 
2353 	if ((!assoc_mgr_tres_list
2354 	     || !list_count(assoc_mgr_tres_list))
2355 	    && !(enforce & ACCOUNTING_ENFORCE_TRES))
2356 		return SLURM_SUCCESS;
2357 
2358 	if (!tres->id) {
2359 		if (!tres->type ||
2360 		    ((!xstrncasecmp(tres->type, "gres:", 5) ||
2361 		      !xstrncasecmp(tres->type, "license:", 8))
2362 		     && !tres->name)) {
2363 			if (enforce & ACCOUNTING_ENFORCE_TRES) {
2364 				error("get_assoc_id: "
2365 				      "Not enough info to "
2366 				      "get an association");
2367 				return SLURM_ERROR;
2368 			} else {
2369 				return SLURM_SUCCESS;
2370 			}
2371 		}
2372 	}
2373 	/* info("looking for tres of (%d)%s:%s", */
2374 	/*      tres->id, tres->type, tres->name); */
2375 	if (!locked)
2376 		assoc_mgr_lock(&locks);
2377 
2378 	xassert(verify_assoc_lock(TRES_LOCK, READ_LOCK));
2379 
2380 	itr = list_iterator_create(assoc_mgr_tres_list);
2381 	while ((found_tres = list_next(itr))) {
2382 		if (tres->id) {
2383 			if (tres->id == found_tres->id)
2384 				break;
2385 		} else if ((tres->type
2386 			    && !xstrcasecmp(tres->type, found_tres->type))
2387 			   && ((!tres->name && !found_tres->name)
2388 			       || ((tres->name && found_tres->name) &&
2389 				   !xstrcasecmp(tres->name, found_tres->name))))
2390 			break;
2391 	}
2392 	list_iterator_destroy(itr);
2393 
2394 	if (!found_tres) {
2395 		if (!locked)
2396 			assoc_mgr_unlock(&locks);
2397 		if (enforce & ACCOUNTING_ENFORCE_TRES)
2398 			return SLURM_ERROR;
2399 		else
2400 			return SLURM_SUCCESS;
2401 	}
2402 	debug3("found correct tres");
2403 	if (tres_pptr)
2404 		*tres_pptr = found_tres;
2405 
2406 	tres->id           = found_tres->id;
2407 
2408 	if (!tres->type)
2409 		tres->type = found_tres->type;
2410 	else {
2411 		xfree(tres->type);
2412 		tres->type = xstrdup(found_tres->type);
2413 	}
2414 
2415 	if (!tres->name)
2416 		tres->name = found_tres->name;
2417 	else {
2418 		xfree(tres->name);
2419 		tres->name = xstrdup(found_tres->name);
2420 	}
2421 
2422 	tres->count        = found_tres->count;
2423 
2424 	if (!locked)
2425 		assoc_mgr_unlock(&locks);
2426 
2427 	return SLURM_SUCCESS;
2428 }
2429 
assoc_mgr_fill_in_assoc(void * db_conn,slurmdb_assoc_rec_t * assoc,int enforce,slurmdb_assoc_rec_t ** assoc_pptr,bool locked)2430 extern int assoc_mgr_fill_in_assoc(void *db_conn,
2431 				   slurmdb_assoc_rec_t *assoc,
2432 				   int enforce,
2433 				   slurmdb_assoc_rec_t **assoc_pptr,
2434 				   bool locked)
2435 {
2436 	slurmdb_assoc_rec_t * ret_assoc = NULL;
2437 	assoc_mgr_lock_t locks = { .assoc = READ_LOCK };
2438 
2439 	if (assoc_pptr)
2440 		*assoc_pptr = NULL;
2441 
2442 	/* Since we might be locked we can't come in here and try to
2443 	 * get the list since we would need the WRITE_LOCK to do that,
2444 	 * so just return as this would only happen on a system not
2445 	 * talking to the database.
2446 	 */
2447 	if (!assoc_mgr_assoc_list) {
2448 		int rc = SLURM_SUCCESS;
2449 
2450 		if (enforce & ACCOUNTING_ENFORCE_ASSOCS) {
2451 			error("No Association list available, "
2452 			      "this should never happen");
2453 			rc = SLURM_ERROR;
2454 		}
2455 		return rc;
2456 	}
2457 
2458 	if ((!assoc_mgr_assoc_list
2459 	     || !list_count(assoc_mgr_assoc_list))
2460 	    && !(enforce & ACCOUNTING_ENFORCE_ASSOCS))
2461 		return SLURM_SUCCESS;
2462 
2463 	if (!assoc->id) {
2464 		if (!assoc->acct) {
2465 			slurmdb_user_rec_t user;
2466 
2467 			if (assoc->uid == NO_VAL) {
2468 				if (enforce & ACCOUNTING_ENFORCE_ASSOCS) {
2469 					error("get_assoc_id: "
2470 					      "Not enough info to "
2471 					      "get an association");
2472 					return SLURM_ERROR;
2473 				} else {
2474 					return SLURM_SUCCESS;
2475 				}
2476 			}
2477 			memset(&user, 0, sizeof(slurmdb_user_rec_t));
2478 			user.uid = assoc->uid;
2479 			if (assoc_mgr_fill_in_user(db_conn, &user,
2480 						   enforce, NULL, locked)
2481 			    == SLURM_ERROR) {
2482 				if (enforce & ACCOUNTING_ENFORCE_ASSOCS) {
2483 					error("User %d not found", assoc->uid);
2484 					return SLURM_ERROR;
2485 				} else {
2486 					debug3("User %d not found", assoc->uid);
2487 					return SLURM_SUCCESS;
2488 				}
2489 			}
2490 			assoc->user = user.name;
2491 			if (user.default_acct)
2492 				assoc->acct = user.default_acct;
2493 			else {
2494 				if (enforce & ACCOUNTING_ENFORCE_ASSOCS) {
2495 					error("User %s(%d) doesn't have a "
2496 					      "default account", assoc->user,
2497 					      assoc->uid);
2498 					return SLURM_ERROR;
2499 				} else {
2500 					debug3("User %s(%d) doesn't have a "
2501 					       "default account", assoc->user,
2502 					       assoc->uid);
2503 					return SLURM_SUCCESS;
2504 				}
2505 			}
2506 		}
2507 
2508 		if (!assoc->cluster)
2509 			assoc->cluster = assoc_mgr_cluster_name;
2510 	}
2511 	debug5("%s: looking for assoc of user=%s(%u), acct=%s, cluster=%s, partition=%s",
2512 	       __func__, assoc->user, assoc->uid, assoc->acct, assoc->cluster,
2513 	       assoc->partition);
2514 	if (!locked)
2515 		assoc_mgr_lock(&locks);
2516 
2517 	xassert(verify_assoc_lock(ASSOC_LOCK, READ_LOCK));
2518 
2519 
2520 	/* First look for the assoc with a partition and then check
2521 	 * for the non-partition association if we don't find one.
2522 	 */
2523 	ret_assoc = _find_assoc_rec(assoc);
2524 	if (!ret_assoc && assoc->partition) {
2525 		char *part_holder = assoc->partition;
2526 		assoc->partition = NULL;
2527 		ret_assoc = _find_assoc_rec(assoc);
2528 		assoc->partition = part_holder;
2529 	}
2530 
2531 	if (!ret_assoc) {
2532 		if (!locked)
2533 			assoc_mgr_unlock(&locks);
2534 		if (enforce & ACCOUNTING_ENFORCE_ASSOCS)
2535 			return SLURM_ERROR;
2536 		else
2537 			return SLURM_SUCCESS;
2538 	}
2539 	debug3("%s: found correct association of user=%s(%u), acct=%s, cluster=%s, partition=%s to assoc=%u acct=%s",
2540 	       __func__, assoc->user, assoc->uid, assoc->acct, assoc->cluster,
2541 	       assoc->partition, ret_assoc->id, ret_assoc->acct);
2542 	if (assoc_pptr)
2543 		*assoc_pptr = ret_assoc;
2544 
2545 	assoc->id              = ret_assoc->id;
2546 
2547 	if (!assoc->acct)
2548 		assoc->acct    = ret_assoc->acct;
2549 
2550 	if (!assoc->cluster)
2551 		assoc->cluster = ret_assoc->cluster;
2552 
2553 	assoc->def_qos_id = ret_assoc->def_qos_id;
2554 
2555 	if (!assoc->grp_tres_mins)
2556 		assoc->grp_tres_mins    = ret_assoc->grp_tres_mins;
2557 	if (!assoc->grp_tres_run_mins)
2558 		assoc->grp_tres_run_mins= ret_assoc->grp_tres_run_mins;
2559 	if (!assoc->grp_tres)
2560 		assoc->grp_tres        = ret_assoc->grp_tres;
2561 	assoc->grp_jobs        = ret_assoc->grp_jobs;
2562 	assoc->grp_jobs_accrue = ret_assoc->grp_jobs_accrue;
2563 	assoc->grp_submit_jobs = ret_assoc->grp_submit_jobs;
2564 	assoc->grp_wall        = ret_assoc->grp_wall;
2565 
2566 	assoc->is_def          = ret_assoc->is_def;
2567 
2568 	assoc->lft             = ret_assoc->lft;
2569 
2570 	if (!assoc->max_tres_mins_pj)
2571 		assoc->max_tres_mins_pj = ret_assoc->max_tres_mins_pj;
2572 	if (!assoc->max_tres_run_mins)
2573 		assoc->max_tres_run_mins = ret_assoc->max_tres_run_mins;
2574 	if (!assoc->max_tres_pj)
2575 		assoc->max_tres_pj     = ret_assoc->max_tres_pj;
2576 	if (!assoc->max_tres_pn)
2577 		assoc->max_tres_pn     = ret_assoc->max_tres_pn;
2578 	assoc->max_jobs        = ret_assoc->max_jobs;
2579 	assoc->max_jobs_accrue = ret_assoc->max_jobs_accrue;
2580 	assoc->min_prio_thresh = ret_assoc->min_prio_thresh;
2581 	assoc->max_submit_jobs = ret_assoc->max_submit_jobs;
2582 	assoc->max_wall_pj     = ret_assoc->max_wall_pj;
2583 
2584 	if (assoc->parent_acct) {
2585 		xfree(assoc->parent_acct);
2586 		assoc->parent_acct       = xstrdup(ret_assoc->parent_acct);
2587 	} else
2588 		assoc->parent_acct       = ret_assoc->parent_acct;
2589 
2590 	assoc->parent_id                 = ret_assoc->parent_id;
2591 
2592 	if (!assoc->partition)
2593 		assoc->partition = ret_assoc->partition;
2594 
2595 	if (!assoc->qos_list)
2596 		assoc->qos_list = ret_assoc->qos_list;
2597 
2598 	assoc->rgt              = ret_assoc->rgt;
2599 
2600 	assoc->shares_raw       = ret_assoc->shares_raw;
2601 
2602 	assoc->uid              = ret_assoc->uid;
2603 
2604 	/* Don't send any usage info since we don't know if the usage
2605 	   is really in existance here, if they really want it they can
2606 	   use the pointer that is returned. */
2607 
2608 	/* if (!assoc->usage->children_list) */
2609 	/* 	assoc->usage->children_list = ret_assoc->usage->children_list; */
2610 	/* assoc->usage->grp_used_tres   = ret_assoc->usage->grp_used_tres; */
2611 	/* assoc->usage->grp_used_tres_run_mins  = */
2612 	/* 	ret_assoc->usage->grp_used_tres_run_mins; */
2613 	/* assoc->usage->grp_used_wall   = ret_assoc->usage->grp_used_wall; */
2614 
2615 	/* assoc->usage->level_shares    = ret_assoc->usage->level_shares; */
2616 
2617 	/* assoc->usage->parent_assoc_ptr = ret_assoc->usage->parent_assoc_ptr; */
2618 	/* assoc->usage->shares_norm      = ret_assoc->usage->shares_norm; */
2619 	/* assoc->usage->usage_efctv      = ret_assoc->usage->usage_efctv; */
2620 	/* assoc->usage->usage_norm       = ret_assoc->usage->usage_norm; */
2621 	/* assoc->usage->usage_raw        = ret_assoc->usage->usage_raw; */
2622 
2623 	/* assoc->usage->used_jobs        = ret_assoc->usage->used_jobs; */
2624 	/* assoc->usage->used_submit_jobs = ret_assoc->usage->used_submit_jobs; */
2625 	/* if (assoc->usage->valid_qos) { */
2626 	/* 	FREE_NULL_BITMAP(assoc->usage->valid_qos); */
2627 	/* 	assoc->usage->valid_qos = bit_copy(ret_assoc->usage->valid_qos); */
2628 	/* } else */
2629 	/* 	assoc->usage->valid_qos = ret_assoc->usage->valid_qos; */
2630 
2631 	if (!assoc->user)
2632 		assoc->user = ret_assoc->user;
2633 	if (!locked)
2634 		assoc_mgr_unlock(&locks);
2635 
2636 	return SLURM_SUCCESS;
2637 }
2638 
assoc_mgr_fill_in_user(void * db_conn,slurmdb_user_rec_t * user,int enforce,slurmdb_user_rec_t ** user_pptr,bool locked)2639 extern int assoc_mgr_fill_in_user(void *db_conn, slurmdb_user_rec_t *user,
2640 				  int enforce,
2641 				  slurmdb_user_rec_t **user_pptr,
2642 				  bool locked)
2643 {
2644 	ListIterator itr = NULL;
2645 	slurmdb_user_rec_t * found_user = NULL;
2646 	assoc_mgr_lock_t locks = { .user = READ_LOCK };
2647 
2648 	if (user_pptr)
2649 		*user_pptr = NULL;
2650 	if (!assoc_mgr_user_list)
2651 		if (_get_assoc_mgr_user_list(db_conn, enforce) == SLURM_ERROR)
2652 			return SLURM_ERROR;
2653 
2654 	if (!locked)
2655 		assoc_mgr_lock(&locks);
2656 
2657 	xassert(verify_assoc_lock(USER_LOCK, READ_LOCK));
2658 
2659 	if ((!assoc_mgr_user_list || !list_count(assoc_mgr_user_list))
2660 	    && !(enforce & ACCOUNTING_ENFORCE_ASSOCS)) {
2661 		if (!locked)
2662 			assoc_mgr_unlock(&locks);
2663 		return SLURM_SUCCESS;
2664 	}
2665 
2666 	itr = list_iterator_create(assoc_mgr_user_list);
2667 	while ((found_user = list_next(itr))) {
2668 		if (user->uid != NO_VAL) {
2669 			if (user->uid == found_user->uid)
2670 				break;
2671 		} else if (user->name
2672 			   && !xstrcasecmp(user->name, found_user->name))
2673 			break;
2674 	}
2675 	list_iterator_destroy(itr);
2676 
2677 	if (!found_user) {
2678 		if (!locked)
2679 			assoc_mgr_unlock(&locks);
2680 		if (enforce & ACCOUNTING_ENFORCE_ASSOCS)
2681 			return SLURM_ERROR;
2682 		else
2683 			return SLURM_SUCCESS;
2684 	}
2685 
2686 	debug3("%s: found correct user: %s(%u)",
2687 	       __func__, found_user->name, found_user->uid);
2688 	if (user_pptr)
2689 		*user_pptr = found_user;
2690 
2691 	/* create coord_accts just in case the list does not exist */
2692 	if (!found_user->coord_accts)
2693 		found_user->coord_accts =
2694 			list_create(slurmdb_destroy_coord_rec);
2695 
2696 	user->admin_level = found_user->admin_level;
2697 	if (!user->assoc_list)
2698 		user->assoc_list = found_user->assoc_list;
2699 	if (!user->coord_accts)
2700 		user->coord_accts = found_user->coord_accts;
2701 	if (!user->default_acct)
2702 		user->default_acct = found_user->default_acct;
2703 	if (!user->default_wckey)
2704 		user->default_wckey = found_user->default_wckey;
2705 	if (!user->name)
2706 		user->name = found_user->name;
2707 	user->uid = found_user->uid;
2708 	if (!user->wckey_list)
2709 		user->wckey_list = found_user->wckey_list;
2710 
2711 	if (!locked)
2712 		assoc_mgr_unlock(&locks);
2713 	return SLURM_SUCCESS;
2714 
2715 }
2716 
assoc_mgr_fill_in_qos(void * db_conn,slurmdb_qos_rec_t * qos,int enforce,slurmdb_qos_rec_t ** qos_pptr,bool locked)2717 extern int assoc_mgr_fill_in_qos(void *db_conn, slurmdb_qos_rec_t *qos,
2718 				 int enforce,
2719 				 slurmdb_qos_rec_t **qos_pptr, bool locked)
2720 {
2721 	ListIterator itr = NULL;
2722 	slurmdb_qos_rec_t * found_qos = NULL;
2723 	assoc_mgr_lock_t locks = { .qos = READ_LOCK };
2724 
2725 	if (qos_pptr)
2726 		*qos_pptr = NULL;
2727 
2728 	if (!locked)
2729 		assoc_mgr_lock(&locks);
2730 
2731 	xassert(verify_assoc_lock(QOS_LOCK, READ_LOCK));
2732 
2733 	/* Since we might be locked we can't come in here and try to
2734 	 * get the list since we would need the WRITE_LOCK to do that,
2735 	 * so just return as this would only happen on a system not
2736 	 * talking to the database.
2737 	 */
2738 	if (!assoc_mgr_qos_list) {
2739 		int rc = SLURM_SUCCESS;
2740 
2741 		if (enforce & ACCOUNTING_ENFORCE_QOS) {
2742 			error("No QOS list available, "
2743 			      "this should never happen");
2744 			rc = SLURM_ERROR;
2745 		}
2746 		if (!locked)
2747 			assoc_mgr_unlock(&locks);
2748 		return rc;
2749 	} else if (!list_count(assoc_mgr_qos_list)
2750 		   && !(enforce & ACCOUNTING_ENFORCE_QOS)) {
2751 		if (!locked)
2752 			assoc_mgr_unlock(&locks);
2753 		return SLURM_SUCCESS;
2754 	}
2755 
2756 	itr = list_iterator_create(assoc_mgr_qos_list);
2757 	while ((found_qos = list_next(itr))) {
2758 		if (qos->id == found_qos->id)
2759 			break;
2760 		else if (qos->name && !xstrcasecmp(qos->name, found_qos->name))
2761 			break;
2762 	}
2763 	list_iterator_destroy(itr);
2764 
2765 	if (!found_qos) {
2766 		if (!locked)
2767 			assoc_mgr_unlock(&locks);
2768 		if (enforce & ACCOUNTING_ENFORCE_QOS)
2769 			return SLURM_ERROR;
2770 		else
2771 			return SLURM_SUCCESS;
2772 	}
2773 
2774 	debug3("found correct qos");
2775 	if (qos_pptr)
2776 		*qos_pptr = found_qos;
2777 
2778 	if (!qos->description)
2779 		qos->description = found_qos->description;
2780 
2781 	qos->id = found_qos->id;
2782 
2783 	qos->grace_time      = found_qos->grace_time;
2784 	if (!qos->grp_tres_mins)
2785 		qos->grp_tres_mins    = found_qos->grp_tres_mins;
2786 	if (!qos->grp_tres_run_mins)
2787 		qos->grp_tres_run_mins= found_qos->grp_tres_run_mins;
2788 	if (!qos->grp_tres)
2789 		qos->grp_tres        = found_qos->grp_tres;
2790 	qos->grp_jobs        = found_qos->grp_jobs;
2791 	qos->grp_jobs_accrue = found_qos->grp_jobs_accrue;
2792 	qos->grp_submit_jobs = found_qos->grp_submit_jobs;
2793 	qos->grp_wall        = found_qos->grp_wall;
2794 
2795 	if (!qos->max_tres_mins_pj)
2796 		qos->max_tres_mins_pj = found_qos->max_tres_mins_pj;
2797 	if (!qos->max_tres_run_mins_pa)
2798 		qos->max_tres_run_mins_pa = found_qos->max_tres_run_mins_pa;
2799 	if (!qos->max_tres_run_mins_pu)
2800 		qos->max_tres_run_mins_pu = found_qos->max_tres_run_mins_pu;
2801 	if (!qos->max_tres_pa)
2802 		qos->max_tres_pa     = found_qos->max_tres_pa;
2803 	if (!qos->max_tres_pj)
2804 		qos->max_tres_pj     = found_qos->max_tres_pj;
2805 	if (!qos->max_tres_pn)
2806 		qos->max_tres_pn     = found_qos->max_tres_pn;
2807 	if (!qos->max_tres_pu)
2808 		qos->max_tres_pu     = found_qos->max_tres_pu;
2809 	qos->max_jobs_pa     = found_qos->max_jobs_pa;
2810 	qos->max_jobs_pu     = found_qos->max_jobs_pu;
2811 	qos->max_jobs_accrue_pa = found_qos->max_jobs_accrue_pa;
2812 	qos->max_jobs_accrue_pu = found_qos->max_jobs_accrue_pu;
2813 	qos->min_prio_thresh    = found_qos->min_prio_thresh;
2814 	qos->max_submit_jobs_pa = found_qos->max_submit_jobs_pa;
2815 	qos->max_submit_jobs_pu = found_qos->max_submit_jobs_pu;
2816 	qos->max_wall_pj     = found_qos->max_wall_pj;
2817 
2818 	if (!qos->min_tres_pj)
2819 		qos->min_tres_pj     = found_qos->min_tres_pj;
2820 
2821 	if (!qos->name)
2822 		qos->name = found_qos->name;
2823 
2824 	if (qos->preempt_bitstr) {
2825 		FREE_NULL_BITMAP(qos->preempt_bitstr);
2826 		qos->preempt_bitstr = bit_copy(found_qos->preempt_bitstr);
2827 	} else
2828 		qos->preempt_bitstr = found_qos->preempt_bitstr;
2829 
2830 	qos->preempt_mode = found_qos->preempt_mode;
2831 	qos->priority = found_qos->priority;
2832 
2833 	/* Don't send any usage info since we don't know if the usage
2834 	   is really in existance here, if they really want it they can
2835 	   use the pointer that is returned. */
2836 
2837 	/* if (!qos->usage->acct_limit_list) */
2838 	/* 	qos->usage->acct_limit_list = found_qos->usage->acct_limit_list; */
2839 
2840 	/* qos->usage->grp_used_tres   = found_qos->usage->grp_used_tres; */
2841 	/* qos->usage->grp_used_tres_run_mins  = */
2842 	/* 	found_qos->usage->grp_used_tres_run_mins; */
2843 	/* qos->usage->grp_used_jobs   = found_qos->usage->grp_used_jobs; */
2844 	/* qos->usage->grp_used_submit_jobs = */
2845 	/* 	found_qos->usage->grp_used_submit_jobs; */
2846 	/* qos->usage->grp_used_wall   = found_qos->usage->grp_used_wall; */
2847 
2848 	/* if (!qos->usage->job_list) */
2849 	/* 	qos->usage->job_list = found_qos->usage->job_list; */
2850 
2851 	/* qos->usage->norm_priority = found_qos->usage->norm_priority; */
2852 
2853 	/* qos->usage->usage_raw = found_qos->usage->usage_raw; */
2854 
2855 	/* if (!qos->usage->user_limit_list) */
2856 	/* 	qos->usage->user_limit_list = found_qos->usage->user_limit_list; */
2857 	qos->usage_factor = found_qos->usage_factor;
2858 
2859 	if (!locked)
2860 		assoc_mgr_unlock(&locks);
2861 	return SLURM_SUCCESS;
2862 }
2863 
assoc_mgr_fill_in_wckey(void * db_conn,slurmdb_wckey_rec_t * wckey,int enforce,slurmdb_wckey_rec_t ** wckey_pptr,bool locked)2864 extern int assoc_mgr_fill_in_wckey(void *db_conn, slurmdb_wckey_rec_t *wckey,
2865 				   int enforce,
2866 				   slurmdb_wckey_rec_t **wckey_pptr,
2867 				   bool locked)
2868 {
2869 	ListIterator itr = NULL;
2870 	slurmdb_wckey_rec_t * found_wckey = NULL;
2871 	slurmdb_wckey_rec_t * ret_wckey = NULL;
2872 	assoc_mgr_lock_t locks = { .wckey = READ_LOCK };
2873 
2874 	if (wckey_pptr)
2875 		*wckey_pptr = NULL;
2876 	if (!assoc_mgr_wckey_list) {
2877 		if (_get_assoc_mgr_wckey_list(db_conn, enforce) == SLURM_ERROR)
2878 			return SLURM_ERROR;
2879 	}
2880 	if ((!assoc_mgr_wckey_list || !list_count(assoc_mgr_wckey_list))
2881 	    && !(enforce & ACCOUNTING_ENFORCE_WCKEYS))
2882 		return SLURM_SUCCESS;
2883 
2884 	if (!wckey->id) {
2885 		if (!wckey->name) {
2886 			slurmdb_user_rec_t user;
2887 
2888 			if (wckey->uid == NO_VAL && !wckey->user) {
2889 				if (enforce & ACCOUNTING_ENFORCE_WCKEYS) {
2890 					error("get_wckey_id: "
2891 					      "Not enough info to "
2892 					      "get an wckey");
2893 					return SLURM_ERROR;
2894 				} else {
2895 					return SLURM_SUCCESS;
2896 				}
2897 			}
2898 			memset(&user, 0, sizeof(slurmdb_user_rec_t));
2899 			user.uid = wckey->uid;
2900 			user.name = wckey->user;
2901 			if (assoc_mgr_fill_in_user(db_conn, &user,
2902 						   enforce, NULL, locked)
2903 			    == SLURM_ERROR) {
2904 				if (enforce & ACCOUNTING_ENFORCE_WCKEYS) {
2905 					error("User %d not found", wckey->uid);
2906 					return SLURM_ERROR;
2907 				} else {
2908 					debug3("User %d not found", wckey->uid);
2909 					return SLURM_SUCCESS;
2910 				}
2911 			}
2912 			if (!wckey->user)
2913 				wckey->user = user.name;
2914 			if (user.default_wckey)
2915 				wckey->name = user.default_wckey;
2916 			else {
2917 				if (enforce & ACCOUNTING_ENFORCE_WCKEYS) {
2918 					error("User %s(%d) doesn't have a "
2919 					      "default wckey", user.name,
2920 					      user.uid);
2921 					return SLURM_ERROR;
2922 				} else {
2923 					debug3("User %s(%d) doesn't have a "
2924 					       "default wckey", user.name,
2925 					       user.uid);
2926 					return SLURM_SUCCESS;
2927 				}
2928 			}
2929 
2930 		} else if (wckey->uid == NO_VAL && !wckey->user) {
2931 			if (enforce & ACCOUNTING_ENFORCE_WCKEYS) {
2932 				error("get_wckey_id: "
2933 				      "Not enough info 2 to "
2934 				      "get an wckey");
2935 				return SLURM_ERROR;
2936 			} else {
2937 				return SLURM_SUCCESS;
2938 			}
2939 		}
2940 
2941 
2942 		if (!wckey->cluster)
2943 			wckey->cluster = assoc_mgr_cluster_name;
2944 	}
2945 /* 	info("looking for wckey of user=%s(%u), name=%s, " */
2946 /* 	     "cluster=%s", */
2947 /* 	     wckey->user, wckey->uid, wckey->name, */
2948 /* 	     wckey->cluster); */
2949 	if (!locked)
2950 		assoc_mgr_lock(&locks);
2951 
2952 	xassert(verify_assoc_lock(WCKEY_LOCK, READ_LOCK));
2953 
2954 	itr = list_iterator_create(assoc_mgr_wckey_list);
2955 	while ((found_wckey = list_next(itr))) {
2956 		/* only and always check for on the slurmdbd */
2957 		if (!assoc_mgr_cluster_name) {
2958 			if (!wckey->cluster) {
2959 				error("No cluster name was given "
2960 				      "to check against, "
2961 				      "we need one to get a wckey.");
2962 				continue;
2963 			}
2964 
2965 			if (xstrcasecmp(wckey->cluster, found_wckey->cluster)) {
2966 				debug4("not the right cluster");
2967 				continue;
2968 			}
2969 		}
2970 
2971 		if (wckey->id) {
2972 			if (wckey->id == found_wckey->id) {
2973 				ret_wckey = found_wckey;
2974 				break;
2975 			}
2976 			continue;
2977 		} else {
2978 			if (wckey->uid != NO_VAL) {
2979 				if (wckey->uid != found_wckey->uid) {
2980 					debug4("not the right user %u != %u",
2981 					       wckey->uid, found_wckey->uid);
2982 					continue;
2983 				}
2984 			} else if (wckey->user &&
2985 				   xstrcasecmp(wckey->user, found_wckey->user))
2986 				continue;
2987 
2988 			if (wckey->name
2989 			    && (!found_wckey->name
2990 				|| xstrcasecmp(wckey->name,
2991 					       found_wckey->name))) {
2992 				debug4("not the right name %s != %s",
2993 				       wckey->name, found_wckey->name);
2994 				continue;
2995 			}
2996 		}
2997 		ret_wckey = found_wckey;
2998 		break;
2999 	}
3000 	list_iterator_destroy(itr);
3001 
3002 	if (!ret_wckey) {
3003 		if (!locked)
3004 			assoc_mgr_unlock(&locks);
3005 		if (enforce & ACCOUNTING_ENFORCE_WCKEYS)
3006 			return SLURM_ERROR;
3007 		else
3008 			return SLURM_SUCCESS;
3009 	}
3010 	debug3("found correct wckey %u", ret_wckey->id);
3011 	if (wckey_pptr)
3012 		*wckey_pptr = ret_wckey;
3013 
3014 	if (!wckey->cluster)
3015 		wckey->cluster = ret_wckey->cluster;
3016 
3017 	wckey->id = ret_wckey->id;
3018 
3019 	if (!wckey->name)
3020 		wckey->name = ret_wckey->name;
3021 
3022 	wckey->uid = ret_wckey->uid;
3023 	if (!wckey->user)
3024 		wckey->user = ret_wckey->user;
3025 
3026 	wckey->is_def = ret_wckey->is_def;
3027 
3028 	if (!locked)
3029 		assoc_mgr_unlock(&locks);
3030 
3031 	return SLURM_SUCCESS;
3032 }
3033 
assoc_mgr_get_admin_level(void * db_conn,uint32_t uid)3034 extern slurmdb_admin_level_t assoc_mgr_get_admin_level(void *db_conn,
3035 						       uint32_t uid)
3036 {
3037 	ListIterator itr = NULL;
3038 	slurmdb_user_rec_t * found_user = NULL;
3039 	assoc_mgr_lock_t locks = { .user = READ_LOCK };
3040 	slurmdb_admin_level_t level = SLURMDB_ADMIN_NOTSET;
3041 
3042 	if (!assoc_mgr_user_list)
3043 		if (_get_assoc_mgr_user_list(db_conn, 0) == SLURM_ERROR)
3044 			return SLURMDB_ADMIN_NOTSET;
3045 
3046 	assoc_mgr_lock(&locks);
3047 	if (!assoc_mgr_user_list) {
3048 		assoc_mgr_unlock(&locks);
3049 		return SLURMDB_ADMIN_NOTSET;
3050 	}
3051 
3052 	itr = list_iterator_create(assoc_mgr_user_list);
3053 	while ((found_user = list_next(itr))) {
3054 		if (uid == found_user->uid)
3055 			break;
3056 	}
3057 	list_iterator_destroy(itr);
3058 
3059 	if (found_user)
3060 		level = found_user->admin_level;
3061 
3062 	assoc_mgr_unlock(&locks);
3063 
3064 	return level;
3065 }
3066 
assoc_mgr_is_user_acct_coord(void * db_conn,uint32_t uid,char * acct_name)3067 extern bool assoc_mgr_is_user_acct_coord(void *db_conn,
3068 					 uint32_t uid,
3069 					 char *acct_name)
3070 {
3071 	ListIterator itr = NULL;
3072 	slurmdb_coord_rec_t *acct = NULL;
3073 	slurmdb_user_rec_t * found_user = NULL;
3074 	assoc_mgr_lock_t locks = { .user = READ_LOCK };
3075 
3076 	if (!acct_name)
3077 		return false;
3078 
3079 	if (!assoc_mgr_user_list)
3080 		if (_get_assoc_mgr_user_list(db_conn, 0) == SLURM_ERROR)
3081 			return false;
3082 
3083 	assoc_mgr_lock(&locks);
3084 	if (!assoc_mgr_user_list) {
3085 		assoc_mgr_unlock(&locks);
3086 		return false;
3087 	}
3088 
3089 	itr = list_iterator_create(assoc_mgr_user_list);
3090 	while ((found_user = list_next(itr))) {
3091 		if (uid == found_user->uid)
3092 			break;
3093 	}
3094 	list_iterator_destroy(itr);
3095 
3096 	if (!found_user || !found_user->coord_accts) {
3097 		assoc_mgr_unlock(&locks);
3098 		return false;
3099 	}
3100 	itr = list_iterator_create(found_user->coord_accts);
3101 	while ((acct = list_next(itr))) {
3102 		if (!xstrcmp(acct_name, acct->name))
3103 			break;
3104 	}
3105 	list_iterator_destroy(itr);
3106 
3107 	if (acct) {
3108 		assoc_mgr_unlock(&locks);
3109 		return true;
3110 	}
3111 	assoc_mgr_unlock(&locks);
3112 
3113 	return false;
3114 }
3115 
assoc_mgr_get_shares(void * db_conn,uid_t uid,shares_request_msg_t * req_msg,shares_response_msg_t * resp_msg)3116 extern void assoc_mgr_get_shares(void *db_conn,
3117 				 uid_t uid, shares_request_msg_t *req_msg,
3118 				 shares_response_msg_t *resp_msg)
3119 {
3120 	ListIterator itr = NULL;
3121 	ListIterator user_itr = NULL;
3122 	ListIterator acct_itr = NULL;
3123 	slurmdb_assoc_rec_t *assoc = NULL;
3124 	assoc_shares_object_t *share = NULL;
3125 	List ret_list = NULL;
3126 	char *tmp_char = NULL;
3127 	slurmdb_user_rec_t user;
3128 	int is_admin=1;
3129 	uint16_t private_data = slurm_get_private_data();
3130 	assoc_mgr_lock_t locks = { .assoc = READ_LOCK, .tres = READ_LOCK };
3131 
3132 	xassert(resp_msg);
3133 
3134 	if (!assoc_mgr_assoc_list || !list_count(assoc_mgr_assoc_list))
3135 		return;
3136 
3137 	memset(&user, 0, sizeof(slurmdb_user_rec_t));
3138 	user.uid = uid;
3139 
3140 	if (req_msg) {
3141 		if (req_msg->user_list && list_count(req_msg->user_list))
3142 			user_itr = list_iterator_create(req_msg->user_list);
3143 
3144 		if (req_msg->acct_list && list_count(req_msg->acct_list))
3145 			acct_itr = list_iterator_create(req_msg->acct_list);
3146 	}
3147 
3148 	if (private_data & PRIVATE_DATA_USAGE) {
3149 		uint32_t slurm_uid = slurm_get_slurm_user_id();
3150 		is_admin = 0;
3151 		/* Check permissions of the requesting user.
3152 		 */
3153 		if ((uid == slurm_uid || uid == 0)
3154 		    || assoc_mgr_get_admin_level(db_conn, uid)
3155 		    >= SLURMDB_ADMIN_OPERATOR)
3156 			is_admin = 1;
3157 		else {
3158 			if (assoc_mgr_fill_in_user(
3159 				    db_conn, &user,
3160 				    ACCOUNTING_ENFORCE_ASSOCS, NULL, false)
3161 			    == SLURM_ERROR) {
3162 				debug3("User %d not found", user.uid);
3163 				goto end_it;
3164 			}
3165 		}
3166 	}
3167 
3168 	resp_msg->assoc_shares_list = ret_list =
3169 		list_create(slurm_destroy_assoc_shares_object);
3170 
3171 	assoc_mgr_lock(&locks);
3172 
3173 	resp_msg->tres_cnt = g_tres_count;
3174 
3175 	/* DON'T FREE, since this shouldn't change while the slurmctld
3176 	 * is running we should be ok.
3177 	*/
3178 	resp_msg->tres_names = assoc_mgr_tres_name_array;
3179 
3180 	itr = list_iterator_create(assoc_mgr_assoc_list);
3181 	while ((assoc = list_next(itr))) {
3182 		if (user_itr && assoc->user) {
3183 			while ((tmp_char = list_next(user_itr))) {
3184 				if (!xstrcasecmp(tmp_char, assoc->user))
3185 					break;
3186 			}
3187 			list_iterator_reset(user_itr);
3188 			/* not correct user */
3189 			if (!tmp_char)
3190 				continue;
3191 		}
3192 
3193 		if (acct_itr) {
3194 			while ((tmp_char = list_next(acct_itr))) {
3195 				if (!xstrcasecmp(tmp_char, assoc->acct))
3196 					break;
3197 			}
3198 			list_iterator_reset(acct_itr);
3199 			/* not correct account */
3200 			if (!tmp_char)
3201 				continue;
3202 		}
3203 
3204 		if (private_data & PRIVATE_DATA_USAGE) {
3205 			if (!is_admin) {
3206 				ListIterator itr = NULL;
3207 				slurmdb_coord_rec_t *coord = NULL;
3208 
3209 				if (assoc->user &&
3210 				    !xstrcmp(assoc->user, user.name))
3211 					goto is_user;
3212 
3213 				if (!user.coord_accts) {
3214 					debug4("This user isn't a coord.");
3215 					goto bad_user;
3216 				}
3217 
3218 				if (!assoc->acct) {
3219 					debug("No account name given "
3220 					      "in association.");
3221 					goto bad_user;
3222 				}
3223 
3224 				itr = list_iterator_create(user.coord_accts);
3225 				while ((coord = list_next(itr))) {
3226 					if (!xstrcasecmp(coord->name,
3227 							 assoc->acct))
3228 						break;
3229 				}
3230 				list_iterator_destroy(itr);
3231 
3232 				if (coord)
3233 					goto is_user;
3234 
3235 			bad_user:
3236 				continue;
3237 			}
3238 		}
3239 	is_user:
3240 
3241 		share = xmalloc(sizeof(assoc_shares_object_t));
3242 		list_append(ret_list, share);
3243 
3244 		share->assoc_id = assoc->id;
3245 		share->cluster = xstrdup(assoc->cluster);
3246 
3247 		if (assoc == assoc_mgr_root_assoc)
3248 			share->shares_raw = NO_VAL;
3249 		else
3250 			share->shares_raw = assoc->shares_raw;
3251 
3252 		share->shares_norm = assoc->usage->shares_norm;
3253 		share->usage_raw = (uint64_t)assoc->usage->usage_raw;
3254 
3255 		share->usage_tres_raw = xcalloc(g_tres_count,
3256 						sizeof(long double));
3257 		memcpy(share->usage_tres_raw,
3258 		       assoc->usage->usage_tres_raw,
3259 		       sizeof(long double) * g_tres_count);
3260 
3261 		share->tres_grp_mins = xcalloc(g_tres_count, sizeof(uint64_t));
3262 		memcpy(share->tres_grp_mins, assoc->grp_tres_mins_ctld,
3263 		       sizeof(uint64_t) * g_tres_count);
3264 		share->tres_run_secs = xcalloc(g_tres_count, sizeof(uint64_t));
3265 		memcpy(share->tres_run_secs,
3266 		       assoc->usage->grp_used_tres_run_secs,
3267 		       sizeof(uint64_t) * g_tres_count);
3268 		share->fs_factor = assoc->usage->fs_factor;
3269 		share->level_fs = assoc->usage->level_fs;
3270 
3271 		if (assoc->partition) {
3272 			share->partition =  xstrdup(assoc->partition);
3273 		} else {
3274 			share->partition = NULL;
3275 		}
3276 
3277 		if (assoc->user) {
3278 			/* We only calculate user effective usage when
3279 			 * we need it
3280 			 */
3281 			if (fuzzy_equal(assoc->usage->usage_efctv, NO_VAL))
3282 				priority_g_set_assoc_usage(assoc);
3283 
3284 			share->name = xstrdup(assoc->user);
3285 			share->parent = xstrdup(assoc->acct);
3286 			share->user = 1;
3287 		} else {
3288 			share->name = xstrdup(assoc->acct);
3289 			if (!assoc->parent_acct
3290 			    && assoc->usage->parent_assoc_ptr)
3291 				share->parent = xstrdup(
3292 					assoc->usage->parent_assoc_ptr->acct);
3293 			else
3294 				share->parent = xstrdup(assoc->parent_acct);
3295 		}
3296 		share->usage_norm = (double)assoc->usage->usage_norm;
3297 		share->usage_efctv = (double)assoc->usage->usage_efctv;
3298 	}
3299 	list_iterator_destroy(itr);
3300 	assoc_mgr_unlock(&locks);
3301 end_it:
3302 	if (user_itr)
3303 		list_iterator_destroy(user_itr);
3304 	if (acct_itr)
3305 		list_iterator_destroy(acct_itr);
3306 
3307 	/* The ret_list should already be sorted correctly, so no need
3308 	   to do it again.
3309 	*/
3310 	return;
3311 }
3312 
assoc_mgr_info_get_pack_msg(char ** buffer_ptr,int * buffer_size,assoc_mgr_info_request_msg_t * msg,uid_t uid,void * db_conn,uint16_t protocol_version)3313 extern void assoc_mgr_info_get_pack_msg(
3314 	char **buffer_ptr, int *buffer_size,
3315 	assoc_mgr_info_request_msg_t *msg, uid_t uid,
3316 	void *db_conn, uint16_t protocol_version)
3317 {
3318 	ListIterator itr = NULL;
3319 	ListIterator user_itr = NULL, acct_itr = NULL, qos_itr = NULL;
3320 	slurmdb_qos_rec_t *qos_rec = NULL;
3321 	slurmdb_assoc_rec_t *assoc_rec = NULL;
3322 	List ret_list = NULL, tmp_list;
3323 	char *tmp_char = NULL;
3324 	slurmdb_user_rec_t user, *user_rec = NULL;
3325 	int is_admin=1;
3326 	void *object;
3327 	uint32_t flags = 0;
3328 
3329 	uint16_t private_data = slurm_get_private_data();
3330 	assoc_mgr_lock_t locks = { .assoc = READ_LOCK, .res = READ_LOCK,
3331 				   .tres = READ_LOCK, .user = READ_LOCK };
3332 	Buf buffer;
3333 
3334 	buffer_ptr[0] = NULL;
3335 	*buffer_size = 0;
3336 
3337 	memset(&user, 0, sizeof(slurmdb_user_rec_t));
3338 	user.uid = uid;
3339 
3340 	if (msg) {
3341 		if (msg->user_list && list_count(msg->user_list))
3342 			user_itr = list_iterator_create(msg->user_list);
3343 
3344 		if (msg->acct_list && list_count(msg->acct_list))
3345 			acct_itr = list_iterator_create(msg->acct_list);
3346 
3347 		if (msg->qos_list && list_count(msg->qos_list))
3348 			qos_itr = list_iterator_create(msg->qos_list);
3349 		flags = msg->flags;
3350 	}
3351 
3352 	if (private_data & (PRIVATE_DATA_USAGE | PRIVATE_DATA_USERS)) {
3353 		uint32_t slurm_uid = slurm_get_slurm_user_id();
3354 		is_admin = 0;
3355 		/* Check permissions of the requesting user.
3356 		 */
3357 		if ((uid == slurm_uid || uid == 0)
3358 		    || assoc_mgr_get_admin_level(db_conn, uid)
3359 		    >= SLURMDB_ADMIN_OPERATOR)
3360 			is_admin = 1;
3361 		else {
3362 			if (assoc_mgr_fill_in_user(
3363 				    db_conn, &user,
3364 				    ACCOUNTING_ENFORCE_ASSOCS, NULL, false)
3365 			    == SLURM_ERROR) {
3366 				debug3("User %d not found", user.uid);
3367 				goto end_it;
3368 			}
3369 		}
3370 	}
3371 
3372 	/* This is where we start to pack */
3373 	buffer = init_buf(BUF_SIZE);
3374 
3375 	packstr_array(assoc_mgr_tres_name_array, g_tres_count, buffer);
3376 
3377 	ret_list = list_create(NULL);
3378 
3379 	assoc_mgr_lock(&locks);
3380 
3381 	if (!(flags & ASSOC_MGR_INFO_FLAG_ASSOC))
3382 		goto no_assocs;
3383 
3384 	itr = list_iterator_create(assoc_mgr_assoc_list);
3385 	while ((assoc_rec = list_next(itr))) {
3386 		if (user_itr && assoc_rec->user) {
3387 			while ((tmp_char = list_next(user_itr))) {
3388 				if (!xstrcasecmp(tmp_char, assoc_rec->user))
3389 					break;
3390 			}
3391 			list_iterator_reset(user_itr);
3392 			/* not correct user */
3393 			if (!tmp_char)
3394 				continue;
3395 		}
3396 
3397 		if (acct_itr) {
3398 			while ((tmp_char = list_next(acct_itr))) {
3399 				if (!xstrcasecmp(tmp_char, assoc_rec->acct))
3400 					break;
3401 			}
3402 			list_iterator_reset(acct_itr);
3403 			/* not correct account */
3404 			if (!tmp_char)
3405 				continue;
3406 		}
3407 
3408 		if (private_data & PRIVATE_DATA_USAGE) {
3409 			if (!is_admin) {
3410 				ListIterator itr = NULL;
3411 				slurmdb_coord_rec_t *coord = NULL;
3412 
3413 				if (assoc_rec->user &&
3414 				    !xstrcmp(assoc_rec->user, user.name))
3415 					goto is_user;
3416 
3417 				if (!user.coord_accts) {
3418 					debug4("This user isn't a coord.");
3419 					goto bad_user;
3420 				}
3421 
3422 				if (!assoc_rec->acct) {
3423 					debug("No account name given "
3424 					      "in association.");
3425 					goto bad_user;
3426 				}
3427 
3428 				itr = list_iterator_create(user.coord_accts);
3429 				while ((coord = list_next(itr))) {
3430 					if (!xstrcasecmp(coord->name,
3431 							 assoc_rec->acct))
3432 						break;
3433 				}
3434 				list_iterator_destroy(itr);
3435 
3436 				if (coord)
3437 					goto is_user;
3438 
3439 			bad_user:
3440 				continue;
3441 			}
3442 		}
3443 	is_user:
3444 
3445 		list_append(ret_list, assoc_rec);
3446 	}
3447 	list_iterator_destroy(itr);
3448 
3449 no_assocs:
3450 
3451 	/* pack the associations requested/allowed */
3452 	pack32(list_count(ret_list), buffer);
3453 	itr = list_iterator_create(ret_list);
3454 	while ((object = list_next(itr)))
3455 		slurmdb_pack_assoc_rec_with_usage(
3456 			object, protocol_version, buffer);
3457 	list_iterator_destroy(itr);
3458 	list_flush(ret_list);
3459 
3460 	if (!(flags & ASSOC_MGR_INFO_FLAG_QOS)) {
3461 		tmp_list = ret_list;
3462 		goto no_qos;
3463 	}
3464 
3465 	/* now filter out the qos */
3466 	if (qos_itr) {
3467 		while ((tmp_char = list_next(qos_itr)))
3468 			if ((qos_rec = list_find_first(
3469 				     assoc_mgr_qos_list,
3470 				     slurmdb_find_qos_in_list_by_name,
3471 				     tmp_char)))
3472 				list_append(ret_list, qos_rec);
3473 		tmp_list = ret_list;
3474 	} else
3475 		tmp_list = assoc_mgr_qos_list;
3476 
3477 no_qos:
3478 	/* pack the qos requested */
3479 	if (tmp_list) {
3480 		pack32(list_count(tmp_list), buffer);
3481 		itr = list_iterator_create(tmp_list);
3482 		while ((object = list_next(itr)))
3483 			slurmdb_pack_qos_rec_with_usage(
3484 				object, protocol_version, buffer);
3485 		list_iterator_destroy(itr);
3486 	} else
3487 		pack32(0, buffer);
3488 
3489 	if (qos_itr)
3490 		list_flush(ret_list);
3491 
3492 	if (!(flags & ASSOC_MGR_INFO_FLAG_USERS) || !assoc_mgr_user_list)
3493 		goto no_users;
3494 
3495 	/* now filter out the users */
3496 	itr = list_iterator_create(assoc_mgr_user_list);
3497 	while ((user_rec = list_next(itr))) {
3498 		if (!is_admin && (private_data & PRIVATE_DATA_USERS) &&
3499 		    xstrcasecmp(user_rec->name, user.name))
3500 			continue;
3501 
3502 		if (user_itr) {
3503 			while ((tmp_char = list_next(user_itr)))
3504 				if (!xstrcasecmp(tmp_char, user_rec->name))
3505 					break;
3506 			list_iterator_reset(user_itr);
3507 			/* not correct user */
3508 			if (!tmp_char)
3509 				continue;
3510 		}
3511 
3512 		list_append(ret_list, user_rec);
3513 	}
3514 
3515 no_users:
3516 
3517 	/* pack the users requested/allowed */
3518 	pack32(list_count(ret_list), buffer);
3519 	itr = list_iterator_create(ret_list);
3520 	while ((object = list_next(itr)))
3521 		slurmdb_pack_user_rec(object, protocol_version, buffer);
3522 	list_iterator_destroy(itr);
3523 //	list_flush(ret_list);
3524 
3525 	FREE_NULL_LIST(ret_list);
3526 
3527 	assoc_mgr_unlock(&locks);
3528 
3529 	/* put the real record count in the message body header */
3530 	*buffer_size = get_buf_offset(buffer);
3531 	buffer_ptr[0] = xfer_buf_data(buffer);
3532 
3533 end_it:
3534 	if (user_itr)
3535 		list_iterator_destroy(user_itr);
3536 	if (acct_itr)
3537 		list_iterator_destroy(acct_itr);
3538 	if (qos_itr)
3539 		list_iterator_destroy(qos_itr);
3540 
3541 	return;
3542 }
3543 
assoc_mgr_info_unpack_msg(assoc_mgr_info_msg_t ** object,Buf buffer,uint16_t protocol_version)3544 extern int assoc_mgr_info_unpack_msg(
3545 	assoc_mgr_info_msg_t **object, Buf buffer, uint16_t protocol_version)
3546 {
3547 	assoc_mgr_info_msg_t *object_ptr =
3548 		xmalloc(sizeof(assoc_mgr_info_msg_t));
3549 	void *list_object = NULL;
3550 	uint32_t count;
3551 	int i;
3552 
3553 	*object = object_ptr;
3554 
3555 	safe_unpackstr_array(&object_ptr->tres_names, &object_ptr->tres_cnt,
3556 			     buffer);
3557 
3558 	safe_unpack32(&count, buffer);
3559 	if (count > NO_VAL)
3560 		goto unpack_error;
3561 	if (count) {
3562 		object_ptr->assoc_list =
3563 			list_create(slurmdb_destroy_assoc_rec);
3564 		for (i = 0; i < count; i++) {
3565 			if (slurmdb_unpack_assoc_rec_with_usage(
3566 				    &list_object, protocol_version,
3567 				    buffer)
3568 			    != SLURM_SUCCESS)
3569 				goto unpack_error;
3570 			list_append(object_ptr->assoc_list, list_object);
3571 		}
3572 	}
3573 
3574 	safe_unpack32(&count, buffer);
3575 	if (count > NO_VAL)
3576 		goto unpack_error;
3577 	if (count) {
3578 		object_ptr->qos_list =
3579 			list_create(slurmdb_destroy_qos_rec);
3580 		for (i = 0; i < count; i++) {
3581 			if (slurmdb_unpack_qos_rec_with_usage(
3582 				    &list_object, protocol_version, buffer)
3583 			    != SLURM_SUCCESS)
3584 				goto unpack_error;
3585 			list_append(object_ptr->qos_list, list_object);
3586 		}
3587 	}
3588 
3589 	safe_unpack32(&count, buffer);
3590 	if (count > NO_VAL)
3591 		goto unpack_error;
3592 	if (count) {
3593 		object_ptr->user_list =
3594 			list_create(slurmdb_destroy_user_rec);
3595 		for (i = 0; i < count; i++) {
3596 			if (slurmdb_unpack_user_rec(
3597 				    &list_object, protocol_version, buffer)
3598 			    != SLURM_SUCCESS)
3599 				goto unpack_error;
3600 			list_append(object_ptr->user_list, list_object);
3601 		}
3602 	}
3603 
3604 	return SLURM_SUCCESS;
3605 unpack_error:
3606 	slurm_free_assoc_mgr_info_msg(object_ptr);
3607 	*object = NULL;
3608 	return SLURM_ERROR;
3609 }
3610 
3611 /*
3612  * assoc_mgr_update - update the association manager
3613  * IN update_list: updates to perform
3614  * RET: error code
3615  * NOTE: the items in update_list are not deleted
3616  */
assoc_mgr_update(List update_list,bool locked)3617 extern int assoc_mgr_update(List update_list, bool locked)
3618 {
3619 	int rc = SLURM_SUCCESS;
3620 	ListIterator itr = NULL;
3621 	slurmdb_update_object_t *object = NULL;
3622 
3623 	xassert(update_list);
3624 	itr = list_iterator_create(update_list);
3625 	while ((object = list_next(itr))) {
3626 		if (!object->objects || !list_count(object->objects))
3627 			continue;
3628 
3629 		switch(object->type) {
3630 		case SLURMDB_MODIFY_USER:
3631 		case SLURMDB_ADD_USER:
3632 		case SLURMDB_REMOVE_USER:
3633 		case SLURMDB_ADD_COORD:
3634 		case SLURMDB_REMOVE_COORD:
3635 			rc = assoc_mgr_update_users(object, locked);
3636 			break;
3637 		case SLURMDB_ADD_ASSOC:
3638 		case SLURMDB_MODIFY_ASSOC:
3639 		case SLURMDB_REMOVE_ASSOC:
3640 		case SLURMDB_REMOVE_ASSOC_USAGE:
3641 			rc = assoc_mgr_update_assocs(object, locked);
3642 			break;
3643 		case SLURMDB_ADD_QOS:
3644 		case SLURMDB_MODIFY_QOS:
3645 		case SLURMDB_REMOVE_QOS:
3646 		case SLURMDB_REMOVE_QOS_USAGE:
3647 			rc = assoc_mgr_update_qos(object, locked);
3648 			break;
3649 		case SLURMDB_ADD_WCKEY:
3650 		case SLURMDB_MODIFY_WCKEY:
3651 		case SLURMDB_REMOVE_WCKEY:
3652 			rc = assoc_mgr_update_wckeys(object, locked);
3653 			break;
3654 		case SLURMDB_ADD_RES:
3655 		case SLURMDB_MODIFY_RES:
3656 		case SLURMDB_REMOVE_RES:
3657 			rc = assoc_mgr_update_res(object, locked);
3658 			break;
3659 		case SLURMDB_ADD_CLUSTER:
3660 		case SLURMDB_REMOVE_CLUSTER:
3661 			/* These are used in the accounting_storage
3662 			   plugins for rollback purposes, just skip here.
3663 			*/
3664 			break;
3665 		case SLURMDB_ADD_TRES:
3666 			rc = assoc_mgr_update_tres(object, locked);
3667 			break;
3668 		case SLURMDB_UPDATE_FEDS:
3669 			/* Only handled in the slurmctld. */
3670 			break;
3671 		case SLURMDB_UPDATE_NOTSET:
3672 		default:
3673 			error("unknown type set in "
3674 			      "update_object: %d",
3675 			      object->type);
3676 			break;
3677 		}
3678 	}
3679 	list_iterator_destroy(itr);
3680 	return rc;
3681 }
3682 
assoc_mgr_update_assocs(slurmdb_update_object_t * update,bool locked)3683 extern int assoc_mgr_update_assocs(slurmdb_update_object_t *update, bool locked)
3684 {
3685 	slurmdb_assoc_rec_t * rec = NULL;
3686 	slurmdb_assoc_rec_t * object = NULL;
3687 	ListIterator itr = NULL;
3688 	int rc = SLURM_SUCCESS, i;
3689 	int parents_changed = 0;
3690 	int run_update_resvs = 0;
3691 	int resort = 0;
3692 	int redo_priority = 0;
3693 	List remove_list = NULL;
3694 	List update_list = NULL;
3695 	assoc_mgr_lock_t locks = { .assoc = WRITE_LOCK, .qos = WRITE_LOCK,
3696 				   .tres = READ_LOCK, .user = WRITE_LOCK };
3697 
3698 	if (!locked)
3699 		assoc_mgr_lock(&locks);
3700 	if (!assoc_mgr_assoc_list) {
3701 		if (!locked)
3702 			assoc_mgr_unlock(&locks);
3703 		return SLURM_SUCCESS;
3704 	}
3705 
3706 	while ((object = list_pop(update->objects))) {
3707 		bool update_jobs = false;
3708 		if (object->cluster && assoc_mgr_cluster_name) {
3709 			/* only update the local clusters assocs */
3710 			if (xstrcasecmp(object->cluster,
3711 					assoc_mgr_cluster_name)) {
3712 				slurmdb_destroy_assoc_rec(object);
3713 				continue;
3714 			}
3715 		} else if (assoc_mgr_cluster_name) {
3716 			error("We don't have a cluster here, no "
3717 			      "idea if this is our association.");
3718 			continue;
3719 		} else if (!object->cluster) {
3720 			/* This clause is only here for testing
3721 			   purposes, it shouldn't really happen in
3722 			   real senarios.
3723 			*/
3724 			debug("THIS SHOULD ONLY HAPPEN IN A TEST ENVIRONMENT");
3725 			object->cluster = xstrdup("test");
3726 		}
3727 
3728 		rec = _find_assoc_rec(object);
3729 
3730 		//info("%d assoc %u", update->type, object->id);
3731 		switch(update->type) {
3732 		case SLURMDB_MODIFY_ASSOC:
3733 			if (!rec) {
3734 				error("SLURMDB_MODIFY_ASSOC: assoc %u(%s, %s, %s) not found, unable to update.",
3735 				     object->id, object->acct,
3736 				     object->user, object->partition);
3737 				rc = SLURM_ERROR;
3738 				break;
3739 			}
3740 
3741 			if (object->shares_raw != NO_VAL) {
3742 				rec->shares_raw = object->shares_raw;
3743 				if (setup_children) {
3744 					/* we need to update the shares on
3745 					   each sibling and child
3746 					   association now
3747 					*/
3748 					parents_changed = 1;
3749 				}
3750 			}
3751 
3752 			if (object->grp_tres) {
3753 				update_jobs = true;
3754 				/* If we have a blank string that
3755 				 * means it is cleared.
3756 				 */
3757 				xfree(rec->grp_tres);
3758 				if (object->grp_tres[0]) {
3759 					rec->grp_tres = object->grp_tres;
3760 					object->grp_tres = NULL;
3761 				}
3762 				assoc_mgr_set_tres_cnt_array(
3763 					&rec->grp_tres_ctld,
3764 					rec->grp_tres, INFINITE64, 1);
3765 			}
3766 
3767 			if (object->grp_tres_mins) {
3768 				xfree(rec->grp_tres_mins);
3769 				if (object->grp_tres_mins[0]) {
3770 					rec->grp_tres_mins =
3771 						object->grp_tres_mins;
3772 					object->grp_tres_mins = NULL;
3773 				}
3774 				assoc_mgr_set_tres_cnt_array(
3775 					&rec->grp_tres_mins_ctld,
3776 					rec->grp_tres_mins, INFINITE64, 1);
3777 			}
3778 
3779 			if (object->grp_tres_run_mins) {
3780 				xfree(rec->grp_tres_run_mins);
3781 				if (object->grp_tres_run_mins[0]) {
3782 					rec->grp_tres_run_mins =
3783 						object->grp_tres_run_mins;
3784 					object->grp_tres_run_mins = NULL;
3785 				}
3786 				assoc_mgr_set_tres_cnt_array(
3787 					&rec->grp_tres_run_mins_ctld,
3788 					rec->grp_tres_run_mins, INFINITE64, 1);
3789 			}
3790 
3791 			if (object->grp_jobs != NO_VAL)
3792 				rec->grp_jobs = object->grp_jobs;
3793 			if (object->grp_jobs_accrue != NO_VAL)
3794 				rec->grp_jobs_accrue = object->grp_jobs_accrue;
3795 			if (object->grp_submit_jobs != NO_VAL)
3796 				rec->grp_submit_jobs = object->grp_submit_jobs;
3797 			if (object->grp_wall != NO_VAL) {
3798 				update_jobs = true;
3799 				rec->grp_wall = object->grp_wall;
3800 			}
3801 
3802 			if (object->lft != NO_VAL) {
3803 				rec->lft = object->lft;
3804 				resort = 1;
3805 			}
3806 
3807 			if (object->max_tres_pj) {
3808 				update_jobs = true;
3809 				xfree(rec->max_tres_pj);
3810 				if (object->max_tres_pj[0]) {
3811 					rec->max_tres_pj = object->max_tres_pj;
3812 					object->max_tres_pj = NULL;
3813 				}
3814 				assoc_mgr_set_tres_cnt_array(
3815 					&rec->max_tres_ctld,
3816 					rec->max_tres_pj, INFINITE64, 1);
3817 			}
3818 
3819 			if (object->max_tres_pn) {
3820 				update_jobs = true;
3821 				xfree(rec->max_tres_pn);
3822 				if (object->max_tres_pn[0]) {
3823 					rec->max_tres_pn = object->max_tres_pn;
3824 					object->max_tres_pn = NULL;
3825 				}
3826 				assoc_mgr_set_tres_cnt_array(
3827 					&rec->max_tres_pn_ctld,
3828 					rec->max_tres_pn, INFINITE64, 1);
3829 			}
3830 
3831 			if (object->max_tres_mins_pj) {
3832 				xfree(rec->max_tres_mins_pj);
3833 				if (object->max_tres_mins_pj[0]) {
3834 					rec->max_tres_mins_pj =
3835 						object->max_tres_mins_pj;
3836 					object->max_tres_mins_pj = NULL;
3837 				}
3838 				assoc_mgr_set_tres_cnt_array(
3839 					&rec->max_tres_mins_ctld,
3840 					rec->max_tres_mins_pj, INFINITE64, 1);
3841 			}
3842 
3843 			if (object->max_tres_run_mins) {
3844 				xfree(rec->max_tres_run_mins);
3845 				if (object->max_tres_run_mins[0]) {
3846 					rec->max_tres_run_mins =
3847 						object->max_tres_run_mins;
3848 					object->max_tres_run_mins = NULL;
3849 				}
3850 				assoc_mgr_set_tres_cnt_array(
3851 					&rec->max_tres_run_mins_ctld,
3852 					rec->max_tres_run_mins, INFINITE64, 1);
3853 			}
3854 
3855 			if (object->max_jobs != NO_VAL)
3856 				rec->max_jobs = object->max_jobs;
3857 			if (object->max_jobs_accrue != NO_VAL)
3858 				rec->max_jobs_accrue = object->max_jobs_accrue;
3859 			if (object->min_prio_thresh != NO_VAL)
3860 				rec->min_prio_thresh = object->min_prio_thresh;
3861 			if (object->max_submit_jobs != NO_VAL)
3862 				rec->max_submit_jobs = object->max_submit_jobs;
3863 			if (object->max_wall_pj != NO_VAL) {
3864 				update_jobs = true;
3865 				rec->max_wall_pj = object->max_wall_pj;
3866 			}
3867 
3868 			if (object->parent_acct) {
3869 				xfree(rec->parent_acct);
3870 				rec->parent_acct = xstrdup(object->parent_acct);
3871 			}
3872 			if (object->parent_id) {
3873 				rec->parent_id = object->parent_id;
3874 				// after all new parents have been set we will
3875 				// reset the parent pointers below
3876 				parents_changed = 1;
3877 			}
3878 
3879 			if (object->priority != NO_VAL) {
3880 				if (rec->priority == g_assoc_max_priority)
3881 					redo_priority = 2;
3882 
3883 				rec->priority = object->priority;
3884 
3885 				if ((rec->priority != INFINITE) &&
3886 				    (rec->priority > g_assoc_max_priority)) {
3887 					g_assoc_max_priority = rec->priority;
3888 					redo_priority = 1;
3889 				} else if (redo_priority != 2)
3890 					_set_assoc_norm_priority(rec);
3891 			}
3892 
3893 			if (object->qos_list) {
3894 				if (rec->qos_list) {
3895 					_local_update_assoc_qos_list(
3896 						rec, object->qos_list);
3897 				} else {
3898 					rec->qos_list = object->qos_list;
3899 					object->qos_list = NULL;
3900 				}
3901 
3902 				if (rec->user && (g_qos_count > 0)) {
3903 					if (!rec->usage->valid_qos
3904 					    || (bit_size(rec->usage->valid_qos)
3905 						!= g_qos_count)) {
3906 						FREE_NULL_BITMAP(
3907 							rec->usage->valid_qos);
3908 						rec->usage->valid_qos =
3909 							bit_alloc(g_qos_count);
3910 					} else
3911 						bit_nclear(rec->usage->
3912 							   valid_qos, 0,
3913 							   (bit_size(rec->
3914 								     usage->
3915 								     valid_qos)
3916 							    - 1));
3917 					set_qos_bitstr_from_list(
3918 						rec->usage->valid_qos,
3919 						rec->qos_list);
3920 				}
3921 			}
3922 
3923 			/* info("rec has def of %d %d", */
3924 			/*      rec->def_qos_id, object->def_qos_id); */
3925 			if (object->def_qos_id != NO_VAL &&
3926 			    object->def_qos_id >= g_qos_count) {
3927 				error("qos %d doesn't exist", rec->def_qos_id);
3928 				rec->def_qos_id = 0;
3929 			} else  if (object->def_qos_id != NO_VAL)
3930 				rec->def_qos_id = object->def_qos_id;
3931 
3932 			if (rec->def_qos_id && rec->user
3933 			    && rec->usage && rec->usage->valid_qos
3934 			    && !bit_test(rec->usage->valid_qos,
3935 					 rec->def_qos_id)) {
3936 				error("assoc %u doesn't have access "
3937 				      "to it's default qos '%s'",
3938 				      rec->id,
3939 				      slurmdb_qos_str(assoc_mgr_qos_list,
3940 						      rec->def_qos_id));
3941 				rec->def_qos_id = 0;
3942 			}
3943 
3944 			if (object->is_def != NO_VAL16) {
3945 				rec->is_def = object->is_def;
3946 				/* parents_changed will set this later
3947 				   so try to avoid doing it twice.
3948 				*/
3949 				if (rec->is_def && !parents_changed)
3950 					_set_user_default_acct(rec);
3951 			}
3952 
3953 			/* info("now rec has def of %d", rec->def_qos_id); */
3954 
3955 			if (update_jobs && init_setup.update_assoc_notify) {
3956 				/* since there are some deadlock
3957 				   issues while inside our lock here
3958 				   we have to process a notify later
3959 				*/
3960 				if (!update_list)
3961 					update_list = list_create(NULL);
3962 				list_append(update_list, rec);
3963 			}
3964 
3965 			if (!slurmdbd_conf && !parents_changed) {
3966 				debug("updating assoc %u", rec->id);
3967 				log_assoc_rec(rec, assoc_mgr_qos_list);
3968 			}
3969 			break;
3970 		case SLURMDB_ADD_ASSOC:
3971 			if (rec) {
3972 				//rc = SLURM_ERROR;
3973 				break;
3974 			}
3975 
3976 			if (!object->usage)
3977 				object->usage =
3978 					slurmdb_create_assoc_usage(
3979 						g_tres_count);
3980 			/* If is_def is uninitialized the value will
3981 			   be NO_VAL, so if it isn't 1 make it 0.
3982 			*/
3983 			if (object->is_def != 1)
3984 				object->is_def = 0;
3985 
3986 			if ((object->priority != INFINITE) &&
3987 			    (object->priority > g_assoc_max_priority)) {
3988 				g_assoc_max_priority = object->priority;
3989 				redo_priority = 1;
3990 			} else
3991 				_set_assoc_norm_priority(object);
3992 
3993 			/* Set something so we know to add it to the hash */
3994 			object->uid = INFINITE;
3995 
3996 			assoc_mgr_set_assoc_tres_cnt(object);
3997 
3998 			list_append(assoc_mgr_assoc_list, object);
3999 
4000 			object = NULL;
4001 			parents_changed = 1; /* set since we need to
4002 						set the parent
4003 					     */
4004 			run_update_resvs = 1; /* needed for updating
4005 						 reservations */
4006 
4007 			break;
4008 		case SLURMDB_REMOVE_ASSOC:
4009 			if (!rec) {
4010 				//rc = SLURM_ERROR;
4011 				break;
4012 			}
4013 
4014 			run_update_resvs = 1; /* needed for updating
4015 						 reservations */
4016 
4017 			if (setup_children)
4018 				parents_changed = 1; /* set since we need to
4019 							set the shares
4020 							of surrounding children
4021 						     */
4022 
4023 			/* We need to renormalize of something else */
4024 			if (rec->priority == g_assoc_max_priority)
4025 				redo_priority = 2;
4026 
4027 			_delete_assoc_hash(rec);
4028 			_remove_from_assoc_list(rec);
4029 			if (init_setup.remove_assoc_notify) {
4030 				/* since there are some deadlock
4031 				   issues while inside our lock here
4032 				   we have to process a notify later
4033 				*/
4034 				if (!remove_list)
4035 					remove_list = list_create(
4036 						slurmdb_destroy_assoc_rec);
4037 				list_append(remove_list, rec);
4038 			} else
4039 				slurmdb_destroy_assoc_rec(rec);
4040 			break;
4041 		case SLURMDB_REMOVE_ASSOC_USAGE:
4042 			if (!rec) {
4043 				//rc = SLURM_ERROR;
4044 				break;
4045 			}
4046 			assoc_mgr_remove_assoc_usage(rec);
4047 			break;
4048 		default:
4049 			break;
4050 		}
4051 
4052 		slurmdb_destroy_assoc_rec(object);
4053 	}
4054 
4055 	if (redo_priority)
4056 		_calculate_assoc_norm_priorities(redo_priority == 2);
4057 
4058 	/* We have to do this after the entire list is processed since
4059 	 * we may have added the parent which wasn't in the list before
4060 	 */
4061 	if (parents_changed) {
4062 		int reset = 1;
4063 		g_user_assoc_count = 0;
4064 		slurmdb_sort_hierarchical_assoc_list(
4065 			assoc_mgr_assoc_list, true);
4066 
4067 		itr = list_iterator_create(assoc_mgr_assoc_list);
4068 		/* flush the children lists */
4069 		if (setup_children) {
4070 			while ((object = list_next(itr))) {
4071 				if (object->usage->children_list)
4072 					list_flush(object->usage->
4073 						   children_list);
4074 			}
4075 			list_iterator_reset(itr);
4076 		}
4077 		while ((object = list_next(itr))) {
4078 			bool addit = false;
4079 			/* reset the limits because since a parent
4080 			   changed we could have different usage
4081 			*/
4082 			if (!object->user) {
4083 				_clear_used_assoc_info(object);
4084 				object->usage->usage_raw = 0;
4085 				for (i=0; i<object->usage->tres_cnt; i++)
4086 					object->usage->usage_tres_raw[i] = 0;
4087 				object->usage->grp_used_wall = 0;
4088 			}
4089 
4090 			/* This means we were just added, so we need
4091 			   to be added to the hash after the uid is set.
4092 			*/
4093 			if (object->uid == INFINITE)
4094 				addit = true;
4095 			/* _set_assoc_parent_and_user() may change the uid if
4096 			 * unset which changes the hash value. */
4097 			if (object->user &&
4098 			    (object->uid == NO_VAL || object->uid == 0)) {
4099 				_delete_assoc_hash(object);
4100 				addit = true;
4101 			}
4102 
4103 			_set_assoc_parent_and_user(object, reset);
4104 
4105 			if (addit)
4106 				_add_assoc_hash(object);
4107 			reset = 0;
4108 		}
4109 		/* Now that we have set up the parents correctly we
4110 		   can update the used limits
4111 		*/
4112 		list_iterator_reset(itr);
4113 		while ((object = list_next(itr))) {
4114 			if (setup_children) {
4115 				List children = object->usage->children_list;
4116 				if (!children || list_is_empty(children))
4117 					goto is_user;
4118 
4119 				_set_children_level_shares(
4120 					object,
4121 					_get_children_level_shares(object));
4122 			}
4123 		is_user:
4124 			if (!object->user)
4125 				continue;
4126 
4127 			rec = object;
4128 			/* look for a parent since we are starting at
4129 			   the parent instead of the child
4130 			*/
4131 			while (object->usage->parent_assoc_ptr) {
4132 				/* we need to get the parent first
4133 				   here since we start at the child
4134 				*/
4135 				object = object->usage->parent_assoc_ptr;
4136 
4137 				_addto_used_info(object, rec);
4138 			}
4139 		}
4140 		if (setup_children) {
4141 			/* Now normalize the static shares */
4142 			list_iterator_reset(itr);
4143 			while ((object = list_next(itr))) {
4144 				assoc_mgr_normalize_assoc_shares(object);
4145 				log_assoc_rec(object, assoc_mgr_qos_list);
4146 			}
4147 		}
4148 		list_iterator_destroy(itr);
4149 	} else if (resort)
4150 		slurmdb_sort_hierarchical_assoc_list(
4151 			assoc_mgr_assoc_list, true);
4152 
4153 	if (!locked)
4154 		assoc_mgr_unlock(&locks);
4155 
4156 	/* This needs to happen outside of the
4157 	   assoc_mgr_lock */
4158 	if (remove_list) {
4159 		itr = list_iterator_create(remove_list);
4160 		while ((rec = list_next(itr)))
4161 			init_setup.remove_assoc_notify(rec);
4162 		list_iterator_destroy(itr);
4163 		FREE_NULL_LIST(remove_list);
4164 	}
4165 
4166 	if (update_list) {
4167 		itr = list_iterator_create(update_list);
4168 		while ((rec = list_next(itr)))
4169 			init_setup.update_assoc_notify(rec);
4170 		list_iterator_destroy(itr);
4171 		FREE_NULL_LIST(update_list);
4172 	}
4173 
4174 	if (run_update_resvs && init_setup.update_resvs)
4175 		init_setup.update_resvs();
4176 
4177 	return rc;
4178 }
4179 
assoc_mgr_update_wckeys(slurmdb_update_object_t * update,bool locked)4180 extern int assoc_mgr_update_wckeys(slurmdb_update_object_t *update, bool locked)
4181 {
4182 	slurmdb_wckey_rec_t * rec = NULL;
4183 	slurmdb_wckey_rec_t * object = NULL;
4184 	ListIterator itr = NULL;
4185 	int rc = SLURM_SUCCESS;
4186 	uid_t pw_uid;
4187 	assoc_mgr_lock_t locks = { .user = WRITE_LOCK, .wckey = WRITE_LOCK };
4188 
4189 	if (!locked)
4190 		assoc_mgr_lock(&locks);
4191 	if (!assoc_mgr_wckey_list) {
4192 		if (!locked)
4193 			assoc_mgr_unlock(&locks);
4194 		return SLURM_SUCCESS;
4195 	}
4196 
4197 	itr = list_iterator_create(assoc_mgr_wckey_list);
4198 	while ((object = list_pop(update->objects))) {
4199 		if (object->cluster && assoc_mgr_cluster_name) {
4200 			/* only update the local clusters assocs */
4201 			if (xstrcasecmp(object->cluster,
4202 					assoc_mgr_cluster_name)) {
4203 				slurmdb_destroy_wckey_rec(object);
4204 				continue;
4205 			}
4206 		} else if (assoc_mgr_cluster_name) {
4207 			error("We don't have a cluster here, no "
4208 			      "idea if this is our wckey.");
4209 			continue;
4210 		}
4211 
4212 		list_iterator_reset(itr);
4213 		while ((rec = list_next(itr))) {
4214 			/* only and always check for on the slurmdbd */
4215 			if (!assoc_mgr_cluster_name &&
4216 			    xstrcasecmp(object->cluster, rec->cluster)) {
4217 				debug4("not the right cluster");
4218 				continue;
4219 			}
4220 			if (object->id) {
4221 				if (object->id == rec->id) {
4222 					break;
4223 				}
4224 				continue;
4225 			} else {
4226 				if (object->uid != rec->uid) {
4227 					debug4("not the right user");
4228 					continue;
4229 				}
4230 
4231 				if (object->name
4232 				    && (!rec->name
4233 					|| xstrcasecmp(object->name,
4234 						       rec->name))) {
4235 					debug4("not the right wckey");
4236 					continue;
4237 				}
4238 				break;
4239 			}
4240 		}
4241 		//info("%d WCKEY %u", update->type, object->id);
4242 		switch(update->type) {
4243 		case SLURMDB_MODIFY_WCKEY:
4244 			if (!rec) {
4245 				error("SLURMDB_MODIFY_WCKEY: wckey %u(%s) not found, unable to update.",
4246 				     object->id, object->name);
4247 				rc = SLURM_ERROR;
4248 				break;
4249 			}
4250 
4251 			if (object->is_def != NO_VAL16) {
4252 				rec->is_def = object->is_def;
4253 				if (rec->is_def)
4254 					_set_user_default_wckey(rec);
4255 			}
4256 
4257 			break;
4258 		case SLURMDB_ADD_WCKEY:
4259 			if (rec) {
4260 				//rc = SLURM_ERROR;
4261 				break;
4262 			}
4263 			if (uid_from_string (object->user, &pw_uid) < 0) {
4264 				debug("wckey add couldn't get a uid "
4265 				      "for user %s",
4266 				      object->user);
4267 				object->uid = NO_VAL;
4268 			} else
4269 				object->uid = pw_uid;
4270 
4271 			/* If is_def is uninitialized the value will
4272 			   be NO_VAL, so if it isn't 1 make it 0.
4273 			*/
4274 			if (object->is_def == 1)
4275 				_set_user_default_wckey(object);
4276 			else
4277 				object->is_def = 0;
4278 			list_append(assoc_mgr_wckey_list, object);
4279 			object = NULL;
4280 			break;
4281 		case SLURMDB_REMOVE_WCKEY:
4282 			if (!rec) {
4283 				//rc = SLURM_ERROR;
4284 				break;
4285 			}
4286 			list_delete_item(itr);
4287 			break;
4288 		default:
4289 			break;
4290 		}
4291 
4292 		slurmdb_destroy_wckey_rec(object);
4293 	}
4294 	list_iterator_destroy(itr);
4295 	if (!locked)
4296 		assoc_mgr_unlock(&locks);
4297 
4298 	return rc;
4299 }
4300 
assoc_mgr_update_users(slurmdb_update_object_t * update,bool locked)4301 extern int assoc_mgr_update_users(slurmdb_update_object_t *update, bool locked)
4302 {
4303 	slurmdb_user_rec_t * rec = NULL;
4304 	slurmdb_user_rec_t * object = NULL;
4305 
4306 	ListIterator itr = NULL;
4307 	int rc = SLURM_SUCCESS;
4308 	uid_t pw_uid;
4309 	assoc_mgr_lock_t locks = { .assoc = WRITE_LOCK, .user = WRITE_LOCK,
4310 				   .wckey = WRITE_LOCK };
4311 
4312 	if (!locked)
4313 		assoc_mgr_lock(&locks);
4314 	if (!assoc_mgr_user_list) {
4315 		if (!locked)
4316 			assoc_mgr_unlock(&locks);
4317 		return SLURM_SUCCESS;
4318 	}
4319 
4320 	itr = list_iterator_create(assoc_mgr_user_list);
4321 	while ((object = list_pop(update->objects))) {
4322 		list_iterator_reset(itr);
4323 		while ((rec = list_next(itr))) {
4324 			char *name;
4325 			if (object->old_name)
4326 				name = object->old_name;
4327 			else
4328 				name = object->name;
4329 			if (!xstrcasecmp(name, rec->name))
4330 				break;
4331 		}
4332 
4333 		//info("%d user %s", update->type, object->name);
4334 		switch(update->type) {
4335 		case SLURMDB_MODIFY_USER:
4336 			if (!rec) {
4337 				error("SLURMDB_MODIFY_USER: user %s not found, unable to update.",
4338 				      object->old_name ?
4339 				      object->old_name : object->name);
4340 				rc = SLURM_ERROR;
4341 				break;
4342 			}
4343 
4344 			if (object->old_name) {
4345 				if (!object->name) {
4346 					error("Tried to alter user %s's name "
4347 					      "without giving a new one.",
4348 					      rec->name);
4349 					break;
4350 				}
4351 				xfree(rec->old_name);
4352 				rec->old_name = rec->name;
4353 				rec->name = object->name;
4354 				object->name = NULL;
4355 				rc = _change_user_name(rec);
4356 			}
4357 
4358 			if (object->default_acct) {
4359 				xfree(rec->default_acct);
4360 				rec->default_acct = object->default_acct;
4361 				object->default_acct = NULL;
4362 			}
4363 
4364 			if (object->default_wckey) {
4365 				xfree(rec->default_wckey);
4366 				rec->default_wckey = object->default_wckey;
4367 				object->default_wckey = NULL;
4368 			}
4369 
4370 			if (object->admin_level != SLURMDB_ADMIN_NOTSET)
4371 				rec->admin_level = object->admin_level;
4372 
4373 			break;
4374 		case SLURMDB_ADD_USER:
4375 			if (rec) {
4376 				//rc = SLURM_ERROR;
4377 				break;
4378 			}
4379 			if (uid_from_string (object->name, &pw_uid) < 0) {
4380 				debug("user add couldn't get a uid for user %s",
4381 				      object->name);
4382 				object->uid = NO_VAL;
4383 			} else
4384 				object->uid = pw_uid;
4385 			list_append(assoc_mgr_user_list, object);
4386 			object = NULL;
4387 			break;
4388 		case SLURMDB_REMOVE_USER:
4389 			if (!rec) {
4390 				//rc = SLURM_ERROR;
4391 				break;
4392 			}
4393 			list_delete_item(itr);
4394 			break;
4395 		case SLURMDB_ADD_COORD:
4396 			/* same as SLURMDB_REMOVE_COORD */
4397 		case SLURMDB_REMOVE_COORD:
4398 			if (!rec) {
4399 				//rc = SLURM_ERROR;
4400 				break;
4401 			}
4402 			/* We always get a complete list here */
4403 			if (!object->coord_accts) {
4404 				if (rec->coord_accts)
4405 					list_flush(rec->coord_accts);
4406 			} else {
4407 				FREE_NULL_LIST(rec->coord_accts);
4408 				rec->coord_accts = object->coord_accts;
4409 				object->coord_accts = NULL;
4410 			}
4411 			break;
4412 		default:
4413 			break;
4414 		}
4415 
4416 		slurmdb_destroy_user_rec(object);
4417 	}
4418 	list_iterator_destroy(itr);
4419 	if (!locked)
4420 		assoc_mgr_unlock(&locks);
4421 
4422 	return rc;
4423 }
4424 
assoc_mgr_update_qos(slurmdb_update_object_t * update,bool locked)4425 extern int assoc_mgr_update_qos(slurmdb_update_object_t *update, bool locked)
4426 {
4427 	slurmdb_qos_rec_t *rec = NULL;
4428 	slurmdb_qos_rec_t *object = NULL;
4429 
4430 	ListIterator itr = NULL, assoc_itr = NULL;
4431 
4432 	slurmdb_assoc_rec_t *assoc = NULL;
4433 	int rc = SLURM_SUCCESS;
4434 	bool resize_qos_bitstr = 0;
4435 	int redo_priority = 0;
4436 	List remove_list = NULL;
4437 	List update_list = NULL;
4438 	assoc_mgr_lock_t locks = { .assoc = WRITE_LOCK, .qos = WRITE_LOCK };
4439 
4440 	if (!locked)
4441 		assoc_mgr_lock(&locks);
4442 	if (!assoc_mgr_qos_list) {
4443 		if (!locked)
4444 			assoc_mgr_unlock(&locks);
4445 		return SLURM_SUCCESS;
4446 	}
4447 
4448 	itr = list_iterator_create(assoc_mgr_qos_list);
4449 	while ((object = list_pop(update->objects))) {
4450 		bool update_jobs = false;
4451 		list_iterator_reset(itr);
4452 		while ((rec = list_next(itr))) {
4453 			if (object->id == rec->id) {
4454 				break;
4455 			}
4456 		}
4457 
4458 		//info("%d qos %s", update->type, object->name);
4459 		switch(update->type) {
4460 		case SLURMDB_ADD_QOS:
4461 			if (rec) {
4462 				//rc = SLURM_ERROR;
4463 				break;
4464 			}
4465 
4466 			if (!object->usage)
4467 				object->usage = slurmdb_create_qos_usage(
4468 					g_tres_count);
4469 
4470 			assoc_mgr_set_qos_tres_cnt(object);
4471 
4472 			list_append(assoc_mgr_qos_list, object);
4473 /* 			char *tmp = get_qos_complete_str_bitstr( */
4474 /* 				assoc_mgr_qos_list, */
4475 /* 				object->preempt_bitstr); */
4476 
4477 /* 			info("new qos %s(%d) now preempts %s",  */
4478 /* 			     object->name, object->id, tmp); */
4479 /* 			xfree(tmp); */
4480 
4481 			/* Since in the database id's don't start at 1
4482 			   instead of 0 we need to ignore the 0 bit and start
4483 			   with 1 so increase the count by 1.
4484 			*/
4485 			if (object->id+1 > g_qos_count) {
4486 				resize_qos_bitstr = 1;
4487 				g_qos_count = object->id+1;
4488 			}
4489 
4490 			if (object->priority > g_qos_max_priority) {
4491 				g_qos_max_priority = object->priority;
4492 				redo_priority = 1;
4493 			} else
4494 				_set_qos_norm_priority(object);
4495 
4496 			object = NULL;
4497 			break;
4498 		case SLURMDB_MODIFY_QOS:
4499 			if (!rec) {
4500 				error("SLURMDB_MODIFY_QOS: qos %u(%s) not found, unable to update.",
4501 				      object->id, object->name);
4502 				rc = SLURM_ERROR;
4503 				break;
4504 			}
4505 
4506 			if (!(object->flags & QOS_FLAG_NOTSET)) {
4507 				if (object->flags & QOS_FLAG_ADD) {
4508 					rec->flags |= object->flags;
4509 					rec->flags &= (~QOS_FLAG_ADD);
4510 				} else if (object->flags & QOS_FLAG_REMOVE) {
4511 					rec->flags &= ~object->flags;
4512 					rec->flags &= (~QOS_FLAG_REMOVE);
4513 				} else
4514 					rec->flags = object->flags;
4515 			}
4516 
4517 			if (object->grace_time != NO_VAL)
4518 				rec->grace_time = object->grace_time;
4519 
4520 			if (object->grp_tres) {
4521 				update_jobs = true;
4522 				/* If we have a blank string that
4523 				 * means it is cleared.
4524 				 */
4525 				xfree(rec->grp_tres);
4526 				if (object->grp_tres[0]) {
4527 					rec->grp_tres = object->grp_tres;
4528 					object->grp_tres = NULL;
4529 				}
4530 				assoc_mgr_set_tres_cnt_array(
4531 					&rec->grp_tres_ctld, rec->grp_tres,
4532 					INFINITE64, 1);
4533 
4534 			}
4535 
4536 			if (object->grp_tres_mins) {
4537 				xfree(rec->grp_tres_mins);
4538 				if (object->grp_tres_mins[0]) {
4539 					rec->grp_tres_mins =
4540 						object->grp_tres_mins;
4541 					object->grp_tres_mins = NULL;
4542 				}
4543 				assoc_mgr_set_tres_cnt_array(
4544 					&rec->grp_tres_mins_ctld,
4545 					rec->grp_tres_mins, INFINITE64, 1);
4546 			}
4547 
4548 			if (object->grp_tres_run_mins) {
4549 				xfree(rec->grp_tres_run_mins);
4550 				if (object->grp_tres_run_mins[0]) {
4551 					rec->grp_tres_run_mins =
4552 						object->grp_tres_run_mins;
4553 					object->grp_tres_run_mins = NULL;
4554 				}
4555 				assoc_mgr_set_tres_cnt_array(
4556 					&rec->grp_tres_run_mins_ctld,
4557 					rec->grp_tres_run_mins, INFINITE64, 1);
4558 			}
4559 
4560 			if (object->grp_jobs != NO_VAL)
4561 				rec->grp_jobs = object->grp_jobs;
4562 			if (object->grp_jobs_accrue != NO_VAL)
4563 				rec->grp_jobs_accrue = object->grp_jobs_accrue;
4564 			if (object->grp_submit_jobs != NO_VAL)
4565 				rec->grp_submit_jobs = object->grp_submit_jobs;
4566 			if (object->grp_wall != NO_VAL) {
4567 				update_jobs = true;
4568 				rec->grp_wall = object->grp_wall;
4569 			}
4570 
4571 			if (object->max_tres_pa) {
4572 				update_jobs = true;
4573 				xfree(rec->max_tres_pa);
4574 				if (object->max_tres_pa[0]) {
4575 					rec->max_tres_pa = object->max_tres_pa;
4576 					object->max_tres_pa = NULL;
4577 				}
4578 				assoc_mgr_set_tres_cnt_array(
4579 					&rec->max_tres_pa_ctld,
4580 					rec->max_tres_pa, INFINITE64, 1);
4581 			}
4582 
4583 			if (object->max_tres_pj) {
4584 				update_jobs = true;
4585 				xfree(rec->max_tres_pj);
4586 				if (object->max_tres_pj[0]) {
4587 					rec->max_tres_pj = object->max_tres_pj;
4588 					object->max_tres_pj = NULL;
4589 				}
4590 				assoc_mgr_set_tres_cnt_array(
4591 					&rec->max_tres_pj_ctld,
4592 					rec->max_tres_pj, INFINITE64, 1);
4593 			}
4594 
4595 			if (object->max_tres_pn) {
4596 				update_jobs = true;
4597 				xfree(rec->max_tres_pn);
4598 				if (object->max_tres_pn[0]) {
4599 					rec->max_tres_pn = object->max_tres_pn;
4600 					object->max_tres_pn = NULL;
4601 				}
4602 				assoc_mgr_set_tres_cnt_array(
4603 					&rec->max_tres_pn_ctld,
4604 					rec->max_tres_pn, INFINITE64, 1);
4605 			}
4606 
4607 			if (object->max_tres_pu) {
4608 				update_jobs = true;
4609 				xfree(rec->max_tres_pu);
4610 				if (object->max_tres_pu[0]) {
4611 					rec->max_tres_pu = object->max_tres_pu;
4612 					object->max_tres_pu = NULL;
4613 				}
4614 				assoc_mgr_set_tres_cnt_array(
4615 					&rec->max_tres_pu_ctld,
4616 					rec->max_tres_pu, INFINITE64, 1);
4617 			}
4618 
4619 			if (object->max_tres_mins_pj) {
4620 				xfree(rec->max_tres_mins_pj);
4621 				if (object->max_tres_mins_pj[0]) {
4622 					rec->max_tres_mins_pj =
4623 						object->max_tres_mins_pj;
4624 					object->max_tres_mins_pj = NULL;
4625 				}
4626 				assoc_mgr_set_tres_cnt_array(
4627 					&rec->max_tres_mins_pj_ctld,
4628 					rec->max_tres_mins_pj, INFINITE64, 1);
4629 			}
4630 
4631 			if (object->max_tres_run_mins_pa) {
4632 				xfree(rec->max_tres_run_mins_pa);
4633 				if (object->max_tres_run_mins_pa[0]) {
4634 					rec->max_tres_run_mins_pa =
4635 						object->max_tres_run_mins_pa;
4636 					object->max_tres_run_mins_pa = NULL;
4637 				}
4638 				assoc_mgr_set_tres_cnt_array(
4639 					&rec->max_tres_run_mins_pa_ctld,
4640 					rec->max_tres_run_mins_pa,
4641 					INFINITE64, 1);
4642 			}
4643 
4644 			if (object->max_tres_run_mins_pu) {
4645 				xfree(rec->max_tres_run_mins_pu);
4646 				if (object->max_tres_run_mins_pu[0]) {
4647 					rec->max_tres_run_mins_pu =
4648 						object->max_tres_run_mins_pu;
4649 					object->max_tres_run_mins_pu = NULL;
4650 				}
4651 				assoc_mgr_set_tres_cnt_array(
4652 					&rec->max_tres_run_mins_pu_ctld,
4653 					rec->max_tres_run_mins_pu,
4654 					INFINITE64, 1);
4655 			}
4656 
4657 			if (object->max_jobs_pa != NO_VAL)
4658 				rec->max_jobs_pa = object->max_jobs_pa;
4659 
4660 			if (object->max_jobs_pu != NO_VAL)
4661 				rec->max_jobs_pu = object->max_jobs_pu;
4662 
4663 			if (object->max_jobs_accrue_pa != NO_VAL)
4664 				rec->max_jobs_accrue_pa =
4665 					object->max_jobs_accrue_pa;
4666 
4667 			if (object->max_jobs_accrue_pu != NO_VAL)
4668 				rec->max_jobs_accrue_pu =
4669 					object->max_jobs_accrue_pu;
4670 
4671 			if (object->min_prio_thresh != NO_VAL)
4672 				rec->min_prio_thresh = object->min_prio_thresh;
4673 			if (object->max_submit_jobs_pa != NO_VAL)
4674 				rec->max_submit_jobs_pa =
4675 					object->max_submit_jobs_pa;
4676 
4677 			if (object->max_submit_jobs_pu != NO_VAL)
4678 				rec->max_submit_jobs_pu =
4679 					object->max_submit_jobs_pu;
4680 
4681 			if (object->max_wall_pj != NO_VAL) {
4682 				update_jobs = true;
4683 				rec->max_wall_pj = object->max_wall_pj;
4684 			}
4685 
4686 			if (object->min_tres_pj) {
4687 				xfree(rec->min_tres_pj);
4688 				if (object->min_tres_pj[0]) {
4689 					rec->min_tres_pj = object->min_tres_pj;
4690 					object->min_tres_pj = NULL;
4691 				}
4692 				assoc_mgr_set_tres_cnt_array(
4693 					&rec->min_tres_pj_ctld,
4694 					rec->min_tres_pj, INFINITE64, 1);
4695 			}
4696 
4697 			if (object->preempt_bitstr) {
4698 				if (rec->preempt_bitstr)
4699 					FREE_NULL_BITMAP(rec->preempt_bitstr);
4700 
4701 				rec->preempt_bitstr = object->preempt_bitstr;
4702 				object->preempt_bitstr = NULL;
4703 				/* char *tmp = get_qos_complete_str_bitstr( */
4704 /* 					assoc_mgr_qos_list, */
4705 /* 					rec->preempt_bitstr); */
4706 
4707 /* 				info("qos %s(%d) now preempts %s",  */
4708 /* 				     rec->name, rec->id, tmp); */
4709 /* 				xfree(tmp); */
4710 			}
4711 
4712 			if (object->preempt_mode != NO_VAL16)
4713 				rec->preempt_mode = object->preempt_mode;
4714 
4715 			if (object->preempt_exempt_time != NO_VAL)
4716 				rec->preempt_exempt_time =
4717 					object->preempt_exempt_time;
4718 
4719 			if (object->priority != NO_VAL) {
4720 				if (rec->priority == g_qos_max_priority)
4721 					redo_priority = 2;
4722 
4723 				rec->priority = object->priority;
4724 
4725 				if (rec->priority > g_qos_max_priority) {
4726 					g_qos_max_priority = rec->priority;
4727 					redo_priority = 1;
4728 				} else if (redo_priority != 2)
4729 					_set_qos_norm_priority(rec);
4730 			}
4731 
4732 			if (!fuzzy_equal(object->usage_factor, NO_VAL))
4733 				rec->usage_factor = object->usage_factor;
4734 
4735 			if (!fuzzy_equal(object->usage_thres, NO_VAL))
4736 				rec->usage_thres = object->usage_thres;
4737 
4738 			if (update_jobs && init_setup.update_qos_notify) {
4739 				/* since there are some deadlock
4740 				   issues while inside our lock here
4741 				   we have to process a notify later
4742 				*/
4743 				if (!update_list)
4744 					update_list = list_create(NULL);
4745 				list_append(update_list, rec);
4746 			}
4747 
4748 			break;
4749 		case SLURMDB_REMOVE_QOS:
4750 			if (!rec) {
4751 				//rc = SLURM_ERROR;
4752 				break;
4753 			}
4754 
4755 			/* We need to renormalize of something else */
4756 			if (rec->priority == g_qos_max_priority)
4757 				redo_priority = 2;
4758 
4759 			if (init_setup.remove_qos_notify) {
4760 				/* since there are some deadlock
4761 				   issues while inside our lock here
4762 				   we have to process a notify later
4763 				*/
4764 				if (!remove_list)
4765 					remove_list = list_create(
4766 						slurmdb_destroy_qos_rec);
4767 				list_remove(itr);
4768 				list_append(remove_list, rec);
4769 			} else
4770 				list_delete_item(itr);
4771 
4772 			if (!assoc_mgr_assoc_list)
4773 				break;
4774 			/* Remove this qos from all the associations
4775 			   on this cluster.
4776 			*/
4777 			assoc_itr = list_iterator_create(
4778 				assoc_mgr_assoc_list);
4779 			while ((assoc = list_next(assoc_itr))) {
4780 
4781 				if (assoc->def_qos_id == object->id)
4782 					assoc->def_qos_id = 0;
4783 
4784 				if (!assoc->usage->valid_qos)
4785 					continue;
4786 
4787 				if (bit_size(assoc->usage->valid_qos)
4788 				    > object->id)
4789 					bit_clear(assoc->usage->valid_qos,
4790 						  object->id);
4791 			}
4792 			list_iterator_destroy(assoc_itr);
4793 
4794 			break;
4795 		case SLURMDB_REMOVE_QOS_USAGE:
4796 			if (!rec) {
4797 				//rc = SLURM_ERROR;
4798 				break;
4799 			}
4800 			assoc_mgr_remove_qos_usage(rec);
4801 			break;
4802 		default:
4803 			break;
4804 		}
4805 		slurmdb_destroy_qos_rec(object);
4806 	}
4807 
4808 	if (resize_qos_bitstr) {
4809 		/* we need to resize all bitstring's that represent
4810 		   qos' */
4811 		list_iterator_reset(itr);
4812 		while ((object = list_next(itr))) {
4813 			if (!object->preempt_bitstr)
4814 				continue;
4815 
4816 			object->preempt_bitstr =
4817 				bit_realloc(object->preempt_bitstr,
4818 					    g_qos_count);
4819 		}
4820 		if (assoc_mgr_assoc_list) {
4821 			assoc_itr = list_iterator_create(
4822 				assoc_mgr_assoc_list);
4823 			while ((assoc = list_next(assoc_itr))) {
4824 				if (!assoc->usage->valid_qos)
4825 					continue;
4826 				assoc->usage->valid_qos =
4827 					bit_realloc(assoc->usage->valid_qos,
4828 						    g_qos_count);
4829 			}
4830 			list_iterator_destroy(assoc_itr);
4831 		}
4832 	}
4833 
4834 	if (redo_priority == 1) {
4835 		list_iterator_reset(itr);
4836 		while ((object = list_next(itr)))
4837 			_set_qos_norm_priority(object);
4838 	} else if (redo_priority == 2)
4839 		_post_qos_list(assoc_mgr_qos_list);
4840 
4841 	list_iterator_destroy(itr);
4842 
4843 	if (!locked)
4844 		assoc_mgr_unlock(&locks);
4845 
4846 	/* This needs to happen outside of the
4847 	   assoc_mgr_lock */
4848 	if (remove_list) {
4849 		itr = list_iterator_create(remove_list);
4850 		while ((rec = list_next(itr)))
4851 			init_setup.remove_qos_notify(rec);
4852 		list_iterator_destroy(itr);
4853 		FREE_NULL_LIST(remove_list);
4854 	}
4855 
4856 	if (update_list) {
4857 		itr = list_iterator_create(update_list);
4858 		while ((rec = list_next(itr)))
4859 			init_setup.update_qos_notify(rec);
4860 		list_iterator_destroy(itr);
4861 		FREE_NULL_LIST(update_list);
4862 	}
4863 
4864 	if (resize_qos_bitstr && init_setup.resize_qos_notify)
4865 		init_setup.resize_qos_notify();
4866 
4867 	return rc;
4868 }
4869 
4870 /*
4871  * NOTE: This function only works when assoc_mgr_cluster_name is defined.  This
4872  * does not currently work for the slurmdbd.
4873  */
assoc_mgr_update_res(slurmdb_update_object_t * update,bool locked)4874 extern int assoc_mgr_update_res(slurmdb_update_object_t *update, bool locked)
4875 {
4876 	slurmdb_res_rec_t *rec = NULL;
4877 	slurmdb_res_rec_t *object = NULL;
4878 
4879 	ListIterator itr = NULL;
4880 	int rc = SLURM_SUCCESS;
4881 	assoc_mgr_lock_t locks = { .res = WRITE_LOCK };
4882 
4883 	if (!locked)
4884 		assoc_mgr_lock(&locks);
4885 	if (!assoc_mgr_res_list) {
4886 		if (!locked)
4887 			assoc_mgr_unlock(&locks);
4888 		return SLURM_SUCCESS;
4889 	}
4890 
4891 	itr = list_iterator_create(assoc_mgr_res_list);
4892 	while ((object = list_pop(update->objects))) {
4893 		/* If this doesn't already have a clus_res_rec and no
4894 		   clus_res_list then the resource it self changed so
4895 		   update counts.
4896 		*/
4897 		if (assoc_mgr_cluster_name && object->clus_res_rec) {
4898 			if (!object->clus_res_rec->cluster) {
4899 				error("Resource doesn't have a cluster name?");
4900 				slurmdb_destroy_res_rec(object);
4901 				continue;
4902 			} else if (xstrcmp(object->clus_res_rec->cluster,
4903 					   assoc_mgr_cluster_name)) {
4904 				debug("Not for our cluster for '%s'",
4905 				      object->clus_res_rec->cluster);
4906 				slurmdb_destroy_res_rec(object);
4907 				continue;
4908 			}
4909 		}
4910 
4911 		/* just get rid of clus_res_list if it exists (we only
4912 		   look at objects with clus_res_rec or none
4913 		*/
4914 		FREE_NULL_LIST(object->clus_res_list);
4915 
4916 		list_iterator_reset(itr);
4917 		while ((rec = list_next(itr))) {
4918 			if (object->id == rec->id)
4919 				break;
4920 		}
4921 		switch(update->type) {
4922 		case SLURMDB_ADD_RES:
4923 			if (rec) {
4924 				//rc = SLURM_ERROR;
4925 				break;
4926 			}
4927 			if (!object->clus_res_rec) {
4928 				error("trying to add resource without a "
4929 				      "clus_res_rec!  This should never "
4930 				      "happen.");
4931 				break;
4932 			}
4933 			list_append(assoc_mgr_res_list, object);
4934 			switch (object->type) {
4935 			case SLURMDB_RESOURCE_LICENSE:
4936 				if (init_setup.add_license_notify)
4937 					init_setup.add_license_notify(object);
4938 				break;
4939 			default:
4940 				error("SLURMDB_ADD_RES: unknown type %d",
4941 				      object->type);
4942 				break;
4943 			}
4944 			object = NULL;
4945 			break;
4946 		case SLURMDB_MODIFY_RES:
4947 			if (!rec) {
4948 				//rc = SLURM_ERROR;
4949 				break;
4950 			}
4951 			if (!object->clus_res_rec) {
4952 				error("trying to Modify resource without a "
4953 				      "clus_res_rec!  This should never "
4954 				      "happen.");
4955 				break;
4956 			}
4957 
4958 			if (!(object->flags & SLURMDB_RES_FLAG_NOTSET)) {
4959 				uint32_t base_flags = (object->flags &
4960 						       SLURMDB_RES_FLAG_BASE);
4961 				if (object->flags & SLURMDB_RES_FLAG_ADD) {
4962 					rec->flags |= base_flags;
4963 				} else if (object->flags
4964 					   & SLURMDB_RES_FLAG_REMOVE) {
4965 					rec->flags &= ~base_flags;
4966 				} else
4967 					rec->flags = base_flags;
4968 			}
4969 
4970 			if (object->count != NO_VAL)
4971 				rec->count = object->count;
4972 
4973 			if (object->type != SLURMDB_RESOURCE_NOTSET)
4974 				rec->type = object->type;
4975 
4976 			if (object->clus_res_rec->percent_allowed != NO_VAL16)
4977 				rec->clus_res_rec->percent_allowed =
4978 					object->clus_res_rec->percent_allowed;
4979 
4980 			switch (rec->type) {
4981 			case SLURMDB_RESOURCE_LICENSE:
4982 				if (init_setup.update_license_notify)
4983 					init_setup.update_license_notify(rec);
4984 				break;
4985 			default:
4986 				error("SLURMDB_MODIFY_RES: "
4987 				      "unknown type %d",
4988 				      rec->type);
4989 				break;
4990 			}
4991 			break;
4992 		case SLURMDB_REMOVE_RES:
4993 			if (!rec) {
4994 				//rc = SLURM_ERROR;
4995 				break;
4996 			}
4997 			switch (rec->type) {
4998 			case SLURMDB_RESOURCE_LICENSE:
4999 				if (init_setup.remove_license_notify)
5000 					init_setup.remove_license_notify(rec);
5001 				break;
5002 			default:
5003 				error("SLURMDB_REMOVE_RES: "
5004 				      "unknown type %d",
5005 				      rec->type);
5006 				break;
5007 			}
5008 
5009 			list_delete_item(itr);
5010 			break;
5011 		default:
5012 			break;
5013 		}
5014 
5015 		slurmdb_destroy_res_rec(object);
5016 	}
5017 	list_iterator_destroy(itr);
5018 	if (!locked)
5019 		assoc_mgr_unlock(&locks);
5020 	return rc;
5021 }
5022 
assoc_mgr_update_tres(slurmdb_update_object_t * update,bool locked)5023 extern int assoc_mgr_update_tres(slurmdb_update_object_t *update, bool locked)
5024 {
5025 	slurmdb_tres_rec_t *rec = NULL;
5026 	slurmdb_tres_rec_t *object = NULL;
5027 
5028 	ListIterator itr = NULL;
5029 	List tmp_list;
5030 	bool changed = false, freeit = false;
5031 	int rc = SLURM_SUCCESS;
5032 	assoc_mgr_lock_t locks = { .assoc = WRITE_LOCK, .qos = WRITE_LOCK,
5033 				   .tres = WRITE_LOCK };
5034 	if (!locked)
5035 		assoc_mgr_lock(&locks);
5036 
5037 	if (!assoc_mgr_tres_list) {
5038 		tmp_list = list_create(slurmdb_destroy_tres_rec);
5039 		freeit = true;
5040 	} else {
5041 		/* Since assoc_mgr_tres_list gets freed later we need
5042 		 * to swap things out to avoid memory corruption.
5043 		 */
5044 		tmp_list = assoc_mgr_tres_list;
5045 		assoc_mgr_tres_list = NULL;
5046 	}
5047 
5048 	itr = list_iterator_create(tmp_list);
5049 	while ((object = list_pop(update->objects))) {
5050 		list_iterator_reset(itr);
5051 		while ((rec = list_next(itr))) {
5052 			if (object->id == rec->id)
5053 				break;
5054 		}
5055 
5056 		switch (update->type) {
5057 		case SLURMDB_ADD_TRES:
5058 			if (rec) {
5059 				//rc = SLURM_ERROR;
5060 				break;
5061 			}
5062 			if (!object->id) {
5063 				error("trying to add resource without an id!  "
5064 				      "This should never happen.");
5065 				break;
5066 			}
5067 			list_append(tmp_list, object);
5068 			object = NULL;
5069 			changed = true;
5070 			break;
5071 		default:
5072 			break;
5073 		}
5074 
5075 		slurmdb_destroy_tres_rec(object);
5076 	}
5077 	list_iterator_destroy(itr);
5078 	if (changed) {
5079 		/* We want to run this on the assoc_mgr_tres_list, but we need
5080 		 * to make a tmp variable since assoc_mgr_post_tres_list will
5081 		 * set assoc_mgr_tres_list for us.
5082 		 */
5083 		assoc_mgr_post_tres_list(tmp_list);
5084 	} else if (freeit)
5085 		FREE_NULL_LIST(tmp_list);
5086 	else
5087 		assoc_mgr_tres_list = tmp_list;
5088 
5089 	if (!locked)
5090 		assoc_mgr_unlock(&locks);
5091 	return rc;
5092 }
5093 
assoc_mgr_validate_assoc_id(void * db_conn,uint32_t assoc_id,int enforce)5094 extern int assoc_mgr_validate_assoc_id(void *db_conn,
5095 				       uint32_t assoc_id,
5096 				       int enforce)
5097 {
5098 	slurmdb_assoc_rec_t * found_assoc = NULL;
5099 	assoc_mgr_lock_t locks = { .assoc = READ_LOCK };
5100 
5101 	/* Call assoc_mgr_refresh_lists instead of just getting the
5102 	   association list because we need qos and user lists before
5103 	   the association list can be made.
5104 	*/
5105 	if (!assoc_mgr_assoc_list)
5106 		if (assoc_mgr_refresh_lists(db_conn, 0) == SLURM_ERROR)
5107 			return SLURM_ERROR;
5108 
5109 	assoc_mgr_lock(&locks);
5110 	if ((!assoc_mgr_assoc_list
5111 	     || !list_count(assoc_mgr_assoc_list))
5112 	    && !(enforce & ACCOUNTING_ENFORCE_ASSOCS)) {
5113 		assoc_mgr_unlock(&locks);
5114 		return SLURM_SUCCESS;
5115 	}
5116 
5117 	found_assoc = _find_assoc_rec_id(assoc_id);
5118 	assoc_mgr_unlock(&locks);
5119 
5120 	if (found_assoc || !(enforce & ACCOUNTING_ENFORCE_ASSOCS))
5121 		return SLURM_SUCCESS;
5122 
5123 	return SLURM_ERROR;
5124 }
5125 
assoc_mgr_clear_used_info(void)5126 extern void assoc_mgr_clear_used_info(void)
5127 {
5128 	ListIterator itr = NULL;
5129 	slurmdb_assoc_rec_t * found_assoc = NULL;
5130 	slurmdb_qos_rec_t * found_qos = NULL;
5131 	assoc_mgr_lock_t locks = { .assoc = WRITE_LOCK, .qos = WRITE_LOCK };
5132 
5133 	assoc_mgr_lock(&locks);
5134 	if (assoc_mgr_assoc_list) {
5135 		itr = list_iterator_create(assoc_mgr_assoc_list);
5136 		while ((found_assoc = list_next(itr))) {
5137 			_clear_used_assoc_info(found_assoc);
5138 		}
5139 		list_iterator_destroy(itr);
5140 	}
5141 
5142 	if (assoc_mgr_qos_list) {
5143 		itr = list_iterator_create(assoc_mgr_qos_list);
5144 		while ((found_qos = list_next(itr))) {
5145 			_clear_used_qos_info(found_qos);
5146 		}
5147 		list_iterator_destroy(itr);
5148 	}
5149 
5150 	assoc_mgr_unlock(&locks);
5151 }
5152 
_reset_children_usages(List children_list)5153 static void _reset_children_usages(List children_list)
5154 {
5155 	slurmdb_assoc_rec_t *assoc = NULL;
5156 	ListIterator itr = NULL;
5157 	int i;
5158 
5159 	if (!children_list || !list_count(children_list))
5160 		return;
5161 
5162 	itr = list_iterator_create(children_list);
5163 	while ((assoc = list_next(itr))) {
5164 		assoc->usage->usage_raw = 0.0;
5165 		assoc->usage->grp_used_wall = 0.0;
5166 		for (i=0; i<assoc->usage->tres_cnt; i++)
5167 			assoc->usage->usage_tres_raw[i] = 0;
5168 
5169 		if (assoc->user)
5170 			continue;
5171 
5172 		_reset_children_usages(assoc->usage->children_list);
5173 	}
5174 	list_iterator_destroy(itr);
5175 }
5176 
5177 /* tres read lock needs to be locked before calling this. */
_make_usage_tres_raw_str(long double * tres_cnt)5178 static char *_make_usage_tres_raw_str(long double *tres_cnt)
5179 {
5180 	int i;
5181 	char *tres_str = NULL;
5182 
5183 	if (!tres_cnt)
5184 		return NULL;
5185 
5186 	for (i=0; i<g_tres_count; i++) {
5187 		if (!assoc_mgr_tres_array[i] || !tres_cnt[i])
5188 			continue;
5189 		xstrfmtcat(tres_str, "%s%u=%Lf", tres_str ? "," : "",
5190 			   assoc_mgr_tres_array[i]->id, tres_cnt[i]);
5191 	}
5192 
5193 	return tres_str;
5194 }
5195 
_set_usage_tres_raw(long double * tres_cnt,char * tres_str)5196 static void _set_usage_tres_raw(long double *tres_cnt, char *tres_str)
5197 {
5198 	char *tmp_str = tres_str;
5199 	int pos, id;
5200 	char *endptr;
5201 	slurmdb_tres_rec_t tres_rec;
5202 
5203 	xassert(tres_cnt);
5204 
5205 	if (!tres_str || !tres_str[0])
5206 		return;
5207 
5208 	if (tmp_str[0] == ',')
5209 		tmp_str++;
5210 
5211 	memset(&tres_rec, 0, sizeof(slurmdb_tres_rec_t));
5212 
5213 	while (tmp_str) {
5214 		id = atoi(tmp_str);
5215 		/* 0 isn't a valid tres id */
5216 		if (id <= 0) {
5217 			error("_set_usage_tres_raw: no id "
5218 			      "found at %s instead", tmp_str);
5219 			break;
5220 		}
5221 		if (!(tmp_str = strchr(tmp_str, '='))) {
5222 			error("_set_usage_tres_raw: "
5223 			      "no value found %s", tres_str);
5224 			break;
5225 		}
5226 
5227 		tres_rec.id = id;
5228 		pos = assoc_mgr_find_tres_pos(&tres_rec, true);
5229 		if (pos != -1) {
5230 			/* set the index to the count */
5231 			tres_cnt[pos] = strtold(++tmp_str, &endptr);
5232 		} else {
5233 			debug("_set_usage_tres_raw: "
5234 			       "no tres of id %u found in the array",
5235 			       tres_rec.id);
5236 		}
5237 		if (!(tmp_str = strchr(tmp_str, ',')))
5238 			break;
5239 		tmp_str++;
5240 	}
5241 
5242 
5243 	return;
5244 }
5245 
assoc_mgr_remove_assoc_usage(slurmdb_assoc_rec_t * assoc)5246 extern void assoc_mgr_remove_assoc_usage(slurmdb_assoc_rec_t *assoc)
5247 {
5248 	char *child;
5249 	char *child_str;
5250 	long double old_usage_raw = 0.0;
5251 	long double old_usage_tres_raw[g_tres_count];
5252 	int i;
5253 	double old_grp_used_wall = 0.0;
5254 	slurmdb_assoc_rec_t *sav_assoc = assoc;
5255 
5256 	xassert(assoc);
5257 	xassert(assoc->usage);
5258 
5259 	if (assoc->user) {
5260 		child = "user";
5261 		child_str = assoc->user;
5262 	} else {
5263 		child = "account";
5264 		child_str = assoc->acct;
5265 	}
5266 	info("Resetting usage for %s %s", child, child_str);
5267 
5268 	old_usage_raw = assoc->usage->usage_raw;
5269 	/* clang needs this memset to avoid a warning */
5270 	memset(old_usage_tres_raw, 0, sizeof(old_usage_tres_raw));
5271 	for (i=0; i<g_tres_count; i++)
5272 		old_usage_tres_raw[i] = assoc->usage->usage_tres_raw[i];
5273 	old_grp_used_wall = assoc->usage->grp_used_wall;
5274 /*
5275  *	Reset this association's raw and group usages and subtract its
5276  *	current usages from all parental units
5277  */
5278 	while (assoc) {
5279 		info("Subtracting %Lf from %Lf raw usage and %f from "
5280 		     "%f group wall for assoc %u (user='%s' acct='%s')",
5281 		     old_usage_raw, assoc->usage->usage_raw,
5282 		     old_grp_used_wall, assoc->usage->grp_used_wall,
5283 		     assoc->id, assoc->user, assoc->acct);
5284 
5285 		assoc->usage->usage_raw -= old_usage_raw;
5286 
5287 		for (i=0; i<g_tres_count; i++)
5288 			assoc->usage->usage_tres_raw[i] -=
5289 				old_usage_tres_raw[i];
5290 
5291 		assoc->usage->grp_used_wall -= old_grp_used_wall;
5292 		assoc = assoc->usage->parent_assoc_ptr;
5293 	}
5294 	if (sav_assoc->user)
5295 		return;
5296 /*
5297  *	The assoc is an account, so reset all children
5298  */
5299 	_reset_children_usages(sav_assoc->usage->children_list);
5300 }
5301 
assoc_mgr_remove_qos_usage(slurmdb_qos_rec_t * qos)5302 extern void assoc_mgr_remove_qos_usage(slurmdb_qos_rec_t *qos)
5303 {
5304 	int i;
5305 
5306 	xassert(qos);
5307 	xassert(qos->usage);
5308 
5309 	info("Resetting usage for QOS %s", qos->name);
5310 
5311 	qos->usage->usage_raw = 0;
5312 	qos->usage->grp_used_wall = 0;
5313 
5314 	for (i=0; i<qos->usage->tres_cnt; i++) {
5315 		qos->usage->usage_tres_raw[i] = 0;
5316 		if (!qos->usage->grp_used_tres[i])
5317 			qos->usage->grp_used_tres_run_secs[i] = 0;
5318 	}
5319 }
5320 
dump_assoc_mgr_state(void)5321 extern int dump_assoc_mgr_state(void)
5322 {
5323 	static int high_buffer_size = (1024 * 1024);
5324 	int error_code = 0, log_fd;
5325 	char *old_file = NULL, *new_file = NULL, *reg_file = NULL,
5326 		*tmp_char = NULL;
5327 	dbd_list_msg_t msg;
5328 	Buf buffer = NULL;
5329 	assoc_mgr_lock_t locks = { .assoc = READ_LOCK, .file = WRITE_LOCK,
5330 				   .qos = READ_LOCK, .res = READ_LOCK,
5331 				   .tres = READ_LOCK, .user = READ_LOCK,
5332 				   .wckey = READ_LOCK};
5333 	DEF_TIMERS;
5334 
5335 	xassert(init_setup.state_save_location &&
5336 		*init_setup.state_save_location);
5337 
5338 	START_TIMER;
5339 
5340 	/* now make a file for last_tres */
5341 	buffer = init_buf(high_buffer_size);
5342 
5343 	/* write header: version, time */
5344 	pack16(SLURM_PROTOCOL_VERSION, buffer);
5345 	pack_time(time(NULL), buffer);
5346 
5347 	assoc_mgr_lock(&locks);
5348 	if (assoc_mgr_tres_list) {
5349 		memset(&msg, 0, sizeof(dbd_list_msg_t));
5350 		msg.my_list = assoc_mgr_tres_list;
5351 		slurmdbd_pack_list_msg(&msg, SLURM_PROTOCOL_VERSION,
5352 				       DBD_ADD_TRES, buffer);
5353 	}
5354 
5355 	reg_file = xstrdup_printf("%s/last_tres",
5356 				  *init_setup.state_save_location);
5357 	old_file = xstrdup_printf("%s.old", reg_file);
5358 	new_file = xstrdup_printf("%s.new", reg_file);
5359 
5360 	log_fd = creat(new_file, 0600);
5361 	if (log_fd < 0) {
5362 		error("Can't save state, create file %s error %m",
5363 		      new_file);
5364 		error_code = errno;
5365 	} else {
5366 		int pos = 0, nwrite = get_buf_offset(buffer), amount;
5367 		char *data = (char *)get_buf_data(buffer);
5368 		high_buffer_size = MAX(nwrite, high_buffer_size);
5369 		while (nwrite > 0) {
5370 			amount = write(log_fd, &data[pos], nwrite);
5371 			if ((amount < 0) && (errno != EINTR)) {
5372 				error("Error writing file %s, %m", new_file);
5373 				error_code = errno;
5374 				break;
5375 			}
5376 			nwrite -= amount;
5377 			pos    += amount;
5378 		}
5379 		fsync(log_fd);
5380 		close(log_fd);
5381 	}
5382 	if (error_code)
5383 		(void) unlink(new_file);
5384 	else {			/* file shuffle */
5385 		(void) unlink(old_file);
5386 		if (link(reg_file, old_file))
5387 			debug4("unable to create link for %s -> %s: %m",
5388 			       reg_file, old_file);
5389 		(void) unlink(reg_file);
5390 		if (link(new_file, reg_file))
5391 			debug4("unable to create link for %s -> %s: %m",
5392 			       new_file, reg_file);
5393 		(void) unlink(new_file);
5394 	}
5395 	xfree(old_file);
5396 	xfree(reg_file);
5397 	xfree(new_file);
5398 
5399 	free_buf(buffer);
5400 
5401 	/* Now write the rest of the lists */
5402 	buffer = init_buf(high_buffer_size);
5403 
5404 	/* write header: version, time */
5405 	pack16(SLURM_PROTOCOL_VERSION, buffer);
5406 	pack_time(time(NULL), buffer);
5407 
5408 	if (assoc_mgr_user_list) {
5409 		memset(&msg, 0, sizeof(dbd_list_msg_t));
5410 		msg.my_list = assoc_mgr_user_list;
5411 		/* let us know what to unpack */
5412 		pack16(DBD_ADD_USERS, buffer);
5413 		slurmdbd_pack_list_msg(&msg, SLURM_PROTOCOL_VERSION,
5414 				       DBD_ADD_USERS, buffer);
5415 	}
5416 
5417 	if (assoc_mgr_res_list) {
5418 		memset(&msg, 0, sizeof(dbd_list_msg_t));
5419 		msg.my_list = assoc_mgr_res_list;
5420 		/* let us know what to unpack */
5421 		pack16(DBD_ADD_RES, buffer);
5422 		slurmdbd_pack_list_msg(&msg, SLURM_PROTOCOL_VERSION,
5423 				       DBD_ADD_RES, buffer);
5424 	}
5425 
5426 	if (assoc_mgr_qos_list) {
5427 		memset(&msg, 0, sizeof(dbd_list_msg_t));
5428 		msg.my_list = assoc_mgr_qos_list;
5429 		/* let us know what to unpack */
5430 		pack16(DBD_ADD_QOS, buffer);
5431 		slurmdbd_pack_list_msg(&msg, SLURM_PROTOCOL_VERSION,
5432 				       DBD_ADD_QOS, buffer);
5433 	}
5434 
5435 	if (assoc_mgr_wckey_list) {
5436 		memset(&msg, 0, sizeof(dbd_list_msg_t));
5437 		msg.my_list = assoc_mgr_wckey_list;
5438 		/* let us know what to unpack */
5439 		pack16(DBD_ADD_WCKEYS, buffer);
5440 		slurmdbd_pack_list_msg(&msg, SLURM_PROTOCOL_VERSION,
5441 				       DBD_ADD_WCKEYS, buffer);
5442 	}
5443 	/* this needs to be done last so qos is set up
5444 	 * before hand when loading it back */
5445 	if (assoc_mgr_assoc_list) {
5446 		memset(&msg, 0, sizeof(dbd_list_msg_t));
5447 		msg.my_list = assoc_mgr_assoc_list;
5448 		/* let us know what to unpack */
5449 		pack16(DBD_ADD_ASSOCS, buffer);
5450 		slurmdbd_pack_list_msg(&msg, SLURM_PROTOCOL_VERSION,
5451 				       DBD_ADD_ASSOCS, buffer);
5452 	}
5453 
5454 	/* write the buffer to file */
5455 	reg_file = xstrdup_printf("%s/assoc_mgr_state",
5456 				  *init_setup.state_save_location);
5457 	old_file = xstrdup_printf("%s.old", reg_file);
5458 	new_file = xstrdup_printf("%s.new", reg_file);
5459 
5460 	log_fd = creat(new_file, 0600);
5461 	if (log_fd < 0) {
5462 		error("Can't save state, create file %s error %m",
5463 		      new_file);
5464 		error_code = errno;
5465 	} else {
5466 		int pos = 0, nwrite = get_buf_offset(buffer), amount;
5467 		char *data = (char *)get_buf_data(buffer);
5468 		high_buffer_size = MAX(nwrite, high_buffer_size);
5469 		while (nwrite > 0) {
5470 			amount = write(log_fd, &data[pos], nwrite);
5471 			if ((amount < 0) && (errno != EINTR)) {
5472 				error("Error writing file %s, %m", new_file);
5473 				error_code = errno;
5474 				break;
5475 			}
5476 			nwrite -= amount;
5477 			pos    += amount;
5478 		}
5479 		fsync(log_fd);
5480 		close(log_fd);
5481 	}
5482 	if (error_code)
5483 		(void) unlink(new_file);
5484 	else {			/* file shuffle */
5485 		(void) unlink(old_file);
5486 		if (link(reg_file, old_file))
5487 			debug4("unable to create link for %s -> %s: %m",
5488 			       reg_file, old_file);
5489 		(void) unlink(reg_file);
5490 		if (link(new_file, reg_file))
5491 			debug4("unable to create link for %s -> %s: %m",
5492 			       new_file, reg_file);
5493 		(void) unlink(new_file);
5494 	}
5495 	xfree(old_file);
5496 	xfree(reg_file);
5497 	xfree(new_file);
5498 
5499 	free_buf(buffer);
5500 	/* now make a file for assoc_usage */
5501 
5502 	buffer = init_buf(high_buffer_size);
5503 	/* write header: version, time */
5504 	pack16(SLURM_PROTOCOL_VERSION, buffer);
5505 	pack_time(time(NULL), buffer);
5506 
5507 	if (assoc_mgr_assoc_list) {
5508 		ListIterator itr = NULL;
5509 		slurmdb_assoc_rec_t *assoc = NULL;
5510 		itr = list_iterator_create(assoc_mgr_assoc_list);
5511 		while ((assoc = list_next(itr))) {
5512 			if (!assoc->user)
5513 				continue;
5514 
5515 			pack32(assoc->id, buffer);
5516 			packlongdouble(assoc->usage->usage_raw, buffer);
5517 			tmp_char = _make_usage_tres_raw_str(
5518 				assoc->usage->usage_tres_raw);
5519 			packstr(tmp_char, buffer);
5520 			xfree(tmp_char);
5521 			pack32(assoc->usage->grp_used_wall, buffer);
5522 		}
5523 		list_iterator_destroy(itr);
5524 	}
5525 
5526 	reg_file = xstrdup_printf("%s/assoc_usage",
5527 				  *init_setup.state_save_location);
5528 	old_file = xstrdup_printf("%s.old", reg_file);
5529 	new_file = xstrdup_printf("%s.new", reg_file);
5530 
5531 	log_fd = creat(new_file, 0600);
5532 	if (log_fd < 0) {
5533 		error("Can't save state, create file %s error %m",
5534 		      new_file);
5535 		error_code = errno;
5536 	} else {
5537 		int pos = 0, nwrite = get_buf_offset(buffer), amount;
5538 		char *data = (char *)get_buf_data(buffer);
5539 		high_buffer_size = MAX(nwrite, high_buffer_size);
5540 		while (nwrite > 0) {
5541 			amount = write(log_fd, &data[pos], nwrite);
5542 			if ((amount < 0) && (errno != EINTR)) {
5543 				error("Error writing file %s, %m", new_file);
5544 				error_code = errno;
5545 				break;
5546 			}
5547 			nwrite -= amount;
5548 			pos    += amount;
5549 		}
5550 		fsync(log_fd);
5551 		close(log_fd);
5552 	}
5553 	if (error_code)
5554 		(void) unlink(new_file);
5555 	else {			/* file shuffle */
5556 		(void) unlink(old_file);
5557 		if (link(reg_file, old_file))
5558 			debug4("unable to create link for %s -> %s: %m",
5559 			       reg_file, old_file);
5560 		(void) unlink(reg_file);
5561 		if (link(new_file, reg_file))
5562 			debug4("unable to create link for %s -> %s: %m",
5563 			       new_file, reg_file);
5564 		(void) unlink(new_file);
5565 	}
5566 	xfree(old_file);
5567 	xfree(reg_file);
5568 	xfree(new_file);
5569 
5570 	free_buf(buffer);
5571 	/* now make a file for qos_usage */
5572 
5573 	buffer = init_buf(high_buffer_size);
5574 	/* write header: version, time */
5575 	pack16(SLURM_PROTOCOL_VERSION, buffer);
5576 	pack_time(time(NULL), buffer);
5577 
5578 	if (assoc_mgr_qos_list) {
5579 		ListIterator itr = NULL;
5580 		slurmdb_qos_rec_t *qos = NULL;
5581 		itr = list_iterator_create(assoc_mgr_qos_list);
5582 		while ((qos = list_next(itr))) {
5583 			pack32(qos->id, buffer);
5584 			packlongdouble(qos->usage->usage_raw, buffer);
5585 			tmp_char = _make_usage_tres_raw_str(
5586 				qos->usage->usage_tres_raw);
5587 			packstr(tmp_char, buffer);
5588 			xfree(tmp_char);
5589 			pack32(qos->usage->grp_used_wall, buffer);
5590 		}
5591 		list_iterator_destroy(itr);
5592 	}
5593 
5594 	reg_file = xstrdup_printf("%s/qos_usage",
5595 				  *init_setup.state_save_location);
5596 	old_file = xstrdup_printf("%s.old", reg_file);
5597 	new_file = xstrdup_printf("%s.new", reg_file);
5598 
5599 	log_fd = creat(new_file, 0600);
5600 	if (log_fd < 0) {
5601 		error("Can't save state, create file %s error %m",
5602 		      new_file);
5603 		error_code = errno;
5604 	} else {
5605 		int pos = 0, nwrite = get_buf_offset(buffer), amount;
5606 		char *data = (char *)get_buf_data(buffer);
5607 		high_buffer_size = MAX(nwrite, high_buffer_size);
5608 		while (nwrite > 0) {
5609 			amount = write(log_fd, &data[pos], nwrite);
5610 			if ((amount < 0) && (errno != EINTR)) {
5611 				error("Error writing file %s, %m", new_file);
5612 				error_code = errno;
5613 				break;
5614 			}
5615 			nwrite -= amount;
5616 			pos    += amount;
5617 		}
5618 		fsync(log_fd);
5619 		close(log_fd);
5620 	}
5621 	if (error_code)
5622 		(void) unlink(new_file);
5623 	else {			/* file shuffle */
5624 		(void) unlink(old_file);
5625 		if (link(reg_file, old_file))
5626 			debug4("unable to create link for %s -> %s: %m",
5627 			       reg_file, old_file);
5628 		(void) unlink(reg_file);
5629 		if (link(new_file, reg_file))
5630 			debug4("unable to create link for %s -> %s: %m",
5631 			       new_file, reg_file);
5632 		(void) unlink(new_file);
5633 	}
5634 	xfree(old_file);
5635 	xfree(reg_file);
5636 	xfree(new_file);
5637 	assoc_mgr_unlock(&locks);
5638 
5639 	free_buf(buffer);
5640 	END_TIMER2("dump_assoc_mgr_state");
5641 	return error_code;
5642 
5643 }
5644 
load_assoc_usage(void)5645 extern int load_assoc_usage(void)
5646 {
5647 	int i;
5648 	uint16_t ver = 0;
5649 	char *state_file, *tmp_str = NULL;
5650 	Buf buffer = NULL;
5651 	time_t buf_time;
5652 	assoc_mgr_lock_t locks = { .assoc = WRITE_LOCK, .file = READ_LOCK };
5653 
5654 	if (!assoc_mgr_assoc_list)
5655 		return SLURM_SUCCESS;
5656 
5657 	xassert(init_setup.state_save_location &&
5658 		*init_setup.state_save_location);
5659 
5660 	/* read the file */
5661 	state_file = xstrdup(*init_setup.state_save_location);
5662 	xstrcat(state_file, "/assoc_usage");	/* Always ignore .old file */
5663 	//info("looking at the %s file", state_file);
5664 	assoc_mgr_lock(&locks);
5665 
5666 	if (!(buffer = create_mmap_buf(state_file))) {
5667 		debug2("No Assoc usage file (%s) to recover", state_file);
5668 		xfree(state_file);
5669 		assoc_mgr_unlock(&locks);
5670 		return ENOENT;
5671 	}
5672 	xfree(state_file);
5673 
5674 	safe_unpack16(&ver, buffer);
5675 	debug3("Version in assoc_usage header is %u", ver);
5676 	if (ver > SLURM_PROTOCOL_VERSION || ver < SLURM_MIN_PROTOCOL_VERSION) {
5677 		if (!ignore_state_errors)
5678 			fatal("Can not recover assoc_usage state, incompatible version, got %u need >= %u <= %u, start with '-i' to ignore this. Warning: using -i will lose the data that can't be recovered.",
5679 			      ver, SLURM_MIN_PROTOCOL_VERSION,
5680 			      SLURM_PROTOCOL_VERSION);
5681 		error("***********************************************");
5682 		error("Can not recover assoc_usage state, "
5683 		      "incompatible version, got %u need >= %u <= %u", ver,
5684 		      SLURM_MIN_PROTOCOL_VERSION, SLURM_PROTOCOL_VERSION);
5685 		error("***********************************************");
5686 		free_buf(buffer);
5687 		assoc_mgr_unlock(&locks);
5688 		return EFAULT;
5689 	}
5690 
5691 	safe_unpack_time(&buf_time, buffer);
5692 
5693 	while (remaining_buf(buffer) > 0) {
5694 		uint32_t assoc_id = 0;
5695 		uint32_t grp_used_wall = 0;
5696 		long double usage_raw = 0;
5697 		slurmdb_assoc_rec_t *assoc = NULL;
5698 		uint32_t tmp32;
5699 		long double usage_tres_raw[g_tres_count];
5700 
5701 		safe_unpack32(&assoc_id, buffer);
5702 		safe_unpacklongdouble(&usage_raw, buffer);
5703 		safe_unpackstr_xmalloc(&tmp_str, &tmp32, buffer);
5704 		safe_unpack32(&grp_used_wall, buffer);
5705 
5706 		assoc = _find_assoc_rec_id(assoc_id);
5707 
5708 		/* We want to do this all the way up to and including
5709 		   root.  This way we can keep track of how much usage
5710 		   has occured on the entire system and use that to
5711 		   normalize against.
5712 		*/
5713 		if (assoc) {
5714 			assoc->usage->grp_used_wall = 0;
5715 			assoc->usage->usage_raw = 0;
5716 			for (i=0; i < g_tres_count; i++)
5717 				assoc->usage->usage_tres_raw[i] = 0;
5718 			memset(usage_tres_raw, 0, sizeof(usage_tres_raw));
5719 			_set_usage_tres_raw(usage_tres_raw, tmp_str);
5720 		}
5721 		while (assoc) {
5722 			assoc->usage->grp_used_wall += grp_used_wall;
5723 			assoc->usage->usage_raw += usage_raw;
5724 			for (i=0; i < g_tres_count; i++)
5725 				assoc->usage->usage_tres_raw[i] +=
5726 					usage_tres_raw[i];
5727 			assoc = assoc->usage->parent_assoc_ptr;
5728 		}
5729 
5730 		xfree(tmp_str);
5731 	}
5732 	assoc_mgr_unlock(&locks);
5733 
5734 	free_buf(buffer);
5735 	return SLURM_SUCCESS;
5736 
5737 unpack_error:
5738 	if (!ignore_state_errors)
5739 		fatal("Incomplete assoc usage state file, start with '-i' to ignore this. Warning: using -i will lose the data that can't be recovered.");
5740 	error("Incomplete assoc usage state file");
5741 
5742 	free_buf(buffer);
5743 
5744 	xfree(tmp_str);
5745 	assoc_mgr_unlock(&locks);
5746 	return SLURM_ERROR;
5747 }
5748 
load_qos_usage(void)5749 extern int load_qos_usage(void)
5750 {
5751 	uint16_t ver = 0;
5752 	char *state_file, *tmp_str = NULL;
5753 	Buf buffer = NULL;
5754 	time_t buf_time;
5755 	ListIterator itr = NULL;
5756 	assoc_mgr_lock_t locks = { .file = READ_LOCK, .qos = WRITE_LOCK };
5757 
5758 	if (!assoc_mgr_qos_list)
5759 		return SLURM_SUCCESS;
5760 
5761 	xassert(init_setup.state_save_location &&
5762 		*init_setup.state_save_location);
5763 
5764 	/* read the file */
5765 	state_file = xstrdup(*init_setup.state_save_location);
5766 	xstrcat(state_file, "/qos_usage");	/* Always ignore .old file */
5767 	//info("looking at the %s file", state_file);
5768 	assoc_mgr_lock(&locks);
5769 
5770 	if (!(buffer = create_mmap_buf(state_file))) {
5771 		debug2("No Qos usage file (%s) to recover", state_file);
5772 		xfree(state_file);
5773 		assoc_mgr_unlock(&locks);
5774 		return ENOENT;
5775 	}
5776 	xfree(state_file);
5777 
5778 	safe_unpack16(&ver, buffer);
5779 	debug3("Version in qos_usage header is %u", ver);
5780 	if (ver > SLURM_PROTOCOL_VERSION || ver < SLURM_MIN_PROTOCOL_VERSION) {
5781 		if (!ignore_state_errors)
5782 			fatal("Can not recover qos_usage state, incompatible version, "
5783 			      "got %u need >= %u <= %u, start with '-i' to ignore this. Warning: using -i will lose the data that can't be recovered.",
5784 			      ver, SLURM_MIN_PROTOCOL_VERSION, SLURM_PROTOCOL_VERSION);
5785 		error("***********************************************");
5786 		error("Can not recover qos_usage state, "
5787 		      "incompatible version, got %u need > %u <= %u", ver,
5788 		      SLURM_MIN_PROTOCOL_VERSION, SLURM_PROTOCOL_VERSION);
5789 		error("***********************************************");
5790 		free_buf(buffer);
5791 		assoc_mgr_unlock(&locks);
5792 		return EFAULT;
5793 	}
5794 
5795 	safe_unpack_time(&buf_time, buffer);
5796 
5797 	itr = list_iterator_create(assoc_mgr_qos_list);
5798 	while (remaining_buf(buffer) > 0) {
5799 		uint32_t qos_id = 0;
5800 		uint32_t grp_used_wall = 0;
5801 		uint32_t tmp32;
5802 		long double usage_raw = 0;
5803 		slurmdb_qos_rec_t *qos = NULL;
5804 
5805 		safe_unpack32(&qos_id, buffer);
5806 		safe_unpacklongdouble(&usage_raw, buffer);
5807 		safe_unpackstr_xmalloc(&tmp_str, &tmp32, buffer);
5808 		safe_unpack32(&grp_used_wall, buffer);
5809 
5810 		while ((qos = list_next(itr)))
5811 			if (qos->id == qos_id)
5812 				break;
5813 		if (qos) {
5814 			qos->usage->grp_used_wall = grp_used_wall;
5815 			qos->usage->usage_raw = usage_raw;
5816 			_set_usage_tres_raw(qos->usage->usage_tres_raw,
5817 					    tmp_str);
5818 		}
5819 
5820 		xfree(tmp_str);
5821 		list_iterator_reset(itr);
5822 	}
5823 	list_iterator_destroy(itr);
5824 	assoc_mgr_unlock(&locks);
5825 
5826 	free_buf(buffer);
5827 	return SLURM_SUCCESS;
5828 
5829 unpack_error:
5830 	if (!ignore_state_errors)
5831 		fatal("Incomplete QOS usage state file, start with '-i' to ignore this. Warning: using -i will lose the data that can't be recovered.");
5832 	error("Incomplete QOS usage state file");
5833 
5834 	free_buf(buffer);
5835 
5836 	if (itr)
5837 		list_iterator_destroy(itr);
5838 	xfree(tmp_str);
5839 	assoc_mgr_unlock(&locks);
5840 	return SLURM_ERROR;
5841 }
5842 
load_assoc_mgr_last_tres(void)5843 extern int load_assoc_mgr_last_tres(void)
5844 {
5845 	int error_code = SLURM_SUCCESS;
5846 	uint16_t ver = 0;
5847 	char *state_file;
5848 	Buf buffer = NULL;
5849 	time_t buf_time;
5850 	dbd_list_msg_t *msg = NULL;
5851 	assoc_mgr_lock_t locks = { .tres = WRITE_LOCK };
5852 
5853 	xassert(init_setup.state_save_location &&
5854 		*init_setup.state_save_location);
5855 
5856 	/* read the file Always ignore .old file */
5857 	state_file = xstrdup_printf("%s/last_tres",
5858 				    *init_setup.state_save_location);
5859 	//info("looking at the %s file", state_file);
5860 	assoc_mgr_lock(&locks);
5861 
5862 	if (!(buffer = create_mmap_buf(state_file))) {
5863 		debug2("No last_tres file (%s) to recover", state_file);
5864 		xfree(state_file);
5865 		assoc_mgr_unlock(&locks);
5866 		return ENOENT;
5867 	}
5868 	xfree(state_file);
5869 
5870 	safe_unpack16(&ver, buffer);
5871 	debug3("Version in last_tres header is %u", ver);
5872 	if (ver > SLURM_PROTOCOL_VERSION || ver < SLURM_MIN_PROTOCOL_VERSION) {
5873 		if (!ignore_state_errors)
5874 			fatal("Can not recover last_tres state, incompatible version, got %u need >= %u <= %u, start with '-i' to ignore this. Warning: using -i will lose the data that can't be recovered.",
5875 			      ver, SLURM_MIN_PROTOCOL_VERSION, SLURM_PROTOCOL_VERSION);
5876 		error("***********************************************");
5877 		error("Can not recover last_tres state, incompatible version, got %u need > %u <= %u", ver,
5878 		      SLURM_MIN_PROTOCOL_VERSION, SLURM_PROTOCOL_VERSION);
5879 		error("***********************************************");
5880 		free_buf(buffer);
5881 		assoc_mgr_unlock(&locks);
5882 		return EFAULT;
5883 	}
5884 
5885 	safe_unpack_time(&buf_time, buffer);
5886 	error_code = slurmdbd_unpack_list_msg(&msg, ver, DBD_ADD_TRES, buffer);
5887 	if (error_code != SLURM_SUCCESS)
5888 		goto unpack_error;
5889 	else if (!msg->my_list) {
5890 		error("No tres retrieved");
5891 	} else {
5892 		FREE_NULL_LIST(assoc_mgr_tres_list);
5893 		assoc_mgr_post_tres_list(msg->my_list);
5894 		/* assoc_mgr_tres_list gets set in assoc_mgr_post_tres_list */
5895 		debug("Recovered %u tres",
5896 		      list_count(assoc_mgr_tres_list));
5897 		msg->my_list = NULL;
5898 	}
5899 	slurmdbd_free_list_msg(msg);
5900 	assoc_mgr_unlock(&locks);
5901 	free_buf(buffer);
5902 	return SLURM_SUCCESS;
5903 
5904 unpack_error:
5905 	if (!ignore_state_errors)
5906 		fatal("Incomplete last_tres state file, start with '-i' to ignore this. Warning: using -i will lose the data that can't be recovered.");
5907 	error("Incomplete last_tres state file");
5908 
5909 	free_buf(buffer);
5910 
5911 	assoc_mgr_unlock(&locks);
5912 	return SLURM_ERROR;
5913 }
5914 
load_assoc_mgr_state(bool only_tres)5915 extern int load_assoc_mgr_state(bool only_tres)
5916 {
5917 	int error_code = SLURM_SUCCESS;
5918 	uint16_t type = 0;
5919 	uint16_t ver = 0;
5920 	char *state_file;
5921 	Buf buffer = NULL;
5922 	time_t buf_time;
5923 	dbd_list_msg_t *msg = NULL;
5924 	assoc_mgr_lock_t locks = { .assoc = WRITE_LOCK, .file = READ_LOCK,
5925 				   .qos = WRITE_LOCK, .res = WRITE_LOCK,
5926 				   .tres = WRITE_LOCK, .user = WRITE_LOCK,
5927 				   .wckey = WRITE_LOCK };
5928 
5929 	xassert(init_setup.state_save_location &&
5930 		*init_setup.state_save_location);
5931 
5932 	/* read the file */
5933 	state_file = xstrdup(*init_setup.state_save_location);
5934 	xstrcat(state_file, "/assoc_mgr_state"); /* Always ignore .old file */
5935 	//info("looking at the %s file", state_file);
5936 	assoc_mgr_lock(&locks);
5937 
5938 	if (!(buffer = create_mmap_buf(state_file))) {
5939 		debug2("No association state file (%s) to recover", state_file);
5940 		xfree(state_file);
5941 		assoc_mgr_unlock(&locks);
5942 		return ENOENT;
5943 	}
5944 	xfree(state_file);
5945 
5946 	safe_unpack16(&ver, buffer);
5947 	debug3("Version in assoc_mgr_state header is %u", ver);
5948 	if (ver > SLURM_PROTOCOL_VERSION || ver < SLURM_MIN_PROTOCOL_VERSION) {
5949 		if (!ignore_state_errors)
5950 			fatal("Can not recover assoc_mgr state, incompatible version, "
5951 			      "got %u need >= %u <= %u, start with '-i' to ignore this. Warning: using -i will lose the data that can't be recovered.",
5952 			      ver, SLURM_MIN_PROTOCOL_VERSION, SLURM_PROTOCOL_VERSION);
5953 		error("***********************************************");
5954 		error("Can not recover assoc_mgr state, incompatible version, "
5955 		      "got %u need > %u <= %u", ver,
5956 		      SLURM_MIN_PROTOCOL_VERSION, SLURM_PROTOCOL_VERSION);
5957 		error("***********************************************");
5958 		free_buf(buffer);
5959 		assoc_mgr_unlock(&locks);
5960 		return EFAULT;
5961 	}
5962 
5963 	safe_unpack_time(&buf_time, buffer);
5964 	while (remaining_buf(buffer) > 0) {
5965 		safe_unpack16(&type, buffer);
5966 		switch(type) {
5967 		case DBD_ADD_ASSOCS:
5968 			if (!g_tres_count)
5969 				fatal("load_assoc_mgr_state: "
5970 				      "Unable to run cache without TRES, "
5971 				      "please make sure you have a connection "
5972 				      "to your database to continue.");
5973 			error_code = slurmdbd_unpack_list_msg(
5974 				&msg, ver, DBD_ADD_ASSOCS, buffer);
5975 			if (error_code != SLURM_SUCCESS)
5976 				goto unpack_error;
5977 			else if (!msg->my_list) {
5978 				error("No associations retrieved");
5979 				break;
5980 			}
5981 			FREE_NULL_LIST(assoc_mgr_assoc_list);
5982 			assoc_mgr_assoc_list = msg->my_list;
5983 			_post_assoc_list();
5984 
5985 			debug("Recovered %u associations",
5986 			      list_count(assoc_mgr_assoc_list));
5987 			msg->my_list = NULL;
5988 			slurmdbd_free_list_msg(msg);
5989 			break;
5990 		case DBD_ADD_USERS:
5991 			error_code = slurmdbd_unpack_list_msg(
5992 				&msg, ver, DBD_ADD_USERS, buffer);
5993 			if (error_code != SLURM_SUCCESS)
5994 				goto unpack_error;
5995 			else if (!msg->my_list) {
5996 				error("No users retrieved");
5997 				break;
5998 			}
5999 			FREE_NULL_LIST(assoc_mgr_user_list);
6000 			assoc_mgr_user_list = msg->my_list;
6001 			_post_user_list(assoc_mgr_user_list);
6002 			debug("Recovered %u users",
6003 			      list_count(assoc_mgr_user_list));
6004 			msg->my_list = NULL;
6005 			slurmdbd_free_list_msg(msg);
6006 			break;
6007 		case DBD_ADD_RES:
6008 			error_code = slurmdbd_unpack_list_msg(
6009 				&msg, ver, DBD_ADD_RES, buffer);
6010 			if (error_code != SLURM_SUCCESS)
6011 				goto unpack_error;
6012 			else if (!msg->my_list) {
6013 				error("No resources retrieved");
6014 				break;
6015 			}
6016 			FREE_NULL_LIST(assoc_mgr_res_list);
6017 			assoc_mgr_res_list = msg->my_list;
6018 			_post_res_list(assoc_mgr_res_list);
6019 			debug("Recovered %u resources",
6020 			      list_count(assoc_mgr_res_list));
6021 			msg->my_list = NULL;
6022 			slurmdbd_free_list_msg(msg);
6023 			break;
6024 		case DBD_ADD_QOS:
6025 			if (!g_tres_count)
6026 				fatal("load_assoc_mgr_state: "
6027 				      "Unable to run cache without TRES, "
6028 				      "please make sure you have a connection "
6029 				      "to your database to continue.");
6030 			error_code = slurmdbd_unpack_list_msg(
6031 				&msg, ver, DBD_ADD_QOS, buffer);
6032 			if (error_code != SLURM_SUCCESS)
6033 				goto unpack_error;
6034 			else if (!msg->my_list) {
6035 				error("No qos retrieved");
6036 				break;
6037 			}
6038 			FREE_NULL_LIST(assoc_mgr_qos_list);
6039 			assoc_mgr_qos_list = msg->my_list;
6040 			_post_qos_list(assoc_mgr_qos_list);
6041 			debug("Recovered %u qos",
6042 			      list_count(assoc_mgr_qos_list));
6043 			msg->my_list = NULL;
6044 			slurmdbd_free_list_msg(msg);
6045 			break;
6046 		case DBD_ADD_WCKEYS:
6047 			error_code = slurmdbd_unpack_list_msg(
6048 				&msg, ver, DBD_ADD_WCKEYS, buffer);
6049 			if (error_code != SLURM_SUCCESS)
6050 				goto unpack_error;
6051 			else if (!msg->my_list) {
6052 				error("No wckeys retrieved");
6053 				break;
6054 			}
6055 			FREE_NULL_LIST(assoc_mgr_wckey_list);
6056 			assoc_mgr_wckey_list = msg->my_list;
6057 			debug("Recovered %u wckeys",
6058 			      list_count(assoc_mgr_wckey_list));
6059 			msg->my_list = NULL;
6060 			slurmdbd_free_list_msg(msg);
6061 			break;
6062 		default:
6063 			error("unknown type %u given", type);
6064 			goto unpack_error;
6065 			break;
6066 		}
6067 		/* The tres, if here, will always be first */
6068 		if (only_tres)
6069 			break;
6070 	}
6071 
6072 	if (!only_tres && init_setup.running_cache)
6073 		*init_setup.running_cache = 1;
6074 
6075 	free_buf(buffer);
6076 	assoc_mgr_unlock(&locks);
6077 	return SLURM_SUCCESS;
6078 
6079 unpack_error:
6080 	if (!ignore_state_errors)
6081 		fatal("Incomplete assoc mgr state file, start with '-i' to ignore this. Warning: using -i will lose the data that can't be recovered.");
6082 	error("Incomplete assoc mgr state file");
6083 
6084 	free_buf(buffer);
6085 
6086 	assoc_mgr_unlock(&locks);
6087 	return SLURM_ERROR;
6088 }
6089 
assoc_mgr_refresh_lists(void * db_conn,uint16_t cache_level)6090 extern int assoc_mgr_refresh_lists(void *db_conn, uint16_t cache_level)
6091 {
6092 	bool partial_list = 1;
6093 
6094 	if (!cache_level) {
6095 		cache_level = init_setup.cache_level;
6096 		partial_list = 0;
6097 	}
6098 
6099 	/* get tres before association and qos since it is used there */
6100 	if (cache_level & ASSOC_MGR_CACHE_TRES) {
6101 		if (_refresh_assoc_mgr_tres_list(
6102 			    db_conn, init_setup.enforce) == SLURM_ERROR)
6103 			return SLURM_ERROR;
6104 	}
6105 
6106 	/* get qos before association since it is used there */
6107 	if (cache_level & ASSOC_MGR_CACHE_QOS)
6108 		if (_refresh_assoc_mgr_qos_list(
6109 			    db_conn, init_setup.enforce) == SLURM_ERROR)
6110 			return SLURM_ERROR;
6111 
6112 	/* get user before association/wckey since it is used there */
6113 	if (cache_level & ASSOC_MGR_CACHE_USER)
6114 		if (_refresh_assoc_mgr_user_list(
6115 			    db_conn, init_setup.enforce) == SLURM_ERROR)
6116 			return SLURM_ERROR;
6117 
6118 	if (cache_level & ASSOC_MGR_CACHE_ASSOC) {
6119 		if (_refresh_assoc_mgr_assoc_list(
6120 			    db_conn, init_setup.enforce) == SLURM_ERROR)
6121 			return SLURM_ERROR;
6122 	}
6123 	if (cache_level & ASSOC_MGR_CACHE_WCKEY)
6124 		if (_refresh_assoc_wckey_list(
6125 			    db_conn, init_setup.enforce) == SLURM_ERROR)
6126 			return SLURM_ERROR;
6127 	if (cache_level & ASSOC_MGR_CACHE_RES)
6128 		if (_refresh_assoc_mgr_res_list(
6129 			    db_conn, init_setup.enforce) == SLURM_ERROR)
6130 			return SLURM_ERROR;
6131 
6132 	if (!partial_list && _running_cache())
6133 		*init_setup.running_cache = 0;
6134 
6135 	return SLURM_SUCCESS;
6136 }
6137 
assoc_mgr_set_missing_uids()6138 extern int assoc_mgr_set_missing_uids()
6139 {
6140 	uid_t pw_uid;
6141 	ListIterator itr = NULL;
6142 	assoc_mgr_lock_t locks = { .assoc = WRITE_LOCK, .user = WRITE_LOCK,
6143 				   .wckey = WRITE_LOCK };
6144 
6145 	assoc_mgr_lock(&locks);
6146 	if (assoc_mgr_assoc_list) {
6147 		slurmdb_assoc_rec_t *object = NULL;
6148 		itr = list_iterator_create(assoc_mgr_assoc_list);
6149 		while ((object = list_next(itr))) {
6150 			if (object->user && (object->uid == NO_VAL)) {
6151 				if (uid_from_string(
6152 					    object->user, &pw_uid) < 0) {
6153 					debug2("refresh association "
6154 					       "couldn't get a uid for user %s",
6155 					       object->user);
6156 				} else {
6157 					/* Since the uid changed the
6158 					   hash as well will change.  Remove
6159 					   the assoc from the hash before the
6160 					   change or you won't find it.
6161 					*/
6162 					_delete_assoc_hash(object);
6163 
6164 					object->uid = pw_uid;
6165 					_add_assoc_hash(object);
6166 				}
6167 			}
6168 		}
6169 		list_iterator_destroy(itr);
6170 	}
6171 
6172 	if (assoc_mgr_wckey_list) {
6173 		slurmdb_wckey_rec_t *object = NULL;
6174 		itr = list_iterator_create(assoc_mgr_wckey_list);
6175 		while ((object = list_next(itr))) {
6176 			if (object->user && (object->uid == NO_VAL)) {
6177 				if (uid_from_string(
6178 					    object->user, &pw_uid) < 0) {
6179 					debug2("refresh wckey "
6180 					       "couldn't get a uid for user %s",
6181 					       object->user);
6182 				} else
6183 					object->uid = pw_uid;
6184 			}
6185 		}
6186 		list_iterator_destroy(itr);
6187 	}
6188 
6189 	if (assoc_mgr_user_list) {
6190 		slurmdb_user_rec_t *object = NULL;
6191 		itr = list_iterator_create(assoc_mgr_user_list);
6192 		while ((object = list_next(itr))) {
6193 			if (object->name && (object->uid == NO_VAL)) {
6194 				if (uid_from_string(
6195 					    object->name, &pw_uid) < 0) {
6196 					debug3("%s: refresh user couldn't get uid for user %s",
6197 					       __func__, object->name);
6198 				} else {
6199 					debug5("%s: found uid %u for user %s",
6200 					       __func__, pw_uid, object->name);
6201 					object->uid = pw_uid;
6202 				}
6203 			}
6204 		}
6205 		list_iterator_destroy(itr);
6206 	}
6207 	assoc_mgr_unlock(&locks);
6208 
6209 	return SLURM_SUCCESS;
6210 }
6211 
6212 /* you should check for assoc == NULL before this function */
assoc_mgr_normalize_assoc_shares(slurmdb_assoc_rec_t * assoc)6213 extern void assoc_mgr_normalize_assoc_shares(slurmdb_assoc_rec_t *assoc)
6214 {
6215 	xassert(assoc);
6216 	/*
6217 	 * Use slurmctld_conf.priority_flags directly instead of using a
6218 	 * global flags variable. assoc_mgr_init() would be the logical
6219 	 * place to set a global, but there is no great location for
6220 	 * resetting it when scontrol reconfigure is called
6221 	 */
6222 	if (slurmctld_conf.priority_flags & PRIORITY_FLAGS_FAIR_TREE)
6223 		_normalize_assoc_shares_fair_tree(assoc);
6224 	else
6225 		_normalize_assoc_shares_traditional(assoc);
6226 }
6227 
6228 /*
6229  * Find the position of the given TRES ID or type/name in the
6230  * assoc_mgr_tres_array. If the TRES name or ID isn't found -1 is returned.
6231  */
assoc_mgr_find_tres_pos(slurmdb_tres_rec_t * tres_rec,bool locked)6232 extern int assoc_mgr_find_tres_pos(slurmdb_tres_rec_t *tres_rec, bool locked)
6233 {
6234 	int i, tres_pos = -1;
6235 	assoc_mgr_lock_t locks = { .tres = READ_LOCK };
6236 
6237 	if (!tres_rec->id && !tres_rec->type)
6238 		return tres_pos;
6239 
6240 	if (!locked)
6241 		assoc_mgr_lock(&locks);
6242 
6243 	xassert(assoc_mgr_tres_array);
6244 	xassert(g_tres_count);
6245 	xassert(assoc_mgr_tres_array[g_tres_count - 1]);
6246 
6247 	for (i = 0; i < g_tres_count; i++) {
6248 		if (tres_rec->id &&
6249 		    assoc_mgr_tres_array[i]->id == tres_rec->id) {
6250 			tres_pos = i;
6251 			break;
6252 		} else if (!xstrcasecmp(assoc_mgr_tres_array[i]->type,
6253 					tres_rec->type) &&
6254 			  !xstrcasecmp(assoc_mgr_tres_array[i]->name,
6255 				       tres_rec->name)) {
6256 			tres_pos = i;
6257 			break;
6258 		}
6259 	}
6260 
6261 	if (!locked)
6262 		assoc_mgr_unlock(&locks);
6263 
6264 	return tres_pos;
6265 }
6266 
6267 /*
6268  * Find the position of the given TRES name in the
6269  * assoc_mgr_tres_array. Ignore anything after ":" in the TRES name.
6270  * So tres_rec->name of "gpu" can match accounting TRES name of "gpu:tesla".
6271  * If the TRES name isn't found -1 is returned.
6272  */
assoc_mgr_find_tres_pos2(slurmdb_tres_rec_t * tres_rec,bool locked)6273 extern int assoc_mgr_find_tres_pos2(slurmdb_tres_rec_t *tres_rec, bool locked)
6274 {
6275 	int i, len, tres_pos = -1;
6276 	assoc_mgr_lock_t locks = { .tres = READ_LOCK };
6277 
6278 	if (!tres_rec->type)
6279 		return tres_pos;
6280 
6281 	if (!locked)
6282 		assoc_mgr_lock(&locks);
6283 
6284 	xassert(assoc_mgr_tres_array);
6285 	xassert(g_tres_count);
6286 	xassert(assoc_mgr_tres_array[g_tres_count - 1]);
6287 
6288 	len = strlen(tres_rec->name);
6289 	for (i = 0; i < g_tres_count; i++) {
6290 		if (xstrcasecmp(assoc_mgr_tres_array[i]->type, tres_rec->type))
6291 			continue;
6292 		if (xstrncasecmp(assoc_mgr_tres_array[i]->name, tres_rec->name,
6293 				 len) ||
6294 		    (assoc_mgr_tres_array[i]->name[len] != ':'))
6295 			continue;
6296 		tres_pos = i;
6297 		break;
6298 	}
6299 
6300 	if (!locked)
6301 		assoc_mgr_unlock(&locks);
6302 
6303 	return tres_pos;
6304 }
6305 
6306 /*
6307  * Calls assoc_mgr_find_tres_pos and returns the pointer in the
6308  * assoc_mgr_tres_array.
6309  * NOTE: The assoc_mgr tres read lock needs to be locked before calling this
6310  * function and while using the returned record.
6311  */
assoc_mgr_find_tres_rec(slurmdb_tres_rec_t * tres_rec)6312 extern slurmdb_tres_rec_t *assoc_mgr_find_tres_rec(slurmdb_tres_rec_t *tres_rec)
6313 {
6314 	int pos = assoc_mgr_find_tres_pos(tres_rec, 1);
6315 
6316 	if (pos == -1)
6317 		return NULL;
6318 	else
6319 		return assoc_mgr_tres_array[pos];
6320 }
6321 
6322 /*
6323  * Calls assoc_mgr_find_tres_pos and returns the pointer in the
6324  * assoc_mgr_tres_array. Ignores GRES "type" option.
6325  * NOTE: The assoc_mgr tres read lock needs to be locked before calling this
6326  * function and while using the returned record.
6327  */
assoc_mgr_find_tres_rec2(slurmdb_tres_rec_t * tres_rec)6328 extern slurmdb_tres_rec_t *assoc_mgr_find_tres_rec2(
6329 		slurmdb_tres_rec_t *tres_rec)
6330 {
6331 	int pos = assoc_mgr_find_tres_pos2(tres_rec, 1);
6332 
6333 	if (pos == -1)
6334 		return NULL;
6335 	else
6336 		return assoc_mgr_tres_array[pos];
6337 }
6338 
assoc_mgr_set_tres_cnt_array(uint64_t ** tres_cnt,char * tres_str,uint64_t init_val,bool locked)6339 extern int assoc_mgr_set_tres_cnt_array(uint64_t **tres_cnt, char *tres_str,
6340 					uint64_t init_val, bool locked)
6341 {
6342 	int diff_cnt = 0, i;
6343 
6344 	xassert(tres_cnt);
6345 
6346 	/* When doing the cnt the string is always the
6347 	 * complete string, so always set everything to 0 to
6348 	 * catch anything that was removed.
6349 	 */
6350 	xfree(*tres_cnt);
6351 	if (!init_val)
6352 		*tres_cnt = xcalloc(g_tres_count, sizeof(uint64_t));
6353 	else {
6354 		*tres_cnt = xcalloc_nz(g_tres_count, sizeof(uint64_t));
6355 		for (i=0; i<g_tres_count; i++)
6356 			(*tres_cnt)[i] = init_val;
6357 	}
6358 
6359 	if (tres_str) {
6360 		List tmp_list = NULL;
6361 		/* info("got %s", tres_str); */
6362 		slurmdb_tres_list_from_string(
6363 			&tmp_list, tres_str, TRES_STR_FLAG_NONE);
6364 		if (tmp_list) {
6365 			slurmdb_tres_rec_t *tres_rec;
6366 			ListIterator itr = list_iterator_create(tmp_list);
6367 			while ((tres_rec = list_next(itr))) {
6368 				int pos = assoc_mgr_find_tres_pos(
6369 					tres_rec, locked);
6370 				if (pos == -1) {
6371 					debug2("assoc_mgr_set_tres_cnt_array: "
6372 					       "no tres "
6373 					       "of id %u found in the array",
6374 					       tres_rec->id);
6375 					continue;
6376 				}
6377 				/* set the index to the count */
6378 				(*tres_cnt)[pos] = tres_rec->count;
6379 				/* info("%d pos %d has count of %"PRIu64, */
6380 				/*      tres_rec->id, */
6381 				/*      pos, tres_rec->count); */
6382 			}
6383 			list_iterator_destroy(itr);
6384 			if (g_tres_count != list_count(tmp_list))
6385 				diff_cnt = 1;
6386 			FREE_NULL_LIST(tmp_list);
6387 		}
6388 	}
6389 	return diff_cnt;
6390 }
6391 
6392 /* tres read lock needs to be locked before this is called. */
assoc_mgr_set_assoc_tres_cnt(slurmdb_assoc_rec_t * assoc)6393 extern void assoc_mgr_set_assoc_tres_cnt(slurmdb_assoc_rec_t *assoc)
6394 {
6395 	/* This isn't needed on the dbd */
6396 	if (slurmdbd_conf)
6397 		return;
6398 
6399 	xassert(assoc_mgr_tres_array);
6400 
6401 	assoc_mgr_set_tres_cnt_array(&assoc->grp_tres_ctld, assoc->grp_tres,
6402 				     INFINITE64, 1);
6403 	assoc_mgr_set_tres_cnt_array(&assoc->grp_tres_mins_ctld,
6404 				     assoc->grp_tres_mins, INFINITE64, 1);
6405 	assoc_mgr_set_tres_cnt_array(&assoc->grp_tres_run_mins_ctld,
6406 				     assoc->grp_tres_run_mins, INFINITE64, 1);
6407 	assoc_mgr_set_tres_cnt_array(&assoc->max_tres_ctld,
6408 				     assoc->max_tres_pj, INFINITE64, 1);
6409 	assoc_mgr_set_tres_cnt_array(&assoc->max_tres_pn_ctld,
6410 				     assoc->max_tres_pn, INFINITE64, 1);
6411 	assoc_mgr_set_tres_cnt_array(&assoc->max_tres_mins_ctld,
6412 				     assoc->max_tres_mins_pj, INFINITE64, 1);
6413 	assoc_mgr_set_tres_cnt_array(&assoc->max_tres_run_mins_ctld,
6414 				     assoc->max_tres_run_mins, INFINITE64, 1);
6415 }
6416 
6417 /* tres read lock needs to be locked before this is called. */
assoc_mgr_set_qos_tres_cnt(slurmdb_qos_rec_t * qos)6418 extern void assoc_mgr_set_qos_tres_cnt(slurmdb_qos_rec_t *qos)
6419 {
6420 	/* This isn't needed on the dbd */
6421 	if (slurmdbd_conf)
6422 		return;
6423 
6424 	xassert(assoc_mgr_tres_array);
6425 
6426 	assoc_mgr_set_tres_cnt_array(&qos->grp_tres_ctld, qos->grp_tres,
6427 				     INFINITE64, 1);
6428 	assoc_mgr_set_tres_cnt_array(&qos->grp_tres_mins_ctld,
6429 				     qos->grp_tres_mins, INFINITE64, 1);
6430 	assoc_mgr_set_tres_cnt_array(&qos->grp_tres_run_mins_ctld,
6431 				     qos->grp_tres_run_mins, INFINITE64, 1);
6432 	assoc_mgr_set_tres_cnt_array(&qos->max_tres_pa_ctld,
6433 				     qos->max_tres_pa, INFINITE64, 1);
6434 	assoc_mgr_set_tres_cnt_array(&qos->max_tres_pj_ctld,
6435 				     qos->max_tres_pj, INFINITE64, 1);
6436 	assoc_mgr_set_tres_cnt_array(&qos->max_tres_pn_ctld,
6437 				     qos->max_tres_pn, INFINITE64, 1);
6438 	assoc_mgr_set_tres_cnt_array(&qos->max_tres_pu_ctld,
6439 				     qos->max_tres_pu, INFINITE64, 1);
6440 	assoc_mgr_set_tres_cnt_array(&qos->max_tres_mins_pj_ctld,
6441 				     qos->max_tres_mins_pj, INFINITE64, 1);
6442 	assoc_mgr_set_tres_cnt_array(&qos->max_tres_run_mins_pa_ctld,
6443 				     qos->max_tres_run_mins_pa, INFINITE64, 1);
6444 	assoc_mgr_set_tres_cnt_array(&qos->max_tres_run_mins_pu_ctld,
6445 				     qos->max_tres_run_mins_pu, INFINITE64, 1);
6446 	assoc_mgr_set_tres_cnt_array(&qos->min_tres_pj_ctld,
6447 				     qos->min_tres_pj, INFINITE64, 1);
6448 }
6449 
assoc_mgr_make_tres_str_from_array(uint64_t * tres_cnt,uint32_t flags,bool locked)6450 extern char *assoc_mgr_make_tres_str_from_array(
6451 	uint64_t *tres_cnt, uint32_t flags, bool locked)
6452 {
6453 	int i;
6454 	char *tres_str = NULL;
6455 	assoc_mgr_lock_t locks = { .tres = READ_LOCK };
6456 	uint64_t count;
6457 
6458 	if (!tres_cnt)
6459 		return NULL;
6460 
6461 	if (!locked)
6462 		assoc_mgr_lock(&locks);
6463 
6464 	for (i = 0; i < g_tres_count; i++) {
6465 		if (!assoc_mgr_tres_array[i])
6466 			continue;
6467 
6468 		if (flags & TRES_STR_FLAG_ALLOW_REAL) {
6469 			if ((tres_cnt[i] == NO_VAL64) ||
6470 			    (tres_cnt[i] == INFINITE64))
6471 				continue;
6472 		} else if (!tres_cnt[i])
6473 			continue;
6474 
6475 		count = tres_cnt[i];
6476 
6477 		/* We want to print no_consume with a 0 */
6478 		if (count == NO_CONSUME_VAL64)
6479 			count = 0;
6480 
6481 		if (flags & TRES_STR_FLAG_SIMPLE) {
6482 			xstrfmtcat(tres_str, "%s%u=%"PRIu64,
6483 				   tres_str ? "," : "",
6484 				   assoc_mgr_tres_array[i]->id, count);
6485 		} else {
6486 			/* Always skip these when printing out named TRES */
6487 			if ((count == NO_VAL64) ||
6488 			    (count == INFINITE64))
6489 				continue;
6490 			if ((flags & TRES_STR_CONVERT_UNITS) &&
6491 			    ((assoc_mgr_tres_array[i]->id == TRES_MEM) ||
6492 			     !xstrcasecmp(assoc_mgr_tres_array[i]->type,"bb"))){
6493 				char outbuf[32];
6494 				convert_num_unit((double)count, outbuf,
6495 						 sizeof(outbuf), UNIT_MEGA,
6496 						 NO_VAL,
6497 						 CONVERT_NUM_UNIT_EXACT);
6498 				xstrfmtcat(tres_str, "%s%s=%s",
6499 					   tres_str ? "," : "",
6500 					   assoc_mgr_tres_name_array[i],
6501 					   outbuf);
6502 			} else if (!xstrcasecmp(assoc_mgr_tres_array[i]->type,
6503 						"fs") ||
6504 				   !xstrcasecmp(assoc_mgr_tres_array[i]->type,
6505 						"ic")) {
6506 				char outbuf[32];
6507 				convert_num_unit((double)count, outbuf,
6508 						 sizeof(outbuf), UNIT_NONE,
6509 						 NO_VAL,
6510 						 CONVERT_NUM_UNIT_EXACT);
6511 				xstrfmtcat(tres_str, "%s%s=%s",
6512 					   tres_str ? "," : "",
6513 					   assoc_mgr_tres_name_array[i],
6514 					   outbuf);
6515 			} else {
6516 				xstrfmtcat(tres_str, "%s%s=%"PRIu64,
6517 					   tres_str ? "," : "",
6518 					   assoc_mgr_tres_name_array[i],
6519 					   count);
6520 			}
6521 		}
6522 	}
6523 
6524 	if (!locked)
6525 		assoc_mgr_unlock(&locks);
6526 
6527 	return tres_str;
6528 }
6529 
6530 /* READ lock needs to be set on associations before calling this. */
assoc_mgr_get_default_qos_info(slurmdb_assoc_rec_t * assoc_ptr,slurmdb_qos_rec_t * qos_rec)6531 extern void assoc_mgr_get_default_qos_info(
6532 	slurmdb_assoc_rec_t *assoc_ptr, slurmdb_qos_rec_t *qos_rec)
6533 {
6534 	xassert(qos_rec);
6535 
6536 	if (!qos_rec->name && !qos_rec->id) {
6537 		if (assoc_ptr && assoc_ptr->usage->valid_qos) {
6538 			if (assoc_ptr->def_qos_id)
6539 				qos_rec->id = assoc_ptr->def_qos_id;
6540 			else if (bit_set_count(assoc_ptr->usage->valid_qos)
6541 				 == 1)
6542 				qos_rec->id =
6543 					bit_ffs(assoc_ptr->usage->valid_qos);
6544 			else if (assoc_mgr_root_assoc
6545 				 && assoc_mgr_root_assoc->def_qos_id)
6546 				qos_rec->id = assoc_mgr_root_assoc->def_qos_id;
6547 			else
6548 				qos_rec->name = "normal";
6549 		} else if (assoc_mgr_root_assoc
6550 			   && assoc_mgr_root_assoc->def_qos_id)
6551 			qos_rec->id = assoc_mgr_root_assoc->def_qos_id;
6552 		else
6553 			qos_rec->name = "normal";
6554 	}
6555 
6556 	return;
6557 }
6558 
6559 /*
6560  * Calculate a weighted tres value.
6561  * IN: tres_cnt - array of tres values of size g_tres_count.
6562  * IN: weights - weights to apply to tres values of size g_tres_count.
6563  * IN: flags - priority flags (toogle between MAX or SUM of tres).
6564  * IN: locked - whether the tres read assoc mgr lock is locked or not.
6565  * RET: returns the calculated tres weight.
6566  */
assoc_mgr_tres_weighted(uint64_t * tres_cnt,double * weights,uint16_t flags,bool locked)6567 extern double assoc_mgr_tres_weighted(uint64_t *tres_cnt, double *weights,
6568 				      uint16_t flags, bool locked)
6569 {
6570 	int    i;
6571 	double to_bill_node   = 0.0;
6572 	double to_bill_global = 0.0;
6573 	double billable_tres  = 0.0;
6574 	assoc_mgr_lock_t tres_read_lock = { .tres = READ_LOCK };
6575 
6576 	/* We don't have any resources allocated, just return 0. */
6577 	if (!tres_cnt)
6578 		return 0.0;
6579 
6580 	/* Default to cpus if no weights given */
6581 	if (!weights)
6582 		return (double)tres_cnt[TRES_ARRAY_CPU];
6583 
6584 	if (!locked)
6585 		assoc_mgr_lock(&tres_read_lock);
6586 
6587 	for (i = 0; i < g_tres_count; i++) {
6588 		double tres_weight = weights[i];
6589 		char  *tres_type   = assoc_mgr_tres_array[i]->type;
6590 		double tres_value  = tres_cnt[i];
6591 
6592 		if (i == TRES_ARRAY_BILLING)
6593 			continue;
6594 
6595 		if (tres_cnt[i] == NO_CONSUME_VAL64)
6596 			continue;
6597 
6598 		debug3("TRES Weight: %s = %f * %f = %f",
6599 		       assoc_mgr_tres_name_array[i], tres_value, tres_weight,
6600 		       tres_value * tres_weight);
6601 
6602 		tres_value *= tres_weight;
6603 
6604 		if ((flags & PRIORITY_FLAGS_MAX_TRES) &&
6605 		    ((i == TRES_ARRAY_CPU) ||
6606 		     (i == TRES_ARRAY_MEM) ||
6607 		     (i == TRES_ARRAY_NODE) ||
6608 		     (!xstrcasecmp(tres_type, "gres"))))
6609 			to_bill_node = MAX(to_bill_node, tres_value);
6610 		else
6611 			to_bill_global += tres_value;
6612 	}
6613 
6614 	billable_tres = to_bill_node + to_bill_global;
6615 
6616 	debug3("TRES Weighted: %s = %f",
6617 	       (flags & PRIORITY_FLAGS_MAX_TRES) ?
6618 	       "MAX(node TRES) + SUM(Global TRES)" : "SUM(TRES)",
6619 	       billable_tres);
6620 
6621 	if (!locked)
6622 		assoc_mgr_unlock(&tres_read_lock);
6623 
6624 	return billable_tres;
6625 }
6626 
6627 /*
6628  * Must have TRES read locks
6629  */
assoc_mgr_tres_pos_changed()6630 extern int assoc_mgr_tres_pos_changed()
6631 {
6632 	return assoc_mgr_tres_old_pos ? true : false;
6633 }
6634 
6635 /*
6636  * Must have TRES read locks
6637  */
assoc_mgr_get_old_tres_pos(int cur_pos)6638 extern int assoc_mgr_get_old_tres_pos(int cur_pos)
6639 {
6640 	if (!assoc_mgr_tres_old_pos || (cur_pos >= g_tres_count))
6641 		return -1;
6642 	return assoc_mgr_tres_old_pos[cur_pos];
6643 }
6644