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