17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5c6402783Sakolb * Common Development and Distribution License (the "License").
6c6402783Sakolb * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
21c6402783Sakolb
227c478bd9Sstevel@tonic-gate /*
23c6402783Sakolb * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate * lgroup system calls
317c478bd9Sstevel@tonic-gate */
327c478bd9Sstevel@tonic-gate
337c478bd9Sstevel@tonic-gate #include <sys/types.h>
347c478bd9Sstevel@tonic-gate #include <sys/errno.h>
357c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
367c478bd9Sstevel@tonic-gate #include <sys/systm.h>
377c478bd9Sstevel@tonic-gate #include <sys/mman.h>
387c478bd9Sstevel@tonic-gate #include <sys/cpupart.h>
397c478bd9Sstevel@tonic-gate #include <sys/lgrp.h>
407c478bd9Sstevel@tonic-gate #include <sys/lgrp_user.h>
417c478bd9Sstevel@tonic-gate #include <sys/promif.h> /* for prom_printf() */
427c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
437c478bd9Sstevel@tonic-gate
447c478bd9Sstevel@tonic-gate #include <vm/as.h>
457c478bd9Sstevel@tonic-gate
467c478bd9Sstevel@tonic-gate
477c478bd9Sstevel@tonic-gate /* definitions for mi_validity */
487c478bd9Sstevel@tonic-gate #define VALID_ADDR 1
497c478bd9Sstevel@tonic-gate #define VALID_REQ 2
507c478bd9Sstevel@tonic-gate
517c478bd9Sstevel@tonic-gate /*
527c478bd9Sstevel@tonic-gate * run through the given number of addresses and requests and return the
537c478bd9Sstevel@tonic-gate * corresponding memory information for each address
547c478bd9Sstevel@tonic-gate */
557c478bd9Sstevel@tonic-gate static int
meminfo(int addr_count,struct meminfo * mip)567c478bd9Sstevel@tonic-gate meminfo(int addr_count, struct meminfo *mip)
577c478bd9Sstevel@tonic-gate {
587c478bd9Sstevel@tonic-gate size_t in_size, out_size, req_size, val_size;
597c478bd9Sstevel@tonic-gate struct as *as;
607c478bd9Sstevel@tonic-gate struct hat *hat;
617c478bd9Sstevel@tonic-gate int i, j, out_idx, info_count;
627c478bd9Sstevel@tonic-gate lgrp_t *lgrp;
637c478bd9Sstevel@tonic-gate pfn_t pfn;
647c478bd9Sstevel@tonic-gate ssize_t pgsz;
657c478bd9Sstevel@tonic-gate int *req_array, *val_array;
667c478bd9Sstevel@tonic-gate uint64_t *in_array, *out_array;
677c478bd9Sstevel@tonic-gate uint64_t addr, paddr;
687c478bd9Sstevel@tonic-gate uintptr_t vaddr;
697c478bd9Sstevel@tonic-gate int ret = 0;
707c478bd9Sstevel@tonic-gate struct meminfo minfo;
717c478bd9Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL)
727c478bd9Sstevel@tonic-gate struct meminfo32 minfo32;
737c478bd9Sstevel@tonic-gate #endif
747c478bd9Sstevel@tonic-gate
757c478bd9Sstevel@tonic-gate /*
767c478bd9Sstevel@tonic-gate * Make sure that there is at least one address to translate and
777c478bd9Sstevel@tonic-gate * limit how many virtual addresses the kernel can do per call
787c478bd9Sstevel@tonic-gate */
797c478bd9Sstevel@tonic-gate if (addr_count < 1)
807c478bd9Sstevel@tonic-gate return (set_errno(EINVAL));
817c478bd9Sstevel@tonic-gate else if (addr_count > MAX_MEMINFO_CNT)
827c478bd9Sstevel@tonic-gate addr_count = MAX_MEMINFO_CNT;
837c478bd9Sstevel@tonic-gate
847c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) {
857c478bd9Sstevel@tonic-gate if (copyin(mip, &minfo, sizeof (struct meminfo)))
867c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
877c478bd9Sstevel@tonic-gate }
887c478bd9Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL)
897c478bd9Sstevel@tonic-gate else {
907c478bd9Sstevel@tonic-gate bzero(&minfo, sizeof (minfo));
917c478bd9Sstevel@tonic-gate if (copyin(mip, &minfo32, sizeof (struct meminfo32)))
927c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
937c478bd9Sstevel@tonic-gate minfo.mi_inaddr = (const uint64_t *)(uintptr_t)
947c478bd9Sstevel@tonic-gate minfo32.mi_inaddr;
957c478bd9Sstevel@tonic-gate minfo.mi_info_req = (const uint_t *)(uintptr_t)
967c478bd9Sstevel@tonic-gate minfo32.mi_info_req;
977c478bd9Sstevel@tonic-gate minfo.mi_info_count = minfo32.mi_info_count;
987c478bd9Sstevel@tonic-gate minfo.mi_outdata = (uint64_t *)(uintptr_t)
997c478bd9Sstevel@tonic-gate minfo32.mi_outdata;
1007c478bd9Sstevel@tonic-gate minfo.mi_validity = (uint_t *)(uintptr_t)
1017c478bd9Sstevel@tonic-gate minfo32.mi_validity;
1027c478bd9Sstevel@tonic-gate }
1037c478bd9Sstevel@tonic-gate #endif
1047c478bd9Sstevel@tonic-gate /*
1057c478bd9Sstevel@tonic-gate * all the input parameters have been copied in:-
1067c478bd9Sstevel@tonic-gate * addr_count - number of input addresses
1077c478bd9Sstevel@tonic-gate * minfo.mi_inaddr - array of input addresses
1087c478bd9Sstevel@tonic-gate * minfo.mi_info_req - array of types of information requested
1097c478bd9Sstevel@tonic-gate * minfo.mi_info_count - no. of pieces of info requested for each addr
1107c478bd9Sstevel@tonic-gate * minfo.mi_outdata - array into which the results are placed
1117c478bd9Sstevel@tonic-gate * minfo.mi_validity - array containing bitwise result codes; 0th bit
1127c478bd9Sstevel@tonic-gate * evaluates validity of corresponding input
1137c478bd9Sstevel@tonic-gate * address, 1st bit validity of response to first
1147c478bd9Sstevel@tonic-gate * member of info_req, etc.
1157c478bd9Sstevel@tonic-gate */
1167c478bd9Sstevel@tonic-gate
1177c478bd9Sstevel@tonic-gate /* make sure mi_info_count is within limit */
1187c478bd9Sstevel@tonic-gate info_count = minfo.mi_info_count;
1197c478bd9Sstevel@tonic-gate if (info_count < 1 || info_count > MAX_MEMINFO_REQ)
1207c478bd9Sstevel@tonic-gate return (set_errno(EINVAL));
1217c478bd9Sstevel@tonic-gate
1227c478bd9Sstevel@tonic-gate /*
1237c478bd9Sstevel@tonic-gate * allocate buffer in_array for the input addresses and copy them in
1247c478bd9Sstevel@tonic-gate */
1257c478bd9Sstevel@tonic-gate in_size = sizeof (uint64_t) * addr_count;
1267c478bd9Sstevel@tonic-gate in_array = kmem_alloc(in_size, KM_SLEEP);
1277c478bd9Sstevel@tonic-gate if (copyin(minfo.mi_inaddr, in_array, in_size)) {
1287c478bd9Sstevel@tonic-gate kmem_free(in_array, in_size);
1297c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate
1327c478bd9Sstevel@tonic-gate /*
1337c478bd9Sstevel@tonic-gate * allocate buffer req_array for the input info_reqs and copy them in
1347c478bd9Sstevel@tonic-gate */
1357c478bd9Sstevel@tonic-gate req_size = sizeof (uint_t) * info_count;
1367c478bd9Sstevel@tonic-gate req_array = kmem_alloc(req_size, KM_SLEEP);
1377c478bd9Sstevel@tonic-gate if (copyin(minfo.mi_info_req, req_array, req_size)) {
1387c478bd9Sstevel@tonic-gate kmem_free(req_array, req_size);
1397c478bd9Sstevel@tonic-gate kmem_free(in_array, in_size);
1407c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
1417c478bd9Sstevel@tonic-gate }
1427c478bd9Sstevel@tonic-gate
1437c478bd9Sstevel@tonic-gate /*
1447c478bd9Sstevel@tonic-gate * allocate buffer out_array which holds the results and will have
1457c478bd9Sstevel@tonic-gate * to be copied out later
1467c478bd9Sstevel@tonic-gate */
1477c478bd9Sstevel@tonic-gate out_size = sizeof (uint64_t) * addr_count * info_count;
1487c478bd9Sstevel@tonic-gate out_array = kmem_alloc(out_size, KM_SLEEP);
1497c478bd9Sstevel@tonic-gate
1507c478bd9Sstevel@tonic-gate /*
1517c478bd9Sstevel@tonic-gate * allocate buffer val_array which holds the validity bits and will
1527c478bd9Sstevel@tonic-gate * have to be copied out later
1537c478bd9Sstevel@tonic-gate */
1547c478bd9Sstevel@tonic-gate val_size = sizeof (uint_t) * addr_count;
1557c478bd9Sstevel@tonic-gate val_array = kmem_alloc(val_size, KM_SLEEP);
1567c478bd9Sstevel@tonic-gate
1577c478bd9Sstevel@tonic-gate if ((req_array[0] & MEMINFO_MASK) == MEMINFO_PLGRP) {
1587c478bd9Sstevel@tonic-gate /* find the corresponding lgroup for each physical address */
1597c478bd9Sstevel@tonic-gate for (i = 0; i < addr_count; i++) {
1607c478bd9Sstevel@tonic-gate paddr = in_array[i];
1617c478bd9Sstevel@tonic-gate pfn = btop(paddr);
1627c478bd9Sstevel@tonic-gate lgrp = lgrp_pfn_to_lgrp(pfn);
1637c478bd9Sstevel@tonic-gate if (lgrp) {
1647c478bd9Sstevel@tonic-gate out_array[i] = lgrp->lgrp_id;
1657c478bd9Sstevel@tonic-gate val_array[i] = VALID_ADDR | VALID_REQ;
1667c478bd9Sstevel@tonic-gate } else {
1677c478bd9Sstevel@tonic-gate out_array[i] = NULL;
1687c478bd9Sstevel@tonic-gate val_array[i] = 0;
1697c478bd9Sstevel@tonic-gate }
1707c478bd9Sstevel@tonic-gate }
1717c478bd9Sstevel@tonic-gate } else {
1727c478bd9Sstevel@tonic-gate /* get the corresponding memory info for each virtual address */
1737c478bd9Sstevel@tonic-gate as = curproc->p_as;
1747c478bd9Sstevel@tonic-gate
175*fd435bccSJosef 'Jeff' Sipek AS_LOCK_ENTER(as, RW_READER);
1767c478bd9Sstevel@tonic-gate hat = as->a_hat;
1777c478bd9Sstevel@tonic-gate for (i = out_idx = 0; i < addr_count; i++, out_idx +=
1787c478bd9Sstevel@tonic-gate info_count) {
1797c478bd9Sstevel@tonic-gate addr = in_array[i];
1807c478bd9Sstevel@tonic-gate vaddr = (uintptr_t)(addr & ~PAGEOFFSET);
1817c478bd9Sstevel@tonic-gate if (!as_segat(as, (caddr_t)vaddr)) {
1827c478bd9Sstevel@tonic-gate val_array[i] = 0;
1837c478bd9Sstevel@tonic-gate continue;
1847c478bd9Sstevel@tonic-gate }
1857c478bd9Sstevel@tonic-gate val_array[i] = VALID_ADDR;
1867c478bd9Sstevel@tonic-gate pfn = hat_getpfnum(hat, (caddr_t)vaddr);
1877c478bd9Sstevel@tonic-gate if (pfn != PFN_INVALID) {
1887c478bd9Sstevel@tonic-gate paddr = (uint64_t)((pfn << PAGESHIFT) |
1897c478bd9Sstevel@tonic-gate (addr & PAGEOFFSET));
1907c478bd9Sstevel@tonic-gate for (j = 0; j < info_count; j++) {
1917c478bd9Sstevel@tonic-gate switch (req_array[j] & MEMINFO_MASK) {
1927c478bd9Sstevel@tonic-gate case MEMINFO_VPHYSICAL:
1937c478bd9Sstevel@tonic-gate /*
1947c478bd9Sstevel@tonic-gate * return the physical address
1957c478bd9Sstevel@tonic-gate * corresponding to the input
1967c478bd9Sstevel@tonic-gate * virtual address
1977c478bd9Sstevel@tonic-gate */
1987c478bd9Sstevel@tonic-gate out_array[out_idx + j] = paddr;
1997c478bd9Sstevel@tonic-gate val_array[i] |= VALID_REQ << j;
2007c478bd9Sstevel@tonic-gate break;
2017c478bd9Sstevel@tonic-gate case MEMINFO_VLGRP:
2027c478bd9Sstevel@tonic-gate /*
2037c478bd9Sstevel@tonic-gate * return the lgroup of physical
2047c478bd9Sstevel@tonic-gate * page corresponding to the
2057c478bd9Sstevel@tonic-gate * input virtual address
2067c478bd9Sstevel@tonic-gate */
2077c478bd9Sstevel@tonic-gate lgrp = lgrp_pfn_to_lgrp(pfn);
2087c478bd9Sstevel@tonic-gate if (lgrp) {
2097c478bd9Sstevel@tonic-gate out_array[out_idx + j] =
2107c478bd9Sstevel@tonic-gate lgrp->lgrp_id;
2117c478bd9Sstevel@tonic-gate val_array[i] |=
2127c478bd9Sstevel@tonic-gate VALID_REQ << j;
2137c478bd9Sstevel@tonic-gate }
2147c478bd9Sstevel@tonic-gate break;
2157c478bd9Sstevel@tonic-gate case MEMINFO_VPAGESIZE:
2167c478bd9Sstevel@tonic-gate /*
2177c478bd9Sstevel@tonic-gate * return the size of physical
2187c478bd9Sstevel@tonic-gate * page corresponding to the
2197c478bd9Sstevel@tonic-gate * input virtual address
2207c478bd9Sstevel@tonic-gate */
2217c478bd9Sstevel@tonic-gate pgsz = hat_getpagesize(hat,
2227c478bd9Sstevel@tonic-gate (caddr_t)vaddr);
2237c478bd9Sstevel@tonic-gate if (pgsz != -1) {
2247c478bd9Sstevel@tonic-gate out_array[out_idx + j] =
2257c478bd9Sstevel@tonic-gate pgsz;
2267c478bd9Sstevel@tonic-gate val_array[i] |=
2277c478bd9Sstevel@tonic-gate VALID_REQ << j;
2287c478bd9Sstevel@tonic-gate }
2297c478bd9Sstevel@tonic-gate break;
2307c478bd9Sstevel@tonic-gate case MEMINFO_VREPLCNT:
2317c478bd9Sstevel@tonic-gate /*
2327c478bd9Sstevel@tonic-gate * for future use:-
2337c478bd9Sstevel@tonic-gate * return the no. replicated
2347c478bd9Sstevel@tonic-gate * physical pages corresponding
2357c478bd9Sstevel@tonic-gate * to the input virtual address,
2367c478bd9Sstevel@tonic-gate * so it is always 0 at the
2377c478bd9Sstevel@tonic-gate * moment
2387c478bd9Sstevel@tonic-gate */
2397c478bd9Sstevel@tonic-gate out_array[out_idx + j] = 0;
2407c478bd9Sstevel@tonic-gate val_array[i] |= VALID_REQ << j;
2417c478bd9Sstevel@tonic-gate break;
2427c478bd9Sstevel@tonic-gate case MEMINFO_VREPL:
2437c478bd9Sstevel@tonic-gate /*
2447c478bd9Sstevel@tonic-gate * for future use:-
2457c478bd9Sstevel@tonic-gate * return the nth physical
2467c478bd9Sstevel@tonic-gate * replica of the specified
2477c478bd9Sstevel@tonic-gate * virtual address
2487c478bd9Sstevel@tonic-gate */
2497c478bd9Sstevel@tonic-gate break;
2507c478bd9Sstevel@tonic-gate case MEMINFO_VREPL_LGRP:
2517c478bd9Sstevel@tonic-gate /*
2527c478bd9Sstevel@tonic-gate * for future use:-
2537c478bd9Sstevel@tonic-gate * return the lgroup of nth
2547c478bd9Sstevel@tonic-gate * physical replica of the
2557c478bd9Sstevel@tonic-gate * specified virtual address
2567c478bd9Sstevel@tonic-gate */
2577c478bd9Sstevel@tonic-gate break;
2587c478bd9Sstevel@tonic-gate case MEMINFO_PLGRP:
2597c478bd9Sstevel@tonic-gate /*
2607c478bd9Sstevel@tonic-gate * this is for physical address
2617c478bd9Sstevel@tonic-gate * only, shouldn't mix with
2627c478bd9Sstevel@tonic-gate * virtual address
2637c478bd9Sstevel@tonic-gate */
2647c478bd9Sstevel@tonic-gate break;
2657c478bd9Sstevel@tonic-gate default:
2667c478bd9Sstevel@tonic-gate break;
2677c478bd9Sstevel@tonic-gate }
2687c478bd9Sstevel@tonic-gate }
2697c478bd9Sstevel@tonic-gate }
2707c478bd9Sstevel@tonic-gate }
271*fd435bccSJosef 'Jeff' Sipek AS_LOCK_EXIT(as);
2727c478bd9Sstevel@tonic-gate }
2737c478bd9Sstevel@tonic-gate
2747c478bd9Sstevel@tonic-gate /* copy out the results and validity bits and free the buffers */
2757c478bd9Sstevel@tonic-gate if ((copyout(out_array, minfo.mi_outdata, out_size) != 0) ||
2767c478bd9Sstevel@tonic-gate (copyout(val_array, minfo.mi_validity, val_size) != 0))
2777c478bd9Sstevel@tonic-gate ret = set_errno(EFAULT);
2787c478bd9Sstevel@tonic-gate
2797c478bd9Sstevel@tonic-gate kmem_free(in_array, in_size);
2807c478bd9Sstevel@tonic-gate kmem_free(out_array, out_size);
2817c478bd9Sstevel@tonic-gate kmem_free(req_array, req_size);
2827c478bd9Sstevel@tonic-gate kmem_free(val_array, val_size);
2837c478bd9Sstevel@tonic-gate
2847c478bd9Sstevel@tonic-gate return (ret);
2857c478bd9Sstevel@tonic-gate }
2867c478bd9Sstevel@tonic-gate
2877c478bd9Sstevel@tonic-gate
2887c478bd9Sstevel@tonic-gate /*
2897c478bd9Sstevel@tonic-gate * Initialize lgroup affinities for thread
2907c478bd9Sstevel@tonic-gate */
2917c478bd9Sstevel@tonic-gate void
lgrp_affinity_init(lgrp_affinity_t ** bufaddr)2927c478bd9Sstevel@tonic-gate lgrp_affinity_init(lgrp_affinity_t **bufaddr)
2937c478bd9Sstevel@tonic-gate {
2947c478bd9Sstevel@tonic-gate if (bufaddr)
2957c478bd9Sstevel@tonic-gate *bufaddr = NULL;
2967c478bd9Sstevel@tonic-gate }
2977c478bd9Sstevel@tonic-gate
2987c478bd9Sstevel@tonic-gate
2997c478bd9Sstevel@tonic-gate /*
3007c478bd9Sstevel@tonic-gate * Free lgroup affinities for thread and set to NULL
3017c478bd9Sstevel@tonic-gate * just in case thread gets recycled
3027c478bd9Sstevel@tonic-gate */
3037c478bd9Sstevel@tonic-gate void
lgrp_affinity_free(lgrp_affinity_t ** bufaddr)3047c478bd9Sstevel@tonic-gate lgrp_affinity_free(lgrp_affinity_t **bufaddr)
3057c478bd9Sstevel@tonic-gate {
3067c478bd9Sstevel@tonic-gate if (bufaddr && *bufaddr) {
3077c478bd9Sstevel@tonic-gate kmem_free(*bufaddr, nlgrpsmax * sizeof (lgrp_affinity_t));
3087c478bd9Sstevel@tonic-gate *bufaddr = NULL;
3097c478bd9Sstevel@tonic-gate }
3107c478bd9Sstevel@tonic-gate }
3117c478bd9Sstevel@tonic-gate
3127c478bd9Sstevel@tonic-gate
3137c478bd9Sstevel@tonic-gate #define P_ANY -2 /* cookie specifying any ID */
3147c478bd9Sstevel@tonic-gate
3157c478bd9Sstevel@tonic-gate
3167c478bd9Sstevel@tonic-gate /*
3177c478bd9Sstevel@tonic-gate * Find LWP with given ID in specified process and get its affinity for
3187c478bd9Sstevel@tonic-gate * specified lgroup
3197c478bd9Sstevel@tonic-gate */
3207c478bd9Sstevel@tonic-gate lgrp_affinity_t
lgrp_affinity_get_thread(proc_t * p,id_t lwpid,lgrp_id_t lgrp)3217c478bd9Sstevel@tonic-gate lgrp_affinity_get_thread(proc_t *p, id_t lwpid, lgrp_id_t lgrp)
3227c478bd9Sstevel@tonic-gate {
3237c478bd9Sstevel@tonic-gate lgrp_affinity_t aff;
3247c478bd9Sstevel@tonic-gate int found;
3257c478bd9Sstevel@tonic-gate kthread_t *t;
3267c478bd9Sstevel@tonic-gate
3277c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock));
3287c478bd9Sstevel@tonic-gate
3297c478bd9Sstevel@tonic-gate aff = LGRP_AFF_NONE;
3307c478bd9Sstevel@tonic-gate found = 0;
3317c478bd9Sstevel@tonic-gate t = p->p_tlist;
3327c478bd9Sstevel@tonic-gate /*
3337c478bd9Sstevel@tonic-gate * The process may be executing in proc_exit() and its p->p_list may be
3347c478bd9Sstevel@tonic-gate * already NULL.
3357c478bd9Sstevel@tonic-gate */
3367c478bd9Sstevel@tonic-gate if (t == NULL)
3377c478bd9Sstevel@tonic-gate return (set_errno(ESRCH));
3387c478bd9Sstevel@tonic-gate
3397c478bd9Sstevel@tonic-gate do {
3407c478bd9Sstevel@tonic-gate if (t->t_tid == lwpid || lwpid == P_ANY) {
3417c478bd9Sstevel@tonic-gate thread_lock(t);
3427c478bd9Sstevel@tonic-gate /*
3437c478bd9Sstevel@tonic-gate * Check to see whether caller has permission to set
3447c478bd9Sstevel@tonic-gate * affinity for LWP
3457c478bd9Sstevel@tonic-gate */
3467c478bd9Sstevel@tonic-gate if (t->t_cid == 0 || !hasprocperm(t->t_cred, CRED())) {
3477c478bd9Sstevel@tonic-gate thread_unlock(t);
3487c478bd9Sstevel@tonic-gate return (set_errno(EPERM));
3497c478bd9Sstevel@tonic-gate }
3507c478bd9Sstevel@tonic-gate
3517c478bd9Sstevel@tonic-gate if (t->t_lgrp_affinity)
3527c478bd9Sstevel@tonic-gate aff = t->t_lgrp_affinity[lgrp];
3537c478bd9Sstevel@tonic-gate thread_unlock(t);
3547c478bd9Sstevel@tonic-gate found = 1;
3557c478bd9Sstevel@tonic-gate break;
3567c478bd9Sstevel@tonic-gate }
3577c478bd9Sstevel@tonic-gate } while ((t = t->t_forw) != p->p_tlist);
3587c478bd9Sstevel@tonic-gate if (!found)
3597c478bd9Sstevel@tonic-gate aff = set_errno(ESRCH);
3607c478bd9Sstevel@tonic-gate
3617c478bd9Sstevel@tonic-gate return (aff);
3627c478bd9Sstevel@tonic-gate }
3637c478bd9Sstevel@tonic-gate
3647c478bd9Sstevel@tonic-gate
3657c478bd9Sstevel@tonic-gate /*
3667c478bd9Sstevel@tonic-gate * Get lgroup affinity for given LWP
3677c478bd9Sstevel@tonic-gate */
3687c478bd9Sstevel@tonic-gate lgrp_affinity_t
lgrp_affinity_get(lgrp_affinity_args_t * ap)3697c478bd9Sstevel@tonic-gate lgrp_affinity_get(lgrp_affinity_args_t *ap)
3707c478bd9Sstevel@tonic-gate {
3717c478bd9Sstevel@tonic-gate lgrp_affinity_t aff;
3727c478bd9Sstevel@tonic-gate lgrp_affinity_args_t args;
3737c478bd9Sstevel@tonic-gate id_t id;
3747c478bd9Sstevel@tonic-gate idtype_t idtype;
3757c478bd9Sstevel@tonic-gate lgrp_id_t lgrp;
3767c478bd9Sstevel@tonic-gate proc_t *p;
3777c478bd9Sstevel@tonic-gate kthread_t *t;
3787c478bd9Sstevel@tonic-gate
3797c478bd9Sstevel@tonic-gate /*
3807c478bd9Sstevel@tonic-gate * Copyin arguments
3817c478bd9Sstevel@tonic-gate */
3827c478bd9Sstevel@tonic-gate if (copyin(ap, &args, sizeof (lgrp_affinity_args_t)) != 0)
3837c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
3847c478bd9Sstevel@tonic-gate
3857c478bd9Sstevel@tonic-gate id = args.id;
3867c478bd9Sstevel@tonic-gate idtype = args.idtype;
3877c478bd9Sstevel@tonic-gate lgrp = args.lgrp;
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate /*
3907c478bd9Sstevel@tonic-gate * Check for invalid lgroup
3917c478bd9Sstevel@tonic-gate */
3927c478bd9Sstevel@tonic-gate if (lgrp < 0 || lgrp == LGRP_NONE)
3937c478bd9Sstevel@tonic-gate return (set_errno(EINVAL));
3947c478bd9Sstevel@tonic-gate
3957c478bd9Sstevel@tonic-gate /*
3967c478bd9Sstevel@tonic-gate * Check for existing lgroup
3977c478bd9Sstevel@tonic-gate */
3987c478bd9Sstevel@tonic-gate if (lgrp > lgrp_alloc_max)
3997c478bd9Sstevel@tonic-gate return (set_errno(ESRCH));
4007c478bd9Sstevel@tonic-gate
4017c478bd9Sstevel@tonic-gate /*
4027c478bd9Sstevel@tonic-gate * Get lgroup affinity for given LWP or process
4037c478bd9Sstevel@tonic-gate */
4047c478bd9Sstevel@tonic-gate switch (idtype) {
4057c478bd9Sstevel@tonic-gate
4067c478bd9Sstevel@tonic-gate case P_LWPID:
4077c478bd9Sstevel@tonic-gate /*
4087c478bd9Sstevel@tonic-gate * LWP in current process
4097c478bd9Sstevel@tonic-gate */
4107c478bd9Sstevel@tonic-gate p = curproc;
4117c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock);
4127c478bd9Sstevel@tonic-gate if (id != P_MYID) /* different thread */
4137c478bd9Sstevel@tonic-gate aff = lgrp_affinity_get_thread(p, id, lgrp);
4147c478bd9Sstevel@tonic-gate else { /* current thread */
4157c478bd9Sstevel@tonic-gate aff = LGRP_AFF_NONE;
4167c478bd9Sstevel@tonic-gate t = curthread;
4177c478bd9Sstevel@tonic-gate thread_lock(t);
4187c478bd9Sstevel@tonic-gate if (t->t_lgrp_affinity)
4197c478bd9Sstevel@tonic-gate aff = t->t_lgrp_affinity[lgrp];
4207c478bd9Sstevel@tonic-gate thread_unlock(t);
4217c478bd9Sstevel@tonic-gate }
4227c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
4237c478bd9Sstevel@tonic-gate break;
4247c478bd9Sstevel@tonic-gate
4257c478bd9Sstevel@tonic-gate case P_PID:
4267c478bd9Sstevel@tonic-gate /*
4277c478bd9Sstevel@tonic-gate * Process
4287c478bd9Sstevel@tonic-gate */
4297c478bd9Sstevel@tonic-gate mutex_enter(&pidlock);
4307c478bd9Sstevel@tonic-gate
4317c478bd9Sstevel@tonic-gate if (id == P_MYID)
4327c478bd9Sstevel@tonic-gate p = curproc;
4337c478bd9Sstevel@tonic-gate else {
4347c478bd9Sstevel@tonic-gate p = prfind(id);
4357c478bd9Sstevel@tonic-gate if (p == NULL) {
4367c478bd9Sstevel@tonic-gate mutex_exit(&pidlock);
4377c478bd9Sstevel@tonic-gate return (set_errno(ESRCH));
4387c478bd9Sstevel@tonic-gate }
4397c478bd9Sstevel@tonic-gate }
4407c478bd9Sstevel@tonic-gate
4417c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock);
4427c478bd9Sstevel@tonic-gate aff = lgrp_affinity_get_thread(p, P_ANY, lgrp);
4437c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
4447c478bd9Sstevel@tonic-gate
4457c478bd9Sstevel@tonic-gate mutex_exit(&pidlock);
4467c478bd9Sstevel@tonic-gate break;
4477c478bd9Sstevel@tonic-gate
4487c478bd9Sstevel@tonic-gate default:
4497c478bd9Sstevel@tonic-gate aff = set_errno(EINVAL);
4507c478bd9Sstevel@tonic-gate break;
4517c478bd9Sstevel@tonic-gate }
4527c478bd9Sstevel@tonic-gate
4537c478bd9Sstevel@tonic-gate return (aff);
4547c478bd9Sstevel@tonic-gate }
4557c478bd9Sstevel@tonic-gate
4567c478bd9Sstevel@tonic-gate
4577c478bd9Sstevel@tonic-gate /*
4587c478bd9Sstevel@tonic-gate * Find lgroup for which this thread has most affinity in specified partition
45903400a71Sjjc * starting from home lgroup unless specified starting lgroup is preferred
4607c478bd9Sstevel@tonic-gate */
4617c478bd9Sstevel@tonic-gate lpl_t *
lgrp_affinity_best(kthread_t * t,struct cpupart * cpupart,lgrp_id_t start,boolean_t prefer_start)46203400a71Sjjc lgrp_affinity_best(kthread_t *t, struct cpupart *cpupart, lgrp_id_t start,
46303400a71Sjjc boolean_t prefer_start)
4647c478bd9Sstevel@tonic-gate {
4657c478bd9Sstevel@tonic-gate lgrp_affinity_t *affs;
4667c478bd9Sstevel@tonic-gate lgrp_affinity_t best_aff;
4677c478bd9Sstevel@tonic-gate lpl_t *best_lpl;
46803400a71Sjjc lgrp_id_t finish;
4697c478bd9Sstevel@tonic-gate lgrp_id_t home;
4707c478bd9Sstevel@tonic-gate lgrp_id_t lgrpid;
4717c478bd9Sstevel@tonic-gate lpl_t *lpl;
4727c478bd9Sstevel@tonic-gate
4737c478bd9Sstevel@tonic-gate ASSERT(t != NULL);
4747c478bd9Sstevel@tonic-gate ASSERT((MUTEX_HELD(&cpu_lock) || curthread->t_preempt > 0) ||
4757c478bd9Sstevel@tonic-gate (MUTEX_HELD(&ttoproc(t)->p_lock) && THREAD_LOCK_HELD(t)));
4767c478bd9Sstevel@tonic-gate ASSERT(cpupart != NULL);
4777c478bd9Sstevel@tonic-gate
4787c478bd9Sstevel@tonic-gate if (t->t_lgrp_affinity == NULL)
4797c478bd9Sstevel@tonic-gate return (NULL);
4807c478bd9Sstevel@tonic-gate
4817c478bd9Sstevel@tonic-gate affs = t->t_lgrp_affinity;
4827c478bd9Sstevel@tonic-gate
4837c478bd9Sstevel@tonic-gate /*
4847c478bd9Sstevel@tonic-gate * Thread bound to CPU
4857c478bd9Sstevel@tonic-gate */
4867c478bd9Sstevel@tonic-gate if (t->t_bind_cpu != PBIND_NONE) {
4877c478bd9Sstevel@tonic-gate cpu_t *cp;
4887c478bd9Sstevel@tonic-gate
4897c478bd9Sstevel@tonic-gate /*
49003400a71Sjjc * Find which lpl has most affinity among leaf lpl directly
49103400a71Sjjc * containing CPU and its ancestor lpls
4927c478bd9Sstevel@tonic-gate */
4937c478bd9Sstevel@tonic-gate cp = cpu[t->t_bind_cpu];
49403400a71Sjjc
49503400a71Sjjc best_lpl = lpl = cp->cpu_lpl;
49603400a71Sjjc best_aff = affs[best_lpl->lpl_lgrpid];
49703400a71Sjjc while (lpl->lpl_parent != NULL) {
49803400a71Sjjc lpl = lpl->lpl_parent;
49903400a71Sjjc lgrpid = lpl->lpl_lgrpid;
50003400a71Sjjc if (affs[lgrpid] > best_aff) {
50103400a71Sjjc best_lpl = lpl;
50203400a71Sjjc best_aff = affs[lgrpid];
50303400a71Sjjc }
50403400a71Sjjc }
50503400a71Sjjc return (best_lpl);
5067c478bd9Sstevel@tonic-gate }
5077c478bd9Sstevel@tonic-gate
5087c478bd9Sstevel@tonic-gate /*
50903400a71Sjjc * Start searching from home lgroup unless given starting lgroup is
51003400a71Sjjc * preferred or home lgroup isn't in given pset. Use root lgroup as
51103400a71Sjjc * starting point if both home and starting lgroups aren't in given
51203400a71Sjjc * pset.
5137c478bd9Sstevel@tonic-gate */
5147c478bd9Sstevel@tonic-gate ASSERT(start >= 0 && start <= lgrp_alloc_max);
5157c478bd9Sstevel@tonic-gate home = t->t_lpl->lpl_lgrpid;
51603400a71Sjjc if (!prefer_start && LGRP_CPUS_IN_PART(home, cpupart))
51703400a71Sjjc lgrpid = home;
51803400a71Sjjc else if (start != LGRP_NONE && LGRP_CPUS_IN_PART(start, cpupart))
51903400a71Sjjc lgrpid = start;
520c6402783Sakolb else
52103400a71Sjjc lgrpid = LGRP_ROOTID;
5227c478bd9Sstevel@tonic-gate
52303400a71Sjjc best_lpl = &cpupart->cp_lgrploads[lgrpid];
52403400a71Sjjc best_aff = affs[lgrpid];
52503400a71Sjjc finish = lgrpid;
5267c478bd9Sstevel@tonic-gate do {
5277c478bd9Sstevel@tonic-gate /*
5287c478bd9Sstevel@tonic-gate * Skip any lgroups that don't have CPU resources
5297c478bd9Sstevel@tonic-gate * in this processor set.
5307c478bd9Sstevel@tonic-gate */
5317c478bd9Sstevel@tonic-gate if (!LGRP_CPUS_IN_PART(lgrpid, cpupart)) {
5327c478bd9Sstevel@tonic-gate if (++lgrpid > lgrp_alloc_max)
5337c478bd9Sstevel@tonic-gate lgrpid = 0; /* wrap the search */
5347c478bd9Sstevel@tonic-gate continue;
5357c478bd9Sstevel@tonic-gate }
5367c478bd9Sstevel@tonic-gate
5377c478bd9Sstevel@tonic-gate /*
5387c478bd9Sstevel@tonic-gate * Find lgroup with most affinity
5397c478bd9Sstevel@tonic-gate */
5407c478bd9Sstevel@tonic-gate lpl = &cpupart->cp_lgrploads[lgrpid];
5417c478bd9Sstevel@tonic-gate if (affs[lgrpid] > best_aff) {
5427c478bd9Sstevel@tonic-gate best_aff = affs[lgrpid];
5437c478bd9Sstevel@tonic-gate best_lpl = lpl;
5447c478bd9Sstevel@tonic-gate }
5457c478bd9Sstevel@tonic-gate
5467c478bd9Sstevel@tonic-gate if (++lgrpid > lgrp_alloc_max)
5477c478bd9Sstevel@tonic-gate lgrpid = 0; /* wrap the search */
5487c478bd9Sstevel@tonic-gate
54903400a71Sjjc } while (lgrpid != finish);
5507c478bd9Sstevel@tonic-gate
5517c478bd9Sstevel@tonic-gate /*
5527c478bd9Sstevel@tonic-gate * No lgroup (in this pset) with any affinity
5537c478bd9Sstevel@tonic-gate */
5547c478bd9Sstevel@tonic-gate if (best_aff == LGRP_AFF_NONE)
5557c478bd9Sstevel@tonic-gate return (NULL);
5567c478bd9Sstevel@tonic-gate
5577c478bd9Sstevel@tonic-gate lgrpid = best_lpl->lpl_lgrpid;
5587c478bd9Sstevel@tonic-gate ASSERT(LGRP_CPUS_IN_PART(lgrpid, cpupart) && best_lpl->lpl_ncpu > 0);
5597c478bd9Sstevel@tonic-gate
5607c478bd9Sstevel@tonic-gate return (best_lpl);
5617c478bd9Sstevel@tonic-gate }
5627c478bd9Sstevel@tonic-gate
5637c478bd9Sstevel@tonic-gate
5647c478bd9Sstevel@tonic-gate /*
5657c478bd9Sstevel@tonic-gate * Set thread's affinity for given lgroup
5667c478bd9Sstevel@tonic-gate */
5677c478bd9Sstevel@tonic-gate int
lgrp_affinity_set_thread(kthread_t * t,lgrp_id_t lgrp,lgrp_affinity_t aff,lgrp_affinity_t ** aff_buf)5687c478bd9Sstevel@tonic-gate lgrp_affinity_set_thread(kthread_t *t, lgrp_id_t lgrp, lgrp_affinity_t aff,
5697c478bd9Sstevel@tonic-gate lgrp_affinity_t **aff_buf)
5707c478bd9Sstevel@tonic-gate {
571c6402783Sakolb lgrp_affinity_t *affs;
572c6402783Sakolb lgrp_id_t best;
5737c478bd9Sstevel@tonic-gate lpl_t *best_lpl;
5747c478bd9Sstevel@tonic-gate lgrp_id_t home;
5757c478bd9Sstevel@tonic-gate int retval;
5767c478bd9Sstevel@tonic-gate
5777c478bd9Sstevel@tonic-gate ASSERT(t != NULL);
5787c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock));
5797c478bd9Sstevel@tonic-gate
5807c478bd9Sstevel@tonic-gate retval = 0;
5817c478bd9Sstevel@tonic-gate
5827c478bd9Sstevel@tonic-gate thread_lock(t);
5837c478bd9Sstevel@tonic-gate
5847c478bd9Sstevel@tonic-gate /*
5857c478bd9Sstevel@tonic-gate * Check to see whether caller has permission to set affinity for
5867c478bd9Sstevel@tonic-gate * thread
5877c478bd9Sstevel@tonic-gate */
5887c478bd9Sstevel@tonic-gate if (t->t_cid == 0 || !hasprocperm(t->t_cred, CRED())) {
5897c478bd9Sstevel@tonic-gate thread_unlock(t);
5907c478bd9Sstevel@tonic-gate return (set_errno(EPERM));
5917c478bd9Sstevel@tonic-gate }
5927c478bd9Sstevel@tonic-gate
5937c478bd9Sstevel@tonic-gate if (t->t_lgrp_affinity == NULL) {
5947c478bd9Sstevel@tonic-gate if (aff == LGRP_AFF_NONE) {
5957c478bd9Sstevel@tonic-gate thread_unlock(t);
5967c478bd9Sstevel@tonic-gate return (0);
5977c478bd9Sstevel@tonic-gate }
5987c478bd9Sstevel@tonic-gate ASSERT(aff_buf != NULL && *aff_buf != NULL);
5997c478bd9Sstevel@tonic-gate t->t_lgrp_affinity = *aff_buf;
6007c478bd9Sstevel@tonic-gate *aff_buf = NULL;
6017c478bd9Sstevel@tonic-gate }
6027c478bd9Sstevel@tonic-gate
603c6402783Sakolb affs = t->t_lgrp_affinity;
604c6402783Sakolb affs[lgrp] = aff;
6057c478bd9Sstevel@tonic-gate
6067c478bd9Sstevel@tonic-gate /*
6077c478bd9Sstevel@tonic-gate * Find lgroup for which thread has most affinity,
608c6402783Sakolb * starting with lgroup for which affinity being set
6097c478bd9Sstevel@tonic-gate */
61003400a71Sjjc best_lpl = lgrp_affinity_best(t, t->t_cpupart, lgrp, B_TRUE);
6117c478bd9Sstevel@tonic-gate
6127c478bd9Sstevel@tonic-gate /*
613c6402783Sakolb * Rehome if found lgroup with more affinity than home or lgroup for
614c6402783Sakolb * which affinity is being set has same affinity as home
6157c478bd9Sstevel@tonic-gate */
616c6402783Sakolb home = t->t_lpl->lpl_lgrpid;
617c6402783Sakolb if (best_lpl != NULL && best_lpl != t->t_lpl) {
618c6402783Sakolb best = best_lpl->lpl_lgrpid;
619c6402783Sakolb if (affs[best] > affs[home] || (affs[best] == affs[home] &&
620c6402783Sakolb best == lgrp))
6217c478bd9Sstevel@tonic-gate lgrp_move_thread(t, best_lpl, 1);
622c6402783Sakolb }
6237c478bd9Sstevel@tonic-gate
6247c478bd9Sstevel@tonic-gate thread_unlock(t);
6257c478bd9Sstevel@tonic-gate
6267c478bd9Sstevel@tonic-gate return (retval);
6277c478bd9Sstevel@tonic-gate }
6287c478bd9Sstevel@tonic-gate
6297c478bd9Sstevel@tonic-gate
6307c478bd9Sstevel@tonic-gate /*
6317c478bd9Sstevel@tonic-gate * Set process' affinity for specified lgroup
6327c478bd9Sstevel@tonic-gate */
6337c478bd9Sstevel@tonic-gate int
lgrp_affinity_set_proc(proc_t * p,lgrp_id_t lgrp,lgrp_affinity_t aff,lgrp_affinity_t ** aff_buf_array)6347c478bd9Sstevel@tonic-gate lgrp_affinity_set_proc(proc_t *p, lgrp_id_t lgrp, lgrp_affinity_t aff,
6357c478bd9Sstevel@tonic-gate lgrp_affinity_t **aff_buf_array)
6367c478bd9Sstevel@tonic-gate {
6377c478bd9Sstevel@tonic-gate lgrp_affinity_t *buf;
6387c478bd9Sstevel@tonic-gate int err = 0;
6397c478bd9Sstevel@tonic-gate int i;
6407c478bd9Sstevel@tonic-gate int retval;
6417c478bd9Sstevel@tonic-gate kthread_t *t;
6427c478bd9Sstevel@tonic-gate
6437c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pidlock) && MUTEX_HELD(&p->p_lock));
6447c478bd9Sstevel@tonic-gate ASSERT(aff_buf_array != NULL);
6457c478bd9Sstevel@tonic-gate
6467c478bd9Sstevel@tonic-gate i = 0;
6477c478bd9Sstevel@tonic-gate t = p->p_tlist;
6487c478bd9Sstevel@tonic-gate if (t != NULL) {
6497c478bd9Sstevel@tonic-gate do {
6507c478bd9Sstevel@tonic-gate /*
6517c478bd9Sstevel@tonic-gate * Set lgroup affinity for thread
6527c478bd9Sstevel@tonic-gate */
6537c478bd9Sstevel@tonic-gate buf = aff_buf_array[i];
6547c478bd9Sstevel@tonic-gate retval = lgrp_affinity_set_thread(t, lgrp, aff, &buf);
6557c478bd9Sstevel@tonic-gate
6567c478bd9Sstevel@tonic-gate if (err == 0 && retval != 0)
6577c478bd9Sstevel@tonic-gate err = retval;
6587c478bd9Sstevel@tonic-gate
6597c478bd9Sstevel@tonic-gate /*
6607c478bd9Sstevel@tonic-gate * Advance pointer to next buffer
6617c478bd9Sstevel@tonic-gate */
6627c478bd9Sstevel@tonic-gate if (buf == NULL) {
6637c478bd9Sstevel@tonic-gate ASSERT(i < p->p_lwpcnt);
6647c478bd9Sstevel@tonic-gate aff_buf_array[i] = NULL;
6657c478bd9Sstevel@tonic-gate i++;
6667c478bd9Sstevel@tonic-gate }
6677c478bd9Sstevel@tonic-gate
6687c478bd9Sstevel@tonic-gate } while ((t = t->t_forw) != p->p_tlist);
6697c478bd9Sstevel@tonic-gate }
6707c478bd9Sstevel@tonic-gate return (err);
6717c478bd9Sstevel@tonic-gate }
6727c478bd9Sstevel@tonic-gate
6737c478bd9Sstevel@tonic-gate
6747c478bd9Sstevel@tonic-gate /*
6757c478bd9Sstevel@tonic-gate * Set LWP's or process' affinity for specified lgroup
6767c478bd9Sstevel@tonic-gate *
6777c478bd9Sstevel@tonic-gate * When setting affinities, pidlock, process p_lock, and thread_lock()
6787c478bd9Sstevel@tonic-gate * need to be held in that order to protect target thread's pset, process,
6797c478bd9Sstevel@tonic-gate * process contents, and thread contents. thread_lock() does splhigh(),
6807c478bd9Sstevel@tonic-gate * so it ends up having similiar effect as kpreempt_disable(), so it will
6817c478bd9Sstevel@tonic-gate * protect calls to lgrp_move_thread() and lgrp_choose() from pset changes.
6827c478bd9Sstevel@tonic-gate */
6837c478bd9Sstevel@tonic-gate int
lgrp_affinity_set(lgrp_affinity_args_t * ap)6847c478bd9Sstevel@tonic-gate lgrp_affinity_set(lgrp_affinity_args_t *ap)
6857c478bd9Sstevel@tonic-gate {
6867c478bd9Sstevel@tonic-gate lgrp_affinity_t aff;
6877c478bd9Sstevel@tonic-gate lgrp_affinity_t *aff_buf;
6887c478bd9Sstevel@tonic-gate lgrp_affinity_args_t args;
6897c478bd9Sstevel@tonic-gate id_t id;
6907c478bd9Sstevel@tonic-gate idtype_t idtype;
6917c478bd9Sstevel@tonic-gate lgrp_id_t lgrp;
6927c478bd9Sstevel@tonic-gate int nthreads;
6937c478bd9Sstevel@tonic-gate proc_t *p;
6947c478bd9Sstevel@tonic-gate int retval;
6957c478bd9Sstevel@tonic-gate
6967c478bd9Sstevel@tonic-gate /*
6977c478bd9Sstevel@tonic-gate * Copyin arguments
6987c478bd9Sstevel@tonic-gate */
6997c478bd9Sstevel@tonic-gate if (copyin(ap, &args, sizeof (lgrp_affinity_args_t)) != 0)
7007c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
7017c478bd9Sstevel@tonic-gate
7027c478bd9Sstevel@tonic-gate idtype = args.idtype;
7037c478bd9Sstevel@tonic-gate id = args.id;
7047c478bd9Sstevel@tonic-gate lgrp = args.lgrp;
7057c478bd9Sstevel@tonic-gate aff = args.aff;
7067c478bd9Sstevel@tonic-gate
7077c478bd9Sstevel@tonic-gate /*
7087c478bd9Sstevel@tonic-gate * Check for invalid lgroup
7097c478bd9Sstevel@tonic-gate */
7107c478bd9Sstevel@tonic-gate if (lgrp < 0 || lgrp == LGRP_NONE)
7117c478bd9Sstevel@tonic-gate return (set_errno(EINVAL));
7127c478bd9Sstevel@tonic-gate
7137c478bd9Sstevel@tonic-gate /*
7147c478bd9Sstevel@tonic-gate * Check for existing lgroup
7157c478bd9Sstevel@tonic-gate */
7167c478bd9Sstevel@tonic-gate if (lgrp > lgrp_alloc_max)
7177c478bd9Sstevel@tonic-gate return (set_errno(ESRCH));
7187c478bd9Sstevel@tonic-gate
7197c478bd9Sstevel@tonic-gate /*
7207c478bd9Sstevel@tonic-gate * Check for legal affinity
7217c478bd9Sstevel@tonic-gate */
7227c478bd9Sstevel@tonic-gate if (aff != LGRP_AFF_NONE && aff != LGRP_AFF_WEAK &&
7237c478bd9Sstevel@tonic-gate aff != LGRP_AFF_STRONG)
7247c478bd9Sstevel@tonic-gate return (set_errno(EINVAL));
7257c478bd9Sstevel@tonic-gate
7267c478bd9Sstevel@tonic-gate /*
7277c478bd9Sstevel@tonic-gate * Must be process or LWP ID
7287c478bd9Sstevel@tonic-gate */
7297c478bd9Sstevel@tonic-gate if (idtype != P_LWPID && idtype != P_PID)
7307c478bd9Sstevel@tonic-gate return (set_errno(EINVAL));
7317c478bd9Sstevel@tonic-gate
7327c478bd9Sstevel@tonic-gate /*
7337c478bd9Sstevel@tonic-gate * Set given LWP's or process' affinity for specified lgroup
7347c478bd9Sstevel@tonic-gate */
7357c478bd9Sstevel@tonic-gate switch (idtype) {
7367c478bd9Sstevel@tonic-gate
7377c478bd9Sstevel@tonic-gate case P_LWPID:
7387c478bd9Sstevel@tonic-gate /*
7397c478bd9Sstevel@tonic-gate * Allocate memory for thread's lgroup affinities
7407c478bd9Sstevel@tonic-gate * ahead of time w/o holding locks
7417c478bd9Sstevel@tonic-gate */
7427c478bd9Sstevel@tonic-gate aff_buf = kmem_zalloc(nlgrpsmax * sizeof (lgrp_affinity_t),
7437c478bd9Sstevel@tonic-gate KM_SLEEP);
7447c478bd9Sstevel@tonic-gate
7457c478bd9Sstevel@tonic-gate p = curproc;
7467c478bd9Sstevel@tonic-gate
7477c478bd9Sstevel@tonic-gate /*
7487c478bd9Sstevel@tonic-gate * Set affinity for thread
7497c478bd9Sstevel@tonic-gate */
7507c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock);
7517c478bd9Sstevel@tonic-gate if (id == P_MYID) { /* current thread */
7527c478bd9Sstevel@tonic-gate retval = lgrp_affinity_set_thread(curthread, lgrp, aff,
7537c478bd9Sstevel@tonic-gate &aff_buf);
7547c478bd9Sstevel@tonic-gate } else if (p->p_tlist == NULL) {
7557c478bd9Sstevel@tonic-gate retval = set_errno(ESRCH);
7567c478bd9Sstevel@tonic-gate } else { /* other thread */
7577c478bd9Sstevel@tonic-gate int found = 0;
7587c478bd9Sstevel@tonic-gate kthread_t *t;
7597c478bd9Sstevel@tonic-gate
7607c478bd9Sstevel@tonic-gate t = p->p_tlist;
7617c478bd9Sstevel@tonic-gate do {
7627c478bd9Sstevel@tonic-gate if (t->t_tid == id) {
7637c478bd9Sstevel@tonic-gate retval = lgrp_affinity_set_thread(t,
7647c478bd9Sstevel@tonic-gate lgrp, aff, &aff_buf);
7657c478bd9Sstevel@tonic-gate found = 1;
7667c478bd9Sstevel@tonic-gate break;
7677c478bd9Sstevel@tonic-gate }
7687c478bd9Sstevel@tonic-gate } while ((t = t->t_forw) != p->p_tlist);
7697c478bd9Sstevel@tonic-gate if (!found)
7707c478bd9Sstevel@tonic-gate retval = set_errno(ESRCH);
7717c478bd9Sstevel@tonic-gate }
7727c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
7737c478bd9Sstevel@tonic-gate
7747c478bd9Sstevel@tonic-gate /*
7757c478bd9Sstevel@tonic-gate * Free memory for lgroup affinities,
7767c478bd9Sstevel@tonic-gate * since thread didn't need it
7777c478bd9Sstevel@tonic-gate */
7787c478bd9Sstevel@tonic-gate if (aff_buf)
7797c478bd9Sstevel@tonic-gate kmem_free(aff_buf,
7807c478bd9Sstevel@tonic-gate nlgrpsmax * sizeof (lgrp_affinity_t));
7817c478bd9Sstevel@tonic-gate
7827c478bd9Sstevel@tonic-gate break;
7837c478bd9Sstevel@tonic-gate
7847c478bd9Sstevel@tonic-gate case P_PID:
7857c478bd9Sstevel@tonic-gate
7867c478bd9Sstevel@tonic-gate do {
7877c478bd9Sstevel@tonic-gate lgrp_affinity_t **aff_buf_array;
7887c478bd9Sstevel@tonic-gate int i;
7897c478bd9Sstevel@tonic-gate size_t size;
7907c478bd9Sstevel@tonic-gate
7917c478bd9Sstevel@tonic-gate /*
7927c478bd9Sstevel@tonic-gate * Get process
7937c478bd9Sstevel@tonic-gate */
7947c478bd9Sstevel@tonic-gate mutex_enter(&pidlock);
7957c478bd9Sstevel@tonic-gate
7967c478bd9Sstevel@tonic-gate if (id == P_MYID)
7977c478bd9Sstevel@tonic-gate p = curproc;
7987c478bd9Sstevel@tonic-gate else
7997c478bd9Sstevel@tonic-gate p = prfind(id);
8007c478bd9Sstevel@tonic-gate
8017c478bd9Sstevel@tonic-gate if (p == NULL) {
8027c478bd9Sstevel@tonic-gate mutex_exit(&pidlock);
8037c478bd9Sstevel@tonic-gate return (set_errno(ESRCH));
8047c478bd9Sstevel@tonic-gate }
8057c478bd9Sstevel@tonic-gate
8067c478bd9Sstevel@tonic-gate /*
8077c478bd9Sstevel@tonic-gate * Get number of threads in process
8087c478bd9Sstevel@tonic-gate *
8097c478bd9Sstevel@tonic-gate * NOTE: Only care about user processes,
8107c478bd9Sstevel@tonic-gate * so p_lwpcnt should be number of threads.
8117c478bd9Sstevel@tonic-gate */
8127c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock);
8137c478bd9Sstevel@tonic-gate nthreads = p->p_lwpcnt;
8147c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
8157c478bd9Sstevel@tonic-gate
8167c478bd9Sstevel@tonic-gate mutex_exit(&pidlock);
8177c478bd9Sstevel@tonic-gate
8187c478bd9Sstevel@tonic-gate if (nthreads < 1)
8197c478bd9Sstevel@tonic-gate return (set_errno(ESRCH));
8207c478bd9Sstevel@tonic-gate
8217c478bd9Sstevel@tonic-gate /*
8227c478bd9Sstevel@tonic-gate * Preallocate memory for lgroup affinities for
8237c478bd9Sstevel@tonic-gate * each thread in process now to avoid holding
8247c478bd9Sstevel@tonic-gate * any locks. Allocate an array to hold a buffer
8257c478bd9Sstevel@tonic-gate * for each thread.
8267c478bd9Sstevel@tonic-gate */
8277c478bd9Sstevel@tonic-gate aff_buf_array = kmem_zalloc(nthreads *
8287c478bd9Sstevel@tonic-gate sizeof (lgrp_affinity_t *), KM_SLEEP);
8297c478bd9Sstevel@tonic-gate
8307c478bd9Sstevel@tonic-gate size = nlgrpsmax * sizeof (lgrp_affinity_t);
8317c478bd9Sstevel@tonic-gate for (i = 0; i < nthreads; i++)
8327c478bd9Sstevel@tonic-gate aff_buf_array[i] = kmem_zalloc(size, KM_SLEEP);
8337c478bd9Sstevel@tonic-gate
8347c478bd9Sstevel@tonic-gate mutex_enter(&pidlock);
8357c478bd9Sstevel@tonic-gate
8367c478bd9Sstevel@tonic-gate /*
8377c478bd9Sstevel@tonic-gate * Get process again since dropped locks to allocate
8387c478bd9Sstevel@tonic-gate * memory (except current process)
8397c478bd9Sstevel@tonic-gate */
8407c478bd9Sstevel@tonic-gate if (id != P_MYID)
8417c478bd9Sstevel@tonic-gate p = prfind(id);
8427c478bd9Sstevel@tonic-gate
8437c478bd9Sstevel@tonic-gate /*
8447c478bd9Sstevel@tonic-gate * Process went away after we dropped locks and before
8457c478bd9Sstevel@tonic-gate * reacquiring them, so drop locks, free memory, and
8467c478bd9Sstevel@tonic-gate * return.
8477c478bd9Sstevel@tonic-gate */
8487c478bd9Sstevel@tonic-gate if (p == NULL) {
8497c478bd9Sstevel@tonic-gate mutex_exit(&pidlock);
8507c478bd9Sstevel@tonic-gate for (i = 0; i < nthreads; i++)
8517c478bd9Sstevel@tonic-gate kmem_free(aff_buf_array[i], size);
8527c478bd9Sstevel@tonic-gate kmem_free(aff_buf_array,
8537c478bd9Sstevel@tonic-gate nthreads * sizeof (lgrp_affinity_t *));
8547c478bd9Sstevel@tonic-gate return (set_errno(ESRCH));
8557c478bd9Sstevel@tonic-gate }
8567c478bd9Sstevel@tonic-gate
8577c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock);
8587c478bd9Sstevel@tonic-gate
8597c478bd9Sstevel@tonic-gate /*
8607c478bd9Sstevel@tonic-gate * See whether number of threads is same
8617c478bd9Sstevel@tonic-gate * If not, drop locks, free memory, and try again
8627c478bd9Sstevel@tonic-gate */
8637c478bd9Sstevel@tonic-gate if (nthreads != p->p_lwpcnt) {
8647c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
8657c478bd9Sstevel@tonic-gate mutex_exit(&pidlock);
8667c478bd9Sstevel@tonic-gate for (i = 0; i < nthreads; i++)
8677c478bd9Sstevel@tonic-gate kmem_free(aff_buf_array[i], size);
8687c478bd9Sstevel@tonic-gate kmem_free(aff_buf_array,
8697c478bd9Sstevel@tonic-gate nthreads * sizeof (lgrp_affinity_t *));
8707c478bd9Sstevel@tonic-gate continue;
8717c478bd9Sstevel@tonic-gate }
8727c478bd9Sstevel@tonic-gate
8737c478bd9Sstevel@tonic-gate /*
8747c478bd9Sstevel@tonic-gate * Set lgroup affinity for threads in process
8757c478bd9Sstevel@tonic-gate */
8767c478bd9Sstevel@tonic-gate retval = lgrp_affinity_set_proc(p, lgrp, aff,
8777c478bd9Sstevel@tonic-gate aff_buf_array);
8787c478bd9Sstevel@tonic-gate
8797c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
8807c478bd9Sstevel@tonic-gate mutex_exit(&pidlock);
8817c478bd9Sstevel@tonic-gate
8827c478bd9Sstevel@tonic-gate /*
8837c478bd9Sstevel@tonic-gate * Free any leftover memory, since some threads may
8847c478bd9Sstevel@tonic-gate * have already allocated memory and set lgroup
8857c478bd9Sstevel@tonic-gate * affinities before
8867c478bd9Sstevel@tonic-gate */
8877c478bd9Sstevel@tonic-gate for (i = 0; i < nthreads; i++)
8887c478bd9Sstevel@tonic-gate if (aff_buf_array[i] != NULL)
8897c478bd9Sstevel@tonic-gate kmem_free(aff_buf_array[i], size);
8907c478bd9Sstevel@tonic-gate kmem_free(aff_buf_array,
8917c478bd9Sstevel@tonic-gate nthreads * sizeof (lgrp_affinity_t *));
8927c478bd9Sstevel@tonic-gate
8937c478bd9Sstevel@tonic-gate break;
8947c478bd9Sstevel@tonic-gate
8957c478bd9Sstevel@tonic-gate } while (nthreads != p->p_lwpcnt);
8967c478bd9Sstevel@tonic-gate
8977c478bd9Sstevel@tonic-gate break;
8987c478bd9Sstevel@tonic-gate
8997c478bd9Sstevel@tonic-gate default:
9007c478bd9Sstevel@tonic-gate retval = set_errno(EINVAL);
9017c478bd9Sstevel@tonic-gate break;
9027c478bd9Sstevel@tonic-gate }
9037c478bd9Sstevel@tonic-gate
9047c478bd9Sstevel@tonic-gate return (retval);
9057c478bd9Sstevel@tonic-gate }
9067c478bd9Sstevel@tonic-gate
9077c478bd9Sstevel@tonic-gate
9087c478bd9Sstevel@tonic-gate /*
9097c478bd9Sstevel@tonic-gate * Return the latest generation number for the lgroup hierarchy
9107c478bd9Sstevel@tonic-gate * with the given view
9117c478bd9Sstevel@tonic-gate */
9127c478bd9Sstevel@tonic-gate lgrp_gen_t
lgrp_generation(lgrp_view_t view)9137c478bd9Sstevel@tonic-gate lgrp_generation(lgrp_view_t view)
9147c478bd9Sstevel@tonic-gate {
9157c478bd9Sstevel@tonic-gate cpupart_t *cpupart;
9167c478bd9Sstevel@tonic-gate uint_t gen;
9177c478bd9Sstevel@tonic-gate
9187c478bd9Sstevel@tonic-gate kpreempt_disable();
9197c478bd9Sstevel@tonic-gate
9207c478bd9Sstevel@tonic-gate /*
9217c478bd9Sstevel@tonic-gate * Determine generation number for given view
9227c478bd9Sstevel@tonic-gate */
9237c478bd9Sstevel@tonic-gate if (view == LGRP_VIEW_OS)
9247c478bd9Sstevel@tonic-gate /*
9257c478bd9Sstevel@tonic-gate * Return generation number of lgroup hierarchy for OS view
9267c478bd9Sstevel@tonic-gate */
9277c478bd9Sstevel@tonic-gate gen = lgrp_gen;
9287c478bd9Sstevel@tonic-gate else {
9297c478bd9Sstevel@tonic-gate /*
9307c478bd9Sstevel@tonic-gate * For caller's view, use generation numbers for lgroup
9317c478bd9Sstevel@tonic-gate * hierarchy and caller's pset
9327c478bd9Sstevel@tonic-gate * NOTE: Caller needs to check for change in pset ID
9337c478bd9Sstevel@tonic-gate */
9347c478bd9Sstevel@tonic-gate cpupart = curthread->t_cpupart;
9357c478bd9Sstevel@tonic-gate ASSERT(cpupart);
9367c478bd9Sstevel@tonic-gate gen = lgrp_gen + cpupart->cp_gen;
9377c478bd9Sstevel@tonic-gate }
9387c478bd9Sstevel@tonic-gate
9397c478bd9Sstevel@tonic-gate kpreempt_enable();
9407c478bd9Sstevel@tonic-gate
9417c478bd9Sstevel@tonic-gate return (gen);
9427c478bd9Sstevel@tonic-gate }
9437c478bd9Sstevel@tonic-gate
9447c478bd9Sstevel@tonic-gate
9457c478bd9Sstevel@tonic-gate lgrp_id_t
lgrp_home_thread(kthread_t * t)9467c478bd9Sstevel@tonic-gate lgrp_home_thread(kthread_t *t)
9477c478bd9Sstevel@tonic-gate {
9487c478bd9Sstevel@tonic-gate lgrp_id_t home;
9497c478bd9Sstevel@tonic-gate
9507c478bd9Sstevel@tonic-gate ASSERT(t != NULL);
9517c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock));
9527c478bd9Sstevel@tonic-gate
9537c478bd9Sstevel@tonic-gate thread_lock(t);
9547c478bd9Sstevel@tonic-gate
9557c478bd9Sstevel@tonic-gate /*
9567c478bd9Sstevel@tonic-gate * Check to see whether caller has permission to set affinity for
9577c478bd9Sstevel@tonic-gate * thread
9587c478bd9Sstevel@tonic-gate */
9597c478bd9Sstevel@tonic-gate if (t->t_cid == 0 || !hasprocperm(t->t_cred, CRED())) {
9607c478bd9Sstevel@tonic-gate thread_unlock(t);
9617c478bd9Sstevel@tonic-gate return (set_errno(EPERM));
9627c478bd9Sstevel@tonic-gate }
9637c478bd9Sstevel@tonic-gate
9647c478bd9Sstevel@tonic-gate home = lgrp_home_id(t);
9657c478bd9Sstevel@tonic-gate
9667c478bd9Sstevel@tonic-gate thread_unlock(t);
9677c478bd9Sstevel@tonic-gate return (home);
9687c478bd9Sstevel@tonic-gate }
9697c478bd9Sstevel@tonic-gate
9707c478bd9Sstevel@tonic-gate
9717c478bd9Sstevel@tonic-gate /*
9727c478bd9Sstevel@tonic-gate * Get home lgroup of given process or thread
9737c478bd9Sstevel@tonic-gate */
9747c478bd9Sstevel@tonic-gate lgrp_id_t
lgrp_home_get(idtype_t idtype,id_t id)9757c478bd9Sstevel@tonic-gate lgrp_home_get(idtype_t idtype, id_t id)
9767c478bd9Sstevel@tonic-gate {
9777c478bd9Sstevel@tonic-gate proc_t *p;
9787c478bd9Sstevel@tonic-gate lgrp_id_t retval;
9797c478bd9Sstevel@tonic-gate kthread_t *t;
9807c478bd9Sstevel@tonic-gate
9817c478bd9Sstevel@tonic-gate /*
9827c478bd9Sstevel@tonic-gate * Get home lgroup of given LWP or process
9837c478bd9Sstevel@tonic-gate */
9847c478bd9Sstevel@tonic-gate switch (idtype) {
9857c478bd9Sstevel@tonic-gate
9867c478bd9Sstevel@tonic-gate case P_LWPID:
9877c478bd9Sstevel@tonic-gate p = curproc;
9887c478bd9Sstevel@tonic-gate
9897c478bd9Sstevel@tonic-gate /*
9907c478bd9Sstevel@tonic-gate * Set affinity for thread
9917c478bd9Sstevel@tonic-gate */
9927c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock);
9937c478bd9Sstevel@tonic-gate if (id == P_MYID) { /* current thread */
9947c478bd9Sstevel@tonic-gate retval = lgrp_home_thread(curthread);
9957c478bd9Sstevel@tonic-gate } else if (p->p_tlist == NULL) {
9967c478bd9Sstevel@tonic-gate retval = set_errno(ESRCH);
9977c478bd9Sstevel@tonic-gate } else { /* other thread */
9987c478bd9Sstevel@tonic-gate int found = 0;
9997c478bd9Sstevel@tonic-gate
10007c478bd9Sstevel@tonic-gate t = p->p_tlist;
10017c478bd9Sstevel@tonic-gate do {
10027c478bd9Sstevel@tonic-gate if (t->t_tid == id) {
10037c478bd9Sstevel@tonic-gate retval = lgrp_home_thread(t);
10047c478bd9Sstevel@tonic-gate found = 1;
10057c478bd9Sstevel@tonic-gate break;
10067c478bd9Sstevel@tonic-gate }
10077c478bd9Sstevel@tonic-gate } while ((t = t->t_forw) != p->p_tlist);
10087c478bd9Sstevel@tonic-gate if (!found)
10097c478bd9Sstevel@tonic-gate retval = set_errno(ESRCH);
10107c478bd9Sstevel@tonic-gate }
10117c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
10127c478bd9Sstevel@tonic-gate break;
10137c478bd9Sstevel@tonic-gate
10147c478bd9Sstevel@tonic-gate case P_PID:
10157c478bd9Sstevel@tonic-gate /*
10167c478bd9Sstevel@tonic-gate * Get process
10177c478bd9Sstevel@tonic-gate */
10187c478bd9Sstevel@tonic-gate mutex_enter(&pidlock);
10197c478bd9Sstevel@tonic-gate
10207c478bd9Sstevel@tonic-gate if (id == P_MYID)
10217c478bd9Sstevel@tonic-gate p = curproc;
10227c478bd9Sstevel@tonic-gate else
10237c478bd9Sstevel@tonic-gate p = prfind(id);
10247c478bd9Sstevel@tonic-gate
10257c478bd9Sstevel@tonic-gate if (p == NULL) {
10267c478bd9Sstevel@tonic-gate mutex_exit(&pidlock);
10277c478bd9Sstevel@tonic-gate return (set_errno(ESRCH));
10287c478bd9Sstevel@tonic-gate }
10297c478bd9Sstevel@tonic-gate
10307c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock);
10317c478bd9Sstevel@tonic-gate t = p->p_tlist;
10327c478bd9Sstevel@tonic-gate if (t == NULL)
10337c478bd9Sstevel@tonic-gate retval = set_errno(ESRCH);
10347c478bd9Sstevel@tonic-gate else
10357c478bd9Sstevel@tonic-gate retval = lgrp_home_thread(t);
10367c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock);
10377c478bd9Sstevel@tonic-gate
10387c478bd9Sstevel@tonic-gate mutex_exit(&pidlock);
10397c478bd9Sstevel@tonic-gate
10407c478bd9Sstevel@tonic-gate break;
10417c478bd9Sstevel@tonic-gate
10427c478bd9Sstevel@tonic-gate default:
10437c478bd9Sstevel@tonic-gate retval = set_errno(EINVAL);
10447c478bd9Sstevel@tonic-gate break;
10457c478bd9Sstevel@tonic-gate }
10467c478bd9Sstevel@tonic-gate
10477c478bd9Sstevel@tonic-gate return (retval);
10487c478bd9Sstevel@tonic-gate }
10497c478bd9Sstevel@tonic-gate
10507c478bd9Sstevel@tonic-gate
10517c478bd9Sstevel@tonic-gate /*
10527c478bd9Sstevel@tonic-gate * Return latency between "from" and "to" lgroups
10537c478bd9Sstevel@tonic-gate *
10547c478bd9Sstevel@tonic-gate * This latency number can only be used for relative comparison
10557c478bd9Sstevel@tonic-gate * between lgroups on the running system, cannot be used across platforms,
10567c478bd9Sstevel@tonic-gate * and may not reflect the actual latency. It is platform and implementation
10577c478bd9Sstevel@tonic-gate * specific, so platform gets to decide its value. It would be nice if the
10587c478bd9Sstevel@tonic-gate * number was at least proportional to make comparisons more meaningful though.
10597c478bd9Sstevel@tonic-gate */
10607c478bd9Sstevel@tonic-gate int
lgrp_latency(lgrp_id_t from,lgrp_id_t to)10617c478bd9Sstevel@tonic-gate lgrp_latency(lgrp_id_t from, lgrp_id_t to)
10627c478bd9Sstevel@tonic-gate {
10637c478bd9Sstevel@tonic-gate lgrp_t *from_lgrp;
10647c478bd9Sstevel@tonic-gate int i;
10657c478bd9Sstevel@tonic-gate int latency;
10667c478bd9Sstevel@tonic-gate int latency_max;
10677c478bd9Sstevel@tonic-gate lgrp_t *to_lgrp;
10687c478bd9Sstevel@tonic-gate
10697c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock));
10707c478bd9Sstevel@tonic-gate
10717c478bd9Sstevel@tonic-gate if (from < 0 || to < 0)
10727c478bd9Sstevel@tonic-gate return (set_errno(EINVAL));
10737c478bd9Sstevel@tonic-gate
10747c478bd9Sstevel@tonic-gate if (from > lgrp_alloc_max || to > lgrp_alloc_max)
10757c478bd9Sstevel@tonic-gate return (set_errno(ESRCH));
10767c478bd9Sstevel@tonic-gate
10777c478bd9Sstevel@tonic-gate from_lgrp = lgrp_table[from];
10787c478bd9Sstevel@tonic-gate to_lgrp = lgrp_table[to];
10797c478bd9Sstevel@tonic-gate
10807c478bd9Sstevel@tonic-gate if (!LGRP_EXISTS(from_lgrp) || !LGRP_EXISTS(to_lgrp)) {
10817c478bd9Sstevel@tonic-gate return (set_errno(ESRCH));
10827c478bd9Sstevel@tonic-gate }
10837c478bd9Sstevel@tonic-gate
10847c478bd9Sstevel@tonic-gate /*
10857c478bd9Sstevel@tonic-gate * Get latency for same lgroup
10867c478bd9Sstevel@tonic-gate */
10877c478bd9Sstevel@tonic-gate if (from == to) {
10887c478bd9Sstevel@tonic-gate latency = from_lgrp->lgrp_latency;
10897c478bd9Sstevel@tonic-gate return (latency);
10907c478bd9Sstevel@tonic-gate }
10917c478bd9Sstevel@tonic-gate
10927c478bd9Sstevel@tonic-gate /*
10937c478bd9Sstevel@tonic-gate * Get latency between leaf lgroups
10947c478bd9Sstevel@tonic-gate */
10957c478bd9Sstevel@tonic-gate if (from_lgrp->lgrp_childcnt == 0 && to_lgrp->lgrp_childcnt == 0)
10967c478bd9Sstevel@tonic-gate return (lgrp_plat_latency(from_lgrp->lgrp_plathand,
10977c478bd9Sstevel@tonic-gate to_lgrp->lgrp_plathand));
10987c478bd9Sstevel@tonic-gate
10997c478bd9Sstevel@tonic-gate /*
11007c478bd9Sstevel@tonic-gate * Determine max latency between resources in two lgroups
11017c478bd9Sstevel@tonic-gate */
11027c478bd9Sstevel@tonic-gate latency_max = 0;
11037c478bd9Sstevel@tonic-gate for (i = 0; i <= lgrp_alloc_max; i++) {
11047c478bd9Sstevel@tonic-gate lgrp_t *from_rsrc;
11057c478bd9Sstevel@tonic-gate int j;
11067c478bd9Sstevel@tonic-gate lgrp_t *to_rsrc;
11077c478bd9Sstevel@tonic-gate
11087c478bd9Sstevel@tonic-gate from_rsrc = lgrp_table[i];
11097c478bd9Sstevel@tonic-gate if (!LGRP_EXISTS(from_rsrc) ||
11107c478bd9Sstevel@tonic-gate !klgrpset_ismember(from_lgrp->lgrp_set[LGRP_RSRC_CPU], i))
11117c478bd9Sstevel@tonic-gate continue;
11127c478bd9Sstevel@tonic-gate
11137c478bd9Sstevel@tonic-gate for (j = 0; j <= lgrp_alloc_max; j++) {
11147c478bd9Sstevel@tonic-gate to_rsrc = lgrp_table[j];
11157c478bd9Sstevel@tonic-gate if (!LGRP_EXISTS(to_rsrc) ||
11167c478bd9Sstevel@tonic-gate klgrpset_ismember(to_lgrp->lgrp_set[LGRP_RSRC_MEM],
11177c478bd9Sstevel@tonic-gate j) == 0)
11187c478bd9Sstevel@tonic-gate continue;
11197c478bd9Sstevel@tonic-gate latency = lgrp_plat_latency(from_rsrc->lgrp_plathand,
11207c478bd9Sstevel@tonic-gate to_rsrc->lgrp_plathand);
11217c478bd9Sstevel@tonic-gate if (latency > latency_max)
11227c478bd9Sstevel@tonic-gate latency_max = latency;
11237c478bd9Sstevel@tonic-gate }
11247c478bd9Sstevel@tonic-gate }
11257c478bd9Sstevel@tonic-gate return (latency_max);
11267c478bd9Sstevel@tonic-gate }
11277c478bd9Sstevel@tonic-gate
11287c478bd9Sstevel@tonic-gate
11297c478bd9Sstevel@tonic-gate /*
11307c478bd9Sstevel@tonic-gate * Return lgroup interface version number
11317c478bd9Sstevel@tonic-gate * 0 - none
11327c478bd9Sstevel@tonic-gate * 1 - original
11337c478bd9Sstevel@tonic-gate * 2 - lgrp_latency_cookie() and lgrp_resources() added
11347c478bd9Sstevel@tonic-gate */
11357c478bd9Sstevel@tonic-gate int
lgrp_version(int version)11367c478bd9Sstevel@tonic-gate lgrp_version(int version)
11377c478bd9Sstevel@tonic-gate {
11387c478bd9Sstevel@tonic-gate /*
11397c478bd9Sstevel@tonic-gate * Return LGRP_VER_NONE when requested version isn't supported
11407c478bd9Sstevel@tonic-gate */
11417c478bd9Sstevel@tonic-gate if (version < LGRP_VER_NONE || version > LGRP_VER_CURRENT)
11427c478bd9Sstevel@tonic-gate return (LGRP_VER_NONE);
11437c478bd9Sstevel@tonic-gate
11447c478bd9Sstevel@tonic-gate /*
11457c478bd9Sstevel@tonic-gate * Return current version when LGRP_VER_NONE passed in
11467c478bd9Sstevel@tonic-gate */
11477c478bd9Sstevel@tonic-gate if (version == LGRP_VER_NONE)
11487c478bd9Sstevel@tonic-gate return (LGRP_VER_CURRENT);
11497c478bd9Sstevel@tonic-gate
11507c478bd9Sstevel@tonic-gate /*
11517c478bd9Sstevel@tonic-gate * Otherwise, return supported version.
11527c478bd9Sstevel@tonic-gate */
11537c478bd9Sstevel@tonic-gate return (version);
11547c478bd9Sstevel@tonic-gate }
11557c478bd9Sstevel@tonic-gate
11567c478bd9Sstevel@tonic-gate
11577c478bd9Sstevel@tonic-gate /*
11587c478bd9Sstevel@tonic-gate * Snapshot of lgroup hieararchy
11597c478bd9Sstevel@tonic-gate *
11607c478bd9Sstevel@tonic-gate * One snapshot is kept and is based on the kernel's native data model, so
11617c478bd9Sstevel@tonic-gate * a 32-bit snapshot is kept for the 32-bit kernel and a 64-bit one for the
11627c478bd9Sstevel@tonic-gate * 64-bit kernel. If a 32-bit user wants a snapshot from the 64-bit kernel,
11637c478bd9Sstevel@tonic-gate * the kernel generates a 32-bit snapshot from the data in its 64-bit snapshot.
11647c478bd9Sstevel@tonic-gate *
11657c478bd9Sstevel@tonic-gate * The format is defined by lgroup snapshot header and the layout of
11667c478bd9Sstevel@tonic-gate * the snapshot in memory is as follows:
11677c478bd9Sstevel@tonic-gate * 1) lgroup snapshot header
11687c478bd9Sstevel@tonic-gate * - specifies format of snapshot
11697c478bd9Sstevel@tonic-gate * - defined by lgrp_snapshot_header_t
11707c478bd9Sstevel@tonic-gate * 2) lgroup info array
11717c478bd9Sstevel@tonic-gate * - contains information about each lgroup
11727c478bd9Sstevel@tonic-gate * - one element for each lgroup
11737c478bd9Sstevel@tonic-gate * - each element is defined by lgrp_info_t
11747c478bd9Sstevel@tonic-gate * 3) lgroup CPU ID array
11757c478bd9Sstevel@tonic-gate * - contains list (array) of CPU IDs for each lgroup
11767c478bd9Sstevel@tonic-gate * - lgrp_info_t points into array and specifies how many CPUs belong to
11777c478bd9Sstevel@tonic-gate * given lgroup
11787c478bd9Sstevel@tonic-gate * 4) lgroup parents array
11797c478bd9Sstevel@tonic-gate * - contains lgroup bitmask of parents for each lgroup
11807c478bd9Sstevel@tonic-gate * - bitmask is an array of unsigned longs and its size depends on nlgrpsmax
11817c478bd9Sstevel@tonic-gate * 5) lgroup children array
11827c478bd9Sstevel@tonic-gate * - contains lgroup bitmask of children for each lgroup
11837c478bd9Sstevel@tonic-gate * - bitmask is an array of unsigned longs and its size depends on nlgrpsmax
11847c478bd9Sstevel@tonic-gate * 6) lgroup resources array
11857c478bd9Sstevel@tonic-gate * - contains lgroup bitmask of resources for each lgroup
11867c478bd9Sstevel@tonic-gate * - bitmask is an array of unsigned longs and its size depends on nlgrpsmax
11877c478bd9Sstevel@tonic-gate * 7) lgroup latency table
11887c478bd9Sstevel@tonic-gate * - contains latency from each lgroup to each of other lgroups
11897c478bd9Sstevel@tonic-gate *
11907c478bd9Sstevel@tonic-gate * NOTE: Must use nlgrpsmax for per lgroup data structures because lgroups
11917c478bd9Sstevel@tonic-gate * may be sparsely allocated.
11927c478bd9Sstevel@tonic-gate */
11937c478bd9Sstevel@tonic-gate lgrp_snapshot_header_t *lgrp_snap = NULL; /* lgroup snapshot */
11947c478bd9Sstevel@tonic-gate static kmutex_t lgrp_snap_lock; /* snapshot lock */
11957c478bd9Sstevel@tonic-gate
11967c478bd9Sstevel@tonic-gate
11977c478bd9Sstevel@tonic-gate /*
11987c478bd9Sstevel@tonic-gate * Take a snapshot of lgroup hierarchy and return size of buffer
11997c478bd9Sstevel@tonic-gate * needed to hold snapshot
12007c478bd9Sstevel@tonic-gate */
12017c478bd9Sstevel@tonic-gate static int
lgrp_snapshot(void)12027c478bd9Sstevel@tonic-gate lgrp_snapshot(void)
12037c478bd9Sstevel@tonic-gate {
12047c478bd9Sstevel@tonic-gate size_t bitmask_size;
12057c478bd9Sstevel@tonic-gate size_t bitmasks_size;
12067c478bd9Sstevel@tonic-gate size_t bufsize;
12077c478bd9Sstevel@tonic-gate int cpu_index;
12087c478bd9Sstevel@tonic-gate size_t cpuids_size;
12097c478bd9Sstevel@tonic-gate int i;
12107c478bd9Sstevel@tonic-gate int j;
12117c478bd9Sstevel@tonic-gate size_t info_size;
12127c478bd9Sstevel@tonic-gate size_t lats_size;
12137c478bd9Sstevel@tonic-gate ulong_t *lgrp_children;
12147c478bd9Sstevel@tonic-gate processorid_t *lgrp_cpuids;
12157c478bd9Sstevel@tonic-gate lgrp_info_t *lgrp_info;
12167c478bd9Sstevel@tonic-gate int **lgrp_lats;
12177c478bd9Sstevel@tonic-gate ulong_t *lgrp_parents;
12187c478bd9Sstevel@tonic-gate ulong_t *lgrp_rsets;
12197c478bd9Sstevel@tonic-gate ulong_t *lgrpset;
12207c478bd9Sstevel@tonic-gate int snap_ncpus;
12217c478bd9Sstevel@tonic-gate int snap_nlgrps;
12227c478bd9Sstevel@tonic-gate int snap_nlgrpsmax;
12237c478bd9Sstevel@tonic-gate size_t snap_hdr_size;
12247c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
12257c478bd9Sstevel@tonic-gate model_t model = DATAMODEL_NATIVE;
12267c478bd9Sstevel@tonic-gate
12277c478bd9Sstevel@tonic-gate /*
12287c478bd9Sstevel@tonic-gate * Have up-to-date snapshot, so check to see whether caller is 32-bit
12297c478bd9Sstevel@tonic-gate * program and need to return size of 32-bit snapshot now.
12307c478bd9Sstevel@tonic-gate */
12317c478bd9Sstevel@tonic-gate model = get_udatamodel();
12327c478bd9Sstevel@tonic-gate if (model == DATAMODEL_ILP32 && lgrp_snap &&
12337c478bd9Sstevel@tonic-gate lgrp_snap->ss_gen == lgrp_gen) {
12347c478bd9Sstevel@tonic-gate
12357c478bd9Sstevel@tonic-gate snap_nlgrpsmax = lgrp_snap->ss_nlgrps_max;
12367c478bd9Sstevel@tonic-gate
12377c478bd9Sstevel@tonic-gate /*
12387c478bd9Sstevel@tonic-gate * Calculate size of buffer needed for 32-bit snapshot,
12397c478bd9Sstevel@tonic-gate * rounding up size of each object to allow for alignment
12407c478bd9Sstevel@tonic-gate * of next object in buffer.
12417c478bd9Sstevel@tonic-gate */
12427c478bd9Sstevel@tonic-gate snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header32_t),
12437c478bd9Sstevel@tonic-gate sizeof (caddr32_t));
12447c478bd9Sstevel@tonic-gate info_size =
12457c478bd9Sstevel@tonic-gate P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info32_t),
12467c478bd9Sstevel@tonic-gate sizeof (processorid_t));
12477c478bd9Sstevel@tonic-gate cpuids_size =
12487c478bd9Sstevel@tonic-gate P2ROUNDUP(lgrp_snap->ss_ncpus * sizeof (processorid_t),
12497c478bd9Sstevel@tonic-gate sizeof (ulong_t));
12507c478bd9Sstevel@tonic-gate
12517c478bd9Sstevel@tonic-gate /*
12527c478bd9Sstevel@tonic-gate * lgroup bitmasks needed for parents, children, and resources
12537c478bd9Sstevel@tonic-gate * for each lgroup and pset lgroup set
12547c478bd9Sstevel@tonic-gate */
12557c478bd9Sstevel@tonic-gate bitmask_size = BT_SIZEOFMAP(snap_nlgrpsmax);
12567c478bd9Sstevel@tonic-gate bitmasks_size = (((2 + LGRP_RSRC_COUNT) *
12577c478bd9Sstevel@tonic-gate snap_nlgrpsmax) + 1) * bitmask_size;
12587c478bd9Sstevel@tonic-gate
12597c478bd9Sstevel@tonic-gate /*
12607c478bd9Sstevel@tonic-gate * Size of latency table and buffer
12617c478bd9Sstevel@tonic-gate */
12627c478bd9Sstevel@tonic-gate lats_size = snap_nlgrpsmax * sizeof (caddr32_t) +
12637c478bd9Sstevel@tonic-gate snap_nlgrpsmax * snap_nlgrpsmax * sizeof (int);
12647c478bd9Sstevel@tonic-gate
12657c478bd9Sstevel@tonic-gate bufsize = snap_hdr_size + info_size + cpuids_size +
12667c478bd9Sstevel@tonic-gate bitmasks_size + lats_size;
12677c478bd9Sstevel@tonic-gate return (bufsize);
12687c478bd9Sstevel@tonic-gate }
12697c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
12707c478bd9Sstevel@tonic-gate
12717c478bd9Sstevel@tonic-gate /*
12727c478bd9Sstevel@tonic-gate * Check whether snapshot is up-to-date
12737c478bd9Sstevel@tonic-gate * Free it and take another one if not
12747c478bd9Sstevel@tonic-gate */
12757c478bd9Sstevel@tonic-gate if (lgrp_snap) {
12767c478bd9Sstevel@tonic-gate if (lgrp_snap->ss_gen == lgrp_gen)
12777c478bd9Sstevel@tonic-gate return (lgrp_snap->ss_size);
12787c478bd9Sstevel@tonic-gate
12797c478bd9Sstevel@tonic-gate kmem_free(lgrp_snap, lgrp_snap->ss_size);
12807c478bd9Sstevel@tonic-gate lgrp_snap = NULL;
12817c478bd9Sstevel@tonic-gate }
12827c478bd9Sstevel@tonic-gate
12837c478bd9Sstevel@tonic-gate /*
12847c478bd9Sstevel@tonic-gate * Allocate memory for snapshot
12857c478bd9Sstevel@tonic-gate * w/o holding cpu_lock while waiting for memory
12867c478bd9Sstevel@tonic-gate */
12877c478bd9Sstevel@tonic-gate while (lgrp_snap == NULL) {
12887c478bd9Sstevel@tonic-gate int old_generation;
12897c478bd9Sstevel@tonic-gate
12907c478bd9Sstevel@tonic-gate /*
12917c478bd9Sstevel@tonic-gate * Take snapshot of lgroup generation number
12927c478bd9Sstevel@tonic-gate * and configuration size dependent information
12937c478bd9Sstevel@tonic-gate * NOTE: Only count number of online CPUs,
12947c478bd9Sstevel@tonic-gate * since only online CPUs appear in lgroups.
12957c478bd9Sstevel@tonic-gate */
12967c478bd9Sstevel@tonic-gate mutex_enter(&cpu_lock);
12977c478bd9Sstevel@tonic-gate old_generation = lgrp_gen;
12987c478bd9Sstevel@tonic-gate snap_ncpus = ncpus_online;
12997c478bd9Sstevel@tonic-gate snap_nlgrps = nlgrps;
13007c478bd9Sstevel@tonic-gate snap_nlgrpsmax = nlgrpsmax;
13017c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock);
13027c478bd9Sstevel@tonic-gate
13037c478bd9Sstevel@tonic-gate /*
13047c478bd9Sstevel@tonic-gate * Calculate size of buffer needed for snapshot,
13057c478bd9Sstevel@tonic-gate * rounding up size of each object to allow for alignment
13067c478bd9Sstevel@tonic-gate * of next object in buffer.
13077c478bd9Sstevel@tonic-gate */
13087c478bd9Sstevel@tonic-gate snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header_t),
13097c478bd9Sstevel@tonic-gate sizeof (void *));
13107c478bd9Sstevel@tonic-gate info_size = P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info_t),
13117c478bd9Sstevel@tonic-gate sizeof (processorid_t));
13127c478bd9Sstevel@tonic-gate cpuids_size = P2ROUNDUP(snap_ncpus * sizeof (processorid_t),
13137c478bd9Sstevel@tonic-gate sizeof (ulong_t));
13147c478bd9Sstevel@tonic-gate /*
13157c478bd9Sstevel@tonic-gate * lgroup bitmasks needed for pset lgroup set and parents,
13167c478bd9Sstevel@tonic-gate * children, and resource sets for each lgroup
13177c478bd9Sstevel@tonic-gate */
13187c478bd9Sstevel@tonic-gate bitmask_size = BT_SIZEOFMAP(snap_nlgrpsmax);
13197c478bd9Sstevel@tonic-gate bitmasks_size = (((2 + LGRP_RSRC_COUNT) *
13207c478bd9Sstevel@tonic-gate snap_nlgrpsmax) + 1) * bitmask_size;
13217c478bd9Sstevel@tonic-gate
13227c478bd9Sstevel@tonic-gate /*
13237c478bd9Sstevel@tonic-gate * Size of latency table and buffer
13247c478bd9Sstevel@tonic-gate */
13257c478bd9Sstevel@tonic-gate lats_size = snap_nlgrpsmax * sizeof (int *) +
13267c478bd9Sstevel@tonic-gate snap_nlgrpsmax * snap_nlgrpsmax * sizeof (int);
13277c478bd9Sstevel@tonic-gate
13287c478bd9Sstevel@tonic-gate bufsize = snap_hdr_size + info_size + cpuids_size +
13297c478bd9Sstevel@tonic-gate bitmasks_size + lats_size;
13307c478bd9Sstevel@tonic-gate
13317c478bd9Sstevel@tonic-gate /*
13327c478bd9Sstevel@tonic-gate * Allocate memory for buffer
13337c478bd9Sstevel@tonic-gate */
13347c478bd9Sstevel@tonic-gate lgrp_snap = kmem_zalloc(bufsize, KM_NOSLEEP);
13357c478bd9Sstevel@tonic-gate if (lgrp_snap == NULL)
13367c478bd9Sstevel@tonic-gate return (set_errno(ENOMEM));
13377c478bd9Sstevel@tonic-gate
13387c478bd9Sstevel@tonic-gate /*
13397c478bd9Sstevel@tonic-gate * Check whether generation number has changed
13407c478bd9Sstevel@tonic-gate */
13417c478bd9Sstevel@tonic-gate mutex_enter(&cpu_lock);
13427c478bd9Sstevel@tonic-gate if (lgrp_gen == old_generation)
13437c478bd9Sstevel@tonic-gate break; /* hasn't change, so done. */
13447c478bd9Sstevel@tonic-gate
13457c478bd9Sstevel@tonic-gate /*
13467c478bd9Sstevel@tonic-gate * Generation number changed, so free memory and try again.
13477c478bd9Sstevel@tonic-gate */
13487c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock);
13497c478bd9Sstevel@tonic-gate kmem_free(lgrp_snap, bufsize);
13507c478bd9Sstevel@tonic-gate lgrp_snap = NULL;
13517c478bd9Sstevel@tonic-gate }
13527c478bd9Sstevel@tonic-gate
13537c478bd9Sstevel@tonic-gate /*
13547c478bd9Sstevel@tonic-gate * Fill in lgroup snapshot header
13557c478bd9Sstevel@tonic-gate * (including pointers to tables of lgroup info, CPU IDs, and parents
13567c478bd9Sstevel@tonic-gate * and children)
13577c478bd9Sstevel@tonic-gate */
13587c478bd9Sstevel@tonic-gate lgrp_snap->ss_version = LGRP_VER_CURRENT;
13597c478bd9Sstevel@tonic-gate
13607c478bd9Sstevel@tonic-gate /*
13617c478bd9Sstevel@tonic-gate * XXX For now, liblgrp only needs to know whether the hierarchy
13627c478bd9Sstevel@tonic-gate * XXX only has one level or not
13637c478bd9Sstevel@tonic-gate */
13647c478bd9Sstevel@tonic-gate if (snap_nlgrps == 1)
13657c478bd9Sstevel@tonic-gate lgrp_snap->ss_levels = 1;
13667c478bd9Sstevel@tonic-gate else
13677c478bd9Sstevel@tonic-gate lgrp_snap->ss_levels = 2;
13687c478bd9Sstevel@tonic-gate
13697c478bd9Sstevel@tonic-gate lgrp_snap->ss_root = LGRP_ROOTID;
13707c478bd9Sstevel@tonic-gate
13717c478bd9Sstevel@tonic-gate lgrp_snap->ss_nlgrps = lgrp_snap->ss_nlgrps_os = snap_nlgrps;
13727c478bd9Sstevel@tonic-gate lgrp_snap->ss_nlgrps_max = snap_nlgrpsmax;
13737c478bd9Sstevel@tonic-gate lgrp_snap->ss_ncpus = snap_ncpus;
13747c478bd9Sstevel@tonic-gate lgrp_snap->ss_gen = lgrp_gen;
13757c478bd9Sstevel@tonic-gate lgrp_snap->ss_view = LGRP_VIEW_OS;
13767c478bd9Sstevel@tonic-gate lgrp_snap->ss_pset = 0; /* NOTE: caller should set if needed */
13777c478bd9Sstevel@tonic-gate lgrp_snap->ss_size = bufsize;
13787c478bd9Sstevel@tonic-gate lgrp_snap->ss_magic = (uintptr_t)lgrp_snap;
13797c478bd9Sstevel@tonic-gate
13807c478bd9Sstevel@tonic-gate lgrp_snap->ss_info = lgrp_info =
13817c478bd9Sstevel@tonic-gate (lgrp_info_t *)((uintptr_t)lgrp_snap + snap_hdr_size);
13827c478bd9Sstevel@tonic-gate
13837c478bd9Sstevel@tonic-gate lgrp_snap->ss_cpuids = lgrp_cpuids =
13847c478bd9Sstevel@tonic-gate (processorid_t *)((uintptr_t)lgrp_info + info_size);
13857c478bd9Sstevel@tonic-gate
13867c478bd9Sstevel@tonic-gate lgrp_snap->ss_lgrpset = lgrpset =
13877c478bd9Sstevel@tonic-gate (ulong_t *)((uintptr_t)lgrp_cpuids + cpuids_size);
13887c478bd9Sstevel@tonic-gate
13897c478bd9Sstevel@tonic-gate lgrp_snap->ss_parents = lgrp_parents =
13907c478bd9Sstevel@tonic-gate (ulong_t *)((uintptr_t)lgrpset + bitmask_size);
13917c478bd9Sstevel@tonic-gate
13927c478bd9Sstevel@tonic-gate lgrp_snap->ss_children = lgrp_children =
13937c478bd9Sstevel@tonic-gate (ulong_t *)((uintptr_t)lgrp_parents + (snap_nlgrpsmax *
13947c478bd9Sstevel@tonic-gate bitmask_size));
13957c478bd9Sstevel@tonic-gate
13967c478bd9Sstevel@tonic-gate lgrp_snap->ss_rsets = lgrp_rsets =
13977c478bd9Sstevel@tonic-gate (ulong_t *)((uintptr_t)lgrp_children + (snap_nlgrpsmax *
13987c478bd9Sstevel@tonic-gate bitmask_size));
13997c478bd9Sstevel@tonic-gate
14007c478bd9Sstevel@tonic-gate lgrp_snap->ss_latencies = lgrp_lats =
14017c478bd9Sstevel@tonic-gate (int **)((uintptr_t)lgrp_rsets + (LGRP_RSRC_COUNT *
14027c478bd9Sstevel@tonic-gate snap_nlgrpsmax * bitmask_size));
14037c478bd9Sstevel@tonic-gate
14047c478bd9Sstevel@tonic-gate /*
14057c478bd9Sstevel@tonic-gate * Fill in lgroup information
14067c478bd9Sstevel@tonic-gate */
14077c478bd9Sstevel@tonic-gate cpu_index = 0;
14087c478bd9Sstevel@tonic-gate for (i = 0; i < snap_nlgrpsmax; i++) {
14097c478bd9Sstevel@tonic-gate struct cpu *cp;
14107c478bd9Sstevel@tonic-gate int cpu_count;
14117c478bd9Sstevel@tonic-gate struct cpu *head;
14127c478bd9Sstevel@tonic-gate int k;
14137c478bd9Sstevel@tonic-gate lgrp_t *lgrp;
14147c478bd9Sstevel@tonic-gate
14157c478bd9Sstevel@tonic-gate lgrp = lgrp_table[i];
14167c478bd9Sstevel@tonic-gate if (!LGRP_EXISTS(lgrp)) {
14177c478bd9Sstevel@tonic-gate bzero(&lgrp_info[i], sizeof (lgrp_info[i]));
14187c478bd9Sstevel@tonic-gate lgrp_info[i].info_lgrpid = LGRP_NONE;
14197c478bd9Sstevel@tonic-gate continue;
14207c478bd9Sstevel@tonic-gate }
14217c478bd9Sstevel@tonic-gate
14227c478bd9Sstevel@tonic-gate lgrp_info[i].info_lgrpid = i;
14237c478bd9Sstevel@tonic-gate lgrp_info[i].info_latency = lgrp->lgrp_latency;
14247c478bd9Sstevel@tonic-gate
14257c478bd9Sstevel@tonic-gate /*
14267c478bd9Sstevel@tonic-gate * Fill in parents, children, and lgroup resources
14277c478bd9Sstevel@tonic-gate */
14287c478bd9Sstevel@tonic-gate lgrp_info[i].info_parents =
14297c478bd9Sstevel@tonic-gate (ulong_t *)((uintptr_t)lgrp_parents + (i * bitmask_size));
14307c478bd9Sstevel@tonic-gate
14317c478bd9Sstevel@tonic-gate if (lgrp->lgrp_parent)
14327c478bd9Sstevel@tonic-gate BT_SET(lgrp_info[i].info_parents,
14337c478bd9Sstevel@tonic-gate lgrp->lgrp_parent->lgrp_id);
14347c478bd9Sstevel@tonic-gate
14357c478bd9Sstevel@tonic-gate lgrp_info[i].info_children =
14367c478bd9Sstevel@tonic-gate (ulong_t *)((uintptr_t)lgrp_children + (i * bitmask_size));
14377c478bd9Sstevel@tonic-gate
14387c478bd9Sstevel@tonic-gate for (j = 0; j < snap_nlgrpsmax; j++)
14397c478bd9Sstevel@tonic-gate if (klgrpset_ismember(lgrp->lgrp_children, j))
14407c478bd9Sstevel@tonic-gate BT_SET(lgrp_info[i].info_children, j);
14417c478bd9Sstevel@tonic-gate
14427c478bd9Sstevel@tonic-gate lgrp_info[i].info_rset =
14437c478bd9Sstevel@tonic-gate (ulong_t *)((uintptr_t)lgrp_rsets +
14447c478bd9Sstevel@tonic-gate (i * LGRP_RSRC_COUNT * bitmask_size));
14457c478bd9Sstevel@tonic-gate
14467c478bd9Sstevel@tonic-gate for (j = 0; j < LGRP_RSRC_COUNT; j++) {
14477c478bd9Sstevel@tonic-gate ulong_t *rset;
14487c478bd9Sstevel@tonic-gate
14497c478bd9Sstevel@tonic-gate rset = (ulong_t *)((uintptr_t)lgrp_info[i].info_rset +
14507c478bd9Sstevel@tonic-gate (j * bitmask_size));
14517c478bd9Sstevel@tonic-gate for (k = 0; k < snap_nlgrpsmax; k++)
14527c478bd9Sstevel@tonic-gate if (klgrpset_ismember(lgrp->lgrp_set[j], k))
14537c478bd9Sstevel@tonic-gate BT_SET(rset, k);
14547c478bd9Sstevel@tonic-gate }
14557c478bd9Sstevel@tonic-gate
14567c478bd9Sstevel@tonic-gate /*
14577c478bd9Sstevel@tonic-gate * Fill in CPU IDs
14587c478bd9Sstevel@tonic-gate */
14597c478bd9Sstevel@tonic-gate cpu_count = 0;
14607c478bd9Sstevel@tonic-gate lgrp_info[i].info_cpuids = NULL;
14617c478bd9Sstevel@tonic-gate cp = head = lgrp->lgrp_cpu;
14627c478bd9Sstevel@tonic-gate if (head != NULL) {
14637c478bd9Sstevel@tonic-gate lgrp_info[i].info_cpuids = &lgrp_cpuids[cpu_index];
14647c478bd9Sstevel@tonic-gate do {
14657c478bd9Sstevel@tonic-gate lgrp_cpuids[cpu_index] = cp->cpu_id;
14667c478bd9Sstevel@tonic-gate cpu_index++;
14677c478bd9Sstevel@tonic-gate cpu_count++;
14687c478bd9Sstevel@tonic-gate cp = cp->cpu_next_lgrp;
14697c478bd9Sstevel@tonic-gate } while (cp != head);
14707c478bd9Sstevel@tonic-gate }
14717c478bd9Sstevel@tonic-gate ASSERT(cpu_count == lgrp->lgrp_cpucnt);
14727c478bd9Sstevel@tonic-gate lgrp_info[i].info_ncpus = cpu_count;
14737c478bd9Sstevel@tonic-gate
14747c478bd9Sstevel@tonic-gate /*
14757c478bd9Sstevel@tonic-gate * Fill in memory sizes for lgroups that directly contain
14767c478bd9Sstevel@tonic-gate * memory
14777c478bd9Sstevel@tonic-gate */
14787c478bd9Sstevel@tonic-gate if (klgrpset_ismember(lgrp->lgrp_set[LGRP_RSRC_MEM], i)) {
14797c478bd9Sstevel@tonic-gate lgrp_info[i].info_mem_free =
14807c478bd9Sstevel@tonic-gate lgrp_mem_size(i, LGRP_MEM_SIZE_FREE);
14817c478bd9Sstevel@tonic-gate lgrp_info[i].info_mem_install =
14827c478bd9Sstevel@tonic-gate lgrp_mem_size(i, LGRP_MEM_SIZE_INSTALL);
14837c478bd9Sstevel@tonic-gate }
14847c478bd9Sstevel@tonic-gate
14857c478bd9Sstevel@tonic-gate /*
14867c478bd9Sstevel@tonic-gate * Fill in latency table and buffer
14877c478bd9Sstevel@tonic-gate */
14887c478bd9Sstevel@tonic-gate lgrp_lats[i] = (int *)((uintptr_t)lgrp_lats + snap_nlgrpsmax *
14897c478bd9Sstevel@tonic-gate sizeof (int *) + i * snap_nlgrpsmax * sizeof (int));
14907c478bd9Sstevel@tonic-gate for (j = 0; j < snap_nlgrpsmax; j++) {
14917c478bd9Sstevel@tonic-gate lgrp_t *to;
14927c478bd9Sstevel@tonic-gate
14937c478bd9Sstevel@tonic-gate to = lgrp_table[j];
14947c478bd9Sstevel@tonic-gate if (!LGRP_EXISTS(to))
14957c478bd9Sstevel@tonic-gate continue;
14967c478bd9Sstevel@tonic-gate lgrp_lats[i][j] = lgrp_latency(lgrp->lgrp_id,
14977c478bd9Sstevel@tonic-gate to->lgrp_id);
14987c478bd9Sstevel@tonic-gate }
14997c478bd9Sstevel@tonic-gate }
15007c478bd9Sstevel@tonic-gate ASSERT(cpu_index == snap_ncpus);
15017c478bd9Sstevel@tonic-gate
15027c478bd9Sstevel@tonic-gate
15037c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock);
15047c478bd9Sstevel@tonic-gate
15057c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
15067c478bd9Sstevel@tonic-gate /*
15077c478bd9Sstevel@tonic-gate * Check to see whether caller is 32-bit program and need to return
15087c478bd9Sstevel@tonic-gate * size of 32-bit snapshot now that snapshot has been taken/updated.
15097c478bd9Sstevel@tonic-gate * May not have been able to do this earlier if snapshot was out of
15107c478bd9Sstevel@tonic-gate * date or didn't exist yet.
15117c478bd9Sstevel@tonic-gate */
15127c478bd9Sstevel@tonic-gate if (model == DATAMODEL_ILP32) {
15137c478bd9Sstevel@tonic-gate
15147c478bd9Sstevel@tonic-gate snap_nlgrpsmax = lgrp_snap->ss_nlgrps_max;
15157c478bd9Sstevel@tonic-gate
15167c478bd9Sstevel@tonic-gate /*
15177c478bd9Sstevel@tonic-gate * Calculate size of buffer needed for 32-bit snapshot,
15187c478bd9Sstevel@tonic-gate * rounding up size of each object to allow for alignment
15197c478bd9Sstevel@tonic-gate * of next object in buffer.
15207c478bd9Sstevel@tonic-gate */
15217c478bd9Sstevel@tonic-gate snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header32_t),
15227c478bd9Sstevel@tonic-gate sizeof (caddr32_t));
15237c478bd9Sstevel@tonic-gate info_size =
15247c478bd9Sstevel@tonic-gate P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info32_t),
15257c478bd9Sstevel@tonic-gate sizeof (processorid_t));
15267c478bd9Sstevel@tonic-gate cpuids_size =
15277c478bd9Sstevel@tonic-gate P2ROUNDUP(lgrp_snap->ss_ncpus * sizeof (processorid_t),
15287c478bd9Sstevel@tonic-gate sizeof (ulong_t));
15297c478bd9Sstevel@tonic-gate
15307c478bd9Sstevel@tonic-gate bitmask_size = BT_SIZEOFMAP(snap_nlgrpsmax);
15317c478bd9Sstevel@tonic-gate bitmasks_size = (((2 + LGRP_RSRC_COUNT) * snap_nlgrpsmax) +
15327c478bd9Sstevel@tonic-gate 1) * bitmask_size;
15337c478bd9Sstevel@tonic-gate
15347c478bd9Sstevel@tonic-gate
15357c478bd9Sstevel@tonic-gate /*
15367c478bd9Sstevel@tonic-gate * Size of latency table and buffer
15377c478bd9Sstevel@tonic-gate */
15387c478bd9Sstevel@tonic-gate lats_size = (snap_nlgrpsmax * sizeof (caddr32_t)) +
15397c478bd9Sstevel@tonic-gate (snap_nlgrpsmax * snap_nlgrpsmax * sizeof (int));
15407c478bd9Sstevel@tonic-gate
15417c478bd9Sstevel@tonic-gate bufsize = snap_hdr_size + info_size + cpuids_size +
15427c478bd9Sstevel@tonic-gate bitmasks_size + lats_size;
15437c478bd9Sstevel@tonic-gate return (bufsize);
15447c478bd9Sstevel@tonic-gate }
15457c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
15467c478bd9Sstevel@tonic-gate
15477c478bd9Sstevel@tonic-gate return (lgrp_snap->ss_size);
15487c478bd9Sstevel@tonic-gate }
15497c478bd9Sstevel@tonic-gate
15507c478bd9Sstevel@tonic-gate
15517c478bd9Sstevel@tonic-gate /*
15527c478bd9Sstevel@tonic-gate * Copy snapshot into given user buffer, fix up any pointers in buffer to point
15537c478bd9Sstevel@tonic-gate * into user instead of kernel address space, and return size of buffer
15547c478bd9Sstevel@tonic-gate * needed to hold snapshot
15557c478bd9Sstevel@tonic-gate */
15567c478bd9Sstevel@tonic-gate static int
lgrp_snapshot_copy(char * buf,size_t bufsize)15577c478bd9Sstevel@tonic-gate lgrp_snapshot_copy(char *buf, size_t bufsize)
15587c478bd9Sstevel@tonic-gate {
15597c478bd9Sstevel@tonic-gate size_t bitmask_size;
15607c478bd9Sstevel@tonic-gate int cpu_index;
15617c478bd9Sstevel@tonic-gate size_t cpuids_size;
15627c478bd9Sstevel@tonic-gate int i;
15637c478bd9Sstevel@tonic-gate size_t info_size;
15647c478bd9Sstevel@tonic-gate lgrp_info_t *lgrp_info;
15657c478bd9Sstevel@tonic-gate int retval;
15667c478bd9Sstevel@tonic-gate size_t snap_hdr_size;
15677c478bd9Sstevel@tonic-gate int snap_ncpus;
15687c478bd9Sstevel@tonic-gate int snap_nlgrpsmax;
15697c478bd9Sstevel@tonic-gate lgrp_snapshot_header_t *user_snap;
15707c478bd9Sstevel@tonic-gate lgrp_info_t *user_info;
15717c478bd9Sstevel@tonic-gate lgrp_info_t *user_info_buffer;
15727c478bd9Sstevel@tonic-gate processorid_t *user_cpuids;
15737c478bd9Sstevel@tonic-gate ulong_t *user_lgrpset;
15747c478bd9Sstevel@tonic-gate ulong_t *user_parents;
15757c478bd9Sstevel@tonic-gate ulong_t *user_children;
15767c478bd9Sstevel@tonic-gate int **user_lats;
15777c478bd9Sstevel@tonic-gate int **user_lats_buffer;
15787c478bd9Sstevel@tonic-gate ulong_t *user_rsets;
15797c478bd9Sstevel@tonic-gate
15807c478bd9Sstevel@tonic-gate if (lgrp_snap == NULL)
15817c478bd9Sstevel@tonic-gate return (0);
15827c478bd9Sstevel@tonic-gate
15837c478bd9Sstevel@tonic-gate if (buf == NULL || bufsize <= 0)
15847c478bd9Sstevel@tonic-gate return (lgrp_snap->ss_size);
15857c478bd9Sstevel@tonic-gate
15867c478bd9Sstevel@tonic-gate /*
15877c478bd9Sstevel@tonic-gate * User needs to try getting size of buffer again
15887c478bd9Sstevel@tonic-gate * because given buffer size is too small.
15897c478bd9Sstevel@tonic-gate * The lgroup hierarchy may have changed after they asked for the size
15907c478bd9Sstevel@tonic-gate * but before the snapshot was taken.
15917c478bd9Sstevel@tonic-gate */
15927c478bd9Sstevel@tonic-gate if (bufsize < lgrp_snap->ss_size)
15937c478bd9Sstevel@tonic-gate return (set_errno(EAGAIN));
15947c478bd9Sstevel@tonic-gate
15957c478bd9Sstevel@tonic-gate snap_ncpus = lgrp_snap->ss_ncpus;
15967c478bd9Sstevel@tonic-gate snap_nlgrpsmax = lgrp_snap->ss_nlgrps_max;
15977c478bd9Sstevel@tonic-gate
15987c478bd9Sstevel@tonic-gate /*
15997c478bd9Sstevel@tonic-gate * Fill in lgrpset now because caller may have change psets
16007c478bd9Sstevel@tonic-gate */
16017c478bd9Sstevel@tonic-gate kpreempt_disable();
16027c478bd9Sstevel@tonic-gate for (i = 0; i < snap_nlgrpsmax; i++) {
16037c478bd9Sstevel@tonic-gate if (klgrpset_ismember(curthread->t_cpupart->cp_lgrpset,
16047c478bd9Sstevel@tonic-gate i)) {
16057c478bd9Sstevel@tonic-gate BT_SET(lgrp_snap->ss_lgrpset, i);
16067c478bd9Sstevel@tonic-gate }
16077c478bd9Sstevel@tonic-gate }
16087c478bd9Sstevel@tonic-gate kpreempt_enable();
16097c478bd9Sstevel@tonic-gate
16107c478bd9Sstevel@tonic-gate /*
16117c478bd9Sstevel@tonic-gate * Copy lgroup snapshot (snapshot header, lgroup info, and CPU IDs)
16127c478bd9Sstevel@tonic-gate * into user buffer all at once
16137c478bd9Sstevel@tonic-gate */
16147c478bd9Sstevel@tonic-gate if (copyout(lgrp_snap, buf, lgrp_snap->ss_size) != 0)
16157c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
16167c478bd9Sstevel@tonic-gate
16177c478bd9Sstevel@tonic-gate /*
16187c478bd9Sstevel@tonic-gate * Round up sizes of lgroup snapshot header and info for alignment
16197c478bd9Sstevel@tonic-gate */
16207c478bd9Sstevel@tonic-gate snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header_t),
16217c478bd9Sstevel@tonic-gate sizeof (void *));
16227c478bd9Sstevel@tonic-gate info_size = P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info_t),
16237c478bd9Sstevel@tonic-gate sizeof (processorid_t));
16247c478bd9Sstevel@tonic-gate cpuids_size = P2ROUNDUP(snap_ncpus * sizeof (processorid_t),
16257c478bd9Sstevel@tonic-gate sizeof (ulong_t));
16267c478bd9Sstevel@tonic-gate
16277c478bd9Sstevel@tonic-gate bitmask_size = BT_SIZEOFMAP(snap_nlgrpsmax);
16287c478bd9Sstevel@tonic-gate
16297c478bd9Sstevel@tonic-gate /*
16307c478bd9Sstevel@tonic-gate * Calculate pointers into user buffer for lgroup snapshot header,
16317c478bd9Sstevel@tonic-gate * info, and CPU IDs
16327c478bd9Sstevel@tonic-gate */
16337c478bd9Sstevel@tonic-gate user_snap = (lgrp_snapshot_header_t *)buf;
16347c478bd9Sstevel@tonic-gate user_info = (lgrp_info_t *)((uintptr_t)user_snap + snap_hdr_size);
16357c478bd9Sstevel@tonic-gate user_cpuids = (processorid_t *)((uintptr_t)user_info + info_size);
16367c478bd9Sstevel@tonic-gate user_lgrpset = (ulong_t *)((uintptr_t)user_cpuids + cpuids_size);
16377c478bd9Sstevel@tonic-gate user_parents = (ulong_t *)((uintptr_t)user_lgrpset + bitmask_size);
16387c478bd9Sstevel@tonic-gate user_children = (ulong_t *)((uintptr_t)user_parents +
16397c478bd9Sstevel@tonic-gate (snap_nlgrpsmax * bitmask_size));
16407c478bd9Sstevel@tonic-gate user_rsets = (ulong_t *)((uintptr_t)user_children +
16417c478bd9Sstevel@tonic-gate (snap_nlgrpsmax * bitmask_size));
16427c478bd9Sstevel@tonic-gate user_lats = (int **)((uintptr_t)user_rsets +
16437c478bd9Sstevel@tonic-gate (LGRP_RSRC_COUNT * snap_nlgrpsmax * bitmask_size));
16447c478bd9Sstevel@tonic-gate
16457c478bd9Sstevel@tonic-gate /*
16467c478bd9Sstevel@tonic-gate * Copyout magic number (ie. pointer to beginning of buffer)
16477c478bd9Sstevel@tonic-gate */
16487c478bd9Sstevel@tonic-gate if (copyout(&buf, &user_snap->ss_magic, sizeof (buf)) != 0)
16497c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
16507c478bd9Sstevel@tonic-gate
16517c478bd9Sstevel@tonic-gate /*
16527c478bd9Sstevel@tonic-gate * Fix up pointers in user buffer to point into user buffer
16537c478bd9Sstevel@tonic-gate * not kernel snapshot
16547c478bd9Sstevel@tonic-gate */
16557c478bd9Sstevel@tonic-gate if (copyout(&user_info, &user_snap->ss_info, sizeof (user_info)) != 0)
16567c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
16577c478bd9Sstevel@tonic-gate
16587c478bd9Sstevel@tonic-gate if (copyout(&user_cpuids, &user_snap->ss_cpuids,
16597c478bd9Sstevel@tonic-gate sizeof (user_cpuids)) != 0)
16607c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
16617c478bd9Sstevel@tonic-gate
16627c478bd9Sstevel@tonic-gate if (copyout(&user_lgrpset, &user_snap->ss_lgrpset,
16637c478bd9Sstevel@tonic-gate sizeof (user_lgrpset)) != 0)
16647c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
16657c478bd9Sstevel@tonic-gate
16667c478bd9Sstevel@tonic-gate if (copyout(&user_parents, &user_snap->ss_parents,
16677c478bd9Sstevel@tonic-gate sizeof (user_parents)) != 0)
16687c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
16697c478bd9Sstevel@tonic-gate
16707c478bd9Sstevel@tonic-gate if (copyout(&user_children, &user_snap->ss_children,
16717c478bd9Sstevel@tonic-gate sizeof (user_children)) != 0)
16727c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
16737c478bd9Sstevel@tonic-gate
16747c478bd9Sstevel@tonic-gate if (copyout(&user_rsets, &user_snap->ss_rsets,
16757c478bd9Sstevel@tonic-gate sizeof (user_rsets)) != 0)
16767c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
16777c478bd9Sstevel@tonic-gate
16787c478bd9Sstevel@tonic-gate if (copyout(&user_lats, &user_snap->ss_latencies,
16797c478bd9Sstevel@tonic-gate sizeof (user_lats)) != 0)
16807c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
16817c478bd9Sstevel@tonic-gate
16827c478bd9Sstevel@tonic-gate /*
16837c478bd9Sstevel@tonic-gate * Make copies of lgroup info and latency table, fix up pointers,
16847c478bd9Sstevel@tonic-gate * and then copy them into user buffer
16857c478bd9Sstevel@tonic-gate */
16867c478bd9Sstevel@tonic-gate user_info_buffer = kmem_zalloc(info_size, KM_NOSLEEP);
16877c478bd9Sstevel@tonic-gate if (user_info_buffer == NULL)
16887c478bd9Sstevel@tonic-gate return (set_errno(ENOMEM));
16897c478bd9Sstevel@tonic-gate
16907c478bd9Sstevel@tonic-gate user_lats_buffer = kmem_zalloc(snap_nlgrpsmax * sizeof (int *),
16917c478bd9Sstevel@tonic-gate KM_NOSLEEP);
16927c478bd9Sstevel@tonic-gate if (user_lats_buffer == NULL) {
16937c478bd9Sstevel@tonic-gate kmem_free(user_info_buffer, info_size);
16947c478bd9Sstevel@tonic-gate return (set_errno(ENOMEM));
16957c478bd9Sstevel@tonic-gate }
16967c478bd9Sstevel@tonic-gate
16977c478bd9Sstevel@tonic-gate lgrp_info = (lgrp_info_t *)((uintptr_t)lgrp_snap + snap_hdr_size);
16987c478bd9Sstevel@tonic-gate bcopy(lgrp_info, user_info_buffer, info_size);
16997c478bd9Sstevel@tonic-gate
17007c478bd9Sstevel@tonic-gate cpu_index = 0;
17017c478bd9Sstevel@tonic-gate for (i = 0; i < snap_nlgrpsmax; i++) {
17027c478bd9Sstevel@tonic-gate ulong_t *snap_rset;
17037c478bd9Sstevel@tonic-gate
17047c478bd9Sstevel@tonic-gate /*
17057c478bd9Sstevel@tonic-gate * Skip non-existent lgroups
17067c478bd9Sstevel@tonic-gate */
17077c478bd9Sstevel@tonic-gate if (user_info_buffer[i].info_lgrpid == LGRP_NONE)
17087c478bd9Sstevel@tonic-gate continue;
17097c478bd9Sstevel@tonic-gate
17107c478bd9Sstevel@tonic-gate /*
17117c478bd9Sstevel@tonic-gate * Update free memory size since it changes frequently
17127c478bd9Sstevel@tonic-gate * Only do so for lgroups directly containing memory
17137c478bd9Sstevel@tonic-gate *
17147c478bd9Sstevel@tonic-gate * NOTE: This must be done before changing the pointers to
17157c478bd9Sstevel@tonic-gate * point into user space since we need to dereference
17167c478bd9Sstevel@tonic-gate * lgroup resource set
17177c478bd9Sstevel@tonic-gate */
17187c478bd9Sstevel@tonic-gate snap_rset = &lgrp_info[i].info_rset[LGRP_RSRC_MEM *
17197c478bd9Sstevel@tonic-gate BT_BITOUL(snap_nlgrpsmax)];
17207c478bd9Sstevel@tonic-gate if (BT_TEST(snap_rset, i))
17217c478bd9Sstevel@tonic-gate user_info_buffer[i].info_mem_free =
17227c478bd9Sstevel@tonic-gate lgrp_mem_size(i, LGRP_MEM_SIZE_FREE);
17237c478bd9Sstevel@tonic-gate
17247c478bd9Sstevel@tonic-gate /*
17257c478bd9Sstevel@tonic-gate * Fix up pointers to parents, children, resources, and
17267c478bd9Sstevel@tonic-gate * latencies
17277c478bd9Sstevel@tonic-gate */
17287c478bd9Sstevel@tonic-gate user_info_buffer[i].info_parents =
17297c478bd9Sstevel@tonic-gate (ulong_t *)((uintptr_t)user_parents + (i * bitmask_size));
17307c478bd9Sstevel@tonic-gate user_info_buffer[i].info_children =
17317c478bd9Sstevel@tonic-gate (ulong_t *)((uintptr_t)user_children + (i * bitmask_size));
17327c478bd9Sstevel@tonic-gate user_info_buffer[i].info_rset =
17337c478bd9Sstevel@tonic-gate (ulong_t *)((uintptr_t)user_rsets +
17347c478bd9Sstevel@tonic-gate (i * LGRP_RSRC_COUNT * bitmask_size));
17357c478bd9Sstevel@tonic-gate user_lats_buffer[i] = (int *)((uintptr_t)user_lats +
17367c478bd9Sstevel@tonic-gate (snap_nlgrpsmax * sizeof (int *)) + (i * snap_nlgrpsmax *
17377c478bd9Sstevel@tonic-gate sizeof (int)));
17387c478bd9Sstevel@tonic-gate
17397c478bd9Sstevel@tonic-gate /*
17407c478bd9Sstevel@tonic-gate * Fix up pointer to CPU IDs
17417c478bd9Sstevel@tonic-gate */
17427c478bd9Sstevel@tonic-gate if (user_info_buffer[i].info_ncpus == 0) {
17437c478bd9Sstevel@tonic-gate user_info_buffer[i].info_cpuids = NULL;
17447c478bd9Sstevel@tonic-gate continue;
17457c478bd9Sstevel@tonic-gate }
17467c478bd9Sstevel@tonic-gate user_info_buffer[i].info_cpuids = &user_cpuids[cpu_index];
17477c478bd9Sstevel@tonic-gate cpu_index += user_info_buffer[i].info_ncpus;
17487c478bd9Sstevel@tonic-gate }
17497c478bd9Sstevel@tonic-gate ASSERT(cpu_index == snap_ncpus);
17507c478bd9Sstevel@tonic-gate
17517c478bd9Sstevel@tonic-gate /*
17527c478bd9Sstevel@tonic-gate * Copy lgroup info and latency table with pointers fixed up to point
17537c478bd9Sstevel@tonic-gate * into user buffer out to user buffer now
17547c478bd9Sstevel@tonic-gate */
17557c478bd9Sstevel@tonic-gate retval = lgrp_snap->ss_size;
17567c478bd9Sstevel@tonic-gate if (copyout(user_info_buffer, user_info, info_size) != 0)
17577c478bd9Sstevel@tonic-gate retval = set_errno(EFAULT);
17587c478bd9Sstevel@tonic-gate kmem_free(user_info_buffer, info_size);
17597c478bd9Sstevel@tonic-gate
17607c478bd9Sstevel@tonic-gate if (copyout(user_lats_buffer, user_lats, snap_nlgrpsmax *
17617c478bd9Sstevel@tonic-gate sizeof (int *)) != 0)
17627c478bd9Sstevel@tonic-gate retval = set_errno(EFAULT);
17637c478bd9Sstevel@tonic-gate kmem_free(user_lats_buffer, snap_nlgrpsmax * sizeof (int *));
17647c478bd9Sstevel@tonic-gate
17657c478bd9Sstevel@tonic-gate return (retval);
17667c478bd9Sstevel@tonic-gate }
17677c478bd9Sstevel@tonic-gate
17687c478bd9Sstevel@tonic-gate
17697c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
17707c478bd9Sstevel@tonic-gate /*
17717c478bd9Sstevel@tonic-gate * Make 32-bit copy of snapshot, fix up any pointers in buffer to point
17727c478bd9Sstevel@tonic-gate * into user instead of kernel address space, copy 32-bit snapshot into
17737c478bd9Sstevel@tonic-gate * given user buffer, and return size of buffer needed to hold snapshot
17747c478bd9Sstevel@tonic-gate */
17757c478bd9Sstevel@tonic-gate static int
lgrp_snapshot_copy32(caddr32_t buf,size32_t bufsize)17767c478bd9Sstevel@tonic-gate lgrp_snapshot_copy32(caddr32_t buf, size32_t bufsize)
17777c478bd9Sstevel@tonic-gate {
17787c478bd9Sstevel@tonic-gate size32_t bitmask_size;
17797c478bd9Sstevel@tonic-gate size32_t bitmasks_size;
17807c478bd9Sstevel@tonic-gate size32_t children_size;
17817c478bd9Sstevel@tonic-gate int cpu_index;
17827c478bd9Sstevel@tonic-gate size32_t cpuids_size;
17837c478bd9Sstevel@tonic-gate int i;
17847c478bd9Sstevel@tonic-gate int j;
17857c478bd9Sstevel@tonic-gate size32_t info_size;
17867c478bd9Sstevel@tonic-gate size32_t lats_size;
17877c478bd9Sstevel@tonic-gate lgrp_info_t *lgrp_info;
17887c478bd9Sstevel@tonic-gate lgrp_snapshot_header32_t *lgrp_snap32;
17897c478bd9Sstevel@tonic-gate lgrp_info32_t *lgrp_info32;
17907c478bd9Sstevel@tonic-gate processorid_t *lgrp_cpuids32;
17917c478bd9Sstevel@tonic-gate caddr32_t *lgrp_lats32;
17927c478bd9Sstevel@tonic-gate int **lgrp_lats32_kernel;
17937c478bd9Sstevel@tonic-gate uint_t *lgrp_set32;
17947c478bd9Sstevel@tonic-gate uint_t *lgrp_parents32;
17957c478bd9Sstevel@tonic-gate uint_t *lgrp_children32;
17967c478bd9Sstevel@tonic-gate uint_t *lgrp_rsets32;
17977c478bd9Sstevel@tonic-gate size32_t parents_size;
17987c478bd9Sstevel@tonic-gate size32_t rsets_size;
17997c478bd9Sstevel@tonic-gate size32_t set_size;
18007c478bd9Sstevel@tonic-gate size32_t snap_hdr_size;
18017c478bd9Sstevel@tonic-gate int snap_ncpus;
18027c478bd9Sstevel@tonic-gate int snap_nlgrpsmax;
18037c478bd9Sstevel@tonic-gate size32_t snap_size;
18047c478bd9Sstevel@tonic-gate
18057c478bd9Sstevel@tonic-gate if (lgrp_snap == NULL)
18067c478bd9Sstevel@tonic-gate return (0);
18077c478bd9Sstevel@tonic-gate
18087c478bd9Sstevel@tonic-gate snap_ncpus = lgrp_snap->ss_ncpus;
18097c478bd9Sstevel@tonic-gate snap_nlgrpsmax = lgrp_snap->ss_nlgrps_max;
18107c478bd9Sstevel@tonic-gate
18117c478bd9Sstevel@tonic-gate /*
18127c478bd9Sstevel@tonic-gate * Calculate size of buffer needed for 32-bit snapshot,
18137c478bd9Sstevel@tonic-gate * rounding up size of each object to allow for alignment
18147c478bd9Sstevel@tonic-gate * of next object in buffer.
18157c478bd9Sstevel@tonic-gate */
18167c478bd9Sstevel@tonic-gate snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header32_t),
18177c478bd9Sstevel@tonic-gate sizeof (caddr32_t));
18187c478bd9Sstevel@tonic-gate info_size = P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info32_t),
18197c478bd9Sstevel@tonic-gate sizeof (processorid_t));
18207c478bd9Sstevel@tonic-gate cpuids_size = P2ROUNDUP(snap_ncpus * sizeof (processorid_t),
18217c478bd9Sstevel@tonic-gate sizeof (ulong_t));
18227c478bd9Sstevel@tonic-gate
18237c478bd9Sstevel@tonic-gate bitmask_size = BT_SIZEOFMAP32(snap_nlgrpsmax);
18247c478bd9Sstevel@tonic-gate
18257c478bd9Sstevel@tonic-gate set_size = bitmask_size;
18267c478bd9Sstevel@tonic-gate parents_size = snap_nlgrpsmax * bitmask_size;
18277c478bd9Sstevel@tonic-gate children_size = snap_nlgrpsmax * bitmask_size;
18287c478bd9Sstevel@tonic-gate rsets_size = P2ROUNDUP(LGRP_RSRC_COUNT * snap_nlgrpsmax *
18297c478bd9Sstevel@tonic-gate (int)bitmask_size, sizeof (caddr32_t));
18307c478bd9Sstevel@tonic-gate
18317c478bd9Sstevel@tonic-gate bitmasks_size = set_size + parents_size + children_size + rsets_size;
18327c478bd9Sstevel@tonic-gate
18337c478bd9Sstevel@tonic-gate /*
18347c478bd9Sstevel@tonic-gate * Size of latency table and buffer
18357c478bd9Sstevel@tonic-gate */
18367c478bd9Sstevel@tonic-gate lats_size = (snap_nlgrpsmax * sizeof (caddr32_t)) +
18377c478bd9Sstevel@tonic-gate (snap_nlgrpsmax * snap_nlgrpsmax * sizeof (int));
18387c478bd9Sstevel@tonic-gate
18397c478bd9Sstevel@tonic-gate snap_size = snap_hdr_size + info_size + cpuids_size + bitmasks_size +
18407c478bd9Sstevel@tonic-gate lats_size;
18417c478bd9Sstevel@tonic-gate
18427c478bd9Sstevel@tonic-gate if (buf == NULL || bufsize <= 0) {
18437c478bd9Sstevel@tonic-gate return (snap_size);
18447c478bd9Sstevel@tonic-gate }
18457c478bd9Sstevel@tonic-gate
18467c478bd9Sstevel@tonic-gate /*
18477c478bd9Sstevel@tonic-gate * User needs to try getting size of buffer again
18487c478bd9Sstevel@tonic-gate * because given buffer size is too small.
18497c478bd9Sstevel@tonic-gate * The lgroup hierarchy may have changed after they asked for the size
18507c478bd9Sstevel@tonic-gate * but before the snapshot was taken.
18517c478bd9Sstevel@tonic-gate */
18527c478bd9Sstevel@tonic-gate if (bufsize < snap_size)
18537c478bd9Sstevel@tonic-gate return (set_errno(EAGAIN));
18547c478bd9Sstevel@tonic-gate
18557c478bd9Sstevel@tonic-gate /*
18567c478bd9Sstevel@tonic-gate * Make 32-bit copy of snapshot, fix up pointers to point into user
18577c478bd9Sstevel@tonic-gate * buffer not kernel, and then copy whole thing into user buffer
18587c478bd9Sstevel@tonic-gate */
18597c478bd9Sstevel@tonic-gate lgrp_snap32 = kmem_zalloc(snap_size, KM_NOSLEEP);
18607c478bd9Sstevel@tonic-gate if (lgrp_snap32 == NULL)
18617c478bd9Sstevel@tonic-gate return (set_errno(ENOMEM));
18627c478bd9Sstevel@tonic-gate
18637c478bd9Sstevel@tonic-gate /*
18647c478bd9Sstevel@tonic-gate * Calculate pointers into 32-bit copy of snapshot
18657c478bd9Sstevel@tonic-gate * for lgroup info, CPU IDs, pset lgroup bitmask, parents, children,
18667c478bd9Sstevel@tonic-gate * resources, and latency table and buffer
18677c478bd9Sstevel@tonic-gate */
18687c478bd9Sstevel@tonic-gate lgrp_info32 = (lgrp_info32_t *)((uintptr_t)lgrp_snap32 +
18697c478bd9Sstevel@tonic-gate snap_hdr_size);
18707c478bd9Sstevel@tonic-gate lgrp_cpuids32 = (processorid_t *)((uintptr_t)lgrp_info32 + info_size);
18717c478bd9Sstevel@tonic-gate lgrp_set32 = (uint_t *)((uintptr_t)lgrp_cpuids32 + cpuids_size);
18727c478bd9Sstevel@tonic-gate lgrp_parents32 = (uint_t *)((uintptr_t)lgrp_set32 + set_size);
18737c478bd9Sstevel@tonic-gate lgrp_children32 = (uint_t *)((uintptr_t)lgrp_parents32 + parents_size);
18747c478bd9Sstevel@tonic-gate lgrp_rsets32 = (uint_t *)((uintptr_t)lgrp_children32 + children_size);
18757c478bd9Sstevel@tonic-gate lgrp_lats32 = (caddr32_t *)((uintptr_t)lgrp_rsets32 + rsets_size);
18767c478bd9Sstevel@tonic-gate
18777c478bd9Sstevel@tonic-gate /*
18787c478bd9Sstevel@tonic-gate * Make temporary lgroup latency table of pointers for kernel to use
18797c478bd9Sstevel@tonic-gate * to fill in rows of table with latencies from each lgroup
18807c478bd9Sstevel@tonic-gate */
18817c478bd9Sstevel@tonic-gate lgrp_lats32_kernel = kmem_zalloc(snap_nlgrpsmax * sizeof (int *),
18827c478bd9Sstevel@tonic-gate KM_NOSLEEP);
18837c478bd9Sstevel@tonic-gate if (lgrp_lats32_kernel == NULL) {
18847c478bd9Sstevel@tonic-gate kmem_free(lgrp_snap32, snap_size);
18857c478bd9Sstevel@tonic-gate return (set_errno(ENOMEM));
18867c478bd9Sstevel@tonic-gate }
18877c478bd9Sstevel@tonic-gate
18887c478bd9Sstevel@tonic-gate /*
18897c478bd9Sstevel@tonic-gate * Fill in 32-bit lgroup snapshot header
18907c478bd9Sstevel@tonic-gate * (with pointers into user's buffer for lgroup info, CPU IDs,
18917c478bd9Sstevel@tonic-gate * bit masks, and latencies)
18927c478bd9Sstevel@tonic-gate */
18937c478bd9Sstevel@tonic-gate lgrp_snap32->ss_version = lgrp_snap->ss_version;
18947c478bd9Sstevel@tonic-gate lgrp_snap32->ss_levels = lgrp_snap->ss_levels;
18957c478bd9Sstevel@tonic-gate lgrp_snap32->ss_nlgrps = lgrp_snap32->ss_nlgrps_os =
18967c478bd9Sstevel@tonic-gate lgrp_snap->ss_nlgrps;
18977c478bd9Sstevel@tonic-gate lgrp_snap32->ss_nlgrps_max = snap_nlgrpsmax;
18987c478bd9Sstevel@tonic-gate lgrp_snap32->ss_root = lgrp_snap->ss_root;
18997c478bd9Sstevel@tonic-gate lgrp_snap32->ss_ncpus = lgrp_snap->ss_ncpus;
19007c478bd9Sstevel@tonic-gate lgrp_snap32->ss_gen = lgrp_snap->ss_gen;
19017c478bd9Sstevel@tonic-gate lgrp_snap32->ss_view = LGRP_VIEW_OS;
19027c478bd9Sstevel@tonic-gate lgrp_snap32->ss_size = snap_size;
19037c478bd9Sstevel@tonic-gate lgrp_snap32->ss_magic = buf;
19047c478bd9Sstevel@tonic-gate lgrp_snap32->ss_info = buf + snap_hdr_size;
19057c478bd9Sstevel@tonic-gate lgrp_snap32->ss_cpuids = lgrp_snap32->ss_info + info_size;
19067c478bd9Sstevel@tonic-gate lgrp_snap32->ss_lgrpset = lgrp_snap32->ss_cpuids + cpuids_size;
19077c478bd9Sstevel@tonic-gate lgrp_snap32->ss_parents = lgrp_snap32->ss_lgrpset + bitmask_size;
19087c478bd9Sstevel@tonic-gate lgrp_snap32->ss_children = lgrp_snap32->ss_parents +
19097c478bd9Sstevel@tonic-gate (snap_nlgrpsmax * bitmask_size);
19107c478bd9Sstevel@tonic-gate lgrp_snap32->ss_rsets = lgrp_snap32->ss_children +
19117c478bd9Sstevel@tonic-gate (snap_nlgrpsmax * bitmask_size);
19127c478bd9Sstevel@tonic-gate lgrp_snap32->ss_latencies = lgrp_snap32->ss_rsets +
19137c478bd9Sstevel@tonic-gate (LGRP_RSRC_COUNT * snap_nlgrpsmax * bitmask_size);
19147c478bd9Sstevel@tonic-gate
19157c478bd9Sstevel@tonic-gate /*
19167c478bd9Sstevel@tonic-gate * Fill in lgrpset now because caller may have change psets
19177c478bd9Sstevel@tonic-gate */
19187c478bd9Sstevel@tonic-gate kpreempt_disable();
19197c478bd9Sstevel@tonic-gate for (i = 0; i < snap_nlgrpsmax; i++) {
19207c478bd9Sstevel@tonic-gate if (klgrpset_ismember(curthread->t_cpupart->cp_lgrpset,
19217c478bd9Sstevel@tonic-gate i)) {
19227c478bd9Sstevel@tonic-gate BT_SET32(lgrp_set32, i);
19237c478bd9Sstevel@tonic-gate }
19247c478bd9Sstevel@tonic-gate }
19257c478bd9Sstevel@tonic-gate kpreempt_enable();
19267c478bd9Sstevel@tonic-gate
19277c478bd9Sstevel@tonic-gate /*
19287c478bd9Sstevel@tonic-gate * Fill in 32-bit copy of lgroup info and fix up pointers
19297c478bd9Sstevel@tonic-gate * to point into user's buffer instead of kernel's
19307c478bd9Sstevel@tonic-gate */
19317c478bd9Sstevel@tonic-gate cpu_index = 0;
19327c478bd9Sstevel@tonic-gate lgrp_info = lgrp_snap->ss_info;
19337c478bd9Sstevel@tonic-gate for (i = 0; i < snap_nlgrpsmax; i++) {
19347c478bd9Sstevel@tonic-gate uint_t *children;
19357c478bd9Sstevel@tonic-gate uint_t *lgrp_rset;
19367c478bd9Sstevel@tonic-gate uint_t *parents;
19377c478bd9Sstevel@tonic-gate ulong_t *snap_rset;
19387c478bd9Sstevel@tonic-gate
19397c478bd9Sstevel@tonic-gate /*
19407c478bd9Sstevel@tonic-gate * Skip non-existent lgroups
19417c478bd9Sstevel@tonic-gate */
19427c478bd9Sstevel@tonic-gate if (lgrp_info[i].info_lgrpid == LGRP_NONE) {
19437c478bd9Sstevel@tonic-gate bzero(&lgrp_info32[i], sizeof (lgrp_info32[i]));
19447c478bd9Sstevel@tonic-gate lgrp_info32[i].info_lgrpid = LGRP_NONE;
19457c478bd9Sstevel@tonic-gate continue;
19467c478bd9Sstevel@tonic-gate }
19477c478bd9Sstevel@tonic-gate
19487c478bd9Sstevel@tonic-gate /*
19497c478bd9Sstevel@tonic-gate * Fill in parents, children, lgroup resource set, and
19507c478bd9Sstevel@tonic-gate * latencies from snapshot
19517c478bd9Sstevel@tonic-gate */
19527c478bd9Sstevel@tonic-gate parents = (uint_t *)((uintptr_t)lgrp_parents32 +
19537c478bd9Sstevel@tonic-gate i * bitmask_size);
19547c478bd9Sstevel@tonic-gate children = (uint_t *)((uintptr_t)lgrp_children32 +
19557c478bd9Sstevel@tonic-gate i * bitmask_size);
19567c478bd9Sstevel@tonic-gate snap_rset = (ulong_t *)((uintptr_t)lgrp_snap->ss_rsets +
19577c478bd9Sstevel@tonic-gate (i * LGRP_RSRC_COUNT * BT_SIZEOFMAP(snap_nlgrpsmax)));
19587c478bd9Sstevel@tonic-gate lgrp_rset = (uint_t *)((uintptr_t)lgrp_rsets32 +
19597c478bd9Sstevel@tonic-gate (i * LGRP_RSRC_COUNT * bitmask_size));
19607c478bd9Sstevel@tonic-gate lgrp_lats32_kernel[i] = (int *)((uintptr_t)lgrp_lats32 +
19617c478bd9Sstevel@tonic-gate snap_nlgrpsmax * sizeof (caddr32_t) + i * snap_nlgrpsmax *
19627c478bd9Sstevel@tonic-gate sizeof (int));
19637c478bd9Sstevel@tonic-gate for (j = 0; j < snap_nlgrpsmax; j++) {
19647c478bd9Sstevel@tonic-gate int k;
19657c478bd9Sstevel@tonic-gate uint_t *rset;
19667c478bd9Sstevel@tonic-gate
19677c478bd9Sstevel@tonic-gate if (BT_TEST(&lgrp_snap->ss_parents[i], j))
19687c478bd9Sstevel@tonic-gate BT_SET32(parents, j);
19697c478bd9Sstevel@tonic-gate
19707c478bd9Sstevel@tonic-gate if (BT_TEST(&lgrp_snap->ss_children[i], j))
19717c478bd9Sstevel@tonic-gate BT_SET32(children, j);
19727c478bd9Sstevel@tonic-gate
19737c478bd9Sstevel@tonic-gate for (k = 0; k < LGRP_RSRC_COUNT; k++) {
19747c478bd9Sstevel@tonic-gate rset = (uint_t *)((uintptr_t)lgrp_rset +
19757c478bd9Sstevel@tonic-gate k * bitmask_size);
19767c478bd9Sstevel@tonic-gate if (BT_TEST(&snap_rset[k], j))
19777c478bd9Sstevel@tonic-gate BT_SET32(rset, j);
19787c478bd9Sstevel@tonic-gate }
19797c478bd9Sstevel@tonic-gate
19807c478bd9Sstevel@tonic-gate lgrp_lats32_kernel[i][j] =
19817c478bd9Sstevel@tonic-gate lgrp_snap->ss_latencies[i][j];
19827c478bd9Sstevel@tonic-gate }
19837c478bd9Sstevel@tonic-gate
19847c478bd9Sstevel@tonic-gate /*
19857c478bd9Sstevel@tonic-gate * Fix up pointer to latency buffer
19867c478bd9Sstevel@tonic-gate */
19877c478bd9Sstevel@tonic-gate lgrp_lats32[i] = lgrp_snap32->ss_latencies +
19887c478bd9Sstevel@tonic-gate snap_nlgrpsmax * sizeof (caddr32_t) + i * snap_nlgrpsmax *
19897c478bd9Sstevel@tonic-gate sizeof (int);
19907c478bd9Sstevel@tonic-gate
19917c478bd9Sstevel@tonic-gate /*
19927c478bd9Sstevel@tonic-gate * Fix up pointers for parents, children, and resources
19937c478bd9Sstevel@tonic-gate */
19947c478bd9Sstevel@tonic-gate lgrp_info32[i].info_parents = lgrp_snap32->ss_parents +
19957c478bd9Sstevel@tonic-gate (i * bitmask_size);
19967c478bd9Sstevel@tonic-gate lgrp_info32[i].info_children = lgrp_snap32->ss_children +
19977c478bd9Sstevel@tonic-gate (i * bitmask_size);
19987c478bd9Sstevel@tonic-gate lgrp_info32[i].info_rset = lgrp_snap32->ss_rsets +
19997c478bd9Sstevel@tonic-gate (i * LGRP_RSRC_COUNT * bitmask_size);
20007c478bd9Sstevel@tonic-gate
20017c478bd9Sstevel@tonic-gate /*
20027c478bd9Sstevel@tonic-gate * Fill in memory and CPU info
20037c478bd9Sstevel@tonic-gate * Only fill in memory for lgroups directly containing memory
20047c478bd9Sstevel@tonic-gate */
20057c478bd9Sstevel@tonic-gate snap_rset = &lgrp_info[i].info_rset[LGRP_RSRC_MEM *
20067c478bd9Sstevel@tonic-gate BT_BITOUL(snap_nlgrpsmax)];
20077c478bd9Sstevel@tonic-gate if (BT_TEST(snap_rset, i)) {
20087c478bd9Sstevel@tonic-gate lgrp_info32[i].info_mem_free = lgrp_mem_size(i,
20097c478bd9Sstevel@tonic-gate LGRP_MEM_SIZE_FREE);
20107c478bd9Sstevel@tonic-gate lgrp_info32[i].info_mem_install =
20117c478bd9Sstevel@tonic-gate lgrp_info[i].info_mem_install;
20127c478bd9Sstevel@tonic-gate }
20137c478bd9Sstevel@tonic-gate
20147c478bd9Sstevel@tonic-gate lgrp_info32[i].info_ncpus = lgrp_info[i].info_ncpus;
20157c478bd9Sstevel@tonic-gate
20167c478bd9Sstevel@tonic-gate lgrp_info32[i].info_lgrpid = lgrp_info[i].info_lgrpid;
20177c478bd9Sstevel@tonic-gate lgrp_info32[i].info_latency = lgrp_info[i].info_latency;
20187c478bd9Sstevel@tonic-gate
20197c478bd9Sstevel@tonic-gate if (lgrp_info32[i].info_ncpus == 0) {
20207c478bd9Sstevel@tonic-gate lgrp_info32[i].info_cpuids = 0;
20217c478bd9Sstevel@tonic-gate continue;
20227c478bd9Sstevel@tonic-gate }
20237c478bd9Sstevel@tonic-gate
20247c478bd9Sstevel@tonic-gate /*
20257c478bd9Sstevel@tonic-gate * Fix up pointer for CPU IDs
20267c478bd9Sstevel@tonic-gate */
20277c478bd9Sstevel@tonic-gate lgrp_info32[i].info_cpuids = lgrp_snap32->ss_cpuids +
20287c478bd9Sstevel@tonic-gate (cpu_index * sizeof (processorid_t));
20297c478bd9Sstevel@tonic-gate cpu_index += lgrp_info32[i].info_ncpus;
20307c478bd9Sstevel@tonic-gate }
20317c478bd9Sstevel@tonic-gate ASSERT(cpu_index == snap_ncpus);
20327c478bd9Sstevel@tonic-gate
20337c478bd9Sstevel@tonic-gate /*
20347c478bd9Sstevel@tonic-gate * Copy lgroup CPU IDs into 32-bit snapshot
20357c478bd9Sstevel@tonic-gate * before copying it out into user's buffer
20367c478bd9Sstevel@tonic-gate */
20377c478bd9Sstevel@tonic-gate bcopy(lgrp_snap->ss_cpuids, lgrp_cpuids32, cpuids_size);
20387c478bd9Sstevel@tonic-gate
20397c478bd9Sstevel@tonic-gate /*
20407c478bd9Sstevel@tonic-gate * Copy 32-bit lgroup snapshot into user's buffer all at once
20417c478bd9Sstevel@tonic-gate */
20427c478bd9Sstevel@tonic-gate if (copyout(lgrp_snap32, (void *)(uintptr_t)buf, snap_size) != 0) {
20437c478bd9Sstevel@tonic-gate kmem_free(lgrp_snap32, snap_size);
20447c478bd9Sstevel@tonic-gate kmem_free(lgrp_lats32_kernel, snap_nlgrpsmax * sizeof (int *));
20457c478bd9Sstevel@tonic-gate return (set_errno(EFAULT));
20467c478bd9Sstevel@tonic-gate }
20477c478bd9Sstevel@tonic-gate
20487c478bd9Sstevel@tonic-gate kmem_free(lgrp_snap32, snap_size);
20497c478bd9Sstevel@tonic-gate kmem_free(lgrp_lats32_kernel, snap_nlgrpsmax * sizeof (int *));
20507c478bd9Sstevel@tonic-gate
20517c478bd9Sstevel@tonic-gate return (snap_size);
20527c478bd9Sstevel@tonic-gate }
20537c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
20547c478bd9Sstevel@tonic-gate
20557c478bd9Sstevel@tonic-gate
20567c478bd9Sstevel@tonic-gate int
lgrpsys(int subcode,long ia,void * ap)20577c478bd9Sstevel@tonic-gate lgrpsys(int subcode, long ia, void *ap)
20587c478bd9Sstevel@tonic-gate {
20597c478bd9Sstevel@tonic-gate size_t bufsize;
20607c478bd9Sstevel@tonic-gate int latency;
20617c478bd9Sstevel@tonic-gate
20627c478bd9Sstevel@tonic-gate switch (subcode) {
20637c478bd9Sstevel@tonic-gate
20647c478bd9Sstevel@tonic-gate case LGRP_SYS_AFFINITY_GET:
20657c478bd9Sstevel@tonic-gate return (lgrp_affinity_get((lgrp_affinity_args_t *)ap));
20667c478bd9Sstevel@tonic-gate
20677c478bd9Sstevel@tonic-gate case LGRP_SYS_AFFINITY_SET:
20687c478bd9Sstevel@tonic-gate return (lgrp_affinity_set((lgrp_affinity_args_t *)ap));
20697c478bd9Sstevel@tonic-gate
20707c478bd9Sstevel@tonic-gate case LGRP_SYS_GENERATION:
20717c478bd9Sstevel@tonic-gate return (lgrp_generation(ia));
20727c478bd9Sstevel@tonic-gate
20737c478bd9Sstevel@tonic-gate case LGRP_SYS_HOME:
20747c478bd9Sstevel@tonic-gate return (lgrp_home_get((idtype_t)ia, (id_t)(uintptr_t)ap));
20757c478bd9Sstevel@tonic-gate
20767c478bd9Sstevel@tonic-gate case LGRP_SYS_LATENCY:
20777c478bd9Sstevel@tonic-gate mutex_enter(&cpu_lock);
20787c478bd9Sstevel@tonic-gate latency = lgrp_latency(ia, (lgrp_id_t)(uintptr_t)ap);
20797c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock);
20807c478bd9Sstevel@tonic-gate return (latency);
20817c478bd9Sstevel@tonic-gate
20827c478bd9Sstevel@tonic-gate case LGRP_SYS_MEMINFO:
20837c478bd9Sstevel@tonic-gate return (meminfo(ia, (struct meminfo *)ap));
20847c478bd9Sstevel@tonic-gate
20857c478bd9Sstevel@tonic-gate case LGRP_SYS_VERSION:
20867c478bd9Sstevel@tonic-gate return (lgrp_version(ia));
20877c478bd9Sstevel@tonic-gate
20887c478bd9Sstevel@tonic-gate case LGRP_SYS_SNAPSHOT:
20897c478bd9Sstevel@tonic-gate mutex_enter(&lgrp_snap_lock);
20907c478bd9Sstevel@tonic-gate bufsize = lgrp_snapshot();
20917c478bd9Sstevel@tonic-gate if (ap && ia > 0) {
20927c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE)
20937c478bd9Sstevel@tonic-gate bufsize = lgrp_snapshot_copy(ap, ia);
20947c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
20957c478bd9Sstevel@tonic-gate else
20967c478bd9Sstevel@tonic-gate bufsize = lgrp_snapshot_copy32(
20977c478bd9Sstevel@tonic-gate (caddr32_t)(uintptr_t)ap, ia);
20987c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
20997c478bd9Sstevel@tonic-gate }
21007c478bd9Sstevel@tonic-gate mutex_exit(&lgrp_snap_lock);
21017c478bd9Sstevel@tonic-gate return (bufsize);
21027c478bd9Sstevel@tonic-gate
21037c478bd9Sstevel@tonic-gate default:
21047c478bd9Sstevel@tonic-gate break;
21057c478bd9Sstevel@tonic-gate
21067c478bd9Sstevel@tonic-gate }
21077c478bd9Sstevel@tonic-gate
21087c478bd9Sstevel@tonic-gate return (set_errno(EINVAL));
21097c478bd9Sstevel@tonic-gate }
2110