1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* 30*7c478bd9Sstevel@tonic-gate * lgroup system calls 31*7c478bd9Sstevel@tonic-gate */ 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/systm.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/mman.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/cpupart.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/lgrp.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/lgrp_user.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/promif.h> /* for prom_printf() */ 42*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 43*7c478bd9Sstevel@tonic-gate 44*7c478bd9Sstevel@tonic-gate #include <vm/as.h> 45*7c478bd9Sstevel@tonic-gate 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate /* definitions for mi_validity */ 48*7c478bd9Sstevel@tonic-gate #define VALID_ADDR 1 49*7c478bd9Sstevel@tonic-gate #define VALID_REQ 2 50*7c478bd9Sstevel@tonic-gate 51*7c478bd9Sstevel@tonic-gate /* 52*7c478bd9Sstevel@tonic-gate * run through the given number of addresses and requests and return the 53*7c478bd9Sstevel@tonic-gate * corresponding memory information for each address 54*7c478bd9Sstevel@tonic-gate */ 55*7c478bd9Sstevel@tonic-gate static int 56*7c478bd9Sstevel@tonic-gate meminfo(int addr_count, struct meminfo *mip) 57*7c478bd9Sstevel@tonic-gate { 58*7c478bd9Sstevel@tonic-gate size_t in_size, out_size, req_size, val_size; 59*7c478bd9Sstevel@tonic-gate struct as *as; 60*7c478bd9Sstevel@tonic-gate struct hat *hat; 61*7c478bd9Sstevel@tonic-gate int i, j, out_idx, info_count; 62*7c478bd9Sstevel@tonic-gate lgrp_t *lgrp; 63*7c478bd9Sstevel@tonic-gate pfn_t pfn; 64*7c478bd9Sstevel@tonic-gate ssize_t pgsz; 65*7c478bd9Sstevel@tonic-gate int *req_array, *val_array; 66*7c478bd9Sstevel@tonic-gate uint64_t *in_array, *out_array; 67*7c478bd9Sstevel@tonic-gate uint64_t addr, paddr; 68*7c478bd9Sstevel@tonic-gate uintptr_t vaddr; 69*7c478bd9Sstevel@tonic-gate int ret = 0; 70*7c478bd9Sstevel@tonic-gate struct meminfo minfo; 71*7c478bd9Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL) 72*7c478bd9Sstevel@tonic-gate struct meminfo32 minfo32; 73*7c478bd9Sstevel@tonic-gate #endif 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate /* 76*7c478bd9Sstevel@tonic-gate * Make sure that there is at least one address to translate and 77*7c478bd9Sstevel@tonic-gate * limit how many virtual addresses the kernel can do per call 78*7c478bd9Sstevel@tonic-gate */ 79*7c478bd9Sstevel@tonic-gate if (addr_count < 1) 80*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 81*7c478bd9Sstevel@tonic-gate else if (addr_count > MAX_MEMINFO_CNT) 82*7c478bd9Sstevel@tonic-gate addr_count = MAX_MEMINFO_CNT; 83*7c478bd9Sstevel@tonic-gate 84*7c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) { 85*7c478bd9Sstevel@tonic-gate if (copyin(mip, &minfo, sizeof (struct meminfo))) 86*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 87*7c478bd9Sstevel@tonic-gate } 88*7c478bd9Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL) 89*7c478bd9Sstevel@tonic-gate else { 90*7c478bd9Sstevel@tonic-gate bzero(&minfo, sizeof (minfo)); 91*7c478bd9Sstevel@tonic-gate if (copyin(mip, &minfo32, sizeof (struct meminfo32))) 92*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 93*7c478bd9Sstevel@tonic-gate minfo.mi_inaddr = (const uint64_t *)(uintptr_t) 94*7c478bd9Sstevel@tonic-gate minfo32.mi_inaddr; 95*7c478bd9Sstevel@tonic-gate minfo.mi_info_req = (const uint_t *)(uintptr_t) 96*7c478bd9Sstevel@tonic-gate minfo32.mi_info_req; 97*7c478bd9Sstevel@tonic-gate minfo.mi_info_count = minfo32.mi_info_count; 98*7c478bd9Sstevel@tonic-gate minfo.mi_outdata = (uint64_t *)(uintptr_t) 99*7c478bd9Sstevel@tonic-gate minfo32.mi_outdata; 100*7c478bd9Sstevel@tonic-gate minfo.mi_validity = (uint_t *)(uintptr_t) 101*7c478bd9Sstevel@tonic-gate minfo32.mi_validity; 102*7c478bd9Sstevel@tonic-gate } 103*7c478bd9Sstevel@tonic-gate #endif 104*7c478bd9Sstevel@tonic-gate /* 105*7c478bd9Sstevel@tonic-gate * all the input parameters have been copied in:- 106*7c478bd9Sstevel@tonic-gate * addr_count - number of input addresses 107*7c478bd9Sstevel@tonic-gate * minfo.mi_inaddr - array of input addresses 108*7c478bd9Sstevel@tonic-gate * minfo.mi_info_req - array of types of information requested 109*7c478bd9Sstevel@tonic-gate * minfo.mi_info_count - no. of pieces of info requested for each addr 110*7c478bd9Sstevel@tonic-gate * minfo.mi_outdata - array into which the results are placed 111*7c478bd9Sstevel@tonic-gate * minfo.mi_validity - array containing bitwise result codes; 0th bit 112*7c478bd9Sstevel@tonic-gate * evaluates validity of corresponding input 113*7c478bd9Sstevel@tonic-gate * address, 1st bit validity of response to first 114*7c478bd9Sstevel@tonic-gate * member of info_req, etc. 115*7c478bd9Sstevel@tonic-gate */ 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate /* make sure mi_info_count is within limit */ 118*7c478bd9Sstevel@tonic-gate info_count = minfo.mi_info_count; 119*7c478bd9Sstevel@tonic-gate if (info_count < 1 || info_count > MAX_MEMINFO_REQ) 120*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 121*7c478bd9Sstevel@tonic-gate 122*7c478bd9Sstevel@tonic-gate /* 123*7c478bd9Sstevel@tonic-gate * allocate buffer in_array for the input addresses and copy them in 124*7c478bd9Sstevel@tonic-gate */ 125*7c478bd9Sstevel@tonic-gate in_size = sizeof (uint64_t) * addr_count; 126*7c478bd9Sstevel@tonic-gate in_array = kmem_alloc(in_size, KM_SLEEP); 127*7c478bd9Sstevel@tonic-gate if (copyin(minfo.mi_inaddr, in_array, in_size)) { 128*7c478bd9Sstevel@tonic-gate kmem_free(in_array, in_size); 129*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 130*7c478bd9Sstevel@tonic-gate } 131*7c478bd9Sstevel@tonic-gate 132*7c478bd9Sstevel@tonic-gate /* 133*7c478bd9Sstevel@tonic-gate * allocate buffer req_array for the input info_reqs and copy them in 134*7c478bd9Sstevel@tonic-gate */ 135*7c478bd9Sstevel@tonic-gate req_size = sizeof (uint_t) * info_count; 136*7c478bd9Sstevel@tonic-gate req_array = kmem_alloc(req_size, KM_SLEEP); 137*7c478bd9Sstevel@tonic-gate if (copyin(minfo.mi_info_req, req_array, req_size)) { 138*7c478bd9Sstevel@tonic-gate kmem_free(req_array, req_size); 139*7c478bd9Sstevel@tonic-gate kmem_free(in_array, in_size); 140*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 141*7c478bd9Sstevel@tonic-gate } 142*7c478bd9Sstevel@tonic-gate 143*7c478bd9Sstevel@tonic-gate /* 144*7c478bd9Sstevel@tonic-gate * allocate buffer out_array which holds the results and will have 145*7c478bd9Sstevel@tonic-gate * to be copied out later 146*7c478bd9Sstevel@tonic-gate */ 147*7c478bd9Sstevel@tonic-gate out_size = sizeof (uint64_t) * addr_count * info_count; 148*7c478bd9Sstevel@tonic-gate out_array = kmem_alloc(out_size, KM_SLEEP); 149*7c478bd9Sstevel@tonic-gate 150*7c478bd9Sstevel@tonic-gate /* 151*7c478bd9Sstevel@tonic-gate * allocate buffer val_array which holds the validity bits and will 152*7c478bd9Sstevel@tonic-gate * have to be copied out later 153*7c478bd9Sstevel@tonic-gate */ 154*7c478bd9Sstevel@tonic-gate val_size = sizeof (uint_t) * addr_count; 155*7c478bd9Sstevel@tonic-gate val_array = kmem_alloc(val_size, KM_SLEEP); 156*7c478bd9Sstevel@tonic-gate 157*7c478bd9Sstevel@tonic-gate if ((req_array[0] & MEMINFO_MASK) == MEMINFO_PLGRP) { 158*7c478bd9Sstevel@tonic-gate /* find the corresponding lgroup for each physical address */ 159*7c478bd9Sstevel@tonic-gate for (i = 0; i < addr_count; i++) { 160*7c478bd9Sstevel@tonic-gate paddr = in_array[i]; 161*7c478bd9Sstevel@tonic-gate pfn = btop(paddr); 162*7c478bd9Sstevel@tonic-gate lgrp = lgrp_pfn_to_lgrp(pfn); 163*7c478bd9Sstevel@tonic-gate if (lgrp) { 164*7c478bd9Sstevel@tonic-gate out_array[i] = lgrp->lgrp_id; 165*7c478bd9Sstevel@tonic-gate val_array[i] = VALID_ADDR | VALID_REQ; 166*7c478bd9Sstevel@tonic-gate } else { 167*7c478bd9Sstevel@tonic-gate out_array[i] = NULL; 168*7c478bd9Sstevel@tonic-gate val_array[i] = 0; 169*7c478bd9Sstevel@tonic-gate } 170*7c478bd9Sstevel@tonic-gate } 171*7c478bd9Sstevel@tonic-gate } else { 172*7c478bd9Sstevel@tonic-gate /* get the corresponding memory info for each virtual address */ 173*7c478bd9Sstevel@tonic-gate as = curproc->p_as; 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate AS_LOCK_ENTER(as, &as->a_lock, RW_READER); 176*7c478bd9Sstevel@tonic-gate hat = as->a_hat; 177*7c478bd9Sstevel@tonic-gate for (i = out_idx = 0; i < addr_count; i++, out_idx += 178*7c478bd9Sstevel@tonic-gate info_count) { 179*7c478bd9Sstevel@tonic-gate addr = in_array[i]; 180*7c478bd9Sstevel@tonic-gate vaddr = (uintptr_t)(addr & ~PAGEOFFSET); 181*7c478bd9Sstevel@tonic-gate if (!as_segat(as, (caddr_t)vaddr)) { 182*7c478bd9Sstevel@tonic-gate val_array[i] = 0; 183*7c478bd9Sstevel@tonic-gate continue; 184*7c478bd9Sstevel@tonic-gate } 185*7c478bd9Sstevel@tonic-gate val_array[i] = VALID_ADDR; 186*7c478bd9Sstevel@tonic-gate pfn = hat_getpfnum(hat, (caddr_t)vaddr); 187*7c478bd9Sstevel@tonic-gate if (pfn != PFN_INVALID) { 188*7c478bd9Sstevel@tonic-gate paddr = (uint64_t)((pfn << PAGESHIFT) | 189*7c478bd9Sstevel@tonic-gate (addr & PAGEOFFSET)); 190*7c478bd9Sstevel@tonic-gate for (j = 0; j < info_count; j++) { 191*7c478bd9Sstevel@tonic-gate switch (req_array[j] & MEMINFO_MASK) { 192*7c478bd9Sstevel@tonic-gate case MEMINFO_VPHYSICAL: 193*7c478bd9Sstevel@tonic-gate /* 194*7c478bd9Sstevel@tonic-gate * return the physical address 195*7c478bd9Sstevel@tonic-gate * corresponding to the input 196*7c478bd9Sstevel@tonic-gate * virtual address 197*7c478bd9Sstevel@tonic-gate */ 198*7c478bd9Sstevel@tonic-gate out_array[out_idx + j] = paddr; 199*7c478bd9Sstevel@tonic-gate val_array[i] |= VALID_REQ << j; 200*7c478bd9Sstevel@tonic-gate break; 201*7c478bd9Sstevel@tonic-gate case MEMINFO_VLGRP: 202*7c478bd9Sstevel@tonic-gate /* 203*7c478bd9Sstevel@tonic-gate * return the lgroup of physical 204*7c478bd9Sstevel@tonic-gate * page corresponding to the 205*7c478bd9Sstevel@tonic-gate * input virtual address 206*7c478bd9Sstevel@tonic-gate */ 207*7c478bd9Sstevel@tonic-gate lgrp = lgrp_pfn_to_lgrp(pfn); 208*7c478bd9Sstevel@tonic-gate if (lgrp) { 209*7c478bd9Sstevel@tonic-gate out_array[out_idx + j] = 210*7c478bd9Sstevel@tonic-gate lgrp->lgrp_id; 211*7c478bd9Sstevel@tonic-gate val_array[i] |= 212*7c478bd9Sstevel@tonic-gate VALID_REQ << j; 213*7c478bd9Sstevel@tonic-gate } 214*7c478bd9Sstevel@tonic-gate break; 215*7c478bd9Sstevel@tonic-gate case MEMINFO_VPAGESIZE: 216*7c478bd9Sstevel@tonic-gate /* 217*7c478bd9Sstevel@tonic-gate * return the size of physical 218*7c478bd9Sstevel@tonic-gate * page corresponding to the 219*7c478bd9Sstevel@tonic-gate * input virtual address 220*7c478bd9Sstevel@tonic-gate */ 221*7c478bd9Sstevel@tonic-gate pgsz = hat_getpagesize(hat, 222*7c478bd9Sstevel@tonic-gate (caddr_t)vaddr); 223*7c478bd9Sstevel@tonic-gate if (pgsz != -1) { 224*7c478bd9Sstevel@tonic-gate out_array[out_idx + j] = 225*7c478bd9Sstevel@tonic-gate pgsz; 226*7c478bd9Sstevel@tonic-gate val_array[i] |= 227*7c478bd9Sstevel@tonic-gate VALID_REQ << j; 228*7c478bd9Sstevel@tonic-gate } 229*7c478bd9Sstevel@tonic-gate break; 230*7c478bd9Sstevel@tonic-gate case MEMINFO_VREPLCNT: 231*7c478bd9Sstevel@tonic-gate /* 232*7c478bd9Sstevel@tonic-gate * for future use:- 233*7c478bd9Sstevel@tonic-gate * return the no. replicated 234*7c478bd9Sstevel@tonic-gate * physical pages corresponding 235*7c478bd9Sstevel@tonic-gate * to the input virtual address, 236*7c478bd9Sstevel@tonic-gate * so it is always 0 at the 237*7c478bd9Sstevel@tonic-gate * moment 238*7c478bd9Sstevel@tonic-gate */ 239*7c478bd9Sstevel@tonic-gate out_array[out_idx + j] = 0; 240*7c478bd9Sstevel@tonic-gate val_array[i] |= VALID_REQ << j; 241*7c478bd9Sstevel@tonic-gate break; 242*7c478bd9Sstevel@tonic-gate case MEMINFO_VREPL: 243*7c478bd9Sstevel@tonic-gate /* 244*7c478bd9Sstevel@tonic-gate * for future use:- 245*7c478bd9Sstevel@tonic-gate * return the nth physical 246*7c478bd9Sstevel@tonic-gate * replica of the specified 247*7c478bd9Sstevel@tonic-gate * virtual address 248*7c478bd9Sstevel@tonic-gate */ 249*7c478bd9Sstevel@tonic-gate break; 250*7c478bd9Sstevel@tonic-gate case MEMINFO_VREPL_LGRP: 251*7c478bd9Sstevel@tonic-gate /* 252*7c478bd9Sstevel@tonic-gate * for future use:- 253*7c478bd9Sstevel@tonic-gate * return the lgroup of nth 254*7c478bd9Sstevel@tonic-gate * physical replica of the 255*7c478bd9Sstevel@tonic-gate * specified virtual address 256*7c478bd9Sstevel@tonic-gate */ 257*7c478bd9Sstevel@tonic-gate break; 258*7c478bd9Sstevel@tonic-gate case MEMINFO_PLGRP: 259*7c478bd9Sstevel@tonic-gate /* 260*7c478bd9Sstevel@tonic-gate * this is for physical address 261*7c478bd9Sstevel@tonic-gate * only, shouldn't mix with 262*7c478bd9Sstevel@tonic-gate * virtual address 263*7c478bd9Sstevel@tonic-gate */ 264*7c478bd9Sstevel@tonic-gate break; 265*7c478bd9Sstevel@tonic-gate default: 266*7c478bd9Sstevel@tonic-gate break; 267*7c478bd9Sstevel@tonic-gate } 268*7c478bd9Sstevel@tonic-gate } 269*7c478bd9Sstevel@tonic-gate } 270*7c478bd9Sstevel@tonic-gate } 271*7c478bd9Sstevel@tonic-gate AS_LOCK_EXIT(as, &as->a_lock); 272*7c478bd9Sstevel@tonic-gate } 273*7c478bd9Sstevel@tonic-gate 274*7c478bd9Sstevel@tonic-gate /* copy out the results and validity bits and free the buffers */ 275*7c478bd9Sstevel@tonic-gate if ((copyout(out_array, minfo.mi_outdata, out_size) != 0) || 276*7c478bd9Sstevel@tonic-gate (copyout(val_array, minfo.mi_validity, val_size) != 0)) 277*7c478bd9Sstevel@tonic-gate ret = set_errno(EFAULT); 278*7c478bd9Sstevel@tonic-gate 279*7c478bd9Sstevel@tonic-gate kmem_free(in_array, in_size); 280*7c478bd9Sstevel@tonic-gate kmem_free(out_array, out_size); 281*7c478bd9Sstevel@tonic-gate kmem_free(req_array, req_size); 282*7c478bd9Sstevel@tonic-gate kmem_free(val_array, val_size); 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate return (ret); 285*7c478bd9Sstevel@tonic-gate } 286*7c478bd9Sstevel@tonic-gate 287*7c478bd9Sstevel@tonic-gate 288*7c478bd9Sstevel@tonic-gate /* 289*7c478bd9Sstevel@tonic-gate * Initialize lgroup affinities for thread 290*7c478bd9Sstevel@tonic-gate */ 291*7c478bd9Sstevel@tonic-gate void 292*7c478bd9Sstevel@tonic-gate lgrp_affinity_init(lgrp_affinity_t **bufaddr) 293*7c478bd9Sstevel@tonic-gate { 294*7c478bd9Sstevel@tonic-gate if (bufaddr) 295*7c478bd9Sstevel@tonic-gate *bufaddr = NULL; 296*7c478bd9Sstevel@tonic-gate } 297*7c478bd9Sstevel@tonic-gate 298*7c478bd9Sstevel@tonic-gate 299*7c478bd9Sstevel@tonic-gate /* 300*7c478bd9Sstevel@tonic-gate * Free lgroup affinities for thread and set to NULL 301*7c478bd9Sstevel@tonic-gate * just in case thread gets recycled 302*7c478bd9Sstevel@tonic-gate */ 303*7c478bd9Sstevel@tonic-gate void 304*7c478bd9Sstevel@tonic-gate lgrp_affinity_free(lgrp_affinity_t **bufaddr) 305*7c478bd9Sstevel@tonic-gate { 306*7c478bd9Sstevel@tonic-gate if (bufaddr && *bufaddr) { 307*7c478bd9Sstevel@tonic-gate kmem_free(*bufaddr, nlgrpsmax * sizeof (lgrp_affinity_t)); 308*7c478bd9Sstevel@tonic-gate *bufaddr = NULL; 309*7c478bd9Sstevel@tonic-gate } 310*7c478bd9Sstevel@tonic-gate } 311*7c478bd9Sstevel@tonic-gate 312*7c478bd9Sstevel@tonic-gate 313*7c478bd9Sstevel@tonic-gate #define P_ANY -2 /* cookie specifying any ID */ 314*7c478bd9Sstevel@tonic-gate 315*7c478bd9Sstevel@tonic-gate 316*7c478bd9Sstevel@tonic-gate /* 317*7c478bd9Sstevel@tonic-gate * Find LWP with given ID in specified process and get its affinity for 318*7c478bd9Sstevel@tonic-gate * specified lgroup 319*7c478bd9Sstevel@tonic-gate */ 320*7c478bd9Sstevel@tonic-gate lgrp_affinity_t 321*7c478bd9Sstevel@tonic-gate lgrp_affinity_get_thread(proc_t *p, id_t lwpid, lgrp_id_t lgrp) 322*7c478bd9Sstevel@tonic-gate { 323*7c478bd9Sstevel@tonic-gate lgrp_affinity_t aff; 324*7c478bd9Sstevel@tonic-gate int found; 325*7c478bd9Sstevel@tonic-gate kthread_t *t; 326*7c478bd9Sstevel@tonic-gate 327*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 328*7c478bd9Sstevel@tonic-gate 329*7c478bd9Sstevel@tonic-gate aff = LGRP_AFF_NONE; 330*7c478bd9Sstevel@tonic-gate found = 0; 331*7c478bd9Sstevel@tonic-gate t = p->p_tlist; 332*7c478bd9Sstevel@tonic-gate /* 333*7c478bd9Sstevel@tonic-gate * The process may be executing in proc_exit() and its p->p_list may be 334*7c478bd9Sstevel@tonic-gate * already NULL. 335*7c478bd9Sstevel@tonic-gate */ 336*7c478bd9Sstevel@tonic-gate if (t == NULL) 337*7c478bd9Sstevel@tonic-gate return (set_errno(ESRCH)); 338*7c478bd9Sstevel@tonic-gate 339*7c478bd9Sstevel@tonic-gate do { 340*7c478bd9Sstevel@tonic-gate if (t->t_tid == lwpid || lwpid == P_ANY) { 341*7c478bd9Sstevel@tonic-gate thread_lock(t); 342*7c478bd9Sstevel@tonic-gate /* 343*7c478bd9Sstevel@tonic-gate * Check to see whether caller has permission to set 344*7c478bd9Sstevel@tonic-gate * affinity for LWP 345*7c478bd9Sstevel@tonic-gate */ 346*7c478bd9Sstevel@tonic-gate if (t->t_cid == 0 || !hasprocperm(t->t_cred, CRED())) { 347*7c478bd9Sstevel@tonic-gate thread_unlock(t); 348*7c478bd9Sstevel@tonic-gate return (set_errno(EPERM)); 349*7c478bd9Sstevel@tonic-gate } 350*7c478bd9Sstevel@tonic-gate 351*7c478bd9Sstevel@tonic-gate if (t->t_lgrp_affinity) 352*7c478bd9Sstevel@tonic-gate aff = t->t_lgrp_affinity[lgrp]; 353*7c478bd9Sstevel@tonic-gate thread_unlock(t); 354*7c478bd9Sstevel@tonic-gate found = 1; 355*7c478bd9Sstevel@tonic-gate break; 356*7c478bd9Sstevel@tonic-gate } 357*7c478bd9Sstevel@tonic-gate } while ((t = t->t_forw) != p->p_tlist); 358*7c478bd9Sstevel@tonic-gate if (!found) 359*7c478bd9Sstevel@tonic-gate aff = set_errno(ESRCH); 360*7c478bd9Sstevel@tonic-gate 361*7c478bd9Sstevel@tonic-gate return (aff); 362*7c478bd9Sstevel@tonic-gate } 363*7c478bd9Sstevel@tonic-gate 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate /* 366*7c478bd9Sstevel@tonic-gate * Get lgroup affinity for given LWP 367*7c478bd9Sstevel@tonic-gate */ 368*7c478bd9Sstevel@tonic-gate lgrp_affinity_t 369*7c478bd9Sstevel@tonic-gate lgrp_affinity_get(lgrp_affinity_args_t *ap) 370*7c478bd9Sstevel@tonic-gate { 371*7c478bd9Sstevel@tonic-gate lgrp_affinity_t aff; 372*7c478bd9Sstevel@tonic-gate lgrp_affinity_args_t args; 373*7c478bd9Sstevel@tonic-gate id_t id; 374*7c478bd9Sstevel@tonic-gate idtype_t idtype; 375*7c478bd9Sstevel@tonic-gate lgrp_id_t lgrp; 376*7c478bd9Sstevel@tonic-gate proc_t *p; 377*7c478bd9Sstevel@tonic-gate kthread_t *t; 378*7c478bd9Sstevel@tonic-gate 379*7c478bd9Sstevel@tonic-gate /* 380*7c478bd9Sstevel@tonic-gate * Copyin arguments 381*7c478bd9Sstevel@tonic-gate */ 382*7c478bd9Sstevel@tonic-gate if (copyin(ap, &args, sizeof (lgrp_affinity_args_t)) != 0) 383*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 384*7c478bd9Sstevel@tonic-gate 385*7c478bd9Sstevel@tonic-gate id = args.id; 386*7c478bd9Sstevel@tonic-gate idtype = args.idtype; 387*7c478bd9Sstevel@tonic-gate lgrp = args.lgrp; 388*7c478bd9Sstevel@tonic-gate 389*7c478bd9Sstevel@tonic-gate /* 390*7c478bd9Sstevel@tonic-gate * Check for invalid lgroup 391*7c478bd9Sstevel@tonic-gate */ 392*7c478bd9Sstevel@tonic-gate if (lgrp < 0 || lgrp == LGRP_NONE) 393*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 394*7c478bd9Sstevel@tonic-gate 395*7c478bd9Sstevel@tonic-gate /* 396*7c478bd9Sstevel@tonic-gate * Check for existing lgroup 397*7c478bd9Sstevel@tonic-gate */ 398*7c478bd9Sstevel@tonic-gate if (lgrp > lgrp_alloc_max) 399*7c478bd9Sstevel@tonic-gate return (set_errno(ESRCH)); 400*7c478bd9Sstevel@tonic-gate 401*7c478bd9Sstevel@tonic-gate /* 402*7c478bd9Sstevel@tonic-gate * Get lgroup affinity for given LWP or process 403*7c478bd9Sstevel@tonic-gate */ 404*7c478bd9Sstevel@tonic-gate switch (idtype) { 405*7c478bd9Sstevel@tonic-gate 406*7c478bd9Sstevel@tonic-gate case P_LWPID: 407*7c478bd9Sstevel@tonic-gate /* 408*7c478bd9Sstevel@tonic-gate * LWP in current process 409*7c478bd9Sstevel@tonic-gate */ 410*7c478bd9Sstevel@tonic-gate p = curproc; 411*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 412*7c478bd9Sstevel@tonic-gate if (id != P_MYID) /* different thread */ 413*7c478bd9Sstevel@tonic-gate aff = lgrp_affinity_get_thread(p, id, lgrp); 414*7c478bd9Sstevel@tonic-gate else { /* current thread */ 415*7c478bd9Sstevel@tonic-gate aff = LGRP_AFF_NONE; 416*7c478bd9Sstevel@tonic-gate t = curthread; 417*7c478bd9Sstevel@tonic-gate thread_lock(t); 418*7c478bd9Sstevel@tonic-gate if (t->t_lgrp_affinity) 419*7c478bd9Sstevel@tonic-gate aff = t->t_lgrp_affinity[lgrp]; 420*7c478bd9Sstevel@tonic-gate thread_unlock(t); 421*7c478bd9Sstevel@tonic-gate } 422*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 423*7c478bd9Sstevel@tonic-gate break; 424*7c478bd9Sstevel@tonic-gate 425*7c478bd9Sstevel@tonic-gate case P_PID: 426*7c478bd9Sstevel@tonic-gate /* 427*7c478bd9Sstevel@tonic-gate * Process 428*7c478bd9Sstevel@tonic-gate */ 429*7c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 430*7c478bd9Sstevel@tonic-gate 431*7c478bd9Sstevel@tonic-gate if (id == P_MYID) 432*7c478bd9Sstevel@tonic-gate p = curproc; 433*7c478bd9Sstevel@tonic-gate else { 434*7c478bd9Sstevel@tonic-gate p = prfind(id); 435*7c478bd9Sstevel@tonic-gate if (p == NULL) { 436*7c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 437*7c478bd9Sstevel@tonic-gate return (set_errno(ESRCH)); 438*7c478bd9Sstevel@tonic-gate } 439*7c478bd9Sstevel@tonic-gate } 440*7c478bd9Sstevel@tonic-gate 441*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 442*7c478bd9Sstevel@tonic-gate aff = lgrp_affinity_get_thread(p, P_ANY, lgrp); 443*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 444*7c478bd9Sstevel@tonic-gate 445*7c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 446*7c478bd9Sstevel@tonic-gate break; 447*7c478bd9Sstevel@tonic-gate 448*7c478bd9Sstevel@tonic-gate default: 449*7c478bd9Sstevel@tonic-gate aff = set_errno(EINVAL); 450*7c478bd9Sstevel@tonic-gate break; 451*7c478bd9Sstevel@tonic-gate } 452*7c478bd9Sstevel@tonic-gate 453*7c478bd9Sstevel@tonic-gate return (aff); 454*7c478bd9Sstevel@tonic-gate } 455*7c478bd9Sstevel@tonic-gate 456*7c478bd9Sstevel@tonic-gate 457*7c478bd9Sstevel@tonic-gate /* 458*7c478bd9Sstevel@tonic-gate * Find lgroup for which this thread has most affinity in specified partition 459*7c478bd9Sstevel@tonic-gate */ 460*7c478bd9Sstevel@tonic-gate lpl_t * 461*7c478bd9Sstevel@tonic-gate lgrp_affinity_best(kthread_t *t, struct cpupart *cpupart, lgrp_id_t start) 462*7c478bd9Sstevel@tonic-gate { 463*7c478bd9Sstevel@tonic-gate lgrp_affinity_t *affs; 464*7c478bd9Sstevel@tonic-gate lgrp_affinity_t best_aff; 465*7c478bd9Sstevel@tonic-gate lpl_t *best_lpl; 466*7c478bd9Sstevel@tonic-gate lgrp_id_t home; 467*7c478bd9Sstevel@tonic-gate lgrp_id_t lgrpid; 468*7c478bd9Sstevel@tonic-gate lpl_t *lpl; 469*7c478bd9Sstevel@tonic-gate 470*7c478bd9Sstevel@tonic-gate ASSERT(t != NULL); 471*7c478bd9Sstevel@tonic-gate ASSERT((MUTEX_HELD(&cpu_lock) || curthread->t_preempt > 0) || 472*7c478bd9Sstevel@tonic-gate (MUTEX_HELD(&ttoproc(t)->p_lock) && THREAD_LOCK_HELD(t))); 473*7c478bd9Sstevel@tonic-gate ASSERT(cpupart != NULL); 474*7c478bd9Sstevel@tonic-gate 475*7c478bd9Sstevel@tonic-gate if (t->t_lgrp_affinity == NULL) 476*7c478bd9Sstevel@tonic-gate return (NULL); 477*7c478bd9Sstevel@tonic-gate 478*7c478bd9Sstevel@tonic-gate affs = t->t_lgrp_affinity; 479*7c478bd9Sstevel@tonic-gate 480*7c478bd9Sstevel@tonic-gate /* 481*7c478bd9Sstevel@tonic-gate * Thread bound to CPU 482*7c478bd9Sstevel@tonic-gate */ 483*7c478bd9Sstevel@tonic-gate if (t->t_bind_cpu != PBIND_NONE) { 484*7c478bd9Sstevel@tonic-gate cpu_t *cp; 485*7c478bd9Sstevel@tonic-gate 486*7c478bd9Sstevel@tonic-gate /* 487*7c478bd9Sstevel@tonic-gate * See whether thread has more affinity for root lgroup 488*7c478bd9Sstevel@tonic-gate * than lgroup containing CPU 489*7c478bd9Sstevel@tonic-gate */ 490*7c478bd9Sstevel@tonic-gate cp = cpu[t->t_bind_cpu]; 491*7c478bd9Sstevel@tonic-gate lpl = cp->cpu_lpl; 492*7c478bd9Sstevel@tonic-gate lgrpid = LGRP_ROOTID; 493*7c478bd9Sstevel@tonic-gate if (affs[lgrpid] > affs[lpl->lpl_lgrpid]) 494*7c478bd9Sstevel@tonic-gate return (&cpupart->cp_lgrploads[lgrpid]); 495*7c478bd9Sstevel@tonic-gate return (lpl); 496*7c478bd9Sstevel@tonic-gate } 497*7c478bd9Sstevel@tonic-gate 498*7c478bd9Sstevel@tonic-gate /* 499*7c478bd9Sstevel@tonic-gate * Start searching at given lgroup 500*7c478bd9Sstevel@tonic-gate */ 501*7c478bd9Sstevel@tonic-gate ASSERT(start >= 0 && start <= lgrp_alloc_max); 502*7c478bd9Sstevel@tonic-gate lgrpid = start; 503*7c478bd9Sstevel@tonic-gate 504*7c478bd9Sstevel@tonic-gate /* 505*7c478bd9Sstevel@tonic-gate * Begin with home as best lgroup if it's root or in this pset 506*7c478bd9Sstevel@tonic-gate * Otherwise, use starting lgroup given above as best first. 507*7c478bd9Sstevel@tonic-gate */ 508*7c478bd9Sstevel@tonic-gate home = t->t_lpl->lpl_lgrpid; 509*7c478bd9Sstevel@tonic-gate if (LGRP_CPUS_IN_PART(home, cpupart)) 510*7c478bd9Sstevel@tonic-gate best_lpl = &cpupart->cp_lgrploads[home]; 511*7c478bd9Sstevel@tonic-gate else 512*7c478bd9Sstevel@tonic-gate best_lpl = &cpupart->cp_lgrploads[lgrpid]; 513*7c478bd9Sstevel@tonic-gate 514*7c478bd9Sstevel@tonic-gate best_aff = affs[best_lpl->lpl_lgrpid]; 515*7c478bd9Sstevel@tonic-gate 516*7c478bd9Sstevel@tonic-gate do { 517*7c478bd9Sstevel@tonic-gate /* 518*7c478bd9Sstevel@tonic-gate * Skip any lgroups that don't have CPU resources 519*7c478bd9Sstevel@tonic-gate * in this processor set. 520*7c478bd9Sstevel@tonic-gate */ 521*7c478bd9Sstevel@tonic-gate if (!LGRP_CPUS_IN_PART(lgrpid, cpupart)) { 522*7c478bd9Sstevel@tonic-gate if (++lgrpid > lgrp_alloc_max) 523*7c478bd9Sstevel@tonic-gate lgrpid = 0; /* wrap the search */ 524*7c478bd9Sstevel@tonic-gate continue; 525*7c478bd9Sstevel@tonic-gate } 526*7c478bd9Sstevel@tonic-gate 527*7c478bd9Sstevel@tonic-gate /* 528*7c478bd9Sstevel@tonic-gate * Find lgroup with most affinity 529*7c478bd9Sstevel@tonic-gate */ 530*7c478bd9Sstevel@tonic-gate lpl = &cpupart->cp_lgrploads[lgrpid]; 531*7c478bd9Sstevel@tonic-gate if (affs[lgrpid] > best_aff) { 532*7c478bd9Sstevel@tonic-gate best_aff = affs[lgrpid]; 533*7c478bd9Sstevel@tonic-gate best_lpl = lpl; 534*7c478bd9Sstevel@tonic-gate } 535*7c478bd9Sstevel@tonic-gate 536*7c478bd9Sstevel@tonic-gate if (++lgrpid > lgrp_alloc_max) 537*7c478bd9Sstevel@tonic-gate lgrpid = 0; /* wrap the search */ 538*7c478bd9Sstevel@tonic-gate 539*7c478bd9Sstevel@tonic-gate } while (lgrpid != start); 540*7c478bd9Sstevel@tonic-gate 541*7c478bd9Sstevel@tonic-gate /* 542*7c478bd9Sstevel@tonic-gate * No lgroup (in this pset) with any affinity 543*7c478bd9Sstevel@tonic-gate */ 544*7c478bd9Sstevel@tonic-gate if (best_aff == LGRP_AFF_NONE) 545*7c478bd9Sstevel@tonic-gate return (NULL); 546*7c478bd9Sstevel@tonic-gate 547*7c478bd9Sstevel@tonic-gate lgrpid = best_lpl->lpl_lgrpid; 548*7c478bd9Sstevel@tonic-gate ASSERT(LGRP_CPUS_IN_PART(lgrpid, cpupart) && best_lpl->lpl_ncpu > 0); 549*7c478bd9Sstevel@tonic-gate 550*7c478bd9Sstevel@tonic-gate return (best_lpl); 551*7c478bd9Sstevel@tonic-gate } 552*7c478bd9Sstevel@tonic-gate 553*7c478bd9Sstevel@tonic-gate 554*7c478bd9Sstevel@tonic-gate /* 555*7c478bd9Sstevel@tonic-gate * Set thread's affinity for given lgroup 556*7c478bd9Sstevel@tonic-gate */ 557*7c478bd9Sstevel@tonic-gate int 558*7c478bd9Sstevel@tonic-gate lgrp_affinity_set_thread(kthread_t *t, lgrp_id_t lgrp, lgrp_affinity_t aff, 559*7c478bd9Sstevel@tonic-gate lgrp_affinity_t **aff_buf) 560*7c478bd9Sstevel@tonic-gate { 561*7c478bd9Sstevel@tonic-gate lpl_t *best_lpl; 562*7c478bd9Sstevel@tonic-gate lgrp_id_t home; 563*7c478bd9Sstevel@tonic-gate int retval; 564*7c478bd9Sstevel@tonic-gate lgrp_id_t start; 565*7c478bd9Sstevel@tonic-gate 566*7c478bd9Sstevel@tonic-gate ASSERT(t != NULL); 567*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock)); 568*7c478bd9Sstevel@tonic-gate 569*7c478bd9Sstevel@tonic-gate retval = 0; 570*7c478bd9Sstevel@tonic-gate 571*7c478bd9Sstevel@tonic-gate thread_lock(t); 572*7c478bd9Sstevel@tonic-gate 573*7c478bd9Sstevel@tonic-gate /* 574*7c478bd9Sstevel@tonic-gate * Check to see whether caller has permission to set affinity for 575*7c478bd9Sstevel@tonic-gate * thread 576*7c478bd9Sstevel@tonic-gate */ 577*7c478bd9Sstevel@tonic-gate if (t->t_cid == 0 || !hasprocperm(t->t_cred, CRED())) { 578*7c478bd9Sstevel@tonic-gate thread_unlock(t); 579*7c478bd9Sstevel@tonic-gate return (set_errno(EPERM)); 580*7c478bd9Sstevel@tonic-gate } 581*7c478bd9Sstevel@tonic-gate 582*7c478bd9Sstevel@tonic-gate if (t->t_lgrp_affinity == NULL) { 583*7c478bd9Sstevel@tonic-gate if (aff == LGRP_AFF_NONE) { 584*7c478bd9Sstevel@tonic-gate thread_unlock(t); 585*7c478bd9Sstevel@tonic-gate return (0); 586*7c478bd9Sstevel@tonic-gate } 587*7c478bd9Sstevel@tonic-gate ASSERT(aff_buf != NULL && *aff_buf != NULL); 588*7c478bd9Sstevel@tonic-gate t->t_lgrp_affinity = *aff_buf; 589*7c478bd9Sstevel@tonic-gate *aff_buf = NULL; 590*7c478bd9Sstevel@tonic-gate } 591*7c478bd9Sstevel@tonic-gate 592*7c478bd9Sstevel@tonic-gate t->t_lgrp_affinity[lgrp] = aff; 593*7c478bd9Sstevel@tonic-gate 594*7c478bd9Sstevel@tonic-gate /* 595*7c478bd9Sstevel@tonic-gate * Select a new home if the thread's affinity is being cleared 596*7c478bd9Sstevel@tonic-gate */ 597*7c478bd9Sstevel@tonic-gate if (aff == LGRP_AFF_NONE) { 598*7c478bd9Sstevel@tonic-gate lgrp_move_thread(t, lgrp_choose(t, t->t_cpupart), 1); 599*7c478bd9Sstevel@tonic-gate thread_unlock(t); 600*7c478bd9Sstevel@tonic-gate return (retval); 601*7c478bd9Sstevel@tonic-gate } 602*7c478bd9Sstevel@tonic-gate 603*7c478bd9Sstevel@tonic-gate /* 604*7c478bd9Sstevel@tonic-gate * Find lgroup for which thread has most affinity, 605*7c478bd9Sstevel@tonic-gate * starting after home 606*7c478bd9Sstevel@tonic-gate */ 607*7c478bd9Sstevel@tonic-gate home = t->t_lpl->lpl_lgrpid; 608*7c478bd9Sstevel@tonic-gate start = home + 1; 609*7c478bd9Sstevel@tonic-gate if (start > lgrp_alloc_max) 610*7c478bd9Sstevel@tonic-gate start = 0; 611*7c478bd9Sstevel@tonic-gate 612*7c478bd9Sstevel@tonic-gate best_lpl = lgrp_affinity_best(t, t->t_cpupart, start); 613*7c478bd9Sstevel@tonic-gate 614*7c478bd9Sstevel@tonic-gate /* 615*7c478bd9Sstevel@tonic-gate * Rehome if found lgroup with more affinity than home 616*7c478bd9Sstevel@tonic-gate */ 617*7c478bd9Sstevel@tonic-gate if (best_lpl != NULL && best_lpl != t->t_lpl) 618*7c478bd9Sstevel@tonic-gate lgrp_move_thread(t, best_lpl, 1); 619*7c478bd9Sstevel@tonic-gate 620*7c478bd9Sstevel@tonic-gate thread_unlock(t); 621*7c478bd9Sstevel@tonic-gate 622*7c478bd9Sstevel@tonic-gate return (retval); 623*7c478bd9Sstevel@tonic-gate } 624*7c478bd9Sstevel@tonic-gate 625*7c478bd9Sstevel@tonic-gate 626*7c478bd9Sstevel@tonic-gate /* 627*7c478bd9Sstevel@tonic-gate * Set process' affinity for specified lgroup 628*7c478bd9Sstevel@tonic-gate */ 629*7c478bd9Sstevel@tonic-gate int 630*7c478bd9Sstevel@tonic-gate lgrp_affinity_set_proc(proc_t *p, lgrp_id_t lgrp, lgrp_affinity_t aff, 631*7c478bd9Sstevel@tonic-gate lgrp_affinity_t **aff_buf_array) 632*7c478bd9Sstevel@tonic-gate { 633*7c478bd9Sstevel@tonic-gate lgrp_affinity_t *buf; 634*7c478bd9Sstevel@tonic-gate int err = 0; 635*7c478bd9Sstevel@tonic-gate int i; 636*7c478bd9Sstevel@tonic-gate int retval; 637*7c478bd9Sstevel@tonic-gate kthread_t *t; 638*7c478bd9Sstevel@tonic-gate 639*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pidlock) && MUTEX_HELD(&p->p_lock)); 640*7c478bd9Sstevel@tonic-gate ASSERT(aff_buf_array != NULL); 641*7c478bd9Sstevel@tonic-gate 642*7c478bd9Sstevel@tonic-gate i = 0; 643*7c478bd9Sstevel@tonic-gate t = p->p_tlist; 644*7c478bd9Sstevel@tonic-gate if (t != NULL) { 645*7c478bd9Sstevel@tonic-gate do { 646*7c478bd9Sstevel@tonic-gate /* 647*7c478bd9Sstevel@tonic-gate * Set lgroup affinity for thread 648*7c478bd9Sstevel@tonic-gate */ 649*7c478bd9Sstevel@tonic-gate buf = aff_buf_array[i]; 650*7c478bd9Sstevel@tonic-gate retval = lgrp_affinity_set_thread(t, lgrp, aff, &buf); 651*7c478bd9Sstevel@tonic-gate 652*7c478bd9Sstevel@tonic-gate if (err == 0 && retval != 0) 653*7c478bd9Sstevel@tonic-gate err = retval; 654*7c478bd9Sstevel@tonic-gate 655*7c478bd9Sstevel@tonic-gate /* 656*7c478bd9Sstevel@tonic-gate * Advance pointer to next buffer 657*7c478bd9Sstevel@tonic-gate */ 658*7c478bd9Sstevel@tonic-gate if (buf == NULL) { 659*7c478bd9Sstevel@tonic-gate ASSERT(i < p->p_lwpcnt); 660*7c478bd9Sstevel@tonic-gate aff_buf_array[i] = NULL; 661*7c478bd9Sstevel@tonic-gate i++; 662*7c478bd9Sstevel@tonic-gate } 663*7c478bd9Sstevel@tonic-gate 664*7c478bd9Sstevel@tonic-gate } while ((t = t->t_forw) != p->p_tlist); 665*7c478bd9Sstevel@tonic-gate } 666*7c478bd9Sstevel@tonic-gate return (err); 667*7c478bd9Sstevel@tonic-gate } 668*7c478bd9Sstevel@tonic-gate 669*7c478bd9Sstevel@tonic-gate 670*7c478bd9Sstevel@tonic-gate /* 671*7c478bd9Sstevel@tonic-gate * Set LWP's or process' affinity for specified lgroup 672*7c478bd9Sstevel@tonic-gate * 673*7c478bd9Sstevel@tonic-gate * When setting affinities, pidlock, process p_lock, and thread_lock() 674*7c478bd9Sstevel@tonic-gate * need to be held in that order to protect target thread's pset, process, 675*7c478bd9Sstevel@tonic-gate * process contents, and thread contents. thread_lock() does splhigh(), 676*7c478bd9Sstevel@tonic-gate * so it ends up having similiar effect as kpreempt_disable(), so it will 677*7c478bd9Sstevel@tonic-gate * protect calls to lgrp_move_thread() and lgrp_choose() from pset changes. 678*7c478bd9Sstevel@tonic-gate */ 679*7c478bd9Sstevel@tonic-gate int 680*7c478bd9Sstevel@tonic-gate lgrp_affinity_set(lgrp_affinity_args_t *ap) 681*7c478bd9Sstevel@tonic-gate { 682*7c478bd9Sstevel@tonic-gate lgrp_affinity_t aff; 683*7c478bd9Sstevel@tonic-gate lgrp_affinity_t *aff_buf; 684*7c478bd9Sstevel@tonic-gate lgrp_affinity_args_t args; 685*7c478bd9Sstevel@tonic-gate id_t id; 686*7c478bd9Sstevel@tonic-gate idtype_t idtype; 687*7c478bd9Sstevel@tonic-gate lgrp_id_t lgrp; 688*7c478bd9Sstevel@tonic-gate int nthreads; 689*7c478bd9Sstevel@tonic-gate proc_t *p; 690*7c478bd9Sstevel@tonic-gate int retval; 691*7c478bd9Sstevel@tonic-gate 692*7c478bd9Sstevel@tonic-gate /* 693*7c478bd9Sstevel@tonic-gate * Copyin arguments 694*7c478bd9Sstevel@tonic-gate */ 695*7c478bd9Sstevel@tonic-gate if (copyin(ap, &args, sizeof (lgrp_affinity_args_t)) != 0) 696*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 697*7c478bd9Sstevel@tonic-gate 698*7c478bd9Sstevel@tonic-gate idtype = args.idtype; 699*7c478bd9Sstevel@tonic-gate id = args.id; 700*7c478bd9Sstevel@tonic-gate lgrp = args.lgrp; 701*7c478bd9Sstevel@tonic-gate aff = args.aff; 702*7c478bd9Sstevel@tonic-gate 703*7c478bd9Sstevel@tonic-gate /* 704*7c478bd9Sstevel@tonic-gate * Check for invalid lgroup 705*7c478bd9Sstevel@tonic-gate */ 706*7c478bd9Sstevel@tonic-gate if (lgrp < 0 || lgrp == LGRP_NONE) 707*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 708*7c478bd9Sstevel@tonic-gate 709*7c478bd9Sstevel@tonic-gate /* 710*7c478bd9Sstevel@tonic-gate * Check for existing lgroup 711*7c478bd9Sstevel@tonic-gate */ 712*7c478bd9Sstevel@tonic-gate if (lgrp > lgrp_alloc_max) 713*7c478bd9Sstevel@tonic-gate return (set_errno(ESRCH)); 714*7c478bd9Sstevel@tonic-gate 715*7c478bd9Sstevel@tonic-gate /* 716*7c478bd9Sstevel@tonic-gate * Check for legal affinity 717*7c478bd9Sstevel@tonic-gate */ 718*7c478bd9Sstevel@tonic-gate if (aff != LGRP_AFF_NONE && aff != LGRP_AFF_WEAK && 719*7c478bd9Sstevel@tonic-gate aff != LGRP_AFF_STRONG) 720*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 721*7c478bd9Sstevel@tonic-gate 722*7c478bd9Sstevel@tonic-gate /* 723*7c478bd9Sstevel@tonic-gate * Must be process or LWP ID 724*7c478bd9Sstevel@tonic-gate */ 725*7c478bd9Sstevel@tonic-gate if (idtype != P_LWPID && idtype != P_PID) 726*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 727*7c478bd9Sstevel@tonic-gate 728*7c478bd9Sstevel@tonic-gate /* 729*7c478bd9Sstevel@tonic-gate * Set given LWP's or process' affinity for specified lgroup 730*7c478bd9Sstevel@tonic-gate */ 731*7c478bd9Sstevel@tonic-gate switch (idtype) { 732*7c478bd9Sstevel@tonic-gate 733*7c478bd9Sstevel@tonic-gate case P_LWPID: 734*7c478bd9Sstevel@tonic-gate /* 735*7c478bd9Sstevel@tonic-gate * Allocate memory for thread's lgroup affinities 736*7c478bd9Sstevel@tonic-gate * ahead of time w/o holding locks 737*7c478bd9Sstevel@tonic-gate */ 738*7c478bd9Sstevel@tonic-gate aff_buf = kmem_zalloc(nlgrpsmax * sizeof (lgrp_affinity_t), 739*7c478bd9Sstevel@tonic-gate KM_SLEEP); 740*7c478bd9Sstevel@tonic-gate 741*7c478bd9Sstevel@tonic-gate p = curproc; 742*7c478bd9Sstevel@tonic-gate 743*7c478bd9Sstevel@tonic-gate /* 744*7c478bd9Sstevel@tonic-gate * Set affinity for thread 745*7c478bd9Sstevel@tonic-gate */ 746*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 747*7c478bd9Sstevel@tonic-gate if (id == P_MYID) { /* current thread */ 748*7c478bd9Sstevel@tonic-gate retval = lgrp_affinity_set_thread(curthread, lgrp, aff, 749*7c478bd9Sstevel@tonic-gate &aff_buf); 750*7c478bd9Sstevel@tonic-gate } else if (p->p_tlist == NULL) { 751*7c478bd9Sstevel@tonic-gate retval = set_errno(ESRCH); 752*7c478bd9Sstevel@tonic-gate } else { /* other thread */ 753*7c478bd9Sstevel@tonic-gate int found = 0; 754*7c478bd9Sstevel@tonic-gate kthread_t *t; 755*7c478bd9Sstevel@tonic-gate 756*7c478bd9Sstevel@tonic-gate t = p->p_tlist; 757*7c478bd9Sstevel@tonic-gate do { 758*7c478bd9Sstevel@tonic-gate if (t->t_tid == id) { 759*7c478bd9Sstevel@tonic-gate retval = lgrp_affinity_set_thread(t, 760*7c478bd9Sstevel@tonic-gate lgrp, aff, &aff_buf); 761*7c478bd9Sstevel@tonic-gate found = 1; 762*7c478bd9Sstevel@tonic-gate break; 763*7c478bd9Sstevel@tonic-gate } 764*7c478bd9Sstevel@tonic-gate } while ((t = t->t_forw) != p->p_tlist); 765*7c478bd9Sstevel@tonic-gate if (!found) 766*7c478bd9Sstevel@tonic-gate retval = set_errno(ESRCH); 767*7c478bd9Sstevel@tonic-gate } 768*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 769*7c478bd9Sstevel@tonic-gate 770*7c478bd9Sstevel@tonic-gate /* 771*7c478bd9Sstevel@tonic-gate * Free memory for lgroup affinities, 772*7c478bd9Sstevel@tonic-gate * since thread didn't need it 773*7c478bd9Sstevel@tonic-gate */ 774*7c478bd9Sstevel@tonic-gate if (aff_buf) 775*7c478bd9Sstevel@tonic-gate kmem_free(aff_buf, 776*7c478bd9Sstevel@tonic-gate nlgrpsmax * sizeof (lgrp_affinity_t)); 777*7c478bd9Sstevel@tonic-gate 778*7c478bd9Sstevel@tonic-gate break; 779*7c478bd9Sstevel@tonic-gate 780*7c478bd9Sstevel@tonic-gate case P_PID: 781*7c478bd9Sstevel@tonic-gate 782*7c478bd9Sstevel@tonic-gate do { 783*7c478bd9Sstevel@tonic-gate lgrp_affinity_t **aff_buf_array; 784*7c478bd9Sstevel@tonic-gate int i; 785*7c478bd9Sstevel@tonic-gate size_t size; 786*7c478bd9Sstevel@tonic-gate 787*7c478bd9Sstevel@tonic-gate /* 788*7c478bd9Sstevel@tonic-gate * Get process 789*7c478bd9Sstevel@tonic-gate */ 790*7c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 791*7c478bd9Sstevel@tonic-gate 792*7c478bd9Sstevel@tonic-gate if (id == P_MYID) 793*7c478bd9Sstevel@tonic-gate p = curproc; 794*7c478bd9Sstevel@tonic-gate else 795*7c478bd9Sstevel@tonic-gate p = prfind(id); 796*7c478bd9Sstevel@tonic-gate 797*7c478bd9Sstevel@tonic-gate if (p == NULL) { 798*7c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 799*7c478bd9Sstevel@tonic-gate return (set_errno(ESRCH)); 800*7c478bd9Sstevel@tonic-gate } 801*7c478bd9Sstevel@tonic-gate 802*7c478bd9Sstevel@tonic-gate /* 803*7c478bd9Sstevel@tonic-gate * Get number of threads in process 804*7c478bd9Sstevel@tonic-gate * 805*7c478bd9Sstevel@tonic-gate * NOTE: Only care about user processes, 806*7c478bd9Sstevel@tonic-gate * so p_lwpcnt should be number of threads. 807*7c478bd9Sstevel@tonic-gate */ 808*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 809*7c478bd9Sstevel@tonic-gate nthreads = p->p_lwpcnt; 810*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 811*7c478bd9Sstevel@tonic-gate 812*7c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 813*7c478bd9Sstevel@tonic-gate 814*7c478bd9Sstevel@tonic-gate if (nthreads < 1) 815*7c478bd9Sstevel@tonic-gate return (set_errno(ESRCH)); 816*7c478bd9Sstevel@tonic-gate 817*7c478bd9Sstevel@tonic-gate /* 818*7c478bd9Sstevel@tonic-gate * Preallocate memory for lgroup affinities for 819*7c478bd9Sstevel@tonic-gate * each thread in process now to avoid holding 820*7c478bd9Sstevel@tonic-gate * any locks. Allocate an array to hold a buffer 821*7c478bd9Sstevel@tonic-gate * for each thread. 822*7c478bd9Sstevel@tonic-gate */ 823*7c478bd9Sstevel@tonic-gate aff_buf_array = kmem_zalloc(nthreads * 824*7c478bd9Sstevel@tonic-gate sizeof (lgrp_affinity_t *), KM_SLEEP); 825*7c478bd9Sstevel@tonic-gate 826*7c478bd9Sstevel@tonic-gate size = nlgrpsmax * sizeof (lgrp_affinity_t); 827*7c478bd9Sstevel@tonic-gate for (i = 0; i < nthreads; i++) 828*7c478bd9Sstevel@tonic-gate aff_buf_array[i] = kmem_zalloc(size, KM_SLEEP); 829*7c478bd9Sstevel@tonic-gate 830*7c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 831*7c478bd9Sstevel@tonic-gate 832*7c478bd9Sstevel@tonic-gate /* 833*7c478bd9Sstevel@tonic-gate * Get process again since dropped locks to allocate 834*7c478bd9Sstevel@tonic-gate * memory (except current process) 835*7c478bd9Sstevel@tonic-gate */ 836*7c478bd9Sstevel@tonic-gate if (id != P_MYID) 837*7c478bd9Sstevel@tonic-gate p = prfind(id); 838*7c478bd9Sstevel@tonic-gate 839*7c478bd9Sstevel@tonic-gate /* 840*7c478bd9Sstevel@tonic-gate * Process went away after we dropped locks and before 841*7c478bd9Sstevel@tonic-gate * reacquiring them, so drop locks, free memory, and 842*7c478bd9Sstevel@tonic-gate * return. 843*7c478bd9Sstevel@tonic-gate */ 844*7c478bd9Sstevel@tonic-gate if (p == NULL) { 845*7c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 846*7c478bd9Sstevel@tonic-gate for (i = 0; i < nthreads; i++) 847*7c478bd9Sstevel@tonic-gate kmem_free(aff_buf_array[i], size); 848*7c478bd9Sstevel@tonic-gate kmem_free(aff_buf_array, 849*7c478bd9Sstevel@tonic-gate nthreads * sizeof (lgrp_affinity_t *)); 850*7c478bd9Sstevel@tonic-gate return (set_errno(ESRCH)); 851*7c478bd9Sstevel@tonic-gate } 852*7c478bd9Sstevel@tonic-gate 853*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 854*7c478bd9Sstevel@tonic-gate 855*7c478bd9Sstevel@tonic-gate /* 856*7c478bd9Sstevel@tonic-gate * See whether number of threads is same 857*7c478bd9Sstevel@tonic-gate * If not, drop locks, free memory, and try again 858*7c478bd9Sstevel@tonic-gate */ 859*7c478bd9Sstevel@tonic-gate if (nthreads != p->p_lwpcnt) { 860*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 861*7c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 862*7c478bd9Sstevel@tonic-gate for (i = 0; i < nthreads; i++) 863*7c478bd9Sstevel@tonic-gate kmem_free(aff_buf_array[i], size); 864*7c478bd9Sstevel@tonic-gate kmem_free(aff_buf_array, 865*7c478bd9Sstevel@tonic-gate nthreads * sizeof (lgrp_affinity_t *)); 866*7c478bd9Sstevel@tonic-gate continue; 867*7c478bd9Sstevel@tonic-gate } 868*7c478bd9Sstevel@tonic-gate 869*7c478bd9Sstevel@tonic-gate /* 870*7c478bd9Sstevel@tonic-gate * Set lgroup affinity for threads in process 871*7c478bd9Sstevel@tonic-gate */ 872*7c478bd9Sstevel@tonic-gate retval = lgrp_affinity_set_proc(p, lgrp, aff, 873*7c478bd9Sstevel@tonic-gate aff_buf_array); 874*7c478bd9Sstevel@tonic-gate 875*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 876*7c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 877*7c478bd9Sstevel@tonic-gate 878*7c478bd9Sstevel@tonic-gate /* 879*7c478bd9Sstevel@tonic-gate * Free any leftover memory, since some threads may 880*7c478bd9Sstevel@tonic-gate * have already allocated memory and set lgroup 881*7c478bd9Sstevel@tonic-gate * affinities before 882*7c478bd9Sstevel@tonic-gate */ 883*7c478bd9Sstevel@tonic-gate for (i = 0; i < nthreads; i++) 884*7c478bd9Sstevel@tonic-gate if (aff_buf_array[i] != NULL) 885*7c478bd9Sstevel@tonic-gate kmem_free(aff_buf_array[i], size); 886*7c478bd9Sstevel@tonic-gate kmem_free(aff_buf_array, 887*7c478bd9Sstevel@tonic-gate nthreads * sizeof (lgrp_affinity_t *)); 888*7c478bd9Sstevel@tonic-gate 889*7c478bd9Sstevel@tonic-gate break; 890*7c478bd9Sstevel@tonic-gate 891*7c478bd9Sstevel@tonic-gate } while (nthreads != p->p_lwpcnt); 892*7c478bd9Sstevel@tonic-gate 893*7c478bd9Sstevel@tonic-gate break; 894*7c478bd9Sstevel@tonic-gate 895*7c478bd9Sstevel@tonic-gate default: 896*7c478bd9Sstevel@tonic-gate retval = set_errno(EINVAL); 897*7c478bd9Sstevel@tonic-gate break; 898*7c478bd9Sstevel@tonic-gate } 899*7c478bd9Sstevel@tonic-gate 900*7c478bd9Sstevel@tonic-gate return (retval); 901*7c478bd9Sstevel@tonic-gate } 902*7c478bd9Sstevel@tonic-gate 903*7c478bd9Sstevel@tonic-gate 904*7c478bd9Sstevel@tonic-gate /* 905*7c478bd9Sstevel@tonic-gate * Return the latest generation number for the lgroup hierarchy 906*7c478bd9Sstevel@tonic-gate * with the given view 907*7c478bd9Sstevel@tonic-gate */ 908*7c478bd9Sstevel@tonic-gate lgrp_gen_t 909*7c478bd9Sstevel@tonic-gate lgrp_generation(lgrp_view_t view) 910*7c478bd9Sstevel@tonic-gate { 911*7c478bd9Sstevel@tonic-gate cpupart_t *cpupart; 912*7c478bd9Sstevel@tonic-gate uint_t gen; 913*7c478bd9Sstevel@tonic-gate 914*7c478bd9Sstevel@tonic-gate kpreempt_disable(); 915*7c478bd9Sstevel@tonic-gate 916*7c478bd9Sstevel@tonic-gate /* 917*7c478bd9Sstevel@tonic-gate * Determine generation number for given view 918*7c478bd9Sstevel@tonic-gate */ 919*7c478bd9Sstevel@tonic-gate if (view == LGRP_VIEW_OS) 920*7c478bd9Sstevel@tonic-gate /* 921*7c478bd9Sstevel@tonic-gate * Return generation number of lgroup hierarchy for OS view 922*7c478bd9Sstevel@tonic-gate */ 923*7c478bd9Sstevel@tonic-gate gen = lgrp_gen; 924*7c478bd9Sstevel@tonic-gate else { 925*7c478bd9Sstevel@tonic-gate /* 926*7c478bd9Sstevel@tonic-gate * For caller's view, use generation numbers for lgroup 927*7c478bd9Sstevel@tonic-gate * hierarchy and caller's pset 928*7c478bd9Sstevel@tonic-gate * NOTE: Caller needs to check for change in pset ID 929*7c478bd9Sstevel@tonic-gate */ 930*7c478bd9Sstevel@tonic-gate cpupart = curthread->t_cpupart; 931*7c478bd9Sstevel@tonic-gate ASSERT(cpupart); 932*7c478bd9Sstevel@tonic-gate gen = lgrp_gen + cpupart->cp_gen; 933*7c478bd9Sstevel@tonic-gate } 934*7c478bd9Sstevel@tonic-gate 935*7c478bd9Sstevel@tonic-gate kpreempt_enable(); 936*7c478bd9Sstevel@tonic-gate 937*7c478bd9Sstevel@tonic-gate return (gen); 938*7c478bd9Sstevel@tonic-gate } 939*7c478bd9Sstevel@tonic-gate 940*7c478bd9Sstevel@tonic-gate 941*7c478bd9Sstevel@tonic-gate lgrp_id_t 942*7c478bd9Sstevel@tonic-gate lgrp_home_thread(kthread_t *t) 943*7c478bd9Sstevel@tonic-gate { 944*7c478bd9Sstevel@tonic-gate lgrp_id_t home; 945*7c478bd9Sstevel@tonic-gate 946*7c478bd9Sstevel@tonic-gate ASSERT(t != NULL); 947*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock)); 948*7c478bd9Sstevel@tonic-gate 949*7c478bd9Sstevel@tonic-gate thread_lock(t); 950*7c478bd9Sstevel@tonic-gate 951*7c478bd9Sstevel@tonic-gate /* 952*7c478bd9Sstevel@tonic-gate * Check to see whether caller has permission to set affinity for 953*7c478bd9Sstevel@tonic-gate * thread 954*7c478bd9Sstevel@tonic-gate */ 955*7c478bd9Sstevel@tonic-gate if (t->t_cid == 0 || !hasprocperm(t->t_cred, CRED())) { 956*7c478bd9Sstevel@tonic-gate thread_unlock(t); 957*7c478bd9Sstevel@tonic-gate return (set_errno(EPERM)); 958*7c478bd9Sstevel@tonic-gate } 959*7c478bd9Sstevel@tonic-gate 960*7c478bd9Sstevel@tonic-gate home = lgrp_home_id(t); 961*7c478bd9Sstevel@tonic-gate 962*7c478bd9Sstevel@tonic-gate thread_unlock(t); 963*7c478bd9Sstevel@tonic-gate return (home); 964*7c478bd9Sstevel@tonic-gate } 965*7c478bd9Sstevel@tonic-gate 966*7c478bd9Sstevel@tonic-gate 967*7c478bd9Sstevel@tonic-gate /* 968*7c478bd9Sstevel@tonic-gate * Get home lgroup of given process or thread 969*7c478bd9Sstevel@tonic-gate */ 970*7c478bd9Sstevel@tonic-gate lgrp_id_t 971*7c478bd9Sstevel@tonic-gate lgrp_home_get(idtype_t idtype, id_t id) 972*7c478bd9Sstevel@tonic-gate { 973*7c478bd9Sstevel@tonic-gate proc_t *p; 974*7c478bd9Sstevel@tonic-gate lgrp_id_t retval; 975*7c478bd9Sstevel@tonic-gate kthread_t *t; 976*7c478bd9Sstevel@tonic-gate 977*7c478bd9Sstevel@tonic-gate /* 978*7c478bd9Sstevel@tonic-gate * Get home lgroup of given LWP or process 979*7c478bd9Sstevel@tonic-gate */ 980*7c478bd9Sstevel@tonic-gate switch (idtype) { 981*7c478bd9Sstevel@tonic-gate 982*7c478bd9Sstevel@tonic-gate case P_LWPID: 983*7c478bd9Sstevel@tonic-gate p = curproc; 984*7c478bd9Sstevel@tonic-gate 985*7c478bd9Sstevel@tonic-gate /* 986*7c478bd9Sstevel@tonic-gate * Set affinity for thread 987*7c478bd9Sstevel@tonic-gate */ 988*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 989*7c478bd9Sstevel@tonic-gate if (id == P_MYID) { /* current thread */ 990*7c478bd9Sstevel@tonic-gate retval = lgrp_home_thread(curthread); 991*7c478bd9Sstevel@tonic-gate } else if (p->p_tlist == NULL) { 992*7c478bd9Sstevel@tonic-gate retval = set_errno(ESRCH); 993*7c478bd9Sstevel@tonic-gate } else { /* other thread */ 994*7c478bd9Sstevel@tonic-gate int found = 0; 995*7c478bd9Sstevel@tonic-gate 996*7c478bd9Sstevel@tonic-gate t = p->p_tlist; 997*7c478bd9Sstevel@tonic-gate do { 998*7c478bd9Sstevel@tonic-gate if (t->t_tid == id) { 999*7c478bd9Sstevel@tonic-gate retval = lgrp_home_thread(t); 1000*7c478bd9Sstevel@tonic-gate found = 1; 1001*7c478bd9Sstevel@tonic-gate break; 1002*7c478bd9Sstevel@tonic-gate } 1003*7c478bd9Sstevel@tonic-gate } while ((t = t->t_forw) != p->p_tlist); 1004*7c478bd9Sstevel@tonic-gate if (!found) 1005*7c478bd9Sstevel@tonic-gate retval = set_errno(ESRCH); 1006*7c478bd9Sstevel@tonic-gate } 1007*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 1008*7c478bd9Sstevel@tonic-gate break; 1009*7c478bd9Sstevel@tonic-gate 1010*7c478bd9Sstevel@tonic-gate case P_PID: 1011*7c478bd9Sstevel@tonic-gate /* 1012*7c478bd9Sstevel@tonic-gate * Get process 1013*7c478bd9Sstevel@tonic-gate */ 1014*7c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 1015*7c478bd9Sstevel@tonic-gate 1016*7c478bd9Sstevel@tonic-gate if (id == P_MYID) 1017*7c478bd9Sstevel@tonic-gate p = curproc; 1018*7c478bd9Sstevel@tonic-gate else 1019*7c478bd9Sstevel@tonic-gate p = prfind(id); 1020*7c478bd9Sstevel@tonic-gate 1021*7c478bd9Sstevel@tonic-gate if (p == NULL) { 1022*7c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 1023*7c478bd9Sstevel@tonic-gate return (set_errno(ESRCH)); 1024*7c478bd9Sstevel@tonic-gate } 1025*7c478bd9Sstevel@tonic-gate 1026*7c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 1027*7c478bd9Sstevel@tonic-gate t = p->p_tlist; 1028*7c478bd9Sstevel@tonic-gate if (t == NULL) 1029*7c478bd9Sstevel@tonic-gate retval = set_errno(ESRCH); 1030*7c478bd9Sstevel@tonic-gate else 1031*7c478bd9Sstevel@tonic-gate retval = lgrp_home_thread(t); 1032*7c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 1033*7c478bd9Sstevel@tonic-gate 1034*7c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 1035*7c478bd9Sstevel@tonic-gate 1036*7c478bd9Sstevel@tonic-gate break; 1037*7c478bd9Sstevel@tonic-gate 1038*7c478bd9Sstevel@tonic-gate default: 1039*7c478bd9Sstevel@tonic-gate retval = set_errno(EINVAL); 1040*7c478bd9Sstevel@tonic-gate break; 1041*7c478bd9Sstevel@tonic-gate } 1042*7c478bd9Sstevel@tonic-gate 1043*7c478bd9Sstevel@tonic-gate return (retval); 1044*7c478bd9Sstevel@tonic-gate } 1045*7c478bd9Sstevel@tonic-gate 1046*7c478bd9Sstevel@tonic-gate 1047*7c478bd9Sstevel@tonic-gate /* 1048*7c478bd9Sstevel@tonic-gate * Return latency between "from" and "to" lgroups 1049*7c478bd9Sstevel@tonic-gate * 1050*7c478bd9Sstevel@tonic-gate * This latency number can only be used for relative comparison 1051*7c478bd9Sstevel@tonic-gate * between lgroups on the running system, cannot be used across platforms, 1052*7c478bd9Sstevel@tonic-gate * and may not reflect the actual latency. It is platform and implementation 1053*7c478bd9Sstevel@tonic-gate * specific, so platform gets to decide its value. It would be nice if the 1054*7c478bd9Sstevel@tonic-gate * number was at least proportional to make comparisons more meaningful though. 1055*7c478bd9Sstevel@tonic-gate */ 1056*7c478bd9Sstevel@tonic-gate int 1057*7c478bd9Sstevel@tonic-gate lgrp_latency(lgrp_id_t from, lgrp_id_t to) 1058*7c478bd9Sstevel@tonic-gate { 1059*7c478bd9Sstevel@tonic-gate lgrp_t *from_lgrp; 1060*7c478bd9Sstevel@tonic-gate int i; 1061*7c478bd9Sstevel@tonic-gate int latency; 1062*7c478bd9Sstevel@tonic-gate int latency_max; 1063*7c478bd9Sstevel@tonic-gate lgrp_t *to_lgrp; 1064*7c478bd9Sstevel@tonic-gate 1065*7c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 1066*7c478bd9Sstevel@tonic-gate 1067*7c478bd9Sstevel@tonic-gate if (from < 0 || to < 0) 1068*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 1069*7c478bd9Sstevel@tonic-gate 1070*7c478bd9Sstevel@tonic-gate if (from > lgrp_alloc_max || to > lgrp_alloc_max) 1071*7c478bd9Sstevel@tonic-gate return (set_errno(ESRCH)); 1072*7c478bd9Sstevel@tonic-gate 1073*7c478bd9Sstevel@tonic-gate from_lgrp = lgrp_table[from]; 1074*7c478bd9Sstevel@tonic-gate to_lgrp = lgrp_table[to]; 1075*7c478bd9Sstevel@tonic-gate 1076*7c478bd9Sstevel@tonic-gate if (!LGRP_EXISTS(from_lgrp) || !LGRP_EXISTS(to_lgrp)) { 1077*7c478bd9Sstevel@tonic-gate return (set_errno(ESRCH)); 1078*7c478bd9Sstevel@tonic-gate } 1079*7c478bd9Sstevel@tonic-gate 1080*7c478bd9Sstevel@tonic-gate /* 1081*7c478bd9Sstevel@tonic-gate * Get latency for same lgroup 1082*7c478bd9Sstevel@tonic-gate */ 1083*7c478bd9Sstevel@tonic-gate if (from == to) { 1084*7c478bd9Sstevel@tonic-gate latency = from_lgrp->lgrp_latency; 1085*7c478bd9Sstevel@tonic-gate return (latency); 1086*7c478bd9Sstevel@tonic-gate } 1087*7c478bd9Sstevel@tonic-gate 1088*7c478bd9Sstevel@tonic-gate /* 1089*7c478bd9Sstevel@tonic-gate * Get latency between leaf lgroups 1090*7c478bd9Sstevel@tonic-gate */ 1091*7c478bd9Sstevel@tonic-gate if (from_lgrp->lgrp_childcnt == 0 && to_lgrp->lgrp_childcnt == 0) 1092*7c478bd9Sstevel@tonic-gate return (lgrp_plat_latency(from_lgrp->lgrp_plathand, 1093*7c478bd9Sstevel@tonic-gate to_lgrp->lgrp_plathand)); 1094*7c478bd9Sstevel@tonic-gate 1095*7c478bd9Sstevel@tonic-gate /* 1096*7c478bd9Sstevel@tonic-gate * Determine max latency between resources in two lgroups 1097*7c478bd9Sstevel@tonic-gate */ 1098*7c478bd9Sstevel@tonic-gate latency_max = 0; 1099*7c478bd9Sstevel@tonic-gate for (i = 0; i <= lgrp_alloc_max; i++) { 1100*7c478bd9Sstevel@tonic-gate lgrp_t *from_rsrc; 1101*7c478bd9Sstevel@tonic-gate int j; 1102*7c478bd9Sstevel@tonic-gate lgrp_t *to_rsrc; 1103*7c478bd9Sstevel@tonic-gate 1104*7c478bd9Sstevel@tonic-gate from_rsrc = lgrp_table[i]; 1105*7c478bd9Sstevel@tonic-gate if (!LGRP_EXISTS(from_rsrc) || 1106*7c478bd9Sstevel@tonic-gate !klgrpset_ismember(from_lgrp->lgrp_set[LGRP_RSRC_CPU], i)) 1107*7c478bd9Sstevel@tonic-gate continue; 1108*7c478bd9Sstevel@tonic-gate 1109*7c478bd9Sstevel@tonic-gate for (j = 0; j <= lgrp_alloc_max; j++) { 1110*7c478bd9Sstevel@tonic-gate to_rsrc = lgrp_table[j]; 1111*7c478bd9Sstevel@tonic-gate if (!LGRP_EXISTS(to_rsrc) || 1112*7c478bd9Sstevel@tonic-gate klgrpset_ismember(to_lgrp->lgrp_set[LGRP_RSRC_MEM], 1113*7c478bd9Sstevel@tonic-gate j) == 0) 1114*7c478bd9Sstevel@tonic-gate continue; 1115*7c478bd9Sstevel@tonic-gate latency = lgrp_plat_latency(from_rsrc->lgrp_plathand, 1116*7c478bd9Sstevel@tonic-gate to_rsrc->lgrp_plathand); 1117*7c478bd9Sstevel@tonic-gate if (latency > latency_max) 1118*7c478bd9Sstevel@tonic-gate latency_max = latency; 1119*7c478bd9Sstevel@tonic-gate } 1120*7c478bd9Sstevel@tonic-gate } 1121*7c478bd9Sstevel@tonic-gate return (latency_max); 1122*7c478bd9Sstevel@tonic-gate } 1123*7c478bd9Sstevel@tonic-gate 1124*7c478bd9Sstevel@tonic-gate 1125*7c478bd9Sstevel@tonic-gate /* 1126*7c478bd9Sstevel@tonic-gate * Return lgroup interface version number 1127*7c478bd9Sstevel@tonic-gate * 0 - none 1128*7c478bd9Sstevel@tonic-gate * 1 - original 1129*7c478bd9Sstevel@tonic-gate * 2 - lgrp_latency_cookie() and lgrp_resources() added 1130*7c478bd9Sstevel@tonic-gate */ 1131*7c478bd9Sstevel@tonic-gate int 1132*7c478bd9Sstevel@tonic-gate lgrp_version(int version) 1133*7c478bd9Sstevel@tonic-gate { 1134*7c478bd9Sstevel@tonic-gate /* 1135*7c478bd9Sstevel@tonic-gate * Return LGRP_VER_NONE when requested version isn't supported 1136*7c478bd9Sstevel@tonic-gate */ 1137*7c478bd9Sstevel@tonic-gate if (version < LGRP_VER_NONE || version > LGRP_VER_CURRENT) 1138*7c478bd9Sstevel@tonic-gate return (LGRP_VER_NONE); 1139*7c478bd9Sstevel@tonic-gate 1140*7c478bd9Sstevel@tonic-gate /* 1141*7c478bd9Sstevel@tonic-gate * Return current version when LGRP_VER_NONE passed in 1142*7c478bd9Sstevel@tonic-gate */ 1143*7c478bd9Sstevel@tonic-gate if (version == LGRP_VER_NONE) 1144*7c478bd9Sstevel@tonic-gate return (LGRP_VER_CURRENT); 1145*7c478bd9Sstevel@tonic-gate 1146*7c478bd9Sstevel@tonic-gate /* 1147*7c478bd9Sstevel@tonic-gate * Otherwise, return supported version. 1148*7c478bd9Sstevel@tonic-gate */ 1149*7c478bd9Sstevel@tonic-gate return (version); 1150*7c478bd9Sstevel@tonic-gate } 1151*7c478bd9Sstevel@tonic-gate 1152*7c478bd9Sstevel@tonic-gate 1153*7c478bd9Sstevel@tonic-gate /* 1154*7c478bd9Sstevel@tonic-gate * Snapshot of lgroup hieararchy 1155*7c478bd9Sstevel@tonic-gate * 1156*7c478bd9Sstevel@tonic-gate * One snapshot is kept and is based on the kernel's native data model, so 1157*7c478bd9Sstevel@tonic-gate * a 32-bit snapshot is kept for the 32-bit kernel and a 64-bit one for the 1158*7c478bd9Sstevel@tonic-gate * 64-bit kernel. If a 32-bit user wants a snapshot from the 64-bit kernel, 1159*7c478bd9Sstevel@tonic-gate * the kernel generates a 32-bit snapshot from the data in its 64-bit snapshot. 1160*7c478bd9Sstevel@tonic-gate * 1161*7c478bd9Sstevel@tonic-gate * The format is defined by lgroup snapshot header and the layout of 1162*7c478bd9Sstevel@tonic-gate * the snapshot in memory is as follows: 1163*7c478bd9Sstevel@tonic-gate * 1) lgroup snapshot header 1164*7c478bd9Sstevel@tonic-gate * - specifies format of snapshot 1165*7c478bd9Sstevel@tonic-gate * - defined by lgrp_snapshot_header_t 1166*7c478bd9Sstevel@tonic-gate * 2) lgroup info array 1167*7c478bd9Sstevel@tonic-gate * - contains information about each lgroup 1168*7c478bd9Sstevel@tonic-gate * - one element for each lgroup 1169*7c478bd9Sstevel@tonic-gate * - each element is defined by lgrp_info_t 1170*7c478bd9Sstevel@tonic-gate * 3) lgroup CPU ID array 1171*7c478bd9Sstevel@tonic-gate * - contains list (array) of CPU IDs for each lgroup 1172*7c478bd9Sstevel@tonic-gate * - lgrp_info_t points into array and specifies how many CPUs belong to 1173*7c478bd9Sstevel@tonic-gate * given lgroup 1174*7c478bd9Sstevel@tonic-gate * 4) lgroup parents array 1175*7c478bd9Sstevel@tonic-gate * - contains lgroup bitmask of parents for each lgroup 1176*7c478bd9Sstevel@tonic-gate * - bitmask is an array of unsigned longs and its size depends on nlgrpsmax 1177*7c478bd9Sstevel@tonic-gate * 5) lgroup children array 1178*7c478bd9Sstevel@tonic-gate * - contains lgroup bitmask of children for each lgroup 1179*7c478bd9Sstevel@tonic-gate * - bitmask is an array of unsigned longs and its size depends on nlgrpsmax 1180*7c478bd9Sstevel@tonic-gate * 6) lgroup resources array 1181*7c478bd9Sstevel@tonic-gate * - contains lgroup bitmask of resources for each lgroup 1182*7c478bd9Sstevel@tonic-gate * - bitmask is an array of unsigned longs and its size depends on nlgrpsmax 1183*7c478bd9Sstevel@tonic-gate * 7) lgroup latency table 1184*7c478bd9Sstevel@tonic-gate * - contains latency from each lgroup to each of other lgroups 1185*7c478bd9Sstevel@tonic-gate * 1186*7c478bd9Sstevel@tonic-gate * NOTE: Must use nlgrpsmax for per lgroup data structures because lgroups 1187*7c478bd9Sstevel@tonic-gate * may be sparsely allocated. 1188*7c478bd9Sstevel@tonic-gate */ 1189*7c478bd9Sstevel@tonic-gate lgrp_snapshot_header_t *lgrp_snap = NULL; /* lgroup snapshot */ 1190*7c478bd9Sstevel@tonic-gate static kmutex_t lgrp_snap_lock; /* snapshot lock */ 1191*7c478bd9Sstevel@tonic-gate 1192*7c478bd9Sstevel@tonic-gate 1193*7c478bd9Sstevel@tonic-gate /* 1194*7c478bd9Sstevel@tonic-gate * Take a snapshot of lgroup hierarchy and return size of buffer 1195*7c478bd9Sstevel@tonic-gate * needed to hold snapshot 1196*7c478bd9Sstevel@tonic-gate */ 1197*7c478bd9Sstevel@tonic-gate static int 1198*7c478bd9Sstevel@tonic-gate lgrp_snapshot(void) 1199*7c478bd9Sstevel@tonic-gate { 1200*7c478bd9Sstevel@tonic-gate size_t bitmask_size; 1201*7c478bd9Sstevel@tonic-gate size_t bitmasks_size; 1202*7c478bd9Sstevel@tonic-gate size_t bufsize; 1203*7c478bd9Sstevel@tonic-gate int cpu_index; 1204*7c478bd9Sstevel@tonic-gate size_t cpuids_size; 1205*7c478bd9Sstevel@tonic-gate int i; 1206*7c478bd9Sstevel@tonic-gate int j; 1207*7c478bd9Sstevel@tonic-gate size_t info_size; 1208*7c478bd9Sstevel@tonic-gate size_t lats_size; 1209*7c478bd9Sstevel@tonic-gate ulong_t *lgrp_children; 1210*7c478bd9Sstevel@tonic-gate processorid_t *lgrp_cpuids; 1211*7c478bd9Sstevel@tonic-gate lgrp_info_t *lgrp_info; 1212*7c478bd9Sstevel@tonic-gate int **lgrp_lats; 1213*7c478bd9Sstevel@tonic-gate ulong_t *lgrp_parents; 1214*7c478bd9Sstevel@tonic-gate ulong_t *lgrp_rsets; 1215*7c478bd9Sstevel@tonic-gate ulong_t *lgrpset; 1216*7c478bd9Sstevel@tonic-gate int snap_ncpus; 1217*7c478bd9Sstevel@tonic-gate int snap_nlgrps; 1218*7c478bd9Sstevel@tonic-gate int snap_nlgrpsmax; 1219*7c478bd9Sstevel@tonic-gate size_t snap_hdr_size; 1220*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1221*7c478bd9Sstevel@tonic-gate model_t model = DATAMODEL_NATIVE; 1222*7c478bd9Sstevel@tonic-gate 1223*7c478bd9Sstevel@tonic-gate /* 1224*7c478bd9Sstevel@tonic-gate * Have up-to-date snapshot, so check to see whether caller is 32-bit 1225*7c478bd9Sstevel@tonic-gate * program and need to return size of 32-bit snapshot now. 1226*7c478bd9Sstevel@tonic-gate */ 1227*7c478bd9Sstevel@tonic-gate model = get_udatamodel(); 1228*7c478bd9Sstevel@tonic-gate if (model == DATAMODEL_ILP32 && lgrp_snap && 1229*7c478bd9Sstevel@tonic-gate lgrp_snap->ss_gen == lgrp_gen) { 1230*7c478bd9Sstevel@tonic-gate 1231*7c478bd9Sstevel@tonic-gate snap_nlgrpsmax = lgrp_snap->ss_nlgrps_max; 1232*7c478bd9Sstevel@tonic-gate 1233*7c478bd9Sstevel@tonic-gate /* 1234*7c478bd9Sstevel@tonic-gate * Calculate size of buffer needed for 32-bit snapshot, 1235*7c478bd9Sstevel@tonic-gate * rounding up size of each object to allow for alignment 1236*7c478bd9Sstevel@tonic-gate * of next object in buffer. 1237*7c478bd9Sstevel@tonic-gate */ 1238*7c478bd9Sstevel@tonic-gate snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header32_t), 1239*7c478bd9Sstevel@tonic-gate sizeof (caddr32_t)); 1240*7c478bd9Sstevel@tonic-gate info_size = 1241*7c478bd9Sstevel@tonic-gate P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info32_t), 1242*7c478bd9Sstevel@tonic-gate sizeof (processorid_t)); 1243*7c478bd9Sstevel@tonic-gate cpuids_size = 1244*7c478bd9Sstevel@tonic-gate P2ROUNDUP(lgrp_snap->ss_ncpus * sizeof (processorid_t), 1245*7c478bd9Sstevel@tonic-gate sizeof (ulong_t)); 1246*7c478bd9Sstevel@tonic-gate 1247*7c478bd9Sstevel@tonic-gate /* 1248*7c478bd9Sstevel@tonic-gate * lgroup bitmasks needed for parents, children, and resources 1249*7c478bd9Sstevel@tonic-gate * for each lgroup and pset lgroup set 1250*7c478bd9Sstevel@tonic-gate */ 1251*7c478bd9Sstevel@tonic-gate bitmask_size = BT_SIZEOFMAP(snap_nlgrpsmax); 1252*7c478bd9Sstevel@tonic-gate bitmasks_size = (((2 + LGRP_RSRC_COUNT) * 1253*7c478bd9Sstevel@tonic-gate snap_nlgrpsmax) + 1) * bitmask_size; 1254*7c478bd9Sstevel@tonic-gate 1255*7c478bd9Sstevel@tonic-gate /* 1256*7c478bd9Sstevel@tonic-gate * Size of latency table and buffer 1257*7c478bd9Sstevel@tonic-gate */ 1258*7c478bd9Sstevel@tonic-gate lats_size = snap_nlgrpsmax * sizeof (caddr32_t) + 1259*7c478bd9Sstevel@tonic-gate snap_nlgrpsmax * snap_nlgrpsmax * sizeof (int); 1260*7c478bd9Sstevel@tonic-gate 1261*7c478bd9Sstevel@tonic-gate bufsize = snap_hdr_size + info_size + cpuids_size + 1262*7c478bd9Sstevel@tonic-gate bitmasks_size + lats_size; 1263*7c478bd9Sstevel@tonic-gate return (bufsize); 1264*7c478bd9Sstevel@tonic-gate } 1265*7c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 1266*7c478bd9Sstevel@tonic-gate 1267*7c478bd9Sstevel@tonic-gate /* 1268*7c478bd9Sstevel@tonic-gate * Check whether snapshot is up-to-date 1269*7c478bd9Sstevel@tonic-gate * Free it and take another one if not 1270*7c478bd9Sstevel@tonic-gate */ 1271*7c478bd9Sstevel@tonic-gate if (lgrp_snap) { 1272*7c478bd9Sstevel@tonic-gate if (lgrp_snap->ss_gen == lgrp_gen) 1273*7c478bd9Sstevel@tonic-gate return (lgrp_snap->ss_size); 1274*7c478bd9Sstevel@tonic-gate 1275*7c478bd9Sstevel@tonic-gate kmem_free(lgrp_snap, lgrp_snap->ss_size); 1276*7c478bd9Sstevel@tonic-gate lgrp_snap = NULL; 1277*7c478bd9Sstevel@tonic-gate } 1278*7c478bd9Sstevel@tonic-gate 1279*7c478bd9Sstevel@tonic-gate /* 1280*7c478bd9Sstevel@tonic-gate * Allocate memory for snapshot 1281*7c478bd9Sstevel@tonic-gate * w/o holding cpu_lock while waiting for memory 1282*7c478bd9Sstevel@tonic-gate */ 1283*7c478bd9Sstevel@tonic-gate while (lgrp_snap == NULL) { 1284*7c478bd9Sstevel@tonic-gate int old_generation; 1285*7c478bd9Sstevel@tonic-gate 1286*7c478bd9Sstevel@tonic-gate /* 1287*7c478bd9Sstevel@tonic-gate * Take snapshot of lgroup generation number 1288*7c478bd9Sstevel@tonic-gate * and configuration size dependent information 1289*7c478bd9Sstevel@tonic-gate * NOTE: Only count number of online CPUs, 1290*7c478bd9Sstevel@tonic-gate * since only online CPUs appear in lgroups. 1291*7c478bd9Sstevel@tonic-gate */ 1292*7c478bd9Sstevel@tonic-gate mutex_enter(&cpu_lock); 1293*7c478bd9Sstevel@tonic-gate old_generation = lgrp_gen; 1294*7c478bd9Sstevel@tonic-gate snap_ncpus = ncpus_online; 1295*7c478bd9Sstevel@tonic-gate snap_nlgrps = nlgrps; 1296*7c478bd9Sstevel@tonic-gate snap_nlgrpsmax = nlgrpsmax; 1297*7c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock); 1298*7c478bd9Sstevel@tonic-gate 1299*7c478bd9Sstevel@tonic-gate /* 1300*7c478bd9Sstevel@tonic-gate * Calculate size of buffer needed for snapshot, 1301*7c478bd9Sstevel@tonic-gate * rounding up size of each object to allow for alignment 1302*7c478bd9Sstevel@tonic-gate * of next object in buffer. 1303*7c478bd9Sstevel@tonic-gate */ 1304*7c478bd9Sstevel@tonic-gate snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header_t), 1305*7c478bd9Sstevel@tonic-gate sizeof (void *)); 1306*7c478bd9Sstevel@tonic-gate info_size = P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info_t), 1307*7c478bd9Sstevel@tonic-gate sizeof (processorid_t)); 1308*7c478bd9Sstevel@tonic-gate cpuids_size = P2ROUNDUP(snap_ncpus * sizeof (processorid_t), 1309*7c478bd9Sstevel@tonic-gate sizeof (ulong_t)); 1310*7c478bd9Sstevel@tonic-gate /* 1311*7c478bd9Sstevel@tonic-gate * lgroup bitmasks needed for pset lgroup set and parents, 1312*7c478bd9Sstevel@tonic-gate * children, and resource sets for each lgroup 1313*7c478bd9Sstevel@tonic-gate */ 1314*7c478bd9Sstevel@tonic-gate bitmask_size = BT_SIZEOFMAP(snap_nlgrpsmax); 1315*7c478bd9Sstevel@tonic-gate bitmasks_size = (((2 + LGRP_RSRC_COUNT) * 1316*7c478bd9Sstevel@tonic-gate snap_nlgrpsmax) + 1) * bitmask_size; 1317*7c478bd9Sstevel@tonic-gate 1318*7c478bd9Sstevel@tonic-gate /* 1319*7c478bd9Sstevel@tonic-gate * Size of latency table and buffer 1320*7c478bd9Sstevel@tonic-gate */ 1321*7c478bd9Sstevel@tonic-gate lats_size = snap_nlgrpsmax * sizeof (int *) + 1322*7c478bd9Sstevel@tonic-gate snap_nlgrpsmax * snap_nlgrpsmax * sizeof (int); 1323*7c478bd9Sstevel@tonic-gate 1324*7c478bd9Sstevel@tonic-gate bufsize = snap_hdr_size + info_size + cpuids_size + 1325*7c478bd9Sstevel@tonic-gate bitmasks_size + lats_size; 1326*7c478bd9Sstevel@tonic-gate 1327*7c478bd9Sstevel@tonic-gate /* 1328*7c478bd9Sstevel@tonic-gate * Allocate memory for buffer 1329*7c478bd9Sstevel@tonic-gate */ 1330*7c478bd9Sstevel@tonic-gate lgrp_snap = kmem_zalloc(bufsize, KM_NOSLEEP); 1331*7c478bd9Sstevel@tonic-gate if (lgrp_snap == NULL) 1332*7c478bd9Sstevel@tonic-gate return (set_errno(ENOMEM)); 1333*7c478bd9Sstevel@tonic-gate 1334*7c478bd9Sstevel@tonic-gate /* 1335*7c478bd9Sstevel@tonic-gate * Check whether generation number has changed 1336*7c478bd9Sstevel@tonic-gate */ 1337*7c478bd9Sstevel@tonic-gate mutex_enter(&cpu_lock); 1338*7c478bd9Sstevel@tonic-gate if (lgrp_gen == old_generation) 1339*7c478bd9Sstevel@tonic-gate break; /* hasn't change, so done. */ 1340*7c478bd9Sstevel@tonic-gate 1341*7c478bd9Sstevel@tonic-gate /* 1342*7c478bd9Sstevel@tonic-gate * Generation number changed, so free memory and try again. 1343*7c478bd9Sstevel@tonic-gate */ 1344*7c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock); 1345*7c478bd9Sstevel@tonic-gate kmem_free(lgrp_snap, bufsize); 1346*7c478bd9Sstevel@tonic-gate lgrp_snap = NULL; 1347*7c478bd9Sstevel@tonic-gate } 1348*7c478bd9Sstevel@tonic-gate 1349*7c478bd9Sstevel@tonic-gate /* 1350*7c478bd9Sstevel@tonic-gate * Fill in lgroup snapshot header 1351*7c478bd9Sstevel@tonic-gate * (including pointers to tables of lgroup info, CPU IDs, and parents 1352*7c478bd9Sstevel@tonic-gate * and children) 1353*7c478bd9Sstevel@tonic-gate */ 1354*7c478bd9Sstevel@tonic-gate lgrp_snap->ss_version = LGRP_VER_CURRENT; 1355*7c478bd9Sstevel@tonic-gate 1356*7c478bd9Sstevel@tonic-gate /* 1357*7c478bd9Sstevel@tonic-gate * XXX For now, liblgrp only needs to know whether the hierarchy 1358*7c478bd9Sstevel@tonic-gate * XXX only has one level or not 1359*7c478bd9Sstevel@tonic-gate */ 1360*7c478bd9Sstevel@tonic-gate if (snap_nlgrps == 1) 1361*7c478bd9Sstevel@tonic-gate lgrp_snap->ss_levels = 1; 1362*7c478bd9Sstevel@tonic-gate else 1363*7c478bd9Sstevel@tonic-gate lgrp_snap->ss_levels = 2; 1364*7c478bd9Sstevel@tonic-gate 1365*7c478bd9Sstevel@tonic-gate lgrp_snap->ss_root = LGRP_ROOTID; 1366*7c478bd9Sstevel@tonic-gate 1367*7c478bd9Sstevel@tonic-gate lgrp_snap->ss_nlgrps = lgrp_snap->ss_nlgrps_os = snap_nlgrps; 1368*7c478bd9Sstevel@tonic-gate lgrp_snap->ss_nlgrps_max = snap_nlgrpsmax; 1369*7c478bd9Sstevel@tonic-gate lgrp_snap->ss_ncpus = snap_ncpus; 1370*7c478bd9Sstevel@tonic-gate lgrp_snap->ss_gen = lgrp_gen; 1371*7c478bd9Sstevel@tonic-gate lgrp_snap->ss_view = LGRP_VIEW_OS; 1372*7c478bd9Sstevel@tonic-gate lgrp_snap->ss_pset = 0; /* NOTE: caller should set if needed */ 1373*7c478bd9Sstevel@tonic-gate lgrp_snap->ss_size = bufsize; 1374*7c478bd9Sstevel@tonic-gate lgrp_snap->ss_magic = (uintptr_t)lgrp_snap; 1375*7c478bd9Sstevel@tonic-gate 1376*7c478bd9Sstevel@tonic-gate lgrp_snap->ss_info = lgrp_info = 1377*7c478bd9Sstevel@tonic-gate (lgrp_info_t *)((uintptr_t)lgrp_snap + snap_hdr_size); 1378*7c478bd9Sstevel@tonic-gate 1379*7c478bd9Sstevel@tonic-gate lgrp_snap->ss_cpuids = lgrp_cpuids = 1380*7c478bd9Sstevel@tonic-gate (processorid_t *)((uintptr_t)lgrp_info + info_size); 1381*7c478bd9Sstevel@tonic-gate 1382*7c478bd9Sstevel@tonic-gate lgrp_snap->ss_lgrpset = lgrpset = 1383*7c478bd9Sstevel@tonic-gate (ulong_t *)((uintptr_t)lgrp_cpuids + cpuids_size); 1384*7c478bd9Sstevel@tonic-gate 1385*7c478bd9Sstevel@tonic-gate lgrp_snap->ss_parents = lgrp_parents = 1386*7c478bd9Sstevel@tonic-gate (ulong_t *)((uintptr_t)lgrpset + bitmask_size); 1387*7c478bd9Sstevel@tonic-gate 1388*7c478bd9Sstevel@tonic-gate lgrp_snap->ss_children = lgrp_children = 1389*7c478bd9Sstevel@tonic-gate (ulong_t *)((uintptr_t)lgrp_parents + (snap_nlgrpsmax * 1390*7c478bd9Sstevel@tonic-gate bitmask_size)); 1391*7c478bd9Sstevel@tonic-gate 1392*7c478bd9Sstevel@tonic-gate lgrp_snap->ss_rsets = lgrp_rsets = 1393*7c478bd9Sstevel@tonic-gate (ulong_t *)((uintptr_t)lgrp_children + (snap_nlgrpsmax * 1394*7c478bd9Sstevel@tonic-gate bitmask_size)); 1395*7c478bd9Sstevel@tonic-gate 1396*7c478bd9Sstevel@tonic-gate lgrp_snap->ss_latencies = lgrp_lats = 1397*7c478bd9Sstevel@tonic-gate (int **)((uintptr_t)lgrp_rsets + (LGRP_RSRC_COUNT * 1398*7c478bd9Sstevel@tonic-gate snap_nlgrpsmax * bitmask_size)); 1399*7c478bd9Sstevel@tonic-gate 1400*7c478bd9Sstevel@tonic-gate /* 1401*7c478bd9Sstevel@tonic-gate * Fill in lgroup information 1402*7c478bd9Sstevel@tonic-gate */ 1403*7c478bd9Sstevel@tonic-gate cpu_index = 0; 1404*7c478bd9Sstevel@tonic-gate for (i = 0; i < snap_nlgrpsmax; i++) { 1405*7c478bd9Sstevel@tonic-gate struct cpu *cp; 1406*7c478bd9Sstevel@tonic-gate int cpu_count; 1407*7c478bd9Sstevel@tonic-gate struct cpu *head; 1408*7c478bd9Sstevel@tonic-gate int k; 1409*7c478bd9Sstevel@tonic-gate lgrp_t *lgrp; 1410*7c478bd9Sstevel@tonic-gate 1411*7c478bd9Sstevel@tonic-gate lgrp = lgrp_table[i]; 1412*7c478bd9Sstevel@tonic-gate if (!LGRP_EXISTS(lgrp)) { 1413*7c478bd9Sstevel@tonic-gate bzero(&lgrp_info[i], sizeof (lgrp_info[i])); 1414*7c478bd9Sstevel@tonic-gate lgrp_info[i].info_lgrpid = LGRP_NONE; 1415*7c478bd9Sstevel@tonic-gate continue; 1416*7c478bd9Sstevel@tonic-gate } 1417*7c478bd9Sstevel@tonic-gate 1418*7c478bd9Sstevel@tonic-gate lgrp_info[i].info_lgrpid = i; 1419*7c478bd9Sstevel@tonic-gate lgrp_info[i].info_latency = lgrp->lgrp_latency; 1420*7c478bd9Sstevel@tonic-gate 1421*7c478bd9Sstevel@tonic-gate /* 1422*7c478bd9Sstevel@tonic-gate * Fill in parents, children, and lgroup resources 1423*7c478bd9Sstevel@tonic-gate */ 1424*7c478bd9Sstevel@tonic-gate lgrp_info[i].info_parents = 1425*7c478bd9Sstevel@tonic-gate (ulong_t *)((uintptr_t)lgrp_parents + (i * bitmask_size)); 1426*7c478bd9Sstevel@tonic-gate 1427*7c478bd9Sstevel@tonic-gate if (lgrp->lgrp_parent) 1428*7c478bd9Sstevel@tonic-gate BT_SET(lgrp_info[i].info_parents, 1429*7c478bd9Sstevel@tonic-gate lgrp->lgrp_parent->lgrp_id); 1430*7c478bd9Sstevel@tonic-gate 1431*7c478bd9Sstevel@tonic-gate lgrp_info[i].info_children = 1432*7c478bd9Sstevel@tonic-gate (ulong_t *)((uintptr_t)lgrp_children + (i * bitmask_size)); 1433*7c478bd9Sstevel@tonic-gate 1434*7c478bd9Sstevel@tonic-gate for (j = 0; j < snap_nlgrpsmax; j++) 1435*7c478bd9Sstevel@tonic-gate if (klgrpset_ismember(lgrp->lgrp_children, j)) 1436*7c478bd9Sstevel@tonic-gate BT_SET(lgrp_info[i].info_children, j); 1437*7c478bd9Sstevel@tonic-gate 1438*7c478bd9Sstevel@tonic-gate lgrp_info[i].info_rset = 1439*7c478bd9Sstevel@tonic-gate (ulong_t *)((uintptr_t)lgrp_rsets + 1440*7c478bd9Sstevel@tonic-gate (i * LGRP_RSRC_COUNT * bitmask_size)); 1441*7c478bd9Sstevel@tonic-gate 1442*7c478bd9Sstevel@tonic-gate for (j = 0; j < LGRP_RSRC_COUNT; j++) { 1443*7c478bd9Sstevel@tonic-gate ulong_t *rset; 1444*7c478bd9Sstevel@tonic-gate 1445*7c478bd9Sstevel@tonic-gate rset = (ulong_t *)((uintptr_t)lgrp_info[i].info_rset + 1446*7c478bd9Sstevel@tonic-gate (j * bitmask_size)); 1447*7c478bd9Sstevel@tonic-gate for (k = 0; k < snap_nlgrpsmax; k++) 1448*7c478bd9Sstevel@tonic-gate if (klgrpset_ismember(lgrp->lgrp_set[j], k)) 1449*7c478bd9Sstevel@tonic-gate BT_SET(rset, k); 1450*7c478bd9Sstevel@tonic-gate } 1451*7c478bd9Sstevel@tonic-gate 1452*7c478bd9Sstevel@tonic-gate /* 1453*7c478bd9Sstevel@tonic-gate * Fill in CPU IDs 1454*7c478bd9Sstevel@tonic-gate */ 1455*7c478bd9Sstevel@tonic-gate cpu_count = 0; 1456*7c478bd9Sstevel@tonic-gate lgrp_info[i].info_cpuids = NULL; 1457*7c478bd9Sstevel@tonic-gate cp = head = lgrp->lgrp_cpu; 1458*7c478bd9Sstevel@tonic-gate if (head != NULL) { 1459*7c478bd9Sstevel@tonic-gate lgrp_info[i].info_cpuids = &lgrp_cpuids[cpu_index]; 1460*7c478bd9Sstevel@tonic-gate do { 1461*7c478bd9Sstevel@tonic-gate lgrp_cpuids[cpu_index] = cp->cpu_id; 1462*7c478bd9Sstevel@tonic-gate cpu_index++; 1463*7c478bd9Sstevel@tonic-gate cpu_count++; 1464*7c478bd9Sstevel@tonic-gate cp = cp->cpu_next_lgrp; 1465*7c478bd9Sstevel@tonic-gate } while (cp != head); 1466*7c478bd9Sstevel@tonic-gate } 1467*7c478bd9Sstevel@tonic-gate ASSERT(cpu_count == lgrp->lgrp_cpucnt); 1468*7c478bd9Sstevel@tonic-gate lgrp_info[i].info_ncpus = cpu_count; 1469*7c478bd9Sstevel@tonic-gate 1470*7c478bd9Sstevel@tonic-gate /* 1471*7c478bd9Sstevel@tonic-gate * Fill in memory sizes for lgroups that directly contain 1472*7c478bd9Sstevel@tonic-gate * memory 1473*7c478bd9Sstevel@tonic-gate */ 1474*7c478bd9Sstevel@tonic-gate if (klgrpset_ismember(lgrp->lgrp_set[LGRP_RSRC_MEM], i)) { 1475*7c478bd9Sstevel@tonic-gate lgrp_info[i].info_mem_free = 1476*7c478bd9Sstevel@tonic-gate lgrp_mem_size(i, LGRP_MEM_SIZE_FREE); 1477*7c478bd9Sstevel@tonic-gate lgrp_info[i].info_mem_install = 1478*7c478bd9Sstevel@tonic-gate lgrp_mem_size(i, LGRP_MEM_SIZE_INSTALL); 1479*7c478bd9Sstevel@tonic-gate } 1480*7c478bd9Sstevel@tonic-gate 1481*7c478bd9Sstevel@tonic-gate /* 1482*7c478bd9Sstevel@tonic-gate * Fill in latency table and buffer 1483*7c478bd9Sstevel@tonic-gate */ 1484*7c478bd9Sstevel@tonic-gate lgrp_lats[i] = (int *)((uintptr_t)lgrp_lats + snap_nlgrpsmax * 1485*7c478bd9Sstevel@tonic-gate sizeof (int *) + i * snap_nlgrpsmax * sizeof (int)); 1486*7c478bd9Sstevel@tonic-gate for (j = 0; j < snap_nlgrpsmax; j++) { 1487*7c478bd9Sstevel@tonic-gate lgrp_t *to; 1488*7c478bd9Sstevel@tonic-gate 1489*7c478bd9Sstevel@tonic-gate to = lgrp_table[j]; 1490*7c478bd9Sstevel@tonic-gate if (!LGRP_EXISTS(to)) 1491*7c478bd9Sstevel@tonic-gate continue; 1492*7c478bd9Sstevel@tonic-gate lgrp_lats[i][j] = lgrp_latency(lgrp->lgrp_id, 1493*7c478bd9Sstevel@tonic-gate to->lgrp_id); 1494*7c478bd9Sstevel@tonic-gate } 1495*7c478bd9Sstevel@tonic-gate } 1496*7c478bd9Sstevel@tonic-gate ASSERT(cpu_index == snap_ncpus); 1497*7c478bd9Sstevel@tonic-gate 1498*7c478bd9Sstevel@tonic-gate 1499*7c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock); 1500*7c478bd9Sstevel@tonic-gate 1501*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1502*7c478bd9Sstevel@tonic-gate /* 1503*7c478bd9Sstevel@tonic-gate * Check to see whether caller is 32-bit program and need to return 1504*7c478bd9Sstevel@tonic-gate * size of 32-bit snapshot now that snapshot has been taken/updated. 1505*7c478bd9Sstevel@tonic-gate * May not have been able to do this earlier if snapshot was out of 1506*7c478bd9Sstevel@tonic-gate * date or didn't exist yet. 1507*7c478bd9Sstevel@tonic-gate */ 1508*7c478bd9Sstevel@tonic-gate if (model == DATAMODEL_ILP32) { 1509*7c478bd9Sstevel@tonic-gate 1510*7c478bd9Sstevel@tonic-gate snap_nlgrpsmax = lgrp_snap->ss_nlgrps_max; 1511*7c478bd9Sstevel@tonic-gate 1512*7c478bd9Sstevel@tonic-gate /* 1513*7c478bd9Sstevel@tonic-gate * Calculate size of buffer needed for 32-bit snapshot, 1514*7c478bd9Sstevel@tonic-gate * rounding up size of each object to allow for alignment 1515*7c478bd9Sstevel@tonic-gate * of next object in buffer. 1516*7c478bd9Sstevel@tonic-gate */ 1517*7c478bd9Sstevel@tonic-gate snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header32_t), 1518*7c478bd9Sstevel@tonic-gate sizeof (caddr32_t)); 1519*7c478bd9Sstevel@tonic-gate info_size = 1520*7c478bd9Sstevel@tonic-gate P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info32_t), 1521*7c478bd9Sstevel@tonic-gate sizeof (processorid_t)); 1522*7c478bd9Sstevel@tonic-gate cpuids_size = 1523*7c478bd9Sstevel@tonic-gate P2ROUNDUP(lgrp_snap->ss_ncpus * sizeof (processorid_t), 1524*7c478bd9Sstevel@tonic-gate sizeof (ulong_t)); 1525*7c478bd9Sstevel@tonic-gate 1526*7c478bd9Sstevel@tonic-gate bitmask_size = BT_SIZEOFMAP(snap_nlgrpsmax); 1527*7c478bd9Sstevel@tonic-gate bitmasks_size = (((2 + LGRP_RSRC_COUNT) * snap_nlgrpsmax) + 1528*7c478bd9Sstevel@tonic-gate 1) * bitmask_size; 1529*7c478bd9Sstevel@tonic-gate 1530*7c478bd9Sstevel@tonic-gate 1531*7c478bd9Sstevel@tonic-gate /* 1532*7c478bd9Sstevel@tonic-gate * Size of latency table and buffer 1533*7c478bd9Sstevel@tonic-gate */ 1534*7c478bd9Sstevel@tonic-gate lats_size = (snap_nlgrpsmax * sizeof (caddr32_t)) + 1535*7c478bd9Sstevel@tonic-gate (snap_nlgrpsmax * snap_nlgrpsmax * sizeof (int)); 1536*7c478bd9Sstevel@tonic-gate 1537*7c478bd9Sstevel@tonic-gate bufsize = snap_hdr_size + info_size + cpuids_size + 1538*7c478bd9Sstevel@tonic-gate bitmasks_size + lats_size; 1539*7c478bd9Sstevel@tonic-gate return (bufsize); 1540*7c478bd9Sstevel@tonic-gate } 1541*7c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 1542*7c478bd9Sstevel@tonic-gate 1543*7c478bd9Sstevel@tonic-gate return (lgrp_snap->ss_size); 1544*7c478bd9Sstevel@tonic-gate } 1545*7c478bd9Sstevel@tonic-gate 1546*7c478bd9Sstevel@tonic-gate 1547*7c478bd9Sstevel@tonic-gate /* 1548*7c478bd9Sstevel@tonic-gate * Copy snapshot into given user buffer, fix up any pointers in buffer to point 1549*7c478bd9Sstevel@tonic-gate * into user instead of kernel address space, and return size of buffer 1550*7c478bd9Sstevel@tonic-gate * needed to hold snapshot 1551*7c478bd9Sstevel@tonic-gate */ 1552*7c478bd9Sstevel@tonic-gate static int 1553*7c478bd9Sstevel@tonic-gate lgrp_snapshot_copy(char *buf, size_t bufsize) 1554*7c478bd9Sstevel@tonic-gate { 1555*7c478bd9Sstevel@tonic-gate size_t bitmask_size; 1556*7c478bd9Sstevel@tonic-gate int cpu_index; 1557*7c478bd9Sstevel@tonic-gate size_t cpuids_size; 1558*7c478bd9Sstevel@tonic-gate int i; 1559*7c478bd9Sstevel@tonic-gate size_t info_size; 1560*7c478bd9Sstevel@tonic-gate lgrp_info_t *lgrp_info; 1561*7c478bd9Sstevel@tonic-gate int retval; 1562*7c478bd9Sstevel@tonic-gate size_t snap_hdr_size; 1563*7c478bd9Sstevel@tonic-gate int snap_ncpus; 1564*7c478bd9Sstevel@tonic-gate int snap_nlgrpsmax; 1565*7c478bd9Sstevel@tonic-gate lgrp_snapshot_header_t *user_snap; 1566*7c478bd9Sstevel@tonic-gate lgrp_info_t *user_info; 1567*7c478bd9Sstevel@tonic-gate lgrp_info_t *user_info_buffer; 1568*7c478bd9Sstevel@tonic-gate processorid_t *user_cpuids; 1569*7c478bd9Sstevel@tonic-gate ulong_t *user_lgrpset; 1570*7c478bd9Sstevel@tonic-gate ulong_t *user_parents; 1571*7c478bd9Sstevel@tonic-gate ulong_t *user_children; 1572*7c478bd9Sstevel@tonic-gate int **user_lats; 1573*7c478bd9Sstevel@tonic-gate int **user_lats_buffer; 1574*7c478bd9Sstevel@tonic-gate ulong_t *user_rsets; 1575*7c478bd9Sstevel@tonic-gate 1576*7c478bd9Sstevel@tonic-gate if (lgrp_snap == NULL) 1577*7c478bd9Sstevel@tonic-gate return (0); 1578*7c478bd9Sstevel@tonic-gate 1579*7c478bd9Sstevel@tonic-gate if (buf == NULL || bufsize <= 0) 1580*7c478bd9Sstevel@tonic-gate return (lgrp_snap->ss_size); 1581*7c478bd9Sstevel@tonic-gate 1582*7c478bd9Sstevel@tonic-gate /* 1583*7c478bd9Sstevel@tonic-gate * User needs to try getting size of buffer again 1584*7c478bd9Sstevel@tonic-gate * because given buffer size is too small. 1585*7c478bd9Sstevel@tonic-gate * The lgroup hierarchy may have changed after they asked for the size 1586*7c478bd9Sstevel@tonic-gate * but before the snapshot was taken. 1587*7c478bd9Sstevel@tonic-gate */ 1588*7c478bd9Sstevel@tonic-gate if (bufsize < lgrp_snap->ss_size) 1589*7c478bd9Sstevel@tonic-gate return (set_errno(EAGAIN)); 1590*7c478bd9Sstevel@tonic-gate 1591*7c478bd9Sstevel@tonic-gate snap_ncpus = lgrp_snap->ss_ncpus; 1592*7c478bd9Sstevel@tonic-gate snap_nlgrpsmax = lgrp_snap->ss_nlgrps_max; 1593*7c478bd9Sstevel@tonic-gate 1594*7c478bd9Sstevel@tonic-gate /* 1595*7c478bd9Sstevel@tonic-gate * Fill in lgrpset now because caller may have change psets 1596*7c478bd9Sstevel@tonic-gate */ 1597*7c478bd9Sstevel@tonic-gate kpreempt_disable(); 1598*7c478bd9Sstevel@tonic-gate for (i = 0; i < snap_nlgrpsmax; i++) { 1599*7c478bd9Sstevel@tonic-gate if (klgrpset_ismember(curthread->t_cpupart->cp_lgrpset, 1600*7c478bd9Sstevel@tonic-gate i)) { 1601*7c478bd9Sstevel@tonic-gate BT_SET(lgrp_snap->ss_lgrpset, i); 1602*7c478bd9Sstevel@tonic-gate } 1603*7c478bd9Sstevel@tonic-gate } 1604*7c478bd9Sstevel@tonic-gate kpreempt_enable(); 1605*7c478bd9Sstevel@tonic-gate 1606*7c478bd9Sstevel@tonic-gate /* 1607*7c478bd9Sstevel@tonic-gate * Copy lgroup snapshot (snapshot header, lgroup info, and CPU IDs) 1608*7c478bd9Sstevel@tonic-gate * into user buffer all at once 1609*7c478bd9Sstevel@tonic-gate */ 1610*7c478bd9Sstevel@tonic-gate if (copyout(lgrp_snap, buf, lgrp_snap->ss_size) != 0) 1611*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 1612*7c478bd9Sstevel@tonic-gate 1613*7c478bd9Sstevel@tonic-gate /* 1614*7c478bd9Sstevel@tonic-gate * Round up sizes of lgroup snapshot header and info for alignment 1615*7c478bd9Sstevel@tonic-gate */ 1616*7c478bd9Sstevel@tonic-gate snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header_t), 1617*7c478bd9Sstevel@tonic-gate sizeof (void *)); 1618*7c478bd9Sstevel@tonic-gate info_size = P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info_t), 1619*7c478bd9Sstevel@tonic-gate sizeof (processorid_t)); 1620*7c478bd9Sstevel@tonic-gate cpuids_size = P2ROUNDUP(snap_ncpus * sizeof (processorid_t), 1621*7c478bd9Sstevel@tonic-gate sizeof (ulong_t)); 1622*7c478bd9Sstevel@tonic-gate 1623*7c478bd9Sstevel@tonic-gate bitmask_size = BT_SIZEOFMAP(snap_nlgrpsmax); 1624*7c478bd9Sstevel@tonic-gate 1625*7c478bd9Sstevel@tonic-gate /* 1626*7c478bd9Sstevel@tonic-gate * Calculate pointers into user buffer for lgroup snapshot header, 1627*7c478bd9Sstevel@tonic-gate * info, and CPU IDs 1628*7c478bd9Sstevel@tonic-gate */ 1629*7c478bd9Sstevel@tonic-gate user_snap = (lgrp_snapshot_header_t *)buf; 1630*7c478bd9Sstevel@tonic-gate user_info = (lgrp_info_t *)((uintptr_t)user_snap + snap_hdr_size); 1631*7c478bd9Sstevel@tonic-gate user_cpuids = (processorid_t *)((uintptr_t)user_info + info_size); 1632*7c478bd9Sstevel@tonic-gate user_lgrpset = (ulong_t *)((uintptr_t)user_cpuids + cpuids_size); 1633*7c478bd9Sstevel@tonic-gate user_parents = (ulong_t *)((uintptr_t)user_lgrpset + bitmask_size); 1634*7c478bd9Sstevel@tonic-gate user_children = (ulong_t *)((uintptr_t)user_parents + 1635*7c478bd9Sstevel@tonic-gate (snap_nlgrpsmax * bitmask_size)); 1636*7c478bd9Sstevel@tonic-gate user_rsets = (ulong_t *)((uintptr_t)user_children + 1637*7c478bd9Sstevel@tonic-gate (snap_nlgrpsmax * bitmask_size)); 1638*7c478bd9Sstevel@tonic-gate user_lats = (int **)((uintptr_t)user_rsets + 1639*7c478bd9Sstevel@tonic-gate (LGRP_RSRC_COUNT * snap_nlgrpsmax * bitmask_size)); 1640*7c478bd9Sstevel@tonic-gate 1641*7c478bd9Sstevel@tonic-gate /* 1642*7c478bd9Sstevel@tonic-gate * Copyout magic number (ie. pointer to beginning of buffer) 1643*7c478bd9Sstevel@tonic-gate */ 1644*7c478bd9Sstevel@tonic-gate if (copyout(&buf, &user_snap->ss_magic, sizeof (buf)) != 0) 1645*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 1646*7c478bd9Sstevel@tonic-gate 1647*7c478bd9Sstevel@tonic-gate /* 1648*7c478bd9Sstevel@tonic-gate * Fix up pointers in user buffer to point into user buffer 1649*7c478bd9Sstevel@tonic-gate * not kernel snapshot 1650*7c478bd9Sstevel@tonic-gate */ 1651*7c478bd9Sstevel@tonic-gate if (copyout(&user_info, &user_snap->ss_info, sizeof (user_info)) != 0) 1652*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 1653*7c478bd9Sstevel@tonic-gate 1654*7c478bd9Sstevel@tonic-gate if (copyout(&user_cpuids, &user_snap->ss_cpuids, 1655*7c478bd9Sstevel@tonic-gate sizeof (user_cpuids)) != 0) 1656*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 1657*7c478bd9Sstevel@tonic-gate 1658*7c478bd9Sstevel@tonic-gate if (copyout(&user_lgrpset, &user_snap->ss_lgrpset, 1659*7c478bd9Sstevel@tonic-gate sizeof (user_lgrpset)) != 0) 1660*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 1661*7c478bd9Sstevel@tonic-gate 1662*7c478bd9Sstevel@tonic-gate if (copyout(&user_parents, &user_snap->ss_parents, 1663*7c478bd9Sstevel@tonic-gate sizeof (user_parents)) != 0) 1664*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 1665*7c478bd9Sstevel@tonic-gate 1666*7c478bd9Sstevel@tonic-gate if (copyout(&user_children, &user_snap->ss_children, 1667*7c478bd9Sstevel@tonic-gate sizeof (user_children)) != 0) 1668*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 1669*7c478bd9Sstevel@tonic-gate 1670*7c478bd9Sstevel@tonic-gate if (copyout(&user_rsets, &user_snap->ss_rsets, 1671*7c478bd9Sstevel@tonic-gate sizeof (user_rsets)) != 0) 1672*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 1673*7c478bd9Sstevel@tonic-gate 1674*7c478bd9Sstevel@tonic-gate if (copyout(&user_lats, &user_snap->ss_latencies, 1675*7c478bd9Sstevel@tonic-gate sizeof (user_lats)) != 0) 1676*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 1677*7c478bd9Sstevel@tonic-gate 1678*7c478bd9Sstevel@tonic-gate /* 1679*7c478bd9Sstevel@tonic-gate * Make copies of lgroup info and latency table, fix up pointers, 1680*7c478bd9Sstevel@tonic-gate * and then copy them into user buffer 1681*7c478bd9Sstevel@tonic-gate */ 1682*7c478bd9Sstevel@tonic-gate user_info_buffer = kmem_zalloc(info_size, KM_NOSLEEP); 1683*7c478bd9Sstevel@tonic-gate if (user_info_buffer == NULL) 1684*7c478bd9Sstevel@tonic-gate return (set_errno(ENOMEM)); 1685*7c478bd9Sstevel@tonic-gate 1686*7c478bd9Sstevel@tonic-gate user_lats_buffer = kmem_zalloc(snap_nlgrpsmax * sizeof (int *), 1687*7c478bd9Sstevel@tonic-gate KM_NOSLEEP); 1688*7c478bd9Sstevel@tonic-gate if (user_lats_buffer == NULL) { 1689*7c478bd9Sstevel@tonic-gate kmem_free(user_info_buffer, info_size); 1690*7c478bd9Sstevel@tonic-gate return (set_errno(ENOMEM)); 1691*7c478bd9Sstevel@tonic-gate } 1692*7c478bd9Sstevel@tonic-gate 1693*7c478bd9Sstevel@tonic-gate lgrp_info = (lgrp_info_t *)((uintptr_t)lgrp_snap + snap_hdr_size); 1694*7c478bd9Sstevel@tonic-gate bcopy(lgrp_info, user_info_buffer, info_size); 1695*7c478bd9Sstevel@tonic-gate 1696*7c478bd9Sstevel@tonic-gate cpu_index = 0; 1697*7c478bd9Sstevel@tonic-gate for (i = 0; i < snap_nlgrpsmax; i++) { 1698*7c478bd9Sstevel@tonic-gate ulong_t *snap_rset; 1699*7c478bd9Sstevel@tonic-gate 1700*7c478bd9Sstevel@tonic-gate /* 1701*7c478bd9Sstevel@tonic-gate * Skip non-existent lgroups 1702*7c478bd9Sstevel@tonic-gate */ 1703*7c478bd9Sstevel@tonic-gate if (user_info_buffer[i].info_lgrpid == LGRP_NONE) 1704*7c478bd9Sstevel@tonic-gate continue; 1705*7c478bd9Sstevel@tonic-gate 1706*7c478bd9Sstevel@tonic-gate /* 1707*7c478bd9Sstevel@tonic-gate * Update free memory size since it changes frequently 1708*7c478bd9Sstevel@tonic-gate * Only do so for lgroups directly containing memory 1709*7c478bd9Sstevel@tonic-gate * 1710*7c478bd9Sstevel@tonic-gate * NOTE: This must be done before changing the pointers to 1711*7c478bd9Sstevel@tonic-gate * point into user space since we need to dereference 1712*7c478bd9Sstevel@tonic-gate * lgroup resource set 1713*7c478bd9Sstevel@tonic-gate */ 1714*7c478bd9Sstevel@tonic-gate snap_rset = &lgrp_info[i].info_rset[LGRP_RSRC_MEM * 1715*7c478bd9Sstevel@tonic-gate BT_BITOUL(snap_nlgrpsmax)]; 1716*7c478bd9Sstevel@tonic-gate if (BT_TEST(snap_rset, i)) 1717*7c478bd9Sstevel@tonic-gate user_info_buffer[i].info_mem_free = 1718*7c478bd9Sstevel@tonic-gate lgrp_mem_size(i, LGRP_MEM_SIZE_FREE); 1719*7c478bd9Sstevel@tonic-gate 1720*7c478bd9Sstevel@tonic-gate /* 1721*7c478bd9Sstevel@tonic-gate * Fix up pointers to parents, children, resources, and 1722*7c478bd9Sstevel@tonic-gate * latencies 1723*7c478bd9Sstevel@tonic-gate */ 1724*7c478bd9Sstevel@tonic-gate user_info_buffer[i].info_parents = 1725*7c478bd9Sstevel@tonic-gate (ulong_t *)((uintptr_t)user_parents + (i * bitmask_size)); 1726*7c478bd9Sstevel@tonic-gate user_info_buffer[i].info_children = 1727*7c478bd9Sstevel@tonic-gate (ulong_t *)((uintptr_t)user_children + (i * bitmask_size)); 1728*7c478bd9Sstevel@tonic-gate user_info_buffer[i].info_rset = 1729*7c478bd9Sstevel@tonic-gate (ulong_t *)((uintptr_t)user_rsets + 1730*7c478bd9Sstevel@tonic-gate (i * LGRP_RSRC_COUNT * bitmask_size)); 1731*7c478bd9Sstevel@tonic-gate user_lats_buffer[i] = (int *)((uintptr_t)user_lats + 1732*7c478bd9Sstevel@tonic-gate (snap_nlgrpsmax * sizeof (int *)) + (i * snap_nlgrpsmax * 1733*7c478bd9Sstevel@tonic-gate sizeof (int))); 1734*7c478bd9Sstevel@tonic-gate 1735*7c478bd9Sstevel@tonic-gate /* 1736*7c478bd9Sstevel@tonic-gate * Fix up pointer to CPU IDs 1737*7c478bd9Sstevel@tonic-gate */ 1738*7c478bd9Sstevel@tonic-gate if (user_info_buffer[i].info_ncpus == 0) { 1739*7c478bd9Sstevel@tonic-gate user_info_buffer[i].info_cpuids = NULL; 1740*7c478bd9Sstevel@tonic-gate continue; 1741*7c478bd9Sstevel@tonic-gate } 1742*7c478bd9Sstevel@tonic-gate user_info_buffer[i].info_cpuids = &user_cpuids[cpu_index]; 1743*7c478bd9Sstevel@tonic-gate cpu_index += user_info_buffer[i].info_ncpus; 1744*7c478bd9Sstevel@tonic-gate } 1745*7c478bd9Sstevel@tonic-gate ASSERT(cpu_index == snap_ncpus); 1746*7c478bd9Sstevel@tonic-gate 1747*7c478bd9Sstevel@tonic-gate /* 1748*7c478bd9Sstevel@tonic-gate * Copy lgroup info and latency table with pointers fixed up to point 1749*7c478bd9Sstevel@tonic-gate * into user buffer out to user buffer now 1750*7c478bd9Sstevel@tonic-gate */ 1751*7c478bd9Sstevel@tonic-gate retval = lgrp_snap->ss_size; 1752*7c478bd9Sstevel@tonic-gate if (copyout(user_info_buffer, user_info, info_size) != 0) 1753*7c478bd9Sstevel@tonic-gate retval = set_errno(EFAULT); 1754*7c478bd9Sstevel@tonic-gate kmem_free(user_info_buffer, info_size); 1755*7c478bd9Sstevel@tonic-gate 1756*7c478bd9Sstevel@tonic-gate if (copyout(user_lats_buffer, user_lats, snap_nlgrpsmax * 1757*7c478bd9Sstevel@tonic-gate sizeof (int *)) != 0) 1758*7c478bd9Sstevel@tonic-gate retval = set_errno(EFAULT); 1759*7c478bd9Sstevel@tonic-gate kmem_free(user_lats_buffer, snap_nlgrpsmax * sizeof (int *)); 1760*7c478bd9Sstevel@tonic-gate 1761*7c478bd9Sstevel@tonic-gate return (retval); 1762*7c478bd9Sstevel@tonic-gate } 1763*7c478bd9Sstevel@tonic-gate 1764*7c478bd9Sstevel@tonic-gate 1765*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 1766*7c478bd9Sstevel@tonic-gate /* 1767*7c478bd9Sstevel@tonic-gate * Make 32-bit copy of snapshot, fix up any pointers in buffer to point 1768*7c478bd9Sstevel@tonic-gate * into user instead of kernel address space, copy 32-bit snapshot into 1769*7c478bd9Sstevel@tonic-gate * given user buffer, and return size of buffer needed to hold snapshot 1770*7c478bd9Sstevel@tonic-gate */ 1771*7c478bd9Sstevel@tonic-gate static int 1772*7c478bd9Sstevel@tonic-gate lgrp_snapshot_copy32(caddr32_t buf, size32_t bufsize) 1773*7c478bd9Sstevel@tonic-gate { 1774*7c478bd9Sstevel@tonic-gate size32_t bitmask_size; 1775*7c478bd9Sstevel@tonic-gate size32_t bitmasks_size; 1776*7c478bd9Sstevel@tonic-gate size32_t children_size; 1777*7c478bd9Sstevel@tonic-gate int cpu_index; 1778*7c478bd9Sstevel@tonic-gate size32_t cpuids_size; 1779*7c478bd9Sstevel@tonic-gate int i; 1780*7c478bd9Sstevel@tonic-gate int j; 1781*7c478bd9Sstevel@tonic-gate size32_t info_size; 1782*7c478bd9Sstevel@tonic-gate size32_t lats_size; 1783*7c478bd9Sstevel@tonic-gate lgrp_info_t *lgrp_info; 1784*7c478bd9Sstevel@tonic-gate lgrp_snapshot_header32_t *lgrp_snap32; 1785*7c478bd9Sstevel@tonic-gate lgrp_info32_t *lgrp_info32; 1786*7c478bd9Sstevel@tonic-gate processorid_t *lgrp_cpuids32; 1787*7c478bd9Sstevel@tonic-gate caddr32_t *lgrp_lats32; 1788*7c478bd9Sstevel@tonic-gate int **lgrp_lats32_kernel; 1789*7c478bd9Sstevel@tonic-gate uint_t *lgrp_set32; 1790*7c478bd9Sstevel@tonic-gate uint_t *lgrp_parents32; 1791*7c478bd9Sstevel@tonic-gate uint_t *lgrp_children32; 1792*7c478bd9Sstevel@tonic-gate uint_t *lgrp_rsets32; 1793*7c478bd9Sstevel@tonic-gate size32_t parents_size; 1794*7c478bd9Sstevel@tonic-gate size32_t rsets_size; 1795*7c478bd9Sstevel@tonic-gate size32_t set_size; 1796*7c478bd9Sstevel@tonic-gate size32_t snap_hdr_size; 1797*7c478bd9Sstevel@tonic-gate int snap_ncpus; 1798*7c478bd9Sstevel@tonic-gate int snap_nlgrpsmax; 1799*7c478bd9Sstevel@tonic-gate size32_t snap_size; 1800*7c478bd9Sstevel@tonic-gate 1801*7c478bd9Sstevel@tonic-gate if (lgrp_snap == NULL) 1802*7c478bd9Sstevel@tonic-gate return (0); 1803*7c478bd9Sstevel@tonic-gate 1804*7c478bd9Sstevel@tonic-gate snap_ncpus = lgrp_snap->ss_ncpus; 1805*7c478bd9Sstevel@tonic-gate snap_nlgrpsmax = lgrp_snap->ss_nlgrps_max; 1806*7c478bd9Sstevel@tonic-gate 1807*7c478bd9Sstevel@tonic-gate /* 1808*7c478bd9Sstevel@tonic-gate * Calculate size of buffer needed for 32-bit snapshot, 1809*7c478bd9Sstevel@tonic-gate * rounding up size of each object to allow for alignment 1810*7c478bd9Sstevel@tonic-gate * of next object in buffer. 1811*7c478bd9Sstevel@tonic-gate */ 1812*7c478bd9Sstevel@tonic-gate snap_hdr_size = P2ROUNDUP(sizeof (lgrp_snapshot_header32_t), 1813*7c478bd9Sstevel@tonic-gate sizeof (caddr32_t)); 1814*7c478bd9Sstevel@tonic-gate info_size = P2ROUNDUP(snap_nlgrpsmax * sizeof (lgrp_info32_t), 1815*7c478bd9Sstevel@tonic-gate sizeof (processorid_t)); 1816*7c478bd9Sstevel@tonic-gate cpuids_size = P2ROUNDUP(snap_ncpus * sizeof (processorid_t), 1817*7c478bd9Sstevel@tonic-gate sizeof (ulong_t)); 1818*7c478bd9Sstevel@tonic-gate 1819*7c478bd9Sstevel@tonic-gate bitmask_size = BT_SIZEOFMAP32(snap_nlgrpsmax); 1820*7c478bd9Sstevel@tonic-gate 1821*7c478bd9Sstevel@tonic-gate set_size = bitmask_size; 1822*7c478bd9Sstevel@tonic-gate parents_size = snap_nlgrpsmax * bitmask_size; 1823*7c478bd9Sstevel@tonic-gate children_size = snap_nlgrpsmax * bitmask_size; 1824*7c478bd9Sstevel@tonic-gate rsets_size = P2ROUNDUP(LGRP_RSRC_COUNT * snap_nlgrpsmax * 1825*7c478bd9Sstevel@tonic-gate (int)bitmask_size, sizeof (caddr32_t)); 1826*7c478bd9Sstevel@tonic-gate 1827*7c478bd9Sstevel@tonic-gate bitmasks_size = set_size + parents_size + children_size + rsets_size; 1828*7c478bd9Sstevel@tonic-gate 1829*7c478bd9Sstevel@tonic-gate /* 1830*7c478bd9Sstevel@tonic-gate * Size of latency table and buffer 1831*7c478bd9Sstevel@tonic-gate */ 1832*7c478bd9Sstevel@tonic-gate lats_size = (snap_nlgrpsmax * sizeof (caddr32_t)) + 1833*7c478bd9Sstevel@tonic-gate (snap_nlgrpsmax * snap_nlgrpsmax * sizeof (int)); 1834*7c478bd9Sstevel@tonic-gate 1835*7c478bd9Sstevel@tonic-gate snap_size = snap_hdr_size + info_size + cpuids_size + bitmasks_size + 1836*7c478bd9Sstevel@tonic-gate lats_size; 1837*7c478bd9Sstevel@tonic-gate 1838*7c478bd9Sstevel@tonic-gate if (buf == NULL || bufsize <= 0) { 1839*7c478bd9Sstevel@tonic-gate return (snap_size); 1840*7c478bd9Sstevel@tonic-gate } 1841*7c478bd9Sstevel@tonic-gate 1842*7c478bd9Sstevel@tonic-gate /* 1843*7c478bd9Sstevel@tonic-gate * User needs to try getting size of buffer again 1844*7c478bd9Sstevel@tonic-gate * because given buffer size is too small. 1845*7c478bd9Sstevel@tonic-gate * The lgroup hierarchy may have changed after they asked for the size 1846*7c478bd9Sstevel@tonic-gate * but before the snapshot was taken. 1847*7c478bd9Sstevel@tonic-gate */ 1848*7c478bd9Sstevel@tonic-gate if (bufsize < snap_size) 1849*7c478bd9Sstevel@tonic-gate return (set_errno(EAGAIN)); 1850*7c478bd9Sstevel@tonic-gate 1851*7c478bd9Sstevel@tonic-gate /* 1852*7c478bd9Sstevel@tonic-gate * Make 32-bit copy of snapshot, fix up pointers to point into user 1853*7c478bd9Sstevel@tonic-gate * buffer not kernel, and then copy whole thing into user buffer 1854*7c478bd9Sstevel@tonic-gate */ 1855*7c478bd9Sstevel@tonic-gate lgrp_snap32 = kmem_zalloc(snap_size, KM_NOSLEEP); 1856*7c478bd9Sstevel@tonic-gate if (lgrp_snap32 == NULL) 1857*7c478bd9Sstevel@tonic-gate return (set_errno(ENOMEM)); 1858*7c478bd9Sstevel@tonic-gate 1859*7c478bd9Sstevel@tonic-gate /* 1860*7c478bd9Sstevel@tonic-gate * Calculate pointers into 32-bit copy of snapshot 1861*7c478bd9Sstevel@tonic-gate * for lgroup info, CPU IDs, pset lgroup bitmask, parents, children, 1862*7c478bd9Sstevel@tonic-gate * resources, and latency table and buffer 1863*7c478bd9Sstevel@tonic-gate */ 1864*7c478bd9Sstevel@tonic-gate lgrp_info32 = (lgrp_info32_t *)((uintptr_t)lgrp_snap32 + 1865*7c478bd9Sstevel@tonic-gate snap_hdr_size); 1866*7c478bd9Sstevel@tonic-gate lgrp_cpuids32 = (processorid_t *)((uintptr_t)lgrp_info32 + info_size); 1867*7c478bd9Sstevel@tonic-gate lgrp_set32 = (uint_t *)((uintptr_t)lgrp_cpuids32 + cpuids_size); 1868*7c478bd9Sstevel@tonic-gate lgrp_parents32 = (uint_t *)((uintptr_t)lgrp_set32 + set_size); 1869*7c478bd9Sstevel@tonic-gate lgrp_children32 = (uint_t *)((uintptr_t)lgrp_parents32 + parents_size); 1870*7c478bd9Sstevel@tonic-gate lgrp_rsets32 = (uint_t *)((uintptr_t)lgrp_children32 + children_size); 1871*7c478bd9Sstevel@tonic-gate lgrp_lats32 = (caddr32_t *)((uintptr_t)lgrp_rsets32 + rsets_size); 1872*7c478bd9Sstevel@tonic-gate 1873*7c478bd9Sstevel@tonic-gate /* 1874*7c478bd9Sstevel@tonic-gate * Make temporary lgroup latency table of pointers for kernel to use 1875*7c478bd9Sstevel@tonic-gate * to fill in rows of table with latencies from each lgroup 1876*7c478bd9Sstevel@tonic-gate */ 1877*7c478bd9Sstevel@tonic-gate lgrp_lats32_kernel = kmem_zalloc(snap_nlgrpsmax * sizeof (int *), 1878*7c478bd9Sstevel@tonic-gate KM_NOSLEEP); 1879*7c478bd9Sstevel@tonic-gate if (lgrp_lats32_kernel == NULL) { 1880*7c478bd9Sstevel@tonic-gate kmem_free(lgrp_snap32, snap_size); 1881*7c478bd9Sstevel@tonic-gate return (set_errno(ENOMEM)); 1882*7c478bd9Sstevel@tonic-gate } 1883*7c478bd9Sstevel@tonic-gate 1884*7c478bd9Sstevel@tonic-gate /* 1885*7c478bd9Sstevel@tonic-gate * Fill in 32-bit lgroup snapshot header 1886*7c478bd9Sstevel@tonic-gate * (with pointers into user's buffer for lgroup info, CPU IDs, 1887*7c478bd9Sstevel@tonic-gate * bit masks, and latencies) 1888*7c478bd9Sstevel@tonic-gate */ 1889*7c478bd9Sstevel@tonic-gate lgrp_snap32->ss_version = lgrp_snap->ss_version; 1890*7c478bd9Sstevel@tonic-gate lgrp_snap32->ss_levels = lgrp_snap->ss_levels; 1891*7c478bd9Sstevel@tonic-gate lgrp_snap32->ss_nlgrps = lgrp_snap32->ss_nlgrps_os = 1892*7c478bd9Sstevel@tonic-gate lgrp_snap->ss_nlgrps; 1893*7c478bd9Sstevel@tonic-gate lgrp_snap32->ss_nlgrps_max = snap_nlgrpsmax; 1894*7c478bd9Sstevel@tonic-gate lgrp_snap32->ss_root = lgrp_snap->ss_root; 1895*7c478bd9Sstevel@tonic-gate lgrp_snap32->ss_ncpus = lgrp_snap->ss_ncpus; 1896*7c478bd9Sstevel@tonic-gate lgrp_snap32->ss_gen = lgrp_snap->ss_gen; 1897*7c478bd9Sstevel@tonic-gate lgrp_snap32->ss_view = LGRP_VIEW_OS; 1898*7c478bd9Sstevel@tonic-gate lgrp_snap32->ss_size = snap_size; 1899*7c478bd9Sstevel@tonic-gate lgrp_snap32->ss_magic = buf; 1900*7c478bd9Sstevel@tonic-gate lgrp_snap32->ss_info = buf + snap_hdr_size; 1901*7c478bd9Sstevel@tonic-gate lgrp_snap32->ss_cpuids = lgrp_snap32->ss_info + info_size; 1902*7c478bd9Sstevel@tonic-gate lgrp_snap32->ss_lgrpset = lgrp_snap32->ss_cpuids + cpuids_size; 1903*7c478bd9Sstevel@tonic-gate lgrp_snap32->ss_parents = lgrp_snap32->ss_lgrpset + bitmask_size; 1904*7c478bd9Sstevel@tonic-gate lgrp_snap32->ss_children = lgrp_snap32->ss_parents + 1905*7c478bd9Sstevel@tonic-gate (snap_nlgrpsmax * bitmask_size); 1906*7c478bd9Sstevel@tonic-gate lgrp_snap32->ss_rsets = lgrp_snap32->ss_children + 1907*7c478bd9Sstevel@tonic-gate (snap_nlgrpsmax * bitmask_size); 1908*7c478bd9Sstevel@tonic-gate lgrp_snap32->ss_latencies = lgrp_snap32->ss_rsets + 1909*7c478bd9Sstevel@tonic-gate (LGRP_RSRC_COUNT * snap_nlgrpsmax * bitmask_size); 1910*7c478bd9Sstevel@tonic-gate 1911*7c478bd9Sstevel@tonic-gate /* 1912*7c478bd9Sstevel@tonic-gate * Fill in lgrpset now because caller may have change psets 1913*7c478bd9Sstevel@tonic-gate */ 1914*7c478bd9Sstevel@tonic-gate kpreempt_disable(); 1915*7c478bd9Sstevel@tonic-gate for (i = 0; i < snap_nlgrpsmax; i++) { 1916*7c478bd9Sstevel@tonic-gate if (klgrpset_ismember(curthread->t_cpupart->cp_lgrpset, 1917*7c478bd9Sstevel@tonic-gate i)) { 1918*7c478bd9Sstevel@tonic-gate BT_SET32(lgrp_set32, i); 1919*7c478bd9Sstevel@tonic-gate } 1920*7c478bd9Sstevel@tonic-gate } 1921*7c478bd9Sstevel@tonic-gate kpreempt_enable(); 1922*7c478bd9Sstevel@tonic-gate 1923*7c478bd9Sstevel@tonic-gate /* 1924*7c478bd9Sstevel@tonic-gate * Fill in 32-bit copy of lgroup info and fix up pointers 1925*7c478bd9Sstevel@tonic-gate * to point into user's buffer instead of kernel's 1926*7c478bd9Sstevel@tonic-gate */ 1927*7c478bd9Sstevel@tonic-gate cpu_index = 0; 1928*7c478bd9Sstevel@tonic-gate lgrp_info = lgrp_snap->ss_info; 1929*7c478bd9Sstevel@tonic-gate for (i = 0; i < snap_nlgrpsmax; i++) { 1930*7c478bd9Sstevel@tonic-gate uint_t *children; 1931*7c478bd9Sstevel@tonic-gate uint_t *lgrp_rset; 1932*7c478bd9Sstevel@tonic-gate uint_t *parents; 1933*7c478bd9Sstevel@tonic-gate ulong_t *snap_rset; 1934*7c478bd9Sstevel@tonic-gate 1935*7c478bd9Sstevel@tonic-gate /* 1936*7c478bd9Sstevel@tonic-gate * Skip non-existent lgroups 1937*7c478bd9Sstevel@tonic-gate */ 1938*7c478bd9Sstevel@tonic-gate if (lgrp_info[i].info_lgrpid == LGRP_NONE) { 1939*7c478bd9Sstevel@tonic-gate bzero(&lgrp_info32[i], sizeof (lgrp_info32[i])); 1940*7c478bd9Sstevel@tonic-gate lgrp_info32[i].info_lgrpid = LGRP_NONE; 1941*7c478bd9Sstevel@tonic-gate continue; 1942*7c478bd9Sstevel@tonic-gate } 1943*7c478bd9Sstevel@tonic-gate 1944*7c478bd9Sstevel@tonic-gate /* 1945*7c478bd9Sstevel@tonic-gate * Fill in parents, children, lgroup resource set, and 1946*7c478bd9Sstevel@tonic-gate * latencies from snapshot 1947*7c478bd9Sstevel@tonic-gate */ 1948*7c478bd9Sstevel@tonic-gate parents = (uint_t *)((uintptr_t)lgrp_parents32 + 1949*7c478bd9Sstevel@tonic-gate i * bitmask_size); 1950*7c478bd9Sstevel@tonic-gate children = (uint_t *)((uintptr_t)lgrp_children32 + 1951*7c478bd9Sstevel@tonic-gate i * bitmask_size); 1952*7c478bd9Sstevel@tonic-gate snap_rset = (ulong_t *)((uintptr_t)lgrp_snap->ss_rsets + 1953*7c478bd9Sstevel@tonic-gate (i * LGRP_RSRC_COUNT * BT_SIZEOFMAP(snap_nlgrpsmax))); 1954*7c478bd9Sstevel@tonic-gate lgrp_rset = (uint_t *)((uintptr_t)lgrp_rsets32 + 1955*7c478bd9Sstevel@tonic-gate (i * LGRP_RSRC_COUNT * bitmask_size)); 1956*7c478bd9Sstevel@tonic-gate lgrp_lats32_kernel[i] = (int *)((uintptr_t)lgrp_lats32 + 1957*7c478bd9Sstevel@tonic-gate snap_nlgrpsmax * sizeof (caddr32_t) + i * snap_nlgrpsmax * 1958*7c478bd9Sstevel@tonic-gate sizeof (int)); 1959*7c478bd9Sstevel@tonic-gate for (j = 0; j < snap_nlgrpsmax; j++) { 1960*7c478bd9Sstevel@tonic-gate int k; 1961*7c478bd9Sstevel@tonic-gate uint_t *rset; 1962*7c478bd9Sstevel@tonic-gate 1963*7c478bd9Sstevel@tonic-gate if (BT_TEST(&lgrp_snap->ss_parents[i], j)) 1964*7c478bd9Sstevel@tonic-gate BT_SET32(parents, j); 1965*7c478bd9Sstevel@tonic-gate 1966*7c478bd9Sstevel@tonic-gate if (BT_TEST(&lgrp_snap->ss_children[i], j)) 1967*7c478bd9Sstevel@tonic-gate BT_SET32(children, j); 1968*7c478bd9Sstevel@tonic-gate 1969*7c478bd9Sstevel@tonic-gate for (k = 0; k < LGRP_RSRC_COUNT; k++) { 1970*7c478bd9Sstevel@tonic-gate rset = (uint_t *)((uintptr_t)lgrp_rset + 1971*7c478bd9Sstevel@tonic-gate k * bitmask_size); 1972*7c478bd9Sstevel@tonic-gate if (BT_TEST(&snap_rset[k], j)) 1973*7c478bd9Sstevel@tonic-gate BT_SET32(rset, j); 1974*7c478bd9Sstevel@tonic-gate } 1975*7c478bd9Sstevel@tonic-gate 1976*7c478bd9Sstevel@tonic-gate lgrp_lats32_kernel[i][j] = 1977*7c478bd9Sstevel@tonic-gate lgrp_snap->ss_latencies[i][j]; 1978*7c478bd9Sstevel@tonic-gate } 1979*7c478bd9Sstevel@tonic-gate 1980*7c478bd9Sstevel@tonic-gate /* 1981*7c478bd9Sstevel@tonic-gate * Fix up pointer to latency buffer 1982*7c478bd9Sstevel@tonic-gate */ 1983*7c478bd9Sstevel@tonic-gate lgrp_lats32[i] = lgrp_snap32->ss_latencies + 1984*7c478bd9Sstevel@tonic-gate snap_nlgrpsmax * sizeof (caddr32_t) + i * snap_nlgrpsmax * 1985*7c478bd9Sstevel@tonic-gate sizeof (int); 1986*7c478bd9Sstevel@tonic-gate 1987*7c478bd9Sstevel@tonic-gate /* 1988*7c478bd9Sstevel@tonic-gate * Fix up pointers for parents, children, and resources 1989*7c478bd9Sstevel@tonic-gate */ 1990*7c478bd9Sstevel@tonic-gate lgrp_info32[i].info_parents = lgrp_snap32->ss_parents + 1991*7c478bd9Sstevel@tonic-gate (i * bitmask_size); 1992*7c478bd9Sstevel@tonic-gate lgrp_info32[i].info_children = lgrp_snap32->ss_children + 1993*7c478bd9Sstevel@tonic-gate (i * bitmask_size); 1994*7c478bd9Sstevel@tonic-gate lgrp_info32[i].info_rset = lgrp_snap32->ss_rsets + 1995*7c478bd9Sstevel@tonic-gate (i * LGRP_RSRC_COUNT * bitmask_size); 1996*7c478bd9Sstevel@tonic-gate 1997*7c478bd9Sstevel@tonic-gate /* 1998*7c478bd9Sstevel@tonic-gate * Fill in memory and CPU info 1999*7c478bd9Sstevel@tonic-gate * Only fill in memory for lgroups directly containing memory 2000*7c478bd9Sstevel@tonic-gate */ 2001*7c478bd9Sstevel@tonic-gate snap_rset = &lgrp_info[i].info_rset[LGRP_RSRC_MEM * 2002*7c478bd9Sstevel@tonic-gate BT_BITOUL(snap_nlgrpsmax)]; 2003*7c478bd9Sstevel@tonic-gate if (BT_TEST(snap_rset, i)) { 2004*7c478bd9Sstevel@tonic-gate lgrp_info32[i].info_mem_free = lgrp_mem_size(i, 2005*7c478bd9Sstevel@tonic-gate LGRP_MEM_SIZE_FREE); 2006*7c478bd9Sstevel@tonic-gate lgrp_info32[i].info_mem_install = 2007*7c478bd9Sstevel@tonic-gate lgrp_info[i].info_mem_install; 2008*7c478bd9Sstevel@tonic-gate } 2009*7c478bd9Sstevel@tonic-gate 2010*7c478bd9Sstevel@tonic-gate lgrp_info32[i].info_ncpus = lgrp_info[i].info_ncpus; 2011*7c478bd9Sstevel@tonic-gate 2012*7c478bd9Sstevel@tonic-gate lgrp_info32[i].info_lgrpid = lgrp_info[i].info_lgrpid; 2013*7c478bd9Sstevel@tonic-gate lgrp_info32[i].info_latency = lgrp_info[i].info_latency; 2014*7c478bd9Sstevel@tonic-gate 2015*7c478bd9Sstevel@tonic-gate if (lgrp_info32[i].info_ncpus == 0) { 2016*7c478bd9Sstevel@tonic-gate lgrp_info32[i].info_cpuids = 0; 2017*7c478bd9Sstevel@tonic-gate continue; 2018*7c478bd9Sstevel@tonic-gate } 2019*7c478bd9Sstevel@tonic-gate 2020*7c478bd9Sstevel@tonic-gate /* 2021*7c478bd9Sstevel@tonic-gate * Fix up pointer for CPU IDs 2022*7c478bd9Sstevel@tonic-gate */ 2023*7c478bd9Sstevel@tonic-gate lgrp_info32[i].info_cpuids = lgrp_snap32->ss_cpuids + 2024*7c478bd9Sstevel@tonic-gate (cpu_index * sizeof (processorid_t)); 2025*7c478bd9Sstevel@tonic-gate cpu_index += lgrp_info32[i].info_ncpus; 2026*7c478bd9Sstevel@tonic-gate } 2027*7c478bd9Sstevel@tonic-gate ASSERT(cpu_index == snap_ncpus); 2028*7c478bd9Sstevel@tonic-gate 2029*7c478bd9Sstevel@tonic-gate /* 2030*7c478bd9Sstevel@tonic-gate * Copy lgroup CPU IDs into 32-bit snapshot 2031*7c478bd9Sstevel@tonic-gate * before copying it out into user's buffer 2032*7c478bd9Sstevel@tonic-gate */ 2033*7c478bd9Sstevel@tonic-gate bcopy(lgrp_snap->ss_cpuids, lgrp_cpuids32, cpuids_size); 2034*7c478bd9Sstevel@tonic-gate 2035*7c478bd9Sstevel@tonic-gate /* 2036*7c478bd9Sstevel@tonic-gate * Copy 32-bit lgroup snapshot into user's buffer all at once 2037*7c478bd9Sstevel@tonic-gate */ 2038*7c478bd9Sstevel@tonic-gate if (copyout(lgrp_snap32, (void *)(uintptr_t)buf, snap_size) != 0) { 2039*7c478bd9Sstevel@tonic-gate kmem_free(lgrp_snap32, snap_size); 2040*7c478bd9Sstevel@tonic-gate kmem_free(lgrp_lats32_kernel, snap_nlgrpsmax * sizeof (int *)); 2041*7c478bd9Sstevel@tonic-gate return (set_errno(EFAULT)); 2042*7c478bd9Sstevel@tonic-gate } 2043*7c478bd9Sstevel@tonic-gate 2044*7c478bd9Sstevel@tonic-gate kmem_free(lgrp_snap32, snap_size); 2045*7c478bd9Sstevel@tonic-gate kmem_free(lgrp_lats32_kernel, snap_nlgrpsmax * sizeof (int *)); 2046*7c478bd9Sstevel@tonic-gate 2047*7c478bd9Sstevel@tonic-gate return (snap_size); 2048*7c478bd9Sstevel@tonic-gate } 2049*7c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 2050*7c478bd9Sstevel@tonic-gate 2051*7c478bd9Sstevel@tonic-gate 2052*7c478bd9Sstevel@tonic-gate int 2053*7c478bd9Sstevel@tonic-gate lgrpsys(int subcode, long ia, void *ap) 2054*7c478bd9Sstevel@tonic-gate { 2055*7c478bd9Sstevel@tonic-gate size_t bufsize; 2056*7c478bd9Sstevel@tonic-gate int latency; 2057*7c478bd9Sstevel@tonic-gate 2058*7c478bd9Sstevel@tonic-gate switch (subcode) { 2059*7c478bd9Sstevel@tonic-gate 2060*7c478bd9Sstevel@tonic-gate case LGRP_SYS_AFFINITY_GET: 2061*7c478bd9Sstevel@tonic-gate return (lgrp_affinity_get((lgrp_affinity_args_t *)ap)); 2062*7c478bd9Sstevel@tonic-gate 2063*7c478bd9Sstevel@tonic-gate case LGRP_SYS_AFFINITY_SET: 2064*7c478bd9Sstevel@tonic-gate return (lgrp_affinity_set((lgrp_affinity_args_t *)ap)); 2065*7c478bd9Sstevel@tonic-gate 2066*7c478bd9Sstevel@tonic-gate case LGRP_SYS_GENERATION: 2067*7c478bd9Sstevel@tonic-gate return (lgrp_generation(ia)); 2068*7c478bd9Sstevel@tonic-gate 2069*7c478bd9Sstevel@tonic-gate case LGRP_SYS_HOME: 2070*7c478bd9Sstevel@tonic-gate return (lgrp_home_get((idtype_t)ia, (id_t)(uintptr_t)ap)); 2071*7c478bd9Sstevel@tonic-gate 2072*7c478bd9Sstevel@tonic-gate case LGRP_SYS_LATENCY: 2073*7c478bd9Sstevel@tonic-gate mutex_enter(&cpu_lock); 2074*7c478bd9Sstevel@tonic-gate latency = lgrp_latency(ia, (lgrp_id_t)(uintptr_t)ap); 2075*7c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock); 2076*7c478bd9Sstevel@tonic-gate return (latency); 2077*7c478bd9Sstevel@tonic-gate 2078*7c478bd9Sstevel@tonic-gate case LGRP_SYS_MEMINFO: 2079*7c478bd9Sstevel@tonic-gate return (meminfo(ia, (struct meminfo *)ap)); 2080*7c478bd9Sstevel@tonic-gate 2081*7c478bd9Sstevel@tonic-gate case LGRP_SYS_VERSION: 2082*7c478bd9Sstevel@tonic-gate return (lgrp_version(ia)); 2083*7c478bd9Sstevel@tonic-gate 2084*7c478bd9Sstevel@tonic-gate case LGRP_SYS_SNAPSHOT: 2085*7c478bd9Sstevel@tonic-gate mutex_enter(&lgrp_snap_lock); 2086*7c478bd9Sstevel@tonic-gate bufsize = lgrp_snapshot(); 2087*7c478bd9Sstevel@tonic-gate if (ap && ia > 0) { 2088*7c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) 2089*7c478bd9Sstevel@tonic-gate bufsize = lgrp_snapshot_copy(ap, ia); 2090*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 2091*7c478bd9Sstevel@tonic-gate else 2092*7c478bd9Sstevel@tonic-gate bufsize = lgrp_snapshot_copy32( 2093*7c478bd9Sstevel@tonic-gate (caddr32_t)(uintptr_t)ap, ia); 2094*7c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 2095*7c478bd9Sstevel@tonic-gate } 2096*7c478bd9Sstevel@tonic-gate mutex_exit(&lgrp_snap_lock); 2097*7c478bd9Sstevel@tonic-gate return (bufsize); 2098*7c478bd9Sstevel@tonic-gate 2099*7c478bd9Sstevel@tonic-gate default: 2100*7c478bd9Sstevel@tonic-gate break; 2101*7c478bd9Sstevel@tonic-gate 2102*7c478bd9Sstevel@tonic-gate } 2103*7c478bd9Sstevel@tonic-gate 2104*7c478bd9Sstevel@tonic-gate return (set_errno(EINVAL)); 2105*7c478bd9Sstevel@tonic-gate } 2106