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