xref: /titanic_50/usr/src/uts/common/syscall/lgrpsys.c (revision c64027834c5ffc60c557c2b12555e0cd4d30320c)
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
5*c6402783Sakolb  * Common Development and Distribution License (the "License").
6*c6402783Sakolb  * 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  */
21*c6402783Sakolb 
227c478bd9Sstevel@tonic-gate /*
23*c6402783Sakolb  * 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
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 
1757c478bd9Sstevel@tonic-gate 		AS_LOCK_ENTER(as, &as->a_lock, 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 		}
2717c478bd9Sstevel@tonic-gate 		AS_LOCK_EXIT(as, &as->a_lock);
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
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
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
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
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
4597c478bd9Sstevel@tonic-gate  */
4607c478bd9Sstevel@tonic-gate lpl_t *
4617c478bd9Sstevel@tonic-gate lgrp_affinity_best(kthread_t *t, struct cpupart *cpupart, lgrp_id_t start)
4627c478bd9Sstevel@tonic-gate {
4637c478bd9Sstevel@tonic-gate 	lgrp_affinity_t	*affs;
4647c478bd9Sstevel@tonic-gate 	lgrp_affinity_t	best_aff;
4657c478bd9Sstevel@tonic-gate 	lpl_t		*best_lpl;
4667c478bd9Sstevel@tonic-gate 	lgrp_id_t	home;
4677c478bd9Sstevel@tonic-gate 	lgrp_id_t	lgrpid;
4687c478bd9Sstevel@tonic-gate 	lpl_t		*lpl;
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	ASSERT(t != NULL);
4717c478bd9Sstevel@tonic-gate 	ASSERT((MUTEX_HELD(&cpu_lock) || curthread->t_preempt > 0) ||
4727c478bd9Sstevel@tonic-gate 	    (MUTEX_HELD(&ttoproc(t)->p_lock) && THREAD_LOCK_HELD(t)));
4737c478bd9Sstevel@tonic-gate 	ASSERT(cpupart != NULL);
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	if (t->t_lgrp_affinity == NULL)
4767c478bd9Sstevel@tonic-gate 		return (NULL);
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	affs = t->t_lgrp_affinity;
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 	/*
4817c478bd9Sstevel@tonic-gate 	 * Thread bound to CPU
4827c478bd9Sstevel@tonic-gate 	 */
4837c478bd9Sstevel@tonic-gate 	if (t->t_bind_cpu != PBIND_NONE) {
4847c478bd9Sstevel@tonic-gate 		cpu_t	*cp;
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 		/*
4877c478bd9Sstevel@tonic-gate 		 * See whether thread has more affinity for root lgroup
4887c478bd9Sstevel@tonic-gate 		 * than lgroup containing CPU
4897c478bd9Sstevel@tonic-gate 		 */
4907c478bd9Sstevel@tonic-gate 		cp = cpu[t->t_bind_cpu];
4917c478bd9Sstevel@tonic-gate 		lpl = cp->cpu_lpl;
4927c478bd9Sstevel@tonic-gate 		lgrpid = LGRP_ROOTID;
4937c478bd9Sstevel@tonic-gate 		if (affs[lgrpid] > affs[lpl->lpl_lgrpid])
4947c478bd9Sstevel@tonic-gate 			return (&cpupart->cp_lgrploads[lgrpid]);
4957c478bd9Sstevel@tonic-gate 		return (lpl);
4967c478bd9Sstevel@tonic-gate 	}
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 	/*
4997c478bd9Sstevel@tonic-gate 	 * Start searching at given lgroup
5007c478bd9Sstevel@tonic-gate 	 */
5017c478bd9Sstevel@tonic-gate 	ASSERT(start >= 0 && start <= lgrp_alloc_max);
5027c478bd9Sstevel@tonic-gate 	lgrpid = start;
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 	/*
505*c6402783Sakolb 	 * Use starting lgroup given above as best first
5067c478bd9Sstevel@tonic-gate 	 */
5077c478bd9Sstevel@tonic-gate 	home = t->t_lpl->lpl_lgrpid;
508*c6402783Sakolb 	if (LGRP_CPUS_IN_PART(lgrpid, cpupart))
5097c478bd9Sstevel@tonic-gate 		best_lpl = &cpupart->cp_lgrploads[lgrpid];
510*c6402783Sakolb 	else
511*c6402783Sakolb 		best_lpl = &cpupart->cp_lgrploads[home];
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	best_aff = affs[best_lpl->lpl_lgrpid];
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 	do {
5167c478bd9Sstevel@tonic-gate 		/*
5177c478bd9Sstevel@tonic-gate 		 * Skip any lgroups that don't have CPU resources
5187c478bd9Sstevel@tonic-gate 		 * in this processor set.
5197c478bd9Sstevel@tonic-gate 		 */
5207c478bd9Sstevel@tonic-gate 		if (!LGRP_CPUS_IN_PART(lgrpid, cpupart)) {
5217c478bd9Sstevel@tonic-gate 			if (++lgrpid > lgrp_alloc_max)
5227c478bd9Sstevel@tonic-gate 				lgrpid = 0;	/* wrap the search */
5237c478bd9Sstevel@tonic-gate 			continue;
5247c478bd9Sstevel@tonic-gate 		}
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 		/*
5277c478bd9Sstevel@tonic-gate 		 * Find lgroup with most affinity
5287c478bd9Sstevel@tonic-gate 		 */
5297c478bd9Sstevel@tonic-gate 		lpl = &cpupart->cp_lgrploads[lgrpid];
5307c478bd9Sstevel@tonic-gate 		if (affs[lgrpid] > best_aff) {
5317c478bd9Sstevel@tonic-gate 			best_aff = affs[lgrpid];
5327c478bd9Sstevel@tonic-gate 			best_lpl = lpl;
5337c478bd9Sstevel@tonic-gate 		}
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 		if (++lgrpid > lgrp_alloc_max)
5367c478bd9Sstevel@tonic-gate 			lgrpid = 0;	/* wrap the search */
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 	} while (lgrpid != start);
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	/*
5417c478bd9Sstevel@tonic-gate 	 * No lgroup (in this pset) with any affinity
5427c478bd9Sstevel@tonic-gate 	 */
5437c478bd9Sstevel@tonic-gate 	if (best_aff == LGRP_AFF_NONE)
5447c478bd9Sstevel@tonic-gate 		return (NULL);
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 	lgrpid = best_lpl->lpl_lgrpid;
5477c478bd9Sstevel@tonic-gate 	ASSERT(LGRP_CPUS_IN_PART(lgrpid, cpupart) && best_lpl->lpl_ncpu > 0);
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	return (best_lpl);
5507c478bd9Sstevel@tonic-gate }
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate /*
5547c478bd9Sstevel@tonic-gate  * Set thread's affinity for given lgroup
5557c478bd9Sstevel@tonic-gate  */
5567c478bd9Sstevel@tonic-gate int
5577c478bd9Sstevel@tonic-gate lgrp_affinity_set_thread(kthread_t *t, lgrp_id_t lgrp, lgrp_affinity_t aff,
5587c478bd9Sstevel@tonic-gate     lgrp_affinity_t **aff_buf)
5597c478bd9Sstevel@tonic-gate {
560*c6402783Sakolb 	lgrp_affinity_t	*affs;
561*c6402783Sakolb 	lgrp_id_t	best;
5627c478bd9Sstevel@tonic-gate 	lpl_t		*best_lpl;
5637c478bd9Sstevel@tonic-gate 	lgrp_id_t	home;
5647c478bd9Sstevel@tonic-gate 	int		retval;
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 	ASSERT(t != NULL);
5677c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock));
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 	retval = 0;
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 	thread_lock(t);
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	/*
5747c478bd9Sstevel@tonic-gate 	 * Check to see whether caller has permission to set affinity for
5757c478bd9Sstevel@tonic-gate 	 * thread
5767c478bd9Sstevel@tonic-gate 	 */
5777c478bd9Sstevel@tonic-gate 	if (t->t_cid == 0 || !hasprocperm(t->t_cred, CRED())) {
5787c478bd9Sstevel@tonic-gate 		thread_unlock(t);
5797c478bd9Sstevel@tonic-gate 		return (set_errno(EPERM));
5807c478bd9Sstevel@tonic-gate 	}
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 	if (t->t_lgrp_affinity == NULL) {
5837c478bd9Sstevel@tonic-gate 		if (aff == LGRP_AFF_NONE) {
5847c478bd9Sstevel@tonic-gate 			thread_unlock(t);
5857c478bd9Sstevel@tonic-gate 			return (0);
5867c478bd9Sstevel@tonic-gate 		}
5877c478bd9Sstevel@tonic-gate 		ASSERT(aff_buf != NULL && *aff_buf != NULL);
5887c478bd9Sstevel@tonic-gate 		t->t_lgrp_affinity = *aff_buf;
5897c478bd9Sstevel@tonic-gate 		*aff_buf = NULL;
5907c478bd9Sstevel@tonic-gate 	}
5917c478bd9Sstevel@tonic-gate 
592*c6402783Sakolb 	affs = t->t_lgrp_affinity;
593*c6402783Sakolb 	affs[lgrp] = aff;
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 	/*
5967c478bd9Sstevel@tonic-gate 	 * Find lgroup for which thread has most affinity,
597*c6402783Sakolb 	 * starting with lgroup for which affinity being set
5987c478bd9Sstevel@tonic-gate 	 */
599*c6402783Sakolb 	best_lpl = lgrp_affinity_best(t, t->t_cpupart, lgrp);
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	/*
602*c6402783Sakolb 	 * Rehome if found lgroup with more affinity than home or lgroup for
603*c6402783Sakolb 	 * which affinity is being set has same affinity as home
6047c478bd9Sstevel@tonic-gate 	 */
605*c6402783Sakolb 	home = t->t_lpl->lpl_lgrpid;
606*c6402783Sakolb 	if (best_lpl != NULL && best_lpl != t->t_lpl) {
607*c6402783Sakolb 		best = best_lpl->lpl_lgrpid;
608*c6402783Sakolb 		if (affs[best] > affs[home] || (affs[best] == affs[home] &&
609*c6402783Sakolb 		    best == lgrp))
6107c478bd9Sstevel@tonic-gate 			lgrp_move_thread(t, best_lpl, 1);
611*c6402783Sakolb 	}
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 	thread_unlock(t);
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 	return (retval);
6167c478bd9Sstevel@tonic-gate }
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate /*
6207c478bd9Sstevel@tonic-gate  * Set process' affinity for specified lgroup
6217c478bd9Sstevel@tonic-gate  */
6227c478bd9Sstevel@tonic-gate int
6237c478bd9Sstevel@tonic-gate lgrp_affinity_set_proc(proc_t *p, lgrp_id_t lgrp, lgrp_affinity_t aff,
6247c478bd9Sstevel@tonic-gate     lgrp_affinity_t **aff_buf_array)
6257c478bd9Sstevel@tonic-gate {
6267c478bd9Sstevel@tonic-gate 	lgrp_affinity_t	*buf;
6277c478bd9Sstevel@tonic-gate 	int		err = 0;
6287c478bd9Sstevel@tonic-gate 	int		i;
6297c478bd9Sstevel@tonic-gate 	int		retval;
6307c478bd9Sstevel@tonic-gate 	kthread_t	*t;
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pidlock) && MUTEX_HELD(&p->p_lock));
6337c478bd9Sstevel@tonic-gate 	ASSERT(aff_buf_array != NULL);
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 	i = 0;
6367c478bd9Sstevel@tonic-gate 	t = p->p_tlist;
6377c478bd9Sstevel@tonic-gate 	if (t != NULL) {
6387c478bd9Sstevel@tonic-gate 		do {
6397c478bd9Sstevel@tonic-gate 			/*
6407c478bd9Sstevel@tonic-gate 			 * Set lgroup affinity for thread
6417c478bd9Sstevel@tonic-gate 			 */
6427c478bd9Sstevel@tonic-gate 			buf = aff_buf_array[i];
6437c478bd9Sstevel@tonic-gate 			retval = lgrp_affinity_set_thread(t, lgrp, aff, &buf);
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 			if (err == 0 && retval != 0)
6467c478bd9Sstevel@tonic-gate 				err = retval;
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 			/*
6497c478bd9Sstevel@tonic-gate 			 * Advance pointer to next buffer
6507c478bd9Sstevel@tonic-gate 			 */
6517c478bd9Sstevel@tonic-gate 			if (buf == NULL) {
6527c478bd9Sstevel@tonic-gate 				ASSERT(i < p->p_lwpcnt);
6537c478bd9Sstevel@tonic-gate 				aff_buf_array[i] = NULL;
6547c478bd9Sstevel@tonic-gate 				i++;
6557c478bd9Sstevel@tonic-gate 			}
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 		} while ((t = t->t_forw) != p->p_tlist);
6587c478bd9Sstevel@tonic-gate 	}
6597c478bd9Sstevel@tonic-gate 	return (err);
6607c478bd9Sstevel@tonic-gate }
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate /*
6647c478bd9Sstevel@tonic-gate  * Set LWP's or process' affinity for specified lgroup
6657c478bd9Sstevel@tonic-gate  *
6667c478bd9Sstevel@tonic-gate  * When setting affinities, pidlock, process p_lock, and thread_lock()
6677c478bd9Sstevel@tonic-gate  * need to be held in that order to protect target thread's pset, process,
6687c478bd9Sstevel@tonic-gate  * process contents, and thread contents.  thread_lock() does splhigh(),
6697c478bd9Sstevel@tonic-gate  * so it ends up having similiar effect as kpreempt_disable(), so it will
6707c478bd9Sstevel@tonic-gate  * protect calls to lgrp_move_thread() and lgrp_choose() from pset changes.
6717c478bd9Sstevel@tonic-gate  */
6727c478bd9Sstevel@tonic-gate int
6737c478bd9Sstevel@tonic-gate lgrp_affinity_set(lgrp_affinity_args_t *ap)
6747c478bd9Sstevel@tonic-gate {
6757c478bd9Sstevel@tonic-gate 	lgrp_affinity_t		aff;
6767c478bd9Sstevel@tonic-gate 	lgrp_affinity_t		*aff_buf;
6777c478bd9Sstevel@tonic-gate 	lgrp_affinity_args_t	args;
6787c478bd9Sstevel@tonic-gate 	id_t			id;
6797c478bd9Sstevel@tonic-gate 	idtype_t		idtype;
6807c478bd9Sstevel@tonic-gate 	lgrp_id_t		lgrp;
6817c478bd9Sstevel@tonic-gate 	int			nthreads;
6827c478bd9Sstevel@tonic-gate 	proc_t			*p;
6837c478bd9Sstevel@tonic-gate 	int			retval;
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 	/*
6867c478bd9Sstevel@tonic-gate 	 * Copyin arguments
6877c478bd9Sstevel@tonic-gate 	 */
6887c478bd9Sstevel@tonic-gate 	if (copyin(ap, &args, sizeof (lgrp_affinity_args_t)) != 0)
6897c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 	idtype = args.idtype;
6927c478bd9Sstevel@tonic-gate 	id = args.id;
6937c478bd9Sstevel@tonic-gate 	lgrp = args.lgrp;
6947c478bd9Sstevel@tonic-gate 	aff = args.aff;
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 	/*
6977c478bd9Sstevel@tonic-gate 	 * Check for invalid lgroup
6987c478bd9Sstevel@tonic-gate 	 */
6997c478bd9Sstevel@tonic-gate 	if (lgrp < 0 || lgrp == LGRP_NONE)
7007c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 	/*
7037c478bd9Sstevel@tonic-gate 	 * Check for existing lgroup
7047c478bd9Sstevel@tonic-gate 	 */
7057c478bd9Sstevel@tonic-gate 	if (lgrp > lgrp_alloc_max)
7067c478bd9Sstevel@tonic-gate 		return (set_errno(ESRCH));
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 	/*
7097c478bd9Sstevel@tonic-gate 	 * Check for legal affinity
7107c478bd9Sstevel@tonic-gate 	 */
7117c478bd9Sstevel@tonic-gate 	if (aff != LGRP_AFF_NONE && aff != LGRP_AFF_WEAK &&
7127c478bd9Sstevel@tonic-gate 	    aff != LGRP_AFF_STRONG)
7137c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 	/*
7167c478bd9Sstevel@tonic-gate 	 * Must be process or LWP ID
7177c478bd9Sstevel@tonic-gate 	 */
7187c478bd9Sstevel@tonic-gate 	if (idtype != P_LWPID && idtype != P_PID)
7197c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 	/*
7227c478bd9Sstevel@tonic-gate 	 * Set given LWP's or process' affinity for specified lgroup
7237c478bd9Sstevel@tonic-gate 	 */
7247c478bd9Sstevel@tonic-gate 	switch (idtype) {
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	case P_LWPID:
7277c478bd9Sstevel@tonic-gate 		/*
7287c478bd9Sstevel@tonic-gate 		 * Allocate memory for thread's lgroup affinities
7297c478bd9Sstevel@tonic-gate 		 * ahead of time w/o holding locks
7307c478bd9Sstevel@tonic-gate 		 */
7317c478bd9Sstevel@tonic-gate 		aff_buf = kmem_zalloc(nlgrpsmax * sizeof (lgrp_affinity_t),
7327c478bd9Sstevel@tonic-gate 		    KM_SLEEP);
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 		p = curproc;
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 		/*
7377c478bd9Sstevel@tonic-gate 		 * Set affinity for thread
7387c478bd9Sstevel@tonic-gate 		 */
7397c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
7407c478bd9Sstevel@tonic-gate 		if (id == P_MYID) {		/* current thread */
7417c478bd9Sstevel@tonic-gate 			retval = lgrp_affinity_set_thread(curthread, lgrp, aff,
7427c478bd9Sstevel@tonic-gate 			    &aff_buf);
7437c478bd9Sstevel@tonic-gate 		} else if (p->p_tlist == NULL) {
7447c478bd9Sstevel@tonic-gate 			retval = set_errno(ESRCH);
7457c478bd9Sstevel@tonic-gate 		} else {			/* other thread */
7467c478bd9Sstevel@tonic-gate 			int		found = 0;
7477c478bd9Sstevel@tonic-gate 			kthread_t	*t;
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 			t = p->p_tlist;
7507c478bd9Sstevel@tonic-gate 			do {
7517c478bd9Sstevel@tonic-gate 				if (t->t_tid == id) {
7527c478bd9Sstevel@tonic-gate 					retval = lgrp_affinity_set_thread(t,
7537c478bd9Sstevel@tonic-gate 					    lgrp, aff, &aff_buf);
7547c478bd9Sstevel@tonic-gate 					found = 1;
7557c478bd9Sstevel@tonic-gate 					break;
7567c478bd9Sstevel@tonic-gate 				}
7577c478bd9Sstevel@tonic-gate 			} while ((t = t->t_forw) != p->p_tlist);
7587c478bd9Sstevel@tonic-gate 			if (!found)
7597c478bd9Sstevel@tonic-gate 				retval = set_errno(ESRCH);
7607c478bd9Sstevel@tonic-gate 		}
7617c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 		/*
7647c478bd9Sstevel@tonic-gate 		 * Free memory for lgroup affinities,
7657c478bd9Sstevel@tonic-gate 		 * since thread didn't need it
7667c478bd9Sstevel@tonic-gate 		 */
7677c478bd9Sstevel@tonic-gate 		if (aff_buf)
7687c478bd9Sstevel@tonic-gate 			kmem_free(aff_buf,
7697c478bd9Sstevel@tonic-gate 			    nlgrpsmax * sizeof (lgrp_affinity_t));
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 		break;
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate 	case P_PID:
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 		do {
7767c478bd9Sstevel@tonic-gate 			lgrp_affinity_t	**aff_buf_array;
7777c478bd9Sstevel@tonic-gate 			int		i;
7787c478bd9Sstevel@tonic-gate 			size_t		size;
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 			/*
7817c478bd9Sstevel@tonic-gate 			 * Get process
7827c478bd9Sstevel@tonic-gate 			 */
7837c478bd9Sstevel@tonic-gate 			mutex_enter(&pidlock);
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 			if (id == P_MYID)
7867c478bd9Sstevel@tonic-gate 				p = curproc;
7877c478bd9Sstevel@tonic-gate 			else
7887c478bd9Sstevel@tonic-gate 				p = prfind(id);
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate 			if (p == NULL) {
7917c478bd9Sstevel@tonic-gate 				mutex_exit(&pidlock);
7927c478bd9Sstevel@tonic-gate 				return (set_errno(ESRCH));
7937c478bd9Sstevel@tonic-gate 			}
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 			/*
7967c478bd9Sstevel@tonic-gate 			 * Get number of threads in process
7977c478bd9Sstevel@tonic-gate 			 *
7987c478bd9Sstevel@tonic-gate 			 * NOTE: Only care about user processes,
7997c478bd9Sstevel@tonic-gate 			 *	 so p_lwpcnt should be number of threads.
8007c478bd9Sstevel@tonic-gate 			 */
8017c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
8027c478bd9Sstevel@tonic-gate 			nthreads = p->p_lwpcnt;
8037c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate 			mutex_exit(&pidlock);
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate 			if (nthreads < 1)
8087c478bd9Sstevel@tonic-gate 				return (set_errno(ESRCH));
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 			/*
8117c478bd9Sstevel@tonic-gate 			 * Preallocate memory for lgroup affinities for
8127c478bd9Sstevel@tonic-gate 			 * each thread in process now to avoid holding
8137c478bd9Sstevel@tonic-gate 			 * any locks.  Allocate an array to hold a buffer
8147c478bd9Sstevel@tonic-gate 			 * for each thread.
8157c478bd9Sstevel@tonic-gate 			 */
8167c478bd9Sstevel@tonic-gate 			aff_buf_array = kmem_zalloc(nthreads *
8177c478bd9Sstevel@tonic-gate 			    sizeof (lgrp_affinity_t *), KM_SLEEP);
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 			size = nlgrpsmax * sizeof (lgrp_affinity_t);
8207c478bd9Sstevel@tonic-gate 			for (i = 0; i < nthreads; i++)
8217c478bd9Sstevel@tonic-gate 				aff_buf_array[i] = kmem_zalloc(size, KM_SLEEP);
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 			mutex_enter(&pidlock);
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate 			/*
8267c478bd9Sstevel@tonic-gate 			 * Get process again since dropped locks to allocate
8277c478bd9Sstevel@tonic-gate 			 * memory (except current process)
8287c478bd9Sstevel@tonic-gate 			 */
8297c478bd9Sstevel@tonic-gate 			if (id != P_MYID)
8307c478bd9Sstevel@tonic-gate 				p = prfind(id);
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 			/*
8337c478bd9Sstevel@tonic-gate 			 * Process went away after we dropped locks and before
8347c478bd9Sstevel@tonic-gate 			 * reacquiring them, so drop locks, free memory, and
8357c478bd9Sstevel@tonic-gate 			 * return.
8367c478bd9Sstevel@tonic-gate 			 */
8377c478bd9Sstevel@tonic-gate 			if (p == NULL) {
8387c478bd9Sstevel@tonic-gate 				mutex_exit(&pidlock);
8397c478bd9Sstevel@tonic-gate 				for (i = 0; i < nthreads; i++)
8407c478bd9Sstevel@tonic-gate 					kmem_free(aff_buf_array[i], size);
8417c478bd9Sstevel@tonic-gate 				kmem_free(aff_buf_array,
8427c478bd9Sstevel@tonic-gate 				    nthreads * sizeof (lgrp_affinity_t *));
8437c478bd9Sstevel@tonic-gate 				return (set_errno(ESRCH));
8447c478bd9Sstevel@tonic-gate 			}
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 			/*
8497c478bd9Sstevel@tonic-gate 			 * See whether number of threads is same
8507c478bd9Sstevel@tonic-gate 			 * If not, drop locks, free memory, and try again
8517c478bd9Sstevel@tonic-gate 			 */
8527c478bd9Sstevel@tonic-gate 			if (nthreads != p->p_lwpcnt) {
8537c478bd9Sstevel@tonic-gate 				mutex_exit(&p->p_lock);
8547c478bd9Sstevel@tonic-gate 				mutex_exit(&pidlock);
8557c478bd9Sstevel@tonic-gate 				for (i = 0; i < nthreads; i++)
8567c478bd9Sstevel@tonic-gate 					kmem_free(aff_buf_array[i], size);
8577c478bd9Sstevel@tonic-gate 				kmem_free(aff_buf_array,
8587c478bd9Sstevel@tonic-gate 				    nthreads * sizeof (lgrp_affinity_t *));
8597c478bd9Sstevel@tonic-gate 				continue;
8607c478bd9Sstevel@tonic-gate 			}
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate 			/*
8637c478bd9Sstevel@tonic-gate 			 * Set lgroup affinity for threads in process
8647c478bd9Sstevel@tonic-gate 			 */
8657c478bd9Sstevel@tonic-gate 			retval = lgrp_affinity_set_proc(p, lgrp, aff,
8667c478bd9Sstevel@tonic-gate 			    aff_buf_array);
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
8697c478bd9Sstevel@tonic-gate 			mutex_exit(&pidlock);
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 			/*
8727c478bd9Sstevel@tonic-gate 			 * Free any leftover memory, since some threads may
8737c478bd9Sstevel@tonic-gate 			 * have already allocated memory and set lgroup
8747c478bd9Sstevel@tonic-gate 			 * affinities before
8757c478bd9Sstevel@tonic-gate 			 */
8767c478bd9Sstevel@tonic-gate 			for (i = 0; i < nthreads; i++)
8777c478bd9Sstevel@tonic-gate 				if (aff_buf_array[i] != NULL)
8787c478bd9Sstevel@tonic-gate 					kmem_free(aff_buf_array[i], size);
8797c478bd9Sstevel@tonic-gate 			kmem_free(aff_buf_array,
8807c478bd9Sstevel@tonic-gate 			    nthreads * sizeof (lgrp_affinity_t *));
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 			break;
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 		} while (nthreads != p->p_lwpcnt);
8857c478bd9Sstevel@tonic-gate 
8867c478bd9Sstevel@tonic-gate 		break;
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate 	default:
8897c478bd9Sstevel@tonic-gate 		retval = set_errno(EINVAL);
8907c478bd9Sstevel@tonic-gate 		break;
8917c478bd9Sstevel@tonic-gate 	}
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate 	return (retval);
8947c478bd9Sstevel@tonic-gate }
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate /*
8987c478bd9Sstevel@tonic-gate  * Return the latest generation number for the lgroup hierarchy
8997c478bd9Sstevel@tonic-gate  * with the given view
9007c478bd9Sstevel@tonic-gate  */
9017c478bd9Sstevel@tonic-gate lgrp_gen_t
9027c478bd9Sstevel@tonic-gate lgrp_generation(lgrp_view_t view)
9037c478bd9Sstevel@tonic-gate {
9047c478bd9Sstevel@tonic-gate 	cpupart_t	*cpupart;
9057c478bd9Sstevel@tonic-gate 	uint_t		gen;
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 	kpreempt_disable();
9087c478bd9Sstevel@tonic-gate 
9097c478bd9Sstevel@tonic-gate 	/*
9107c478bd9Sstevel@tonic-gate 	 * Determine generation number for given view
9117c478bd9Sstevel@tonic-gate 	 */
9127c478bd9Sstevel@tonic-gate 	if (view == LGRP_VIEW_OS)
9137c478bd9Sstevel@tonic-gate 		/*
9147c478bd9Sstevel@tonic-gate 		 * Return generation number of lgroup hierarchy for OS view
9157c478bd9Sstevel@tonic-gate 		 */
9167c478bd9Sstevel@tonic-gate 		gen = lgrp_gen;
9177c478bd9Sstevel@tonic-gate 	else {
9187c478bd9Sstevel@tonic-gate 		/*
9197c478bd9Sstevel@tonic-gate 		 * For caller's view, use generation numbers for lgroup
9207c478bd9Sstevel@tonic-gate 		 * hierarchy and caller's pset
9217c478bd9Sstevel@tonic-gate 		 * NOTE: Caller needs to check for change in pset ID
9227c478bd9Sstevel@tonic-gate 		 */
9237c478bd9Sstevel@tonic-gate 		cpupart = curthread->t_cpupart;
9247c478bd9Sstevel@tonic-gate 		ASSERT(cpupart);
9257c478bd9Sstevel@tonic-gate 		gen = lgrp_gen + cpupart->cp_gen;
9267c478bd9Sstevel@tonic-gate 	}
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	kpreempt_enable();
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate 	return (gen);
9317c478bd9Sstevel@tonic-gate }
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate lgrp_id_t
9357c478bd9Sstevel@tonic-gate lgrp_home_thread(kthread_t *t)
9367c478bd9Sstevel@tonic-gate {
9377c478bd9Sstevel@tonic-gate 	lgrp_id_t	home;
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate 	ASSERT(t != NULL);
9407c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock));
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 	thread_lock(t);
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate 	/*
9457c478bd9Sstevel@tonic-gate 	 * Check to see whether caller has permission to set affinity for
9467c478bd9Sstevel@tonic-gate 	 * thread
9477c478bd9Sstevel@tonic-gate 	 */
9487c478bd9Sstevel@tonic-gate 	if (t->t_cid == 0 || !hasprocperm(t->t_cred, CRED())) {
9497c478bd9Sstevel@tonic-gate 		thread_unlock(t);
9507c478bd9Sstevel@tonic-gate 		return (set_errno(EPERM));
9517c478bd9Sstevel@tonic-gate 	}
9527c478bd9Sstevel@tonic-gate 
9537c478bd9Sstevel@tonic-gate 	home = lgrp_home_id(t);
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 	thread_unlock(t);
9567c478bd9Sstevel@tonic-gate 	return (home);
9577c478bd9Sstevel@tonic-gate }
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 
9607c478bd9Sstevel@tonic-gate /*
9617c478bd9Sstevel@tonic-gate  * Get home lgroup of given process or thread
9627c478bd9Sstevel@tonic-gate  */
9637c478bd9Sstevel@tonic-gate lgrp_id_t
9647c478bd9Sstevel@tonic-gate lgrp_home_get(idtype_t idtype, id_t id)
9657c478bd9Sstevel@tonic-gate {
9667c478bd9Sstevel@tonic-gate 	proc_t		*p;
9677c478bd9Sstevel@tonic-gate 	lgrp_id_t	retval;
9687c478bd9Sstevel@tonic-gate 	kthread_t	*t;
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate 	/*
9717c478bd9Sstevel@tonic-gate 	 * Get home lgroup of given LWP or process
9727c478bd9Sstevel@tonic-gate 	 */
9737c478bd9Sstevel@tonic-gate 	switch (idtype) {
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 	case P_LWPID:
9767c478bd9Sstevel@tonic-gate 		p = curproc;
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 		/*
9797c478bd9Sstevel@tonic-gate 		 * Set affinity for thread
9807c478bd9Sstevel@tonic-gate 		 */
9817c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
9827c478bd9Sstevel@tonic-gate 		if (id == P_MYID) {		/* current thread */
9837c478bd9Sstevel@tonic-gate 			retval = lgrp_home_thread(curthread);
9847c478bd9Sstevel@tonic-gate 		} else if (p->p_tlist == NULL) {
9857c478bd9Sstevel@tonic-gate 			retval = set_errno(ESRCH);
9867c478bd9Sstevel@tonic-gate 		} else {			/* other thread */
9877c478bd9Sstevel@tonic-gate 			int	found = 0;
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate 			t = p->p_tlist;
9907c478bd9Sstevel@tonic-gate 			do {
9917c478bd9Sstevel@tonic-gate 				if (t->t_tid == id) {
9927c478bd9Sstevel@tonic-gate 					retval = lgrp_home_thread(t);
9937c478bd9Sstevel@tonic-gate 					found = 1;
9947c478bd9Sstevel@tonic-gate 					break;
9957c478bd9Sstevel@tonic-gate 				}
9967c478bd9Sstevel@tonic-gate 			} while ((t = t->t_forw) != p->p_tlist);
9977c478bd9Sstevel@tonic-gate 			if (!found)
9987c478bd9Sstevel@tonic-gate 				retval = set_errno(ESRCH);
9997c478bd9Sstevel@tonic-gate 		}
10007c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
10017c478bd9Sstevel@tonic-gate 		break;
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate 	case P_PID:
10047c478bd9Sstevel@tonic-gate 		/*
10057c478bd9Sstevel@tonic-gate 		 * Get process
10067c478bd9Sstevel@tonic-gate 		 */
10077c478bd9Sstevel@tonic-gate 		mutex_enter(&pidlock);
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate 		if (id == P_MYID)
10107c478bd9Sstevel@tonic-gate 			p = curproc;
10117c478bd9Sstevel@tonic-gate 		else
10127c478bd9Sstevel@tonic-gate 			p = prfind(id);
10137c478bd9Sstevel@tonic-gate 
10147c478bd9Sstevel@tonic-gate 		if (p == NULL) {
10157c478bd9Sstevel@tonic-gate 			mutex_exit(&pidlock);
10167c478bd9Sstevel@tonic-gate 			return (set_errno(ESRCH));
10177c478bd9Sstevel@tonic-gate 		}
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
10207c478bd9Sstevel@tonic-gate 		t = p->p_tlist;
10217c478bd9Sstevel@tonic-gate 		if (t == NULL)
10227c478bd9Sstevel@tonic-gate 			retval = set_errno(ESRCH);
10237c478bd9Sstevel@tonic-gate 		else
10247c478bd9Sstevel@tonic-gate 			retval = lgrp_home_thread(t);
10257c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate 		break;
10307c478bd9Sstevel@tonic-gate 
10317c478bd9Sstevel@tonic-gate 	default:
10327c478bd9Sstevel@tonic-gate 		retval = set_errno(EINVAL);
10337c478bd9Sstevel@tonic-gate 		break;
10347c478bd9Sstevel@tonic-gate 	}
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate 	return (retval);
10377c478bd9Sstevel@tonic-gate }
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate /*
10417c478bd9Sstevel@tonic-gate  * Return latency between "from" and "to" lgroups
10427c478bd9Sstevel@tonic-gate  *
10437c478bd9Sstevel@tonic-gate  * This latency number can only be used for relative comparison
10447c478bd9Sstevel@tonic-gate  * between lgroups on the running system, cannot be used across platforms,
10457c478bd9Sstevel@tonic-gate  * and may not reflect the actual latency.  It is platform and implementation
10467c478bd9Sstevel@tonic-gate  * specific, so platform gets to decide its value.  It would be nice if the
10477c478bd9Sstevel@tonic-gate  * number was at least proportional to make comparisons more meaningful though.
10487c478bd9Sstevel@tonic-gate  */
10497c478bd9Sstevel@tonic-gate int
10507c478bd9Sstevel@tonic-gate lgrp_latency(lgrp_id_t from, lgrp_id_t to)
10517c478bd9Sstevel@tonic-gate {
10527c478bd9Sstevel@tonic-gate 	lgrp_t		*from_lgrp;
10537c478bd9Sstevel@tonic-gate 	int		i;
10547c478bd9Sstevel@tonic-gate 	int		latency;
10557c478bd9Sstevel@tonic-gate 	int		latency_max;
10567c478bd9Sstevel@tonic-gate 	lgrp_t		*to_lgrp;
10577c478bd9Sstevel@tonic-gate 
10587c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock));
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate 	if (from < 0 || to < 0)
10617c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
10627c478bd9Sstevel@tonic-gate 
10637c478bd9Sstevel@tonic-gate 	if (from > lgrp_alloc_max || to > lgrp_alloc_max)
10647c478bd9Sstevel@tonic-gate 		return (set_errno(ESRCH));
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate 	from_lgrp = lgrp_table[from];
10677c478bd9Sstevel@tonic-gate 	to_lgrp = lgrp_table[to];
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate 	if (!LGRP_EXISTS(from_lgrp) || !LGRP_EXISTS(to_lgrp)) {
10707c478bd9Sstevel@tonic-gate 		return (set_errno(ESRCH));
10717c478bd9Sstevel@tonic-gate 	}
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate 	/*
10747c478bd9Sstevel@tonic-gate 	 * Get latency for same lgroup
10757c478bd9Sstevel@tonic-gate 	 */
10767c478bd9Sstevel@tonic-gate 	if (from == to) {
10777c478bd9Sstevel@tonic-gate 		latency = from_lgrp->lgrp_latency;
10787c478bd9Sstevel@tonic-gate 		return (latency);
10797c478bd9Sstevel@tonic-gate 	}
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate 	/*
10827c478bd9Sstevel@tonic-gate 	 * Get latency between leaf lgroups
10837c478bd9Sstevel@tonic-gate 	 */
10847c478bd9Sstevel@tonic-gate 	if (from_lgrp->lgrp_childcnt == 0 && to_lgrp->lgrp_childcnt == 0)
10857c478bd9Sstevel@tonic-gate 		return (lgrp_plat_latency(from_lgrp->lgrp_plathand,
10867c478bd9Sstevel@tonic-gate 		    to_lgrp->lgrp_plathand));
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate 	/*
10897c478bd9Sstevel@tonic-gate 	 * Determine max latency between resources in two lgroups
10907c478bd9Sstevel@tonic-gate 	 */
10917c478bd9Sstevel@tonic-gate 	latency_max = 0;
10927c478bd9Sstevel@tonic-gate 	for (i = 0; i <= lgrp_alloc_max; i++) {
10937c478bd9Sstevel@tonic-gate 		lgrp_t	*from_rsrc;
10947c478bd9Sstevel@tonic-gate 		int	j;
10957c478bd9Sstevel@tonic-gate 		lgrp_t	*to_rsrc;
10967c478bd9Sstevel@tonic-gate 
10977c478bd9Sstevel@tonic-gate 		from_rsrc = lgrp_table[i];
10987c478bd9Sstevel@tonic-gate 		if (!LGRP_EXISTS(from_rsrc) ||
10997c478bd9Sstevel@tonic-gate 		    !klgrpset_ismember(from_lgrp->lgrp_set[LGRP_RSRC_CPU], i))
11007c478bd9Sstevel@tonic-gate 			continue;
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate 		for (j = 0; j <= lgrp_alloc_max; j++) {
11037c478bd9Sstevel@tonic-gate 			to_rsrc = lgrp_table[j];
11047c478bd9Sstevel@tonic-gate 			if (!LGRP_EXISTS(to_rsrc) ||
11057c478bd9Sstevel@tonic-gate 			    klgrpset_ismember(to_lgrp->lgrp_set[LGRP_RSRC_MEM],
11067c478bd9Sstevel@tonic-gate 			    j) == 0)
11077c478bd9Sstevel@tonic-gate 				continue;
11087c478bd9Sstevel@tonic-gate 			latency = lgrp_plat_latency(from_rsrc->lgrp_plathand,
11097c478bd9Sstevel@tonic-gate 			    to_rsrc->lgrp_plathand);
11107c478bd9Sstevel@tonic-gate 			if (latency > latency_max)
11117c478bd9Sstevel@tonic-gate 				latency_max = latency;
11127c478bd9Sstevel@tonic-gate 		}
11137c478bd9Sstevel@tonic-gate 	}
11147c478bd9Sstevel@tonic-gate 	return (latency_max);
11157c478bd9Sstevel@tonic-gate }
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate /*
11197c478bd9Sstevel@tonic-gate  * Return lgroup interface version number
11207c478bd9Sstevel@tonic-gate  * 0 - none
11217c478bd9Sstevel@tonic-gate  * 1 - original
11227c478bd9Sstevel@tonic-gate  * 2 - lgrp_latency_cookie() and lgrp_resources() added
11237c478bd9Sstevel@tonic-gate  */
11247c478bd9Sstevel@tonic-gate int
11257c478bd9Sstevel@tonic-gate lgrp_version(int version)
11267c478bd9Sstevel@tonic-gate {
11277c478bd9Sstevel@tonic-gate 	/*
11287c478bd9Sstevel@tonic-gate 	 * Return LGRP_VER_NONE when requested version isn't supported
11297c478bd9Sstevel@tonic-gate 	 */
11307c478bd9Sstevel@tonic-gate 	if (version < LGRP_VER_NONE || version > LGRP_VER_CURRENT)
11317c478bd9Sstevel@tonic-gate 		return (LGRP_VER_NONE);
11327c478bd9Sstevel@tonic-gate 
11337c478bd9Sstevel@tonic-gate 	/*
11347c478bd9Sstevel@tonic-gate 	 * Return current version when LGRP_VER_NONE passed in
11357c478bd9Sstevel@tonic-gate 	 */
11367c478bd9Sstevel@tonic-gate 	if (version == LGRP_VER_NONE)
11377c478bd9Sstevel@tonic-gate 		return (LGRP_VER_CURRENT);
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate 	/*
11407c478bd9Sstevel@tonic-gate 	 * Otherwise, return supported version.
11417c478bd9Sstevel@tonic-gate 	 */
11427c478bd9Sstevel@tonic-gate 	return (version);
11437c478bd9Sstevel@tonic-gate }
11447c478bd9Sstevel@tonic-gate 
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate /*
11477c478bd9Sstevel@tonic-gate  * Snapshot of lgroup hieararchy
11487c478bd9Sstevel@tonic-gate  *
11497c478bd9Sstevel@tonic-gate  * One snapshot is kept and is based on the kernel's native data model, so
11507c478bd9Sstevel@tonic-gate  * a 32-bit snapshot is kept for the 32-bit kernel and a 64-bit one for the
11517c478bd9Sstevel@tonic-gate  * 64-bit kernel.  If a 32-bit user wants a snapshot from the 64-bit kernel,
11527c478bd9Sstevel@tonic-gate  * the kernel generates a 32-bit snapshot from the data in its 64-bit snapshot.
11537c478bd9Sstevel@tonic-gate  *
11547c478bd9Sstevel@tonic-gate  * The format is defined by lgroup snapshot header and the layout of
11557c478bd9Sstevel@tonic-gate  * the snapshot in memory is as follows:
11567c478bd9Sstevel@tonic-gate  * 1) lgroup snapshot header
11577c478bd9Sstevel@tonic-gate  *    - specifies format of snapshot
11587c478bd9Sstevel@tonic-gate  *    - defined by lgrp_snapshot_header_t
11597c478bd9Sstevel@tonic-gate  * 2) lgroup info array
11607c478bd9Sstevel@tonic-gate  *    - contains information about each lgroup
11617c478bd9Sstevel@tonic-gate  *    - one element for each lgroup
11627c478bd9Sstevel@tonic-gate  *    - each element is defined by lgrp_info_t
11637c478bd9Sstevel@tonic-gate  * 3) lgroup CPU ID array
11647c478bd9Sstevel@tonic-gate  *    - contains list (array) of CPU IDs for each lgroup
11657c478bd9Sstevel@tonic-gate  *    - lgrp_info_t points into array and specifies how many CPUs belong to
11667c478bd9Sstevel@tonic-gate  *      given lgroup
11677c478bd9Sstevel@tonic-gate  * 4) lgroup parents array
11687c478bd9Sstevel@tonic-gate  *    - contains lgroup bitmask of parents for each lgroup
11697c478bd9Sstevel@tonic-gate  *    - bitmask is an array of unsigned longs and its size depends on nlgrpsmax
11707c478bd9Sstevel@tonic-gate  * 5) lgroup children array
11717c478bd9Sstevel@tonic-gate  *    - contains lgroup bitmask of children for each lgroup
11727c478bd9Sstevel@tonic-gate  *    - bitmask is an array of unsigned longs and its size depends on nlgrpsmax
11737c478bd9Sstevel@tonic-gate  * 6) lgroup resources array
11747c478bd9Sstevel@tonic-gate  *    - contains lgroup bitmask of resources for each lgroup
11757c478bd9Sstevel@tonic-gate  *    - bitmask is an array of unsigned longs and its size depends on nlgrpsmax
11767c478bd9Sstevel@tonic-gate  * 7) lgroup latency table
11777c478bd9Sstevel@tonic-gate  *    - contains latency from each lgroup to each of other lgroups
11787c478bd9Sstevel@tonic-gate  *
11797c478bd9Sstevel@tonic-gate  * NOTE:  Must use nlgrpsmax for per lgroup data structures because lgroups
11807c478bd9Sstevel@tonic-gate  *	  may be sparsely allocated.
11817c478bd9Sstevel@tonic-gate  */
11827c478bd9Sstevel@tonic-gate lgrp_snapshot_header_t	*lgrp_snap = NULL;	/* lgroup snapshot */
11837c478bd9Sstevel@tonic-gate static kmutex_t		lgrp_snap_lock;		/* snapshot lock */
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate /*
11877c478bd9Sstevel@tonic-gate  * Take a snapshot of lgroup hierarchy and return size of buffer
11887c478bd9Sstevel@tonic-gate  * needed to hold snapshot
11897c478bd9Sstevel@tonic-gate  */
11907c478bd9Sstevel@tonic-gate static int
11917c478bd9Sstevel@tonic-gate lgrp_snapshot(void)
11927c478bd9Sstevel@tonic-gate {
11937c478bd9Sstevel@tonic-gate 	size_t		bitmask_size;
11947c478bd9Sstevel@tonic-gate 	size_t		bitmasks_size;
11957c478bd9Sstevel@tonic-gate 	size_t		bufsize;
11967c478bd9Sstevel@tonic-gate 	int		cpu_index;
11977c478bd9Sstevel@tonic-gate 	size_t		cpuids_size;
11987c478bd9Sstevel@tonic-gate 	int		i;
11997c478bd9Sstevel@tonic-gate 	int		j;
12007c478bd9Sstevel@tonic-gate 	size_t		info_size;
12017c478bd9Sstevel@tonic-gate 	size_t		lats_size;
12027c478bd9Sstevel@tonic-gate 	ulong_t		*lgrp_children;
12037c478bd9Sstevel@tonic-gate 	processorid_t	*lgrp_cpuids;
12047c478bd9Sstevel@tonic-gate 	lgrp_info_t	*lgrp_info;
12057c478bd9Sstevel@tonic-gate 	int		**lgrp_lats;
12067c478bd9Sstevel@tonic-gate 	ulong_t		*lgrp_parents;
12077c478bd9Sstevel@tonic-gate 	ulong_t		*lgrp_rsets;
12087c478bd9Sstevel@tonic-gate 	ulong_t		*lgrpset;
12097c478bd9Sstevel@tonic-gate 	int		snap_ncpus;
12107c478bd9Sstevel@tonic-gate 	int		snap_nlgrps;
12117c478bd9Sstevel@tonic-gate 	int		snap_nlgrpsmax;
12127c478bd9Sstevel@tonic-gate 	size_t		snap_hdr_size;
12137c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
12147c478bd9Sstevel@tonic-gate 	model_t		model = DATAMODEL_NATIVE;
12157c478bd9Sstevel@tonic-gate 
12167c478bd9Sstevel@tonic-gate 	/*
12177c478bd9Sstevel@tonic-gate 	 * Have up-to-date snapshot, so check to see whether caller is 32-bit
12187c478bd9Sstevel@tonic-gate 	 * program and need to return size of 32-bit snapshot now.
12197c478bd9Sstevel@tonic-gate 	 */
12207c478bd9Sstevel@tonic-gate 	model = get_udatamodel();
12217c478bd9Sstevel@tonic-gate 	if (model == DATAMODEL_ILP32 && lgrp_snap &&
12227c478bd9Sstevel@tonic-gate 	    lgrp_snap->ss_gen == lgrp_gen) {
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate 		snap_nlgrpsmax = lgrp_snap->ss_nlgrps_max;
12257c478bd9Sstevel@tonic-gate 
12267c478bd9Sstevel@tonic-gate 		/*
12277c478bd9Sstevel@tonic-gate 		 * Calculate size of buffer needed for 32-bit snapshot,
12287c478bd9Sstevel@tonic-gate 		 * rounding up size of each object to allow for alignment
12297c478bd9Sstevel@tonic-gate 		 * of next object in buffer.
12307c478bd9Sstevel@tonic-gate 		 */
12317c478bd9Sstevel@tonic-gate 		snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header32_t),
12327c478bd9Sstevel@tonic-gate 		    sizeof (caddr32_t));
12337c478bd9Sstevel@tonic-gate 		info_size =
12347c478bd9Sstevel@tonic-gate 		    P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info32_t),
12357c478bd9Sstevel@tonic-gate 		    sizeof (processorid_t));
12367c478bd9Sstevel@tonic-gate 		cpuids_size =
12377c478bd9Sstevel@tonic-gate 		    P2ROUNDUP(lgrp_snap->ss_ncpus * sizeof (processorid_t),
12387c478bd9Sstevel@tonic-gate 		    sizeof (ulong_t));
12397c478bd9Sstevel@tonic-gate 
12407c478bd9Sstevel@tonic-gate 		/*
12417c478bd9Sstevel@tonic-gate 		 * lgroup bitmasks needed for parents, children, and resources
12427c478bd9Sstevel@tonic-gate 		 * for each lgroup and pset lgroup set
12437c478bd9Sstevel@tonic-gate 		 */
12447c478bd9Sstevel@tonic-gate 		bitmask_size = BT_SIZEOFMAP(snap_nlgrpsmax);
12457c478bd9Sstevel@tonic-gate 		bitmasks_size = (((2 + LGRP_RSRC_COUNT) *
12467c478bd9Sstevel@tonic-gate 		    snap_nlgrpsmax) + 1) * bitmask_size;
12477c478bd9Sstevel@tonic-gate 
12487c478bd9Sstevel@tonic-gate 		/*
12497c478bd9Sstevel@tonic-gate 		 * Size of latency table and buffer
12507c478bd9Sstevel@tonic-gate 		 */
12517c478bd9Sstevel@tonic-gate 		lats_size = snap_nlgrpsmax * sizeof (caddr32_t) +
12527c478bd9Sstevel@tonic-gate 		    snap_nlgrpsmax * snap_nlgrpsmax * sizeof (int);
12537c478bd9Sstevel@tonic-gate 
12547c478bd9Sstevel@tonic-gate 		bufsize = snap_hdr_size + info_size + cpuids_size +
12557c478bd9Sstevel@tonic-gate 		    bitmasks_size + lats_size;
12567c478bd9Sstevel@tonic-gate 		return (bufsize);
12577c478bd9Sstevel@tonic-gate 	}
12587c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
12597c478bd9Sstevel@tonic-gate 
12607c478bd9Sstevel@tonic-gate 	/*
12617c478bd9Sstevel@tonic-gate 	 * Check whether snapshot is up-to-date
12627c478bd9Sstevel@tonic-gate 	 * Free it and take another one if not
12637c478bd9Sstevel@tonic-gate 	 */
12647c478bd9Sstevel@tonic-gate 	if (lgrp_snap) {
12657c478bd9Sstevel@tonic-gate 		if (lgrp_snap->ss_gen == lgrp_gen)
12667c478bd9Sstevel@tonic-gate 			return (lgrp_snap->ss_size);
12677c478bd9Sstevel@tonic-gate 
12687c478bd9Sstevel@tonic-gate 		kmem_free(lgrp_snap, lgrp_snap->ss_size);
12697c478bd9Sstevel@tonic-gate 		lgrp_snap = NULL;
12707c478bd9Sstevel@tonic-gate 	}
12717c478bd9Sstevel@tonic-gate 
12727c478bd9Sstevel@tonic-gate 	/*
12737c478bd9Sstevel@tonic-gate 	 * Allocate memory for snapshot
12747c478bd9Sstevel@tonic-gate 	 * w/o holding cpu_lock while waiting for memory
12757c478bd9Sstevel@tonic-gate 	 */
12767c478bd9Sstevel@tonic-gate 	while (lgrp_snap == NULL) {
12777c478bd9Sstevel@tonic-gate 		int	old_generation;
12787c478bd9Sstevel@tonic-gate 
12797c478bd9Sstevel@tonic-gate 		/*
12807c478bd9Sstevel@tonic-gate 		 * Take snapshot of lgroup generation number
12817c478bd9Sstevel@tonic-gate 		 * and configuration size dependent information
12827c478bd9Sstevel@tonic-gate 		 * NOTE: Only count number of online CPUs,
12837c478bd9Sstevel@tonic-gate 		 * since only online CPUs appear in lgroups.
12847c478bd9Sstevel@tonic-gate 		 */
12857c478bd9Sstevel@tonic-gate 		mutex_enter(&cpu_lock);
12867c478bd9Sstevel@tonic-gate 		old_generation = lgrp_gen;
12877c478bd9Sstevel@tonic-gate 		snap_ncpus = ncpus_online;
12887c478bd9Sstevel@tonic-gate 		snap_nlgrps = nlgrps;
12897c478bd9Sstevel@tonic-gate 		snap_nlgrpsmax = nlgrpsmax;
12907c478bd9Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
12917c478bd9Sstevel@tonic-gate 
12927c478bd9Sstevel@tonic-gate 		/*
12937c478bd9Sstevel@tonic-gate 		 * Calculate size of buffer needed for snapshot,
12947c478bd9Sstevel@tonic-gate 		 * rounding up size of each object to allow for alignment
12957c478bd9Sstevel@tonic-gate 		 * of next object in buffer.
12967c478bd9Sstevel@tonic-gate 		 */
12977c478bd9Sstevel@tonic-gate 		snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header_t),
12987c478bd9Sstevel@tonic-gate 		    sizeof (void *));
12997c478bd9Sstevel@tonic-gate 		info_size = P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info_t),
13007c478bd9Sstevel@tonic-gate 		    sizeof (processorid_t));
13017c478bd9Sstevel@tonic-gate 		cpuids_size = P2ROUNDUP(snap_ncpus * sizeof (processorid_t),
13027c478bd9Sstevel@tonic-gate 		    sizeof (ulong_t));
13037c478bd9Sstevel@tonic-gate 		/*
13047c478bd9Sstevel@tonic-gate 		 * lgroup bitmasks needed for pset lgroup set and  parents,
13057c478bd9Sstevel@tonic-gate 		 * children, and resource sets for each lgroup
13067c478bd9Sstevel@tonic-gate 		 */
13077c478bd9Sstevel@tonic-gate 		bitmask_size = BT_SIZEOFMAP(snap_nlgrpsmax);
13087c478bd9Sstevel@tonic-gate 		bitmasks_size = (((2 + LGRP_RSRC_COUNT) *
13097c478bd9Sstevel@tonic-gate 		    snap_nlgrpsmax) + 1) * bitmask_size;
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate 		/*
13127c478bd9Sstevel@tonic-gate 		 * Size of latency table and buffer
13137c478bd9Sstevel@tonic-gate 		 */
13147c478bd9Sstevel@tonic-gate 		lats_size = snap_nlgrpsmax * sizeof (int *) +
13157c478bd9Sstevel@tonic-gate 		    snap_nlgrpsmax * snap_nlgrpsmax * sizeof (int);
13167c478bd9Sstevel@tonic-gate 
13177c478bd9Sstevel@tonic-gate 		bufsize = snap_hdr_size + info_size + cpuids_size +
13187c478bd9Sstevel@tonic-gate 		    bitmasks_size + lats_size;
13197c478bd9Sstevel@tonic-gate 
13207c478bd9Sstevel@tonic-gate 		/*
13217c478bd9Sstevel@tonic-gate 		 * Allocate memory for buffer
13227c478bd9Sstevel@tonic-gate 		 */
13237c478bd9Sstevel@tonic-gate 		lgrp_snap = kmem_zalloc(bufsize, KM_NOSLEEP);
13247c478bd9Sstevel@tonic-gate 		if (lgrp_snap == NULL)
13257c478bd9Sstevel@tonic-gate 			return (set_errno(ENOMEM));
13267c478bd9Sstevel@tonic-gate 
13277c478bd9Sstevel@tonic-gate 		/*
13287c478bd9Sstevel@tonic-gate 		 * Check whether generation number has changed
13297c478bd9Sstevel@tonic-gate 		 */
13307c478bd9Sstevel@tonic-gate 		mutex_enter(&cpu_lock);
13317c478bd9Sstevel@tonic-gate 		if (lgrp_gen == old_generation)
13327c478bd9Sstevel@tonic-gate 			break;		/* hasn't change, so done. */
13337c478bd9Sstevel@tonic-gate 
13347c478bd9Sstevel@tonic-gate 		/*
13357c478bd9Sstevel@tonic-gate 		 * Generation number changed, so free memory and try again.
13367c478bd9Sstevel@tonic-gate 		 */
13377c478bd9Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
13387c478bd9Sstevel@tonic-gate 		kmem_free(lgrp_snap, bufsize);
13397c478bd9Sstevel@tonic-gate 		lgrp_snap = NULL;
13407c478bd9Sstevel@tonic-gate 	}
13417c478bd9Sstevel@tonic-gate 
13427c478bd9Sstevel@tonic-gate 	/*
13437c478bd9Sstevel@tonic-gate 	 * Fill in lgroup snapshot header
13447c478bd9Sstevel@tonic-gate 	 * (including pointers to tables of lgroup info, CPU IDs, and parents
13457c478bd9Sstevel@tonic-gate 	 * and children)
13467c478bd9Sstevel@tonic-gate 	 */
13477c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_version = LGRP_VER_CURRENT;
13487c478bd9Sstevel@tonic-gate 
13497c478bd9Sstevel@tonic-gate 	/*
13507c478bd9Sstevel@tonic-gate 	 * XXX For now, liblgrp only needs to know whether the hierarchy
13517c478bd9Sstevel@tonic-gate 	 * XXX only has one level or not
13527c478bd9Sstevel@tonic-gate 	 */
13537c478bd9Sstevel@tonic-gate 	if (snap_nlgrps == 1)
13547c478bd9Sstevel@tonic-gate 		lgrp_snap->ss_levels = 1;
13557c478bd9Sstevel@tonic-gate 	else
13567c478bd9Sstevel@tonic-gate 		lgrp_snap->ss_levels = 2;
13577c478bd9Sstevel@tonic-gate 
13587c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_root = LGRP_ROOTID;
13597c478bd9Sstevel@tonic-gate 
13607c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_nlgrps = lgrp_snap->ss_nlgrps_os = snap_nlgrps;
13617c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_nlgrps_max = snap_nlgrpsmax;
13627c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_ncpus = snap_ncpus;
13637c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_gen = lgrp_gen;
13647c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_view = LGRP_VIEW_OS;
13657c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_pset = 0;		/* NOTE: caller should set if needed */
13667c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_size = bufsize;
13677c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_magic = (uintptr_t)lgrp_snap;
13687c478bd9Sstevel@tonic-gate 
13697c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_info = lgrp_info =
13707c478bd9Sstevel@tonic-gate 	    (lgrp_info_t *)((uintptr_t)lgrp_snap + snap_hdr_size);
13717c478bd9Sstevel@tonic-gate 
13727c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_cpuids = lgrp_cpuids =
13737c478bd9Sstevel@tonic-gate 	    (processorid_t *)((uintptr_t)lgrp_info + info_size);
13747c478bd9Sstevel@tonic-gate 
13757c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_lgrpset = lgrpset =
13767c478bd9Sstevel@tonic-gate 	    (ulong_t *)((uintptr_t)lgrp_cpuids + cpuids_size);
13777c478bd9Sstevel@tonic-gate 
13787c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_parents = lgrp_parents =
13797c478bd9Sstevel@tonic-gate 	    (ulong_t *)((uintptr_t)lgrpset + bitmask_size);
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_children = lgrp_children =
13827c478bd9Sstevel@tonic-gate 	    (ulong_t *)((uintptr_t)lgrp_parents + (snap_nlgrpsmax *
13837c478bd9Sstevel@tonic-gate 	    bitmask_size));
13847c478bd9Sstevel@tonic-gate 
13857c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_rsets = lgrp_rsets =
13867c478bd9Sstevel@tonic-gate 	    (ulong_t *)((uintptr_t)lgrp_children + (snap_nlgrpsmax *
13877c478bd9Sstevel@tonic-gate 	    bitmask_size));
13887c478bd9Sstevel@tonic-gate 
13897c478bd9Sstevel@tonic-gate 	lgrp_snap->ss_latencies = lgrp_lats =
13907c478bd9Sstevel@tonic-gate 	    (int **)((uintptr_t)lgrp_rsets + (LGRP_RSRC_COUNT *
13917c478bd9Sstevel@tonic-gate 		snap_nlgrpsmax * bitmask_size));
13927c478bd9Sstevel@tonic-gate 
13937c478bd9Sstevel@tonic-gate 	/*
13947c478bd9Sstevel@tonic-gate 	 * Fill in lgroup information
13957c478bd9Sstevel@tonic-gate 	 */
13967c478bd9Sstevel@tonic-gate 	cpu_index = 0;
13977c478bd9Sstevel@tonic-gate 	for (i = 0; i < snap_nlgrpsmax; i++) {
13987c478bd9Sstevel@tonic-gate 		struct cpu	*cp;
13997c478bd9Sstevel@tonic-gate 		int		cpu_count;
14007c478bd9Sstevel@tonic-gate 		struct cpu	*head;
14017c478bd9Sstevel@tonic-gate 		int		k;
14027c478bd9Sstevel@tonic-gate 		lgrp_t		*lgrp;
14037c478bd9Sstevel@tonic-gate 
14047c478bd9Sstevel@tonic-gate 		lgrp = lgrp_table[i];
14057c478bd9Sstevel@tonic-gate 		if (!LGRP_EXISTS(lgrp)) {
14067c478bd9Sstevel@tonic-gate 			bzero(&lgrp_info[i], sizeof (lgrp_info[i]));
14077c478bd9Sstevel@tonic-gate 			lgrp_info[i].info_lgrpid = LGRP_NONE;
14087c478bd9Sstevel@tonic-gate 			continue;
14097c478bd9Sstevel@tonic-gate 		}
14107c478bd9Sstevel@tonic-gate 
14117c478bd9Sstevel@tonic-gate 		lgrp_info[i].info_lgrpid = i;
14127c478bd9Sstevel@tonic-gate 		lgrp_info[i].info_latency = lgrp->lgrp_latency;
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 		/*
14157c478bd9Sstevel@tonic-gate 		 * Fill in parents, children, and lgroup resources
14167c478bd9Sstevel@tonic-gate 		 */
14177c478bd9Sstevel@tonic-gate 		lgrp_info[i].info_parents =
14187c478bd9Sstevel@tonic-gate 		    (ulong_t *)((uintptr_t)lgrp_parents + (i * bitmask_size));
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate 		if (lgrp->lgrp_parent)
14217c478bd9Sstevel@tonic-gate 			BT_SET(lgrp_info[i].info_parents,
14227c478bd9Sstevel@tonic-gate 			    lgrp->lgrp_parent->lgrp_id);
14237c478bd9Sstevel@tonic-gate 
14247c478bd9Sstevel@tonic-gate 		lgrp_info[i].info_children =
14257c478bd9Sstevel@tonic-gate 		    (ulong_t *)((uintptr_t)lgrp_children + (i * bitmask_size));
14267c478bd9Sstevel@tonic-gate 
14277c478bd9Sstevel@tonic-gate 		for (j = 0; j < snap_nlgrpsmax; j++)
14287c478bd9Sstevel@tonic-gate 			if (klgrpset_ismember(lgrp->lgrp_children, j))
14297c478bd9Sstevel@tonic-gate 				BT_SET(lgrp_info[i].info_children, j);
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate 		lgrp_info[i].info_rset =
14327c478bd9Sstevel@tonic-gate 		    (ulong_t *)((uintptr_t)lgrp_rsets +
14337c478bd9Sstevel@tonic-gate 		    (i * LGRP_RSRC_COUNT * bitmask_size));
14347c478bd9Sstevel@tonic-gate 
14357c478bd9Sstevel@tonic-gate 		for (j = 0; j < LGRP_RSRC_COUNT; j++) {
14367c478bd9Sstevel@tonic-gate 			ulong_t	*rset;
14377c478bd9Sstevel@tonic-gate 
14387c478bd9Sstevel@tonic-gate 			rset = (ulong_t *)((uintptr_t)lgrp_info[i].info_rset +
14397c478bd9Sstevel@tonic-gate 			    (j * bitmask_size));
14407c478bd9Sstevel@tonic-gate 			for (k = 0; k < snap_nlgrpsmax; k++)
14417c478bd9Sstevel@tonic-gate 				if (klgrpset_ismember(lgrp->lgrp_set[j], k))
14427c478bd9Sstevel@tonic-gate 					BT_SET(rset, k);
14437c478bd9Sstevel@tonic-gate 		}
14447c478bd9Sstevel@tonic-gate 
14457c478bd9Sstevel@tonic-gate 		/*
14467c478bd9Sstevel@tonic-gate 		 * Fill in CPU IDs
14477c478bd9Sstevel@tonic-gate 		 */
14487c478bd9Sstevel@tonic-gate 		cpu_count = 0;
14497c478bd9Sstevel@tonic-gate 		lgrp_info[i].info_cpuids = NULL;
14507c478bd9Sstevel@tonic-gate 		cp = head = lgrp->lgrp_cpu;
14517c478bd9Sstevel@tonic-gate 		if (head != NULL) {
14527c478bd9Sstevel@tonic-gate 			lgrp_info[i].info_cpuids = &lgrp_cpuids[cpu_index];
14537c478bd9Sstevel@tonic-gate 			do {
14547c478bd9Sstevel@tonic-gate 				lgrp_cpuids[cpu_index] = cp->cpu_id;
14557c478bd9Sstevel@tonic-gate 				cpu_index++;
14567c478bd9Sstevel@tonic-gate 				cpu_count++;
14577c478bd9Sstevel@tonic-gate 				cp = cp->cpu_next_lgrp;
14587c478bd9Sstevel@tonic-gate 			} while (cp != head);
14597c478bd9Sstevel@tonic-gate 		}
14607c478bd9Sstevel@tonic-gate 		ASSERT(cpu_count == lgrp->lgrp_cpucnt);
14617c478bd9Sstevel@tonic-gate 		lgrp_info[i].info_ncpus = cpu_count;
14627c478bd9Sstevel@tonic-gate 
14637c478bd9Sstevel@tonic-gate 		/*
14647c478bd9Sstevel@tonic-gate 		 * Fill in memory sizes for lgroups that directly contain
14657c478bd9Sstevel@tonic-gate 		 * memory
14667c478bd9Sstevel@tonic-gate 		 */
14677c478bd9Sstevel@tonic-gate 		if (klgrpset_ismember(lgrp->lgrp_set[LGRP_RSRC_MEM], i)) {
14687c478bd9Sstevel@tonic-gate 			lgrp_info[i].info_mem_free =
14697c478bd9Sstevel@tonic-gate 			    lgrp_mem_size(i, LGRP_MEM_SIZE_FREE);
14707c478bd9Sstevel@tonic-gate 			lgrp_info[i].info_mem_install =
14717c478bd9Sstevel@tonic-gate 			    lgrp_mem_size(i, LGRP_MEM_SIZE_INSTALL);
14727c478bd9Sstevel@tonic-gate 		}
14737c478bd9Sstevel@tonic-gate 
14747c478bd9Sstevel@tonic-gate 		/*
14757c478bd9Sstevel@tonic-gate 		 * Fill in latency table and buffer
14767c478bd9Sstevel@tonic-gate 		 */
14777c478bd9Sstevel@tonic-gate 		lgrp_lats[i] = (int *)((uintptr_t)lgrp_lats + snap_nlgrpsmax *
14787c478bd9Sstevel@tonic-gate 		    sizeof (int *) + i * snap_nlgrpsmax * sizeof (int));
14797c478bd9Sstevel@tonic-gate 		for (j = 0; j < snap_nlgrpsmax; j++) {
14807c478bd9Sstevel@tonic-gate 			lgrp_t	*to;
14817c478bd9Sstevel@tonic-gate 
14827c478bd9Sstevel@tonic-gate 			to = lgrp_table[j];
14837c478bd9Sstevel@tonic-gate 			if (!LGRP_EXISTS(to))
14847c478bd9Sstevel@tonic-gate 				continue;
14857c478bd9Sstevel@tonic-gate 			lgrp_lats[i][j] = lgrp_latency(lgrp->lgrp_id,
14867c478bd9Sstevel@tonic-gate 			    to->lgrp_id);
14877c478bd9Sstevel@tonic-gate 		}
14887c478bd9Sstevel@tonic-gate 	}
14897c478bd9Sstevel@tonic-gate 	ASSERT(cpu_index == snap_ncpus);
14907c478bd9Sstevel@tonic-gate 
14917c478bd9Sstevel@tonic-gate 
14927c478bd9Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
14937c478bd9Sstevel@tonic-gate 
14947c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
14957c478bd9Sstevel@tonic-gate 	/*
14967c478bd9Sstevel@tonic-gate 	 * Check to see whether caller is 32-bit program and need to return
14977c478bd9Sstevel@tonic-gate 	 * size of 32-bit snapshot now that snapshot has been taken/updated.
14987c478bd9Sstevel@tonic-gate 	 * May not have been able to do this earlier if snapshot was out of
14997c478bd9Sstevel@tonic-gate 	 * date or didn't exist yet.
15007c478bd9Sstevel@tonic-gate 	 */
15017c478bd9Sstevel@tonic-gate 	if (model == DATAMODEL_ILP32) {
15027c478bd9Sstevel@tonic-gate 
15037c478bd9Sstevel@tonic-gate 		snap_nlgrpsmax = lgrp_snap->ss_nlgrps_max;
15047c478bd9Sstevel@tonic-gate 
15057c478bd9Sstevel@tonic-gate 		/*
15067c478bd9Sstevel@tonic-gate 		 * Calculate size of buffer needed for 32-bit snapshot,
15077c478bd9Sstevel@tonic-gate 		 * rounding up size of each object to allow for alignment
15087c478bd9Sstevel@tonic-gate 		 * of next object in buffer.
15097c478bd9Sstevel@tonic-gate 		 */
15107c478bd9Sstevel@tonic-gate 		snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header32_t),
15117c478bd9Sstevel@tonic-gate 		    sizeof (caddr32_t));
15127c478bd9Sstevel@tonic-gate 		info_size =
15137c478bd9Sstevel@tonic-gate 		    P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info32_t),
15147c478bd9Sstevel@tonic-gate 		    sizeof (processorid_t));
15157c478bd9Sstevel@tonic-gate 		cpuids_size =
15167c478bd9Sstevel@tonic-gate 		    P2ROUNDUP(lgrp_snap->ss_ncpus * sizeof (processorid_t),
15177c478bd9Sstevel@tonic-gate 		    sizeof (ulong_t));
15187c478bd9Sstevel@tonic-gate 
15197c478bd9Sstevel@tonic-gate 		bitmask_size = BT_SIZEOFMAP(snap_nlgrpsmax);
15207c478bd9Sstevel@tonic-gate 		bitmasks_size = (((2 + LGRP_RSRC_COUNT) * snap_nlgrpsmax) +
15217c478bd9Sstevel@tonic-gate 		    1) * bitmask_size;
15227c478bd9Sstevel@tonic-gate 
15237c478bd9Sstevel@tonic-gate 
15247c478bd9Sstevel@tonic-gate 		/*
15257c478bd9Sstevel@tonic-gate 		 * Size of latency table and buffer
15267c478bd9Sstevel@tonic-gate 		 */
15277c478bd9Sstevel@tonic-gate 		lats_size = (snap_nlgrpsmax * sizeof (caddr32_t)) +
15287c478bd9Sstevel@tonic-gate 		    (snap_nlgrpsmax * snap_nlgrpsmax * sizeof (int));
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate 		bufsize = snap_hdr_size + info_size + cpuids_size +
15317c478bd9Sstevel@tonic-gate 		    bitmasks_size + lats_size;
15327c478bd9Sstevel@tonic-gate 		return (bufsize);
15337c478bd9Sstevel@tonic-gate 	}
15347c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
15357c478bd9Sstevel@tonic-gate 
15367c478bd9Sstevel@tonic-gate 	return (lgrp_snap->ss_size);
15377c478bd9Sstevel@tonic-gate }
15387c478bd9Sstevel@tonic-gate 
15397c478bd9Sstevel@tonic-gate 
15407c478bd9Sstevel@tonic-gate /*
15417c478bd9Sstevel@tonic-gate  * Copy snapshot into given user buffer, fix up any pointers in buffer to point
15427c478bd9Sstevel@tonic-gate  * into user instead of kernel address space, and return size of buffer
15437c478bd9Sstevel@tonic-gate  * needed to hold snapshot
15447c478bd9Sstevel@tonic-gate  */
15457c478bd9Sstevel@tonic-gate static int
15467c478bd9Sstevel@tonic-gate lgrp_snapshot_copy(char *buf, size_t bufsize)
15477c478bd9Sstevel@tonic-gate {
15487c478bd9Sstevel@tonic-gate 	size_t			bitmask_size;
15497c478bd9Sstevel@tonic-gate 	int			cpu_index;
15507c478bd9Sstevel@tonic-gate 	size_t			cpuids_size;
15517c478bd9Sstevel@tonic-gate 	int			i;
15527c478bd9Sstevel@tonic-gate 	size_t			info_size;
15537c478bd9Sstevel@tonic-gate 	lgrp_info_t		*lgrp_info;
15547c478bd9Sstevel@tonic-gate 	int			retval;
15557c478bd9Sstevel@tonic-gate 	size_t			snap_hdr_size;
15567c478bd9Sstevel@tonic-gate 	int			snap_ncpus;
15577c478bd9Sstevel@tonic-gate 	int			snap_nlgrpsmax;
15587c478bd9Sstevel@tonic-gate 	lgrp_snapshot_header_t	*user_snap;
15597c478bd9Sstevel@tonic-gate 	lgrp_info_t		*user_info;
15607c478bd9Sstevel@tonic-gate 	lgrp_info_t		*user_info_buffer;
15617c478bd9Sstevel@tonic-gate 	processorid_t		*user_cpuids;
15627c478bd9Sstevel@tonic-gate 	ulong_t			*user_lgrpset;
15637c478bd9Sstevel@tonic-gate 	ulong_t			*user_parents;
15647c478bd9Sstevel@tonic-gate 	ulong_t			*user_children;
15657c478bd9Sstevel@tonic-gate 	int			**user_lats;
15667c478bd9Sstevel@tonic-gate 	int			**user_lats_buffer;
15677c478bd9Sstevel@tonic-gate 	ulong_t			*user_rsets;
15687c478bd9Sstevel@tonic-gate 
15697c478bd9Sstevel@tonic-gate 	if (lgrp_snap == NULL)
15707c478bd9Sstevel@tonic-gate 		return (0);
15717c478bd9Sstevel@tonic-gate 
15727c478bd9Sstevel@tonic-gate 	if (buf == NULL || bufsize <= 0)
15737c478bd9Sstevel@tonic-gate 		return (lgrp_snap->ss_size);
15747c478bd9Sstevel@tonic-gate 
15757c478bd9Sstevel@tonic-gate 	/*
15767c478bd9Sstevel@tonic-gate 	 * User needs to try getting size of buffer again
15777c478bd9Sstevel@tonic-gate 	 * because given buffer size is too small.
15787c478bd9Sstevel@tonic-gate 	 * The lgroup hierarchy may have changed after they asked for the size
15797c478bd9Sstevel@tonic-gate 	 * but before the snapshot was taken.
15807c478bd9Sstevel@tonic-gate 	 */
15817c478bd9Sstevel@tonic-gate 	if (bufsize < lgrp_snap->ss_size)
15827c478bd9Sstevel@tonic-gate 		return (set_errno(EAGAIN));
15837c478bd9Sstevel@tonic-gate 
15847c478bd9Sstevel@tonic-gate 	snap_ncpus = lgrp_snap->ss_ncpus;
15857c478bd9Sstevel@tonic-gate 	snap_nlgrpsmax = lgrp_snap->ss_nlgrps_max;
15867c478bd9Sstevel@tonic-gate 
15877c478bd9Sstevel@tonic-gate 	/*
15887c478bd9Sstevel@tonic-gate 	 * Fill in lgrpset now because caller may have change psets
15897c478bd9Sstevel@tonic-gate 	 */
15907c478bd9Sstevel@tonic-gate 	kpreempt_disable();
15917c478bd9Sstevel@tonic-gate 	for (i = 0; i < snap_nlgrpsmax; i++) {
15927c478bd9Sstevel@tonic-gate 		if (klgrpset_ismember(curthread->t_cpupart->cp_lgrpset,
15937c478bd9Sstevel@tonic-gate 		    i)) {
15947c478bd9Sstevel@tonic-gate 			BT_SET(lgrp_snap->ss_lgrpset, i);
15957c478bd9Sstevel@tonic-gate 		}
15967c478bd9Sstevel@tonic-gate 	}
15977c478bd9Sstevel@tonic-gate 	kpreempt_enable();
15987c478bd9Sstevel@tonic-gate 
15997c478bd9Sstevel@tonic-gate 	/*
16007c478bd9Sstevel@tonic-gate 	 * Copy lgroup snapshot (snapshot header, lgroup info, and CPU IDs)
16017c478bd9Sstevel@tonic-gate 	 * into user buffer all at once
16027c478bd9Sstevel@tonic-gate 	 */
16037c478bd9Sstevel@tonic-gate 	if (copyout(lgrp_snap, buf, lgrp_snap->ss_size) != 0)
16047c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
16057c478bd9Sstevel@tonic-gate 
16067c478bd9Sstevel@tonic-gate 	/*
16077c478bd9Sstevel@tonic-gate 	 * Round up sizes of lgroup snapshot header and info for alignment
16087c478bd9Sstevel@tonic-gate 	 */
16097c478bd9Sstevel@tonic-gate 	snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header_t),
16107c478bd9Sstevel@tonic-gate 	    sizeof (void *));
16117c478bd9Sstevel@tonic-gate 	info_size = P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info_t),
16127c478bd9Sstevel@tonic-gate 	    sizeof (processorid_t));
16137c478bd9Sstevel@tonic-gate 	cpuids_size = P2ROUNDUP(snap_ncpus * sizeof (processorid_t),
16147c478bd9Sstevel@tonic-gate 	    sizeof (ulong_t));
16157c478bd9Sstevel@tonic-gate 
16167c478bd9Sstevel@tonic-gate 	bitmask_size = BT_SIZEOFMAP(snap_nlgrpsmax);
16177c478bd9Sstevel@tonic-gate 
16187c478bd9Sstevel@tonic-gate 	/*
16197c478bd9Sstevel@tonic-gate 	 * Calculate pointers into user buffer for lgroup snapshot header,
16207c478bd9Sstevel@tonic-gate 	 * info, and CPU IDs
16217c478bd9Sstevel@tonic-gate 	 */
16227c478bd9Sstevel@tonic-gate 	user_snap = (lgrp_snapshot_header_t *)buf;
16237c478bd9Sstevel@tonic-gate 	user_info = (lgrp_info_t *)((uintptr_t)user_snap + snap_hdr_size);
16247c478bd9Sstevel@tonic-gate 	user_cpuids = (processorid_t *)((uintptr_t)user_info + info_size);
16257c478bd9Sstevel@tonic-gate 	user_lgrpset = (ulong_t *)((uintptr_t)user_cpuids + cpuids_size);
16267c478bd9Sstevel@tonic-gate 	user_parents = (ulong_t *)((uintptr_t)user_lgrpset + bitmask_size);
16277c478bd9Sstevel@tonic-gate 	user_children = (ulong_t *)((uintptr_t)user_parents +
16287c478bd9Sstevel@tonic-gate 	    (snap_nlgrpsmax * bitmask_size));
16297c478bd9Sstevel@tonic-gate 	user_rsets = (ulong_t *)((uintptr_t)user_children +
16307c478bd9Sstevel@tonic-gate 	    (snap_nlgrpsmax * bitmask_size));
16317c478bd9Sstevel@tonic-gate 	user_lats = (int **)((uintptr_t)user_rsets +
16327c478bd9Sstevel@tonic-gate 	    (LGRP_RSRC_COUNT * snap_nlgrpsmax * bitmask_size));
16337c478bd9Sstevel@tonic-gate 
16347c478bd9Sstevel@tonic-gate 	/*
16357c478bd9Sstevel@tonic-gate 	 * Copyout magic number (ie. pointer to beginning of buffer)
16367c478bd9Sstevel@tonic-gate 	 */
16377c478bd9Sstevel@tonic-gate 	if (copyout(&buf, &user_snap->ss_magic, sizeof (buf)) != 0)
16387c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
16397c478bd9Sstevel@tonic-gate 
16407c478bd9Sstevel@tonic-gate 	/*
16417c478bd9Sstevel@tonic-gate 	 * Fix up pointers in user buffer to point into user buffer
16427c478bd9Sstevel@tonic-gate 	 * not kernel snapshot
16437c478bd9Sstevel@tonic-gate 	 */
16447c478bd9Sstevel@tonic-gate 	if (copyout(&user_info, &user_snap->ss_info, sizeof (user_info)) != 0)
16457c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
16467c478bd9Sstevel@tonic-gate 
16477c478bd9Sstevel@tonic-gate 	if (copyout(&user_cpuids, &user_snap->ss_cpuids,
16487c478bd9Sstevel@tonic-gate 	    sizeof (user_cpuids)) != 0)
16497c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
16507c478bd9Sstevel@tonic-gate 
16517c478bd9Sstevel@tonic-gate 	if (copyout(&user_lgrpset, &user_snap->ss_lgrpset,
16527c478bd9Sstevel@tonic-gate 	    sizeof (user_lgrpset)) != 0)
16537c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate 	if (copyout(&user_parents, &user_snap->ss_parents,
16567c478bd9Sstevel@tonic-gate 	    sizeof (user_parents)) != 0)
16577c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
16587c478bd9Sstevel@tonic-gate 
16597c478bd9Sstevel@tonic-gate 	if (copyout(&user_children, &user_snap->ss_children,
16607c478bd9Sstevel@tonic-gate 	    sizeof (user_children)) != 0)
16617c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
16627c478bd9Sstevel@tonic-gate 
16637c478bd9Sstevel@tonic-gate 	if (copyout(&user_rsets, &user_snap->ss_rsets,
16647c478bd9Sstevel@tonic-gate 	    sizeof (user_rsets)) != 0)
16657c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
16667c478bd9Sstevel@tonic-gate 
16677c478bd9Sstevel@tonic-gate 	if (copyout(&user_lats, &user_snap->ss_latencies,
16687c478bd9Sstevel@tonic-gate 	    sizeof (user_lats)) != 0)
16697c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
16707c478bd9Sstevel@tonic-gate 
16717c478bd9Sstevel@tonic-gate 	/*
16727c478bd9Sstevel@tonic-gate 	 * Make copies of lgroup info and latency table, fix up pointers,
16737c478bd9Sstevel@tonic-gate 	 * and then copy them into user buffer
16747c478bd9Sstevel@tonic-gate 	 */
16757c478bd9Sstevel@tonic-gate 	user_info_buffer = kmem_zalloc(info_size, KM_NOSLEEP);
16767c478bd9Sstevel@tonic-gate 	if (user_info_buffer == NULL)
16777c478bd9Sstevel@tonic-gate 		return (set_errno(ENOMEM));
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate 	user_lats_buffer = kmem_zalloc(snap_nlgrpsmax * sizeof (int *),
16807c478bd9Sstevel@tonic-gate 	    KM_NOSLEEP);
16817c478bd9Sstevel@tonic-gate 	if (user_lats_buffer == NULL) {
16827c478bd9Sstevel@tonic-gate 		kmem_free(user_info_buffer, info_size);
16837c478bd9Sstevel@tonic-gate 		return (set_errno(ENOMEM));
16847c478bd9Sstevel@tonic-gate 	}
16857c478bd9Sstevel@tonic-gate 
16867c478bd9Sstevel@tonic-gate 	lgrp_info = (lgrp_info_t *)((uintptr_t)lgrp_snap + snap_hdr_size);
16877c478bd9Sstevel@tonic-gate 	bcopy(lgrp_info, user_info_buffer, info_size);
16887c478bd9Sstevel@tonic-gate 
16897c478bd9Sstevel@tonic-gate 	cpu_index = 0;
16907c478bd9Sstevel@tonic-gate 	for (i = 0; i < snap_nlgrpsmax; i++) {
16917c478bd9Sstevel@tonic-gate 		ulong_t	*snap_rset;
16927c478bd9Sstevel@tonic-gate 
16937c478bd9Sstevel@tonic-gate 		/*
16947c478bd9Sstevel@tonic-gate 		 * Skip non-existent lgroups
16957c478bd9Sstevel@tonic-gate 		 */
16967c478bd9Sstevel@tonic-gate 		if (user_info_buffer[i].info_lgrpid == LGRP_NONE)
16977c478bd9Sstevel@tonic-gate 			continue;
16987c478bd9Sstevel@tonic-gate 
16997c478bd9Sstevel@tonic-gate 		/*
17007c478bd9Sstevel@tonic-gate 		 * Update free memory size since it changes frequently
17017c478bd9Sstevel@tonic-gate 		 * Only do so for lgroups directly containing memory
17027c478bd9Sstevel@tonic-gate 		 *
17037c478bd9Sstevel@tonic-gate 		 * NOTE: This must be done before changing the pointers to
17047c478bd9Sstevel@tonic-gate 		 *	 point into user space since we need to dereference
17057c478bd9Sstevel@tonic-gate 		 *	 lgroup resource set
17067c478bd9Sstevel@tonic-gate 		 */
17077c478bd9Sstevel@tonic-gate 		snap_rset = &lgrp_info[i].info_rset[LGRP_RSRC_MEM *
17087c478bd9Sstevel@tonic-gate 		    BT_BITOUL(snap_nlgrpsmax)];
17097c478bd9Sstevel@tonic-gate 		if (BT_TEST(snap_rset, i))
17107c478bd9Sstevel@tonic-gate 			user_info_buffer[i].info_mem_free =
17117c478bd9Sstevel@tonic-gate 			    lgrp_mem_size(i, LGRP_MEM_SIZE_FREE);
17127c478bd9Sstevel@tonic-gate 
17137c478bd9Sstevel@tonic-gate 		/*
17147c478bd9Sstevel@tonic-gate 		 * Fix up pointers to parents, children, resources, and
17157c478bd9Sstevel@tonic-gate 		 * latencies
17167c478bd9Sstevel@tonic-gate 		 */
17177c478bd9Sstevel@tonic-gate 		user_info_buffer[i].info_parents =
17187c478bd9Sstevel@tonic-gate 		    (ulong_t *)((uintptr_t)user_parents + (i * bitmask_size));
17197c478bd9Sstevel@tonic-gate 		user_info_buffer[i].info_children =
17207c478bd9Sstevel@tonic-gate 		    (ulong_t *)((uintptr_t)user_children + (i * bitmask_size));
17217c478bd9Sstevel@tonic-gate 		user_info_buffer[i].info_rset =
17227c478bd9Sstevel@tonic-gate 		    (ulong_t *)((uintptr_t)user_rsets +
17237c478bd9Sstevel@tonic-gate 		    (i * LGRP_RSRC_COUNT * bitmask_size));
17247c478bd9Sstevel@tonic-gate 		user_lats_buffer[i] = (int *)((uintptr_t)user_lats +
17257c478bd9Sstevel@tonic-gate 		    (snap_nlgrpsmax * sizeof (int *)) + (i * snap_nlgrpsmax *
17267c478bd9Sstevel@tonic-gate 		    sizeof (int)));
17277c478bd9Sstevel@tonic-gate 
17287c478bd9Sstevel@tonic-gate 		/*
17297c478bd9Sstevel@tonic-gate 		 * Fix up pointer to CPU IDs
17307c478bd9Sstevel@tonic-gate 		 */
17317c478bd9Sstevel@tonic-gate 		if (user_info_buffer[i].info_ncpus == 0) {
17327c478bd9Sstevel@tonic-gate 			user_info_buffer[i].info_cpuids = NULL;
17337c478bd9Sstevel@tonic-gate 			continue;
17347c478bd9Sstevel@tonic-gate 		}
17357c478bd9Sstevel@tonic-gate 		user_info_buffer[i].info_cpuids = &user_cpuids[cpu_index];
17367c478bd9Sstevel@tonic-gate 		cpu_index += user_info_buffer[i].info_ncpus;
17377c478bd9Sstevel@tonic-gate 	}
17387c478bd9Sstevel@tonic-gate 	ASSERT(cpu_index == snap_ncpus);
17397c478bd9Sstevel@tonic-gate 
17407c478bd9Sstevel@tonic-gate 	/*
17417c478bd9Sstevel@tonic-gate 	 * Copy lgroup info and latency table with pointers fixed up to point
17427c478bd9Sstevel@tonic-gate 	 * into user buffer out to user buffer now
17437c478bd9Sstevel@tonic-gate 	 */
17447c478bd9Sstevel@tonic-gate 	retval = lgrp_snap->ss_size;
17457c478bd9Sstevel@tonic-gate 	if (copyout(user_info_buffer, user_info, info_size) != 0)
17467c478bd9Sstevel@tonic-gate 		retval = set_errno(EFAULT);
17477c478bd9Sstevel@tonic-gate 	kmem_free(user_info_buffer, info_size);
17487c478bd9Sstevel@tonic-gate 
17497c478bd9Sstevel@tonic-gate 	if (copyout(user_lats_buffer, user_lats, snap_nlgrpsmax *
17507c478bd9Sstevel@tonic-gate 	    sizeof (int *)) != 0)
17517c478bd9Sstevel@tonic-gate 		retval = set_errno(EFAULT);
17527c478bd9Sstevel@tonic-gate 	kmem_free(user_lats_buffer, snap_nlgrpsmax * sizeof (int *));
17537c478bd9Sstevel@tonic-gate 
17547c478bd9Sstevel@tonic-gate 	return (retval);
17557c478bd9Sstevel@tonic-gate }
17567c478bd9Sstevel@tonic-gate 
17577c478bd9Sstevel@tonic-gate 
17587c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
17597c478bd9Sstevel@tonic-gate /*
17607c478bd9Sstevel@tonic-gate  * Make 32-bit copy of snapshot, fix up any pointers in buffer to point
17617c478bd9Sstevel@tonic-gate  * into user instead of kernel address space, copy 32-bit snapshot into
17627c478bd9Sstevel@tonic-gate  * given user buffer, and return size of buffer needed to hold snapshot
17637c478bd9Sstevel@tonic-gate  */
17647c478bd9Sstevel@tonic-gate static int
17657c478bd9Sstevel@tonic-gate lgrp_snapshot_copy32(caddr32_t buf, size32_t bufsize)
17667c478bd9Sstevel@tonic-gate {
17677c478bd9Sstevel@tonic-gate 	size32_t			bitmask_size;
17687c478bd9Sstevel@tonic-gate 	size32_t			bitmasks_size;
17697c478bd9Sstevel@tonic-gate 	size32_t			children_size;
17707c478bd9Sstevel@tonic-gate 	int				cpu_index;
17717c478bd9Sstevel@tonic-gate 	size32_t			cpuids_size;
17727c478bd9Sstevel@tonic-gate 	int				i;
17737c478bd9Sstevel@tonic-gate 	int				j;
17747c478bd9Sstevel@tonic-gate 	size32_t			info_size;
17757c478bd9Sstevel@tonic-gate 	size32_t			lats_size;
17767c478bd9Sstevel@tonic-gate 	lgrp_info_t			*lgrp_info;
17777c478bd9Sstevel@tonic-gate 	lgrp_snapshot_header32_t	*lgrp_snap32;
17787c478bd9Sstevel@tonic-gate 	lgrp_info32_t			*lgrp_info32;
17797c478bd9Sstevel@tonic-gate 	processorid_t			*lgrp_cpuids32;
17807c478bd9Sstevel@tonic-gate 	caddr32_t			*lgrp_lats32;
17817c478bd9Sstevel@tonic-gate 	int				**lgrp_lats32_kernel;
17827c478bd9Sstevel@tonic-gate 	uint_t				*lgrp_set32;
17837c478bd9Sstevel@tonic-gate 	uint_t				*lgrp_parents32;
17847c478bd9Sstevel@tonic-gate 	uint_t				*lgrp_children32;
17857c478bd9Sstevel@tonic-gate 	uint_t				*lgrp_rsets32;
17867c478bd9Sstevel@tonic-gate 	size32_t			parents_size;
17877c478bd9Sstevel@tonic-gate 	size32_t			rsets_size;
17887c478bd9Sstevel@tonic-gate 	size32_t			set_size;
17897c478bd9Sstevel@tonic-gate 	size32_t			snap_hdr_size;
17907c478bd9Sstevel@tonic-gate 	int				snap_ncpus;
17917c478bd9Sstevel@tonic-gate 	int				snap_nlgrpsmax;
17927c478bd9Sstevel@tonic-gate 	size32_t			snap_size;
17937c478bd9Sstevel@tonic-gate 
17947c478bd9Sstevel@tonic-gate 	if (lgrp_snap == NULL)
17957c478bd9Sstevel@tonic-gate 		return (0);
17967c478bd9Sstevel@tonic-gate 
17977c478bd9Sstevel@tonic-gate 	snap_ncpus = lgrp_snap->ss_ncpus;
17987c478bd9Sstevel@tonic-gate 	snap_nlgrpsmax = lgrp_snap->ss_nlgrps_max;
17997c478bd9Sstevel@tonic-gate 
18007c478bd9Sstevel@tonic-gate 	/*
18017c478bd9Sstevel@tonic-gate 	 * Calculate size of buffer needed for 32-bit snapshot,
18027c478bd9Sstevel@tonic-gate 	 * rounding up size of each object to allow for alignment
18037c478bd9Sstevel@tonic-gate 	 * of next object in buffer.
18047c478bd9Sstevel@tonic-gate 	 */
18057c478bd9Sstevel@tonic-gate 	snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header32_t),
18067c478bd9Sstevel@tonic-gate 	    sizeof (caddr32_t));
18077c478bd9Sstevel@tonic-gate 	info_size = P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info32_t),
18087c478bd9Sstevel@tonic-gate 	    sizeof (processorid_t));
18097c478bd9Sstevel@tonic-gate 	cpuids_size = P2ROUNDUP(snap_ncpus * sizeof (processorid_t),
18107c478bd9Sstevel@tonic-gate 		    sizeof (ulong_t));
18117c478bd9Sstevel@tonic-gate 
18127c478bd9Sstevel@tonic-gate 	bitmask_size = BT_SIZEOFMAP32(snap_nlgrpsmax);
18137c478bd9Sstevel@tonic-gate 
18147c478bd9Sstevel@tonic-gate 	set_size = bitmask_size;
18157c478bd9Sstevel@tonic-gate 	parents_size = snap_nlgrpsmax * bitmask_size;
18167c478bd9Sstevel@tonic-gate 	children_size = snap_nlgrpsmax * bitmask_size;
18177c478bd9Sstevel@tonic-gate 	rsets_size = P2ROUNDUP(LGRP_RSRC_COUNT * snap_nlgrpsmax *
18187c478bd9Sstevel@tonic-gate 	    (int)bitmask_size, sizeof (caddr32_t));
18197c478bd9Sstevel@tonic-gate 
18207c478bd9Sstevel@tonic-gate 	bitmasks_size = set_size + parents_size + children_size + rsets_size;
18217c478bd9Sstevel@tonic-gate 
18227c478bd9Sstevel@tonic-gate 	/*
18237c478bd9Sstevel@tonic-gate 	 * Size of latency table and buffer
18247c478bd9Sstevel@tonic-gate 	 */
18257c478bd9Sstevel@tonic-gate 	lats_size = (snap_nlgrpsmax * sizeof (caddr32_t)) +
18267c478bd9Sstevel@tonic-gate 	    (snap_nlgrpsmax * snap_nlgrpsmax * sizeof (int));
18277c478bd9Sstevel@tonic-gate 
18287c478bd9Sstevel@tonic-gate 	snap_size = snap_hdr_size + info_size + cpuids_size + bitmasks_size +
18297c478bd9Sstevel@tonic-gate 		lats_size;
18307c478bd9Sstevel@tonic-gate 
18317c478bd9Sstevel@tonic-gate 	if (buf == NULL || bufsize <= 0) {
18327c478bd9Sstevel@tonic-gate 		return (snap_size);
18337c478bd9Sstevel@tonic-gate 	}
18347c478bd9Sstevel@tonic-gate 
18357c478bd9Sstevel@tonic-gate 	/*
18367c478bd9Sstevel@tonic-gate 	 * User needs to try getting size of buffer again
18377c478bd9Sstevel@tonic-gate 	 * because given buffer size is too small.
18387c478bd9Sstevel@tonic-gate 	 * The lgroup hierarchy may have changed after they asked for the size
18397c478bd9Sstevel@tonic-gate 	 * but before the snapshot was taken.
18407c478bd9Sstevel@tonic-gate 	 */
18417c478bd9Sstevel@tonic-gate 	if (bufsize < snap_size)
18427c478bd9Sstevel@tonic-gate 		return (set_errno(EAGAIN));
18437c478bd9Sstevel@tonic-gate 
18447c478bd9Sstevel@tonic-gate 	/*
18457c478bd9Sstevel@tonic-gate 	 * Make 32-bit copy of snapshot, fix up pointers to point into user
18467c478bd9Sstevel@tonic-gate 	 * buffer not kernel, and then copy whole thing into user buffer
18477c478bd9Sstevel@tonic-gate 	 */
18487c478bd9Sstevel@tonic-gate 	lgrp_snap32 = kmem_zalloc(snap_size, KM_NOSLEEP);
18497c478bd9Sstevel@tonic-gate 	if (lgrp_snap32 == NULL)
18507c478bd9Sstevel@tonic-gate 		return (set_errno(ENOMEM));
18517c478bd9Sstevel@tonic-gate 
18527c478bd9Sstevel@tonic-gate 	/*
18537c478bd9Sstevel@tonic-gate 	 * Calculate pointers into 32-bit copy of snapshot
18547c478bd9Sstevel@tonic-gate 	 * for lgroup info, CPU IDs, pset lgroup bitmask, parents, children,
18557c478bd9Sstevel@tonic-gate 	 * resources, and latency table and buffer
18567c478bd9Sstevel@tonic-gate 	 */
18577c478bd9Sstevel@tonic-gate 	lgrp_info32 = (lgrp_info32_t *)((uintptr_t)lgrp_snap32 +
18587c478bd9Sstevel@tonic-gate 	    snap_hdr_size);
18597c478bd9Sstevel@tonic-gate 	lgrp_cpuids32 = (processorid_t *)((uintptr_t)lgrp_info32 + info_size);
18607c478bd9Sstevel@tonic-gate 	lgrp_set32 = (uint_t *)((uintptr_t)lgrp_cpuids32 + cpuids_size);
18617c478bd9Sstevel@tonic-gate 	lgrp_parents32 = (uint_t *)((uintptr_t)lgrp_set32 + set_size);
18627c478bd9Sstevel@tonic-gate 	lgrp_children32 = (uint_t *)((uintptr_t)lgrp_parents32 + parents_size);
18637c478bd9Sstevel@tonic-gate 	lgrp_rsets32 = (uint_t *)((uintptr_t)lgrp_children32 + children_size);
18647c478bd9Sstevel@tonic-gate 	lgrp_lats32 = (caddr32_t *)((uintptr_t)lgrp_rsets32 + rsets_size);
18657c478bd9Sstevel@tonic-gate 
18667c478bd9Sstevel@tonic-gate 	/*
18677c478bd9Sstevel@tonic-gate 	 * Make temporary lgroup latency table of pointers for kernel to use
18687c478bd9Sstevel@tonic-gate 	 * to fill in rows of table with latencies from each lgroup
18697c478bd9Sstevel@tonic-gate 	 */
18707c478bd9Sstevel@tonic-gate 	lgrp_lats32_kernel =  kmem_zalloc(snap_nlgrpsmax * sizeof (int *),
18717c478bd9Sstevel@tonic-gate 	    KM_NOSLEEP);
18727c478bd9Sstevel@tonic-gate 	if (lgrp_lats32_kernel == NULL) {
18737c478bd9Sstevel@tonic-gate 		kmem_free(lgrp_snap32, snap_size);
18747c478bd9Sstevel@tonic-gate 		return (set_errno(ENOMEM));
18757c478bd9Sstevel@tonic-gate 	}
18767c478bd9Sstevel@tonic-gate 
18777c478bd9Sstevel@tonic-gate 	/*
18787c478bd9Sstevel@tonic-gate 	 * Fill in 32-bit lgroup snapshot header
18797c478bd9Sstevel@tonic-gate 	 * (with pointers into user's buffer for lgroup info, CPU IDs,
18807c478bd9Sstevel@tonic-gate 	 * bit masks, and latencies)
18817c478bd9Sstevel@tonic-gate 	 */
18827c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_version = lgrp_snap->ss_version;
18837c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_levels = lgrp_snap->ss_levels;
18847c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_nlgrps = lgrp_snap32->ss_nlgrps_os =
18857c478bd9Sstevel@tonic-gate 	    lgrp_snap->ss_nlgrps;
18867c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_nlgrps_max = snap_nlgrpsmax;
18877c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_root = lgrp_snap->ss_root;
18887c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_ncpus = lgrp_snap->ss_ncpus;
18897c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_gen = lgrp_snap->ss_gen;
18907c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_view = LGRP_VIEW_OS;
18917c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_size = snap_size;
18927c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_magic = buf;
18937c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_info = buf + snap_hdr_size;
18947c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_cpuids = lgrp_snap32->ss_info + info_size;
18957c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_lgrpset = lgrp_snap32->ss_cpuids + cpuids_size;
18967c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_parents = lgrp_snap32->ss_lgrpset + bitmask_size;
18977c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_children = lgrp_snap32->ss_parents +
18987c478bd9Sstevel@tonic-gate 	    (snap_nlgrpsmax * bitmask_size);
18997c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_rsets = lgrp_snap32->ss_children +
19007c478bd9Sstevel@tonic-gate 	    (snap_nlgrpsmax * bitmask_size);
19017c478bd9Sstevel@tonic-gate 	lgrp_snap32->ss_latencies = lgrp_snap32->ss_rsets +
19027c478bd9Sstevel@tonic-gate 	    (LGRP_RSRC_COUNT * snap_nlgrpsmax * bitmask_size);
19037c478bd9Sstevel@tonic-gate 
19047c478bd9Sstevel@tonic-gate 	/*
19057c478bd9Sstevel@tonic-gate 	 * Fill in lgrpset now because caller may have change psets
19067c478bd9Sstevel@tonic-gate 	 */
19077c478bd9Sstevel@tonic-gate 	kpreempt_disable();
19087c478bd9Sstevel@tonic-gate 	for (i = 0; i < snap_nlgrpsmax; i++) {
19097c478bd9Sstevel@tonic-gate 		if (klgrpset_ismember(curthread->t_cpupart->cp_lgrpset,
19107c478bd9Sstevel@tonic-gate 		    i)) {
19117c478bd9Sstevel@tonic-gate 			BT_SET32(lgrp_set32, i);
19127c478bd9Sstevel@tonic-gate 		}
19137c478bd9Sstevel@tonic-gate 	}
19147c478bd9Sstevel@tonic-gate 	kpreempt_enable();
19157c478bd9Sstevel@tonic-gate 
19167c478bd9Sstevel@tonic-gate 	/*
19177c478bd9Sstevel@tonic-gate 	 * Fill in 32-bit copy of lgroup info and fix up pointers
19187c478bd9Sstevel@tonic-gate 	 * to point into user's buffer instead of kernel's
19197c478bd9Sstevel@tonic-gate 	 */
19207c478bd9Sstevel@tonic-gate 	cpu_index = 0;
19217c478bd9Sstevel@tonic-gate 	lgrp_info = lgrp_snap->ss_info;
19227c478bd9Sstevel@tonic-gate 	for (i = 0; i < snap_nlgrpsmax; i++) {
19237c478bd9Sstevel@tonic-gate 		uint_t	*children;
19247c478bd9Sstevel@tonic-gate 		uint_t	*lgrp_rset;
19257c478bd9Sstevel@tonic-gate 		uint_t	*parents;
19267c478bd9Sstevel@tonic-gate 		ulong_t	*snap_rset;
19277c478bd9Sstevel@tonic-gate 
19287c478bd9Sstevel@tonic-gate 		/*
19297c478bd9Sstevel@tonic-gate 		 * Skip non-existent lgroups
19307c478bd9Sstevel@tonic-gate 		 */
19317c478bd9Sstevel@tonic-gate 		if (lgrp_info[i].info_lgrpid == LGRP_NONE) {
19327c478bd9Sstevel@tonic-gate 			bzero(&lgrp_info32[i], sizeof (lgrp_info32[i]));
19337c478bd9Sstevel@tonic-gate 			lgrp_info32[i].info_lgrpid = LGRP_NONE;
19347c478bd9Sstevel@tonic-gate 			continue;
19357c478bd9Sstevel@tonic-gate 		}
19367c478bd9Sstevel@tonic-gate 
19377c478bd9Sstevel@tonic-gate 		/*
19387c478bd9Sstevel@tonic-gate 		 * Fill in parents, children, lgroup resource set, and
19397c478bd9Sstevel@tonic-gate 		 * latencies from snapshot
19407c478bd9Sstevel@tonic-gate 		 */
19417c478bd9Sstevel@tonic-gate 		parents = (uint_t *)((uintptr_t)lgrp_parents32 +
19427c478bd9Sstevel@tonic-gate 		    i * bitmask_size);
19437c478bd9Sstevel@tonic-gate 		children = (uint_t *)((uintptr_t)lgrp_children32 +
19447c478bd9Sstevel@tonic-gate 		    i * bitmask_size);
19457c478bd9Sstevel@tonic-gate 		snap_rset = (ulong_t *)((uintptr_t)lgrp_snap->ss_rsets +
19467c478bd9Sstevel@tonic-gate 		    (i * LGRP_RSRC_COUNT * BT_SIZEOFMAP(snap_nlgrpsmax)));
19477c478bd9Sstevel@tonic-gate 		lgrp_rset = (uint_t *)((uintptr_t)lgrp_rsets32 +
19487c478bd9Sstevel@tonic-gate 		    (i * LGRP_RSRC_COUNT * bitmask_size));
19497c478bd9Sstevel@tonic-gate 		lgrp_lats32_kernel[i] = (int *)((uintptr_t)lgrp_lats32 +
19507c478bd9Sstevel@tonic-gate 		    snap_nlgrpsmax * sizeof (caddr32_t) + i * snap_nlgrpsmax *
19517c478bd9Sstevel@tonic-gate 		    sizeof (int));
19527c478bd9Sstevel@tonic-gate 		for (j = 0; j < snap_nlgrpsmax; j++) {
19537c478bd9Sstevel@tonic-gate 			int	k;
19547c478bd9Sstevel@tonic-gate 			uint_t	*rset;
19557c478bd9Sstevel@tonic-gate 
19567c478bd9Sstevel@tonic-gate 			if (BT_TEST(&lgrp_snap->ss_parents[i], j))
19577c478bd9Sstevel@tonic-gate 				BT_SET32(parents, j);
19587c478bd9Sstevel@tonic-gate 
19597c478bd9Sstevel@tonic-gate 			if (BT_TEST(&lgrp_snap->ss_children[i], j))
19607c478bd9Sstevel@tonic-gate 				BT_SET32(children, j);
19617c478bd9Sstevel@tonic-gate 
19627c478bd9Sstevel@tonic-gate 			for (k = 0; k < LGRP_RSRC_COUNT; k++) {
19637c478bd9Sstevel@tonic-gate 				rset = (uint_t *)((uintptr_t)lgrp_rset +
19647c478bd9Sstevel@tonic-gate 				    k * bitmask_size);
19657c478bd9Sstevel@tonic-gate 				if (BT_TEST(&snap_rset[k], j))
19667c478bd9Sstevel@tonic-gate 					BT_SET32(rset, j);
19677c478bd9Sstevel@tonic-gate 			}
19687c478bd9Sstevel@tonic-gate 
19697c478bd9Sstevel@tonic-gate 			lgrp_lats32_kernel[i][j] =
19707c478bd9Sstevel@tonic-gate 			    lgrp_snap->ss_latencies[i][j];
19717c478bd9Sstevel@tonic-gate 		}
19727c478bd9Sstevel@tonic-gate 
19737c478bd9Sstevel@tonic-gate 		/*
19747c478bd9Sstevel@tonic-gate 		 * Fix up pointer to latency buffer
19757c478bd9Sstevel@tonic-gate 		 */
19767c478bd9Sstevel@tonic-gate 		lgrp_lats32[i] = lgrp_snap32->ss_latencies +
19777c478bd9Sstevel@tonic-gate 		    snap_nlgrpsmax * sizeof (caddr32_t) + i * snap_nlgrpsmax *
19787c478bd9Sstevel@tonic-gate 		    sizeof (int);
19797c478bd9Sstevel@tonic-gate 
19807c478bd9Sstevel@tonic-gate 		/*
19817c478bd9Sstevel@tonic-gate 		 * Fix up pointers for parents, children, and resources
19827c478bd9Sstevel@tonic-gate 		 */
19837c478bd9Sstevel@tonic-gate 		lgrp_info32[i].info_parents = lgrp_snap32->ss_parents +
19847c478bd9Sstevel@tonic-gate 		    (i * bitmask_size);
19857c478bd9Sstevel@tonic-gate 		lgrp_info32[i].info_children = lgrp_snap32->ss_children +
19867c478bd9Sstevel@tonic-gate 		    (i * bitmask_size);
19877c478bd9Sstevel@tonic-gate 		lgrp_info32[i].info_rset = lgrp_snap32->ss_rsets +
19887c478bd9Sstevel@tonic-gate 		    (i * LGRP_RSRC_COUNT * bitmask_size);
19897c478bd9Sstevel@tonic-gate 
19907c478bd9Sstevel@tonic-gate 		/*
19917c478bd9Sstevel@tonic-gate 		 * Fill in memory and CPU info
19927c478bd9Sstevel@tonic-gate 		 * Only fill in memory for lgroups directly containing memory
19937c478bd9Sstevel@tonic-gate 		 */
19947c478bd9Sstevel@tonic-gate 		snap_rset = &lgrp_info[i].info_rset[LGRP_RSRC_MEM *
19957c478bd9Sstevel@tonic-gate 		    BT_BITOUL(snap_nlgrpsmax)];
19967c478bd9Sstevel@tonic-gate 		if (BT_TEST(snap_rset, i)) {
19977c478bd9Sstevel@tonic-gate 			lgrp_info32[i].info_mem_free = lgrp_mem_size(i,
19987c478bd9Sstevel@tonic-gate 			    LGRP_MEM_SIZE_FREE);
19997c478bd9Sstevel@tonic-gate 			lgrp_info32[i].info_mem_install =
20007c478bd9Sstevel@tonic-gate 			    lgrp_info[i].info_mem_install;
20017c478bd9Sstevel@tonic-gate 		}
20027c478bd9Sstevel@tonic-gate 
20037c478bd9Sstevel@tonic-gate 		lgrp_info32[i].info_ncpus = lgrp_info[i].info_ncpus;
20047c478bd9Sstevel@tonic-gate 
20057c478bd9Sstevel@tonic-gate 		lgrp_info32[i].info_lgrpid = lgrp_info[i].info_lgrpid;
20067c478bd9Sstevel@tonic-gate 		lgrp_info32[i].info_latency = lgrp_info[i].info_latency;
20077c478bd9Sstevel@tonic-gate 
20087c478bd9Sstevel@tonic-gate 		if (lgrp_info32[i].info_ncpus == 0) {
20097c478bd9Sstevel@tonic-gate 			lgrp_info32[i].info_cpuids = 0;
20107c478bd9Sstevel@tonic-gate 			continue;
20117c478bd9Sstevel@tonic-gate 		}
20127c478bd9Sstevel@tonic-gate 
20137c478bd9Sstevel@tonic-gate 		/*
20147c478bd9Sstevel@tonic-gate 		 * Fix up pointer for CPU IDs
20157c478bd9Sstevel@tonic-gate 		 */
20167c478bd9Sstevel@tonic-gate 		lgrp_info32[i].info_cpuids = lgrp_snap32->ss_cpuids +
20177c478bd9Sstevel@tonic-gate 		    (cpu_index * sizeof (processorid_t));
20187c478bd9Sstevel@tonic-gate 		cpu_index += lgrp_info32[i].info_ncpus;
20197c478bd9Sstevel@tonic-gate 	}
20207c478bd9Sstevel@tonic-gate 	ASSERT(cpu_index == snap_ncpus);
20217c478bd9Sstevel@tonic-gate 
20227c478bd9Sstevel@tonic-gate 	/*
20237c478bd9Sstevel@tonic-gate 	 * Copy lgroup CPU IDs into 32-bit snapshot
20247c478bd9Sstevel@tonic-gate 	 * before copying it out into user's buffer
20257c478bd9Sstevel@tonic-gate 	 */
20267c478bd9Sstevel@tonic-gate 	bcopy(lgrp_snap->ss_cpuids, lgrp_cpuids32, cpuids_size);
20277c478bd9Sstevel@tonic-gate 
20287c478bd9Sstevel@tonic-gate 	/*
20297c478bd9Sstevel@tonic-gate 	 * Copy 32-bit lgroup snapshot into user's buffer all at once
20307c478bd9Sstevel@tonic-gate 	 */
20317c478bd9Sstevel@tonic-gate 	if (copyout(lgrp_snap32, (void *)(uintptr_t)buf, snap_size) != 0) {
20327c478bd9Sstevel@tonic-gate 		kmem_free(lgrp_snap32, snap_size);
20337c478bd9Sstevel@tonic-gate 		kmem_free(lgrp_lats32_kernel, snap_nlgrpsmax * sizeof (int *));
20347c478bd9Sstevel@tonic-gate 		return (set_errno(EFAULT));
20357c478bd9Sstevel@tonic-gate 	}
20367c478bd9Sstevel@tonic-gate 
20377c478bd9Sstevel@tonic-gate 	kmem_free(lgrp_snap32, snap_size);
20387c478bd9Sstevel@tonic-gate 	kmem_free(lgrp_lats32_kernel, snap_nlgrpsmax * sizeof (int *));
20397c478bd9Sstevel@tonic-gate 
20407c478bd9Sstevel@tonic-gate 	return (snap_size);
20417c478bd9Sstevel@tonic-gate }
20427c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
20437c478bd9Sstevel@tonic-gate 
20447c478bd9Sstevel@tonic-gate 
20457c478bd9Sstevel@tonic-gate int
20467c478bd9Sstevel@tonic-gate lgrpsys(int subcode, long ia, void *ap)
20477c478bd9Sstevel@tonic-gate {
20487c478bd9Sstevel@tonic-gate 	size_t	bufsize;
20497c478bd9Sstevel@tonic-gate 	int	latency;
20507c478bd9Sstevel@tonic-gate 
20517c478bd9Sstevel@tonic-gate 	switch (subcode) {
20527c478bd9Sstevel@tonic-gate 
20537c478bd9Sstevel@tonic-gate 	case LGRP_SYS_AFFINITY_GET:
20547c478bd9Sstevel@tonic-gate 		return (lgrp_affinity_get((lgrp_affinity_args_t *)ap));
20557c478bd9Sstevel@tonic-gate 
20567c478bd9Sstevel@tonic-gate 	case LGRP_SYS_AFFINITY_SET:
20577c478bd9Sstevel@tonic-gate 		return (lgrp_affinity_set((lgrp_affinity_args_t *)ap));
20587c478bd9Sstevel@tonic-gate 
20597c478bd9Sstevel@tonic-gate 	case LGRP_SYS_GENERATION:
20607c478bd9Sstevel@tonic-gate 		return (lgrp_generation(ia));
20617c478bd9Sstevel@tonic-gate 
20627c478bd9Sstevel@tonic-gate 	case LGRP_SYS_HOME:
20637c478bd9Sstevel@tonic-gate 		return (lgrp_home_get((idtype_t)ia, (id_t)(uintptr_t)ap));
20647c478bd9Sstevel@tonic-gate 
20657c478bd9Sstevel@tonic-gate 	case LGRP_SYS_LATENCY:
20667c478bd9Sstevel@tonic-gate 		mutex_enter(&cpu_lock);
20677c478bd9Sstevel@tonic-gate 		latency = lgrp_latency(ia, (lgrp_id_t)(uintptr_t)ap);
20687c478bd9Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
20697c478bd9Sstevel@tonic-gate 		return (latency);
20707c478bd9Sstevel@tonic-gate 
20717c478bd9Sstevel@tonic-gate 	case LGRP_SYS_MEMINFO:
20727c478bd9Sstevel@tonic-gate 		return (meminfo(ia, (struct meminfo *)ap));
20737c478bd9Sstevel@tonic-gate 
20747c478bd9Sstevel@tonic-gate 	case LGRP_SYS_VERSION:
20757c478bd9Sstevel@tonic-gate 		return (lgrp_version(ia));
20767c478bd9Sstevel@tonic-gate 
20777c478bd9Sstevel@tonic-gate 	case LGRP_SYS_SNAPSHOT:
20787c478bd9Sstevel@tonic-gate 		mutex_enter(&lgrp_snap_lock);
20797c478bd9Sstevel@tonic-gate 		bufsize = lgrp_snapshot();
20807c478bd9Sstevel@tonic-gate 		if (ap && ia > 0) {
20817c478bd9Sstevel@tonic-gate 			if (get_udatamodel() == DATAMODEL_NATIVE)
20827c478bd9Sstevel@tonic-gate 				bufsize = lgrp_snapshot_copy(ap, ia);
20837c478bd9Sstevel@tonic-gate #ifdef	_SYSCALL32_IMPL
20847c478bd9Sstevel@tonic-gate 			else
20857c478bd9Sstevel@tonic-gate 				bufsize = lgrp_snapshot_copy32(
20867c478bd9Sstevel@tonic-gate 				    (caddr32_t)(uintptr_t)ap, ia);
20877c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
20887c478bd9Sstevel@tonic-gate 		}
20897c478bd9Sstevel@tonic-gate 		mutex_exit(&lgrp_snap_lock);
20907c478bd9Sstevel@tonic-gate 		return (bufsize);
20917c478bd9Sstevel@tonic-gate 
20927c478bd9Sstevel@tonic-gate 	default:
20937c478bd9Sstevel@tonic-gate 		break;
20947c478bd9Sstevel@tonic-gate 
20957c478bd9Sstevel@tonic-gate 	}
20967c478bd9Sstevel@tonic-gate 
20977c478bd9Sstevel@tonic-gate 	return (set_errno(EINVAL));
20987c478bd9Sstevel@tonic-gate }
2099