1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include "lgrp.h"
28
29 #include <mdb/mdb_modapi.h>
30 #include <sys/cpuvar.h>
31 #include <sys/lgrp.h>
32 #include <sys/cpupart.h>
33
34 int
print_range(int start,int end,int separator)35 print_range(int start, int end, int separator)
36 {
37 int count;
38 char tmp;
39 char *format;
40
41 if (start == end) {
42 /* Unfortunately, mdb_printf returns void */
43 format = separator ? ", %d" : "%d";
44 mdb_printf(format, start);
45 count = mdb_snprintf(&tmp, 1, format, start);
46 } else {
47 format = separator ? ", %d-%d" : "%d-%d";
48 mdb_printf(format, start, end);
49 count = mdb_snprintf(&tmp, 1, format, start, end);
50 }
51
52 return (count);
53 }
54
55 void
print_cpuset_range(ulong_t * cs,int words,int width)56 print_cpuset_range(ulong_t *cs, int words, int width)
57 {
58 int i, j;
59 ulong_t m;
60 int in = 0;
61 int start;
62 int end;
63 int count = 0;
64 int sep = 0;
65
66 for (i = 0; i < words; i++)
67 for (j = 0, m = 1; j < BT_NBIPUL; j++, m <<= 1)
68 if (cs[i] & m) {
69 if (in == 0) {
70 start = i * BT_NBIPUL + j;
71 in = 1;
72 }
73 } else {
74 if (in == 1) {
75 end = i * BT_NBIPUL + j - 1;
76 count += print_range(start, end, sep);
77 sep = 1;
78 in = 0;
79 }
80 }
81 if (in == 1) {
82 end = i * BT_NBIPUL - 1;
83 count += print_range(start, end, sep);
84 }
85
86 /*
87 * print width - count spaces
88 */
89
90 if (width > count)
91 mdb_printf("%*s", width - count, "");
92 }
93 typedef struct lgrp_cpu_walk {
94 uintptr_t lcw_firstcpu;
95 int lcw_cpusleft;
96 } lgrp_cpu_walk_t;
97
98 int
lgrp_cpulist_walk_init(mdb_walk_state_t * wsp)99 lgrp_cpulist_walk_init(mdb_walk_state_t *wsp)
100 {
101 lgrp_cpu_walk_t *lcw;
102 lgrp_t lgrp;
103
104 lcw = mdb_alloc(sizeof (lgrp_cpu_walk_t), UM_SLEEP | UM_GC);
105
106 if (mdb_vread(&lgrp, sizeof (struct lgrp), wsp->walk_addr) == -1) {
107 mdb_warn("couldn't read 'lgrp' at %p", wsp->walk_addr);
108 return (WALK_ERR);
109 }
110
111 lcw->lcw_firstcpu = (uintptr_t)lgrp.lgrp_cpu;
112 lcw->lcw_cpusleft = lgrp.lgrp_cpucnt;
113
114 wsp->walk_data = lcw;
115 wsp->walk_addr = lcw->lcw_firstcpu;
116
117 return (WALK_NEXT);
118 }
119
120 int
lgrp_cpulist_walk_step(mdb_walk_state_t * wsp)121 lgrp_cpulist_walk_step(mdb_walk_state_t *wsp)
122 {
123 lgrp_cpu_walk_t *lcw = (lgrp_cpu_walk_t *)wsp->walk_data;
124 uintptr_t addr = (uintptr_t)wsp->walk_addr;
125 cpu_t cpu;
126 int status;
127
128 if (lcw->lcw_cpusleft-- == 0)
129 return (WALK_DONE);
130
131 if (mdb_vread(&cpu, sizeof (cpu_t), addr) == -1) {
132 mdb_warn("couldn't read 'cpu' at %p", addr);
133 return (WALK_ERR);
134 }
135
136 status = wsp->walk_callback(addr, &cpu, wsp->walk_cbdata);
137
138 if (status != WALK_NEXT)
139 return (status);
140
141 addr = (uintptr_t)cpu.cpu_next_lgrp;
142 wsp->walk_addr = addr;
143
144 if (lcw->lcw_cpusleft == 0 && addr != lcw->lcw_firstcpu) {
145 mdb_warn("number of cpus in lgroup cpu != lgroup cpucnt\n");
146 return (WALK_ERR);
147 }
148
149 return (WALK_NEXT);
150 }
151
152 typedef struct lgrp_cpuwalk_cbdata {
153 uint_t lcc_opt_p;
154 uint_t lcc_count;
155 uint_t lcc_used;
156 uint_t *lcc_psrsetid;
157 ulong_t **lcc_cpuset;
158 uint_t *lcc_cpucnt;
159 int *lcc_loadavg;
160 } lgrp_cpuwalk_cbdata_t;
161
162 /* ARGSUSED */
163 static int
lgrp_cpuwalk_callback(uintptr_t addr,const void * arg,void * cb_data)164 lgrp_cpuwalk_callback(uintptr_t addr, const void *arg, void *cb_data)
165 {
166 cpu_t *cpu = (cpu_t *)arg;
167 lgrp_cpuwalk_cbdata_t *lcc = (lgrp_cpuwalk_cbdata_t *)cb_data;
168 uint_t opt_p = lcc->lcc_opt_p;
169
170 int offset = 0;
171
172 /*
173 * if opt_p is set, we're going to break up info for
174 * each lgrp by processor set.
175 */
176
177 if (opt_p != 0) {
178 cpupartid_t cp_id;
179 cpupart_t cpupart;
180 lpl_t lpl;
181
182
183 if (mdb_vread(&cpupart, sizeof (cpupart_t),
184 (uintptr_t)cpu->cpu_part) == -1) {
185 mdb_warn("cannot read cpu partition at %p",
186 cpu->cpu_part);
187 return (WALK_ERR);
188 }
189 cp_id = cpupart.cp_id;
190
191 for (offset = 0; offset < lcc->lcc_used; offset++)
192 if (cp_id == lcc->lcc_psrsetid[offset]) {
193 goto found;
194 }
195
196 if (offset >= lcc->lcc_count) {
197 mdb_warn(
198 "number of cpu partitions changed during walk");
199 return (WALK_ERR);
200 }
201
202 lcc->lcc_psrsetid[offset] = cp_id;
203 lcc->lcc_used++;
204
205 if (mdb_vread(&lpl, sizeof (lpl_t), (uintptr_t)cpu->cpu_lpl)
206 == -1) {
207 mdb_warn("Cannot read lpl at %p", cpu->cpu_lpl);
208 return (WALK_ERR);
209 }
210
211 lcc->lcc_loadavg[offset] = lpl.lpl_loadavg;
212 }
213
214 found: lcc->lcc_cpucnt[offset]++;
215 BT_SET(lcc->lcc_cpuset[offset], cpu->cpu_id);
216
217 return (WALK_NEXT);
218 }
219
220
221 /* ARGSUSED */
222 int
lgrp(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)223 lgrp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
224 {
225 lgrp_t lgrp;
226 lgrp_cpuwalk_cbdata_t lcc;
227 int cpusetsize;
228 int lcpu; /* cpus in lgrp */
229 int _ncpu;
230 int opt_p = 0; /* display partition fraction loads */
231 int opt_q = 0; /* display only address. */
232 int i;
233 const char *s_index = NULL, *s_handle = NULL, *s_parent = NULL;
234 uintptr_t index = 0;
235 uintptr_t handle = 0;
236 uintptr_t parent = 0;
237 int filters = 0;
238
239 if (!(flags & DCMD_ADDRSPEC)) {
240 if (mdb_walk_dcmd("lgrptbl", "lgrp", argc, argv) == -1) {
241 mdb_warn("can't walk 'lgrps'");
242 return (DCMD_ERR);
243 }
244 return (DCMD_OK);
245 }
246
247 if (mdb_getopts(argc, argv,
248 'p', MDB_OPT_SETBITS, TRUE, &opt_p,
249 'q', MDB_OPT_SETBITS, TRUE, &opt_q,
250 'P', MDB_OPT_STR, &s_parent,
251 'i', MDB_OPT_STR, &s_index,
252 'h', MDB_OPT_STR, &s_handle,
253 NULL) != argc)
254 return (DCMD_USAGE);
255
256 if (s_index != NULL)
257 filters++;
258 if (s_handle != NULL)
259 filters++;
260 if (s_parent != NULL)
261 filters++;
262
263 if (flags & DCMD_PIPE_OUT)
264 opt_q = B_TRUE;
265
266 if (s_index != NULL)
267 index = mdb_strtoull(s_index);
268
269 if (s_parent != NULL)
270 parent = mdb_strtoull(s_parent);
271
272 if (s_handle != NULL) {
273 if (strcmp(s_handle, "NULL") == 0)
274 handle = (uintptr_t)LGRP_NULL_HANDLE;
275 else if (strcmp(s_handle, "DEFAULT") == 0)
276 handle = (uintptr_t)LGRP_DEFAULT_HANDLE;
277 else
278 handle = mdb_strtoull(s_handle);
279 }
280
281 if (DCMD_HDRSPEC(flags) && !opt_q) {
282 if (opt_p == 0)
283 mdb_printf("%9s %?s %?s %?s %9s %9s\n",
284 "LGRPID",
285 "ADDR",
286 "PARENT",
287 "PLATHAND",
288 "#CPU",
289 "CPUS");
290 else
291 mdb_printf("%9s %9s %9s %9s %9s\n",
292 "LGRPID",
293 "PSRSETID",
294 "LOAD",
295 "#CPU",
296 "CPUS");
297 }
298
299 if (mdb_vread(&lgrp, sizeof (struct lgrp), addr) == -1) {
300 mdb_warn("unable to read 'lgrp' at %p", addr);
301 return (DCMD_ERR);
302 }
303
304 /*
305 * Do not report free lgrp unless specifically asked for.
306 */
307 if ((lgrp.lgrp_id == LGRP_NONE) &&
308 ((s_index == NULL) || ((int)index != LGRP_NONE)))
309 return (DCMD_OK);
310
311 /*
312 * If lgrp doesn't pass filtering criteria, don't print anything and
313 * just return.
314 */
315 if (filters) {
316 if ((s_parent != NULL) &&
317 parent != (uintptr_t)lgrp.lgrp_parent)
318 return (DCMD_OK);
319 if ((s_index != NULL) && index != (uintptr_t)lgrp.lgrp_id)
320 return (DCMD_OK);
321 if ((s_handle != NULL) &&
322 handle != (uintptr_t)lgrp.lgrp_plathand)
323 return (DCMD_OK);
324 }
325
326 if (opt_q) {
327 mdb_printf("%0?p\n", addr);
328 return (DCMD_OK);
329 }
330
331
332 /*
333 * figure out what cpus we've got
334 */
335 if (mdb_readsym(&_ncpu, sizeof (int), "_ncpu") == -1) {
336 mdb_warn("symbol '_ncpu' not found");
337 return (DCMD_ERR);
338 }
339
340 /*
341 * allocate enough space for set of longs to hold cpuid bitfield
342 */
343 if (opt_p)
344 lcpu = lgrp.lgrp_cpucnt;
345 else
346 lcpu = 1;
347
348 cpusetsize = BT_BITOUL(_ncpu) * sizeof (uintptr_t);
349
350 lcc.lcc_used = 0;
351 lcc.lcc_cpucnt = mdb_zalloc(sizeof (uint_t) * lcpu,
352 UM_SLEEP | UM_GC);
353 lcc.lcc_psrsetid = mdb_zalloc(sizeof (uint_t) * lcpu,
354 UM_SLEEP | UM_GC);
355 lcc.lcc_cpuset = mdb_zalloc(sizeof (uintptr_t) * lcpu,
356 UM_SLEEP | UM_GC);
357 for (i = 0; i < lcpu; i++)
358 lcc.lcc_cpuset[i] = mdb_zalloc(cpusetsize,
359 UM_SLEEP | UM_GC);
360 lcc.lcc_loadavg = mdb_zalloc(sizeof (int) * lcpu,
361 UM_SLEEP | UM_GC);
362 lcc.lcc_count = lcpu;
363 lcc.lcc_opt_p = opt_p;
364
365 if (mdb_pwalk("lgrp_cpulist", lgrp_cpuwalk_callback, &lcc,
366 addr) == -1) {
367 mdb_warn("unable to walk lgrp_cpulist");
368 }
369
370 if (opt_p == 0) {
371 if (lgrp.lgrp_plathand == LGRP_NULL_HANDLE) {
372 mdb_printf("%9d %?p %?p %?s %9d ",
373 lgrp.lgrp_id,
374 addr,
375 lgrp.lgrp_parent,
376 "NULL",
377 lgrp.lgrp_cpucnt);
378 } else if (lgrp.lgrp_plathand == LGRP_DEFAULT_HANDLE) {
379 mdb_printf("%9d %?p %?p %?s %9d ",
380 lgrp.lgrp_id,
381 addr,
382 lgrp.lgrp_parent,
383 "DEFAULT",
384 lgrp.lgrp_cpucnt);
385 } else {
386 mdb_printf("%9d %?p %?p %?p %9d ",
387 lgrp.lgrp_id,
388 addr,
389 lgrp.lgrp_parent,
390 lgrp.lgrp_plathand,
391 lgrp.lgrp_cpucnt);
392 }
393
394 if (lgrp.lgrp_cpucnt != 0) {
395 print_cpuset_range(lcc.lcc_cpuset[0],
396 cpusetsize/sizeof (ulong_t), 0);
397 }
398 mdb_printf("\n");
399 } else {
400 for (i = 0; i < lcc.lcc_used; i++) {
401 mdb_printf("%9d %9d %9d %9d ",
402 lgrp.lgrp_id,
403 lcc.lcc_psrsetid[i],
404 lcc.lcc_loadavg[i],
405 lcc.lcc_cpucnt[i]);
406 if (lcc.lcc_cpucnt[i])
407 print_cpuset_range(lcc.lcc_cpuset[i],
408 cpusetsize/sizeof (ulong_t), 0);
409 mdb_printf("\n");
410 }
411 }
412 return (DCMD_OK);
413
414 }
415
416 typedef struct lgrp_walk_data {
417 int lwd_nlgrps;
418 uintptr_t *lwd_lgrp_tbl;
419 int lwd_iter;
420 } lgrp_walk_data_t;
421
422 int
lgrp_walk_init(mdb_walk_state_t * wsp)423 lgrp_walk_init(mdb_walk_state_t *wsp)
424 {
425 lgrp_walk_data_t *lwd;
426 GElf_Sym sym;
427
428 lwd = mdb_zalloc(sizeof (lgrp_walk_data_t), UM_SLEEP | UM_GC);
429
430 if (mdb_readsym(&lwd->lwd_nlgrps, sizeof (int),
431 "lgrp_alloc_max") == -1) {
432 mdb_warn("symbol 'lgrp_alloc_max' not found");
433 return (WALK_ERR);
434 }
435
436 if (lwd->lwd_nlgrps < 0) {
437 mdb_warn("lgrp_alloc_max of bounds (%d)\n", lwd->lwd_nlgrps);
438 return (WALK_ERR);
439 }
440
441 lwd->lwd_nlgrps++;
442
443 if (mdb_lookup_by_name("lgrp_table", &sym) == -1) {
444 mdb_warn("failed to find 'lgrp_table'");
445 return (WALK_ERR);
446 }
447
448 /* Get number of valid entries in lgrp_table */
449 if (sym.st_size < lwd->lwd_nlgrps * sizeof (lgrp_t *)) {
450 mdb_warn("lgrp_table size inconsistent with lgrp_alloc_max");
451 return (WALK_ERR);
452 }
453
454 lwd->lwd_lgrp_tbl = mdb_alloc(sym.st_size, UM_SLEEP | UM_GC);
455
456 if (mdb_readsym(lwd->lwd_lgrp_tbl, lwd->lwd_nlgrps * sizeof (lgrp_t *),
457 "lgrp_table") == -1) {
458 mdb_warn("unable to read lgrp_table");
459 return (WALK_ERR);
460 }
461
462
463 wsp->walk_data = lwd;
464 wsp->walk_addr = lwd->lwd_lgrp_tbl[0];
465
466 return (WALK_NEXT);
467 }
468
469 /*
470 * Common routine for several walkers.
471 * Read lgroup from wsp->walk_addr and call wsp->walk_callback for it.
472 * Normally returns the result of the callback.
473 * Returns WALK_DONE if walk_addr is NULL and WALK_ERR if cannot read the
474 * lgroup.
475 */
476 static int
lgrp_walk_step_common(mdb_walk_state_t * wsp)477 lgrp_walk_step_common(mdb_walk_state_t *wsp)
478 {
479 lgrp_t lgrp;
480
481 if (wsp->walk_addr == 0)
482 return (WALK_DONE);
483
484 if (mdb_vread(&lgrp, sizeof (lgrp_t), wsp->walk_addr) == -1) {
485 mdb_warn("unable to read lgrp at %p", wsp->walk_addr);
486 return (WALK_ERR);
487 }
488
489 return (wsp->walk_callback(wsp->walk_addr, &lgrp, wsp->walk_cbdata));
490 }
491
492 /*
493 * Get one lgroup from the lgroup table and adjust lwd_iter to point to the next
494 * one.
495 */
496 int
lgrp_walk_step(mdb_walk_state_t * wsp)497 lgrp_walk_step(mdb_walk_state_t *wsp)
498 {
499 lgrp_walk_data_t *lwd = wsp->walk_data;
500 int status = lgrp_walk_step_common(wsp);
501
502 if (status == WALK_NEXT) {
503 lwd->lwd_iter++;
504
505 if (lwd->lwd_iter >= lwd->lwd_nlgrps) {
506 status = WALK_DONE;
507 } else {
508 wsp->walk_addr = lwd->lwd_lgrp_tbl[lwd->lwd_iter];
509
510 if (wsp->walk_addr == 0) {
511 mdb_warn("NULL lgrp pointer in lgrp_table[%d]",
512 lwd->lwd_iter);
513 return (WALK_ERR);
514 }
515 }
516 }
517
518 return (status);
519 }
520
521 /*
522 * Initialize walker to traverse parents of lgroups. Nothing to do here.
523 */
524 /* ARGSUSED */
525 int
lgrp_parents_walk_init(mdb_walk_state_t * wsp)526 lgrp_parents_walk_init(mdb_walk_state_t *wsp)
527 {
528 return (WALK_NEXT);
529 }
530
531 /*
532 * Call wsp callback on current lgroup in wsp and replace the lgroup with its
533 * parent.
534 */
535 int
lgrp_parents_walk_step(mdb_walk_state_t * wsp)536 lgrp_parents_walk_step(mdb_walk_state_t *wsp)
537 {
538 lgrp_t lgrp;
539 int status;
540
541 if (wsp->walk_addr == 0)
542 return (WALK_DONE);
543
544 if (mdb_vread(&lgrp, sizeof (struct lgrp), wsp->walk_addr) == -1) {
545 mdb_warn("couldn't read 'lgrp' at %p", wsp->walk_addr);
546 return (WALK_ERR);
547 }
548
549 status = wsp->walk_callback(wsp->walk_addr, &lgrp, wsp->walk_cbdata);
550
551 if (status == WALK_NEXT)
552 wsp->walk_addr = (uintptr_t)lgrp.lgrp_parent;
553
554 return (status);
555 }
556
557 /*
558 * Given the set return the ID of the first member of the set.
559 * Returns LGRP_NONE if the set has no elements smaller than max_lgrp.
560 */
561 static lgrp_id_t
lgrp_set_get_first(klgrpset_t set,int max_lgrp)562 lgrp_set_get_first(klgrpset_t set, int max_lgrp)
563 {
564 lgrp_id_t id;
565 klgrpset_t bit = 1;
566
567 if (set == (klgrpset_t)0)
568 return (LGRP_NONE);
569
570 for (id = 0; (id < max_lgrp) && !(set & bit); id++, bit <<= 1)
571 ;
572
573 if (id >= max_lgrp)
574 id = LGRP_NONE;
575
576 return (id);
577 }
578
579 /*
580 * lgrp_set_walk_data is used to walk lgroups specified by a set.
581 * On every iteration one element is removed from the set.
582 */
583 typedef struct lgrp_set_walk_data {
584 int lswd_nlgrps; /* Number of lgroups */
585 uintptr_t *lwsd_lgrp_tbl; /* Full lgroup table */
586 klgrpset_t lwsd_set; /* Set of lgroups to walk */
587 } lgrp_set_walk_data_t;
588
589 /*
590 * Initialize iterator for walkers over a set of lgroups
591 */
592 static int
lgrp_set_walk_init(mdb_walk_state_t * wsp,klgrpset_t set)593 lgrp_set_walk_init(mdb_walk_state_t *wsp, klgrpset_t set)
594 {
595 lgrp_set_walk_data_t *lwsd;
596 int nlgrps;
597 lgrp_id_t id;
598 GElf_Sym sym;
599
600 /* Nothing to do if the set is empty */
601 if (set == (klgrpset_t)0)
602 return (WALK_DONE);
603
604 lwsd = mdb_zalloc(sizeof (lgrp_set_walk_data_t), UM_SLEEP | UM_GC);
605
606 /* Get the total number of lgroups */
607 if (mdb_readsym(&nlgrps, sizeof (int), "lgrp_alloc_max") == -1) {
608 mdb_warn("symbol 'lgrp_alloc_max' not found");
609 return (WALK_ERR);
610 }
611
612 if (nlgrps < 0) {
613 mdb_warn("lgrp_alloc_max of bounds (%d)\n", nlgrps);
614 return (WALK_ERR);
615 }
616
617 nlgrps++;
618
619 /* Find ID of the first lgroup in the set */
620 if ((id = lgrp_set_get_first(set, nlgrps)) == LGRP_NONE) {
621 mdb_warn("No set elements within %d lgroups\n", nlgrps);
622 return (WALK_ERR);
623 }
624
625 /* Read lgroup_table and copy it to lwsd_lgrp_tbl */
626 if (mdb_lookup_by_name("lgrp_table", &sym) == -1) {
627 mdb_warn("failed to find 'lgrp_table'");
628 return (WALK_ERR);
629 }
630
631 /* Get number of valid entries in lgrp_table */
632 if (sym.st_size < nlgrps * sizeof (lgrp_t *)) {
633 mdb_warn("lgrp_table size inconsistent with lgrp_alloc_max");
634 return (WALK_ERR);
635 }
636
637 lwsd->lwsd_lgrp_tbl = mdb_alloc(sym.st_size, UM_SLEEP | UM_GC);
638 lwsd->lswd_nlgrps = nlgrps;
639
640 if (mdb_readsym(lwsd->lwsd_lgrp_tbl, nlgrps * sizeof (lgrp_t *),
641 "lgrp_table") == -1) {
642 mdb_warn("unable to read lgrp_table");
643 return (WALK_ERR);
644 }
645
646 wsp->walk_data = lwsd;
647
648 /* Save the first lgroup from the set and remove it from the set */
649 wsp->walk_addr = lwsd->lwsd_lgrp_tbl[id];
650 lwsd->lwsd_set = set & ~(1 << id);
651
652 return (WALK_NEXT);
653 }
654
655 /*
656 * Get current lgroup and advance the lgroup to the next one in the lwsd_set.
657 */
658 int
lgrp_set_walk_step(mdb_walk_state_t * wsp)659 lgrp_set_walk_step(mdb_walk_state_t *wsp)
660 {
661 lgrp_id_t id = 0;
662 lgrp_set_walk_data_t *lwsd = wsp->walk_data;
663 int status = lgrp_walk_step_common(wsp);
664
665 if (status == WALK_NEXT) {
666 id = lgrp_set_get_first(lwsd->lwsd_set, lwsd->lswd_nlgrps);
667 if (id == LGRP_NONE) {
668 status = WALK_DONE;
669 } else {
670 /* Move to the next lgroup in the set */
671 wsp->walk_addr = lwsd->lwsd_lgrp_tbl[id];
672
673 /* Remove id from the set */
674 lwsd->lwsd_set = lwsd->lwsd_set & ~(1 << id);
675 }
676 }
677
678 return (status);
679 }
680
681 /*
682 * Initialize resource walker for a given lgroup and resource. The lgroup
683 * address is specified in walk_addr.
684 */
685 static int
lgrp_rsrc_walk_init(mdb_walk_state_t * wsp,int resource)686 lgrp_rsrc_walk_init(mdb_walk_state_t *wsp, int resource)
687 {
688 lgrp_t lgrp;
689
690 if (mdb_vread(&lgrp, sizeof (struct lgrp), wsp->walk_addr) == -1) {
691 mdb_warn("couldn't read 'lgrp' at %p", wsp->walk_addr);
692 return (WALK_ERR);
693 }
694
695 return (lgrp_set_walk_init(wsp, lgrp.lgrp_set[resource]));
696 }
697
698 /*
699 * Initialize CPU resource walker
700 */
701 int
lgrp_rsrc_cpu_walk_init(mdb_walk_state_t * wsp)702 lgrp_rsrc_cpu_walk_init(mdb_walk_state_t *wsp)
703 {
704 return (lgrp_rsrc_walk_init(wsp, LGRP_RSRC_CPU));
705 }
706
707 /*
708 * Initialize memory resource walker
709 */
710 int
lgrp_rsrc_mem_walk_init(mdb_walk_state_t * wsp)711 lgrp_rsrc_mem_walk_init(mdb_walk_state_t *wsp)
712 {
713 return (lgrp_rsrc_walk_init(wsp, LGRP_RSRC_MEM));
714 }
715
716 /*
717 * Display bitmap as a list of integers
718 */
719 /* ARGSUSED */
720 int
lgrp_set(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)721 lgrp_set(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
722 {
723 uint64_t set = (uint64_t)addr;
724 uint64_t mask = 1;
725 int i = 0;
726
727 if (!(flags & DCMD_ADDRSPEC)) {
728 return (DCMD_USAGE);
729 }
730
731 if (set == 0)
732 return (DCMD_OK);
733
734 for (; set != (uint64_t)0; i++, mask <<= 1) {
735 if (set & mask) {
736 mdb_printf("%d ", i);
737 set &= ~mask;
738 }
739 }
740 mdb_printf("\n");
741 return (DCMD_OK);
742 }
743