1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/types.h> 29 #include <sys/param.h> 30 #include <sys/var.h> 31 #include <sys/thread.h> 32 #include <sys/cpuvar.h> 33 #include <sys/kstat.h> 34 #include <sys/uadmin.h> 35 #include <sys/systm.h> 36 #include <sys/errno.h> 37 #include <sys/cmn_err.h> 38 #include <sys/procset.h> 39 #include <sys/processor.h> 40 #include <sys/debug.h> 41 #include <sys/task.h> 42 #include <sys/project.h> 43 #include <sys/zone.h> 44 #include <sys/contract_impl.h> 45 #include <sys/contract/process_impl.h> 46 47 /* 48 * Bind all the threads of a process to a CPU. 49 */ 50 static int 51 cpu_bind_process(proc_t *pp, processorid_t bind, processorid_t *obind, 52 int *error) 53 { 54 kthread_t *tp; 55 kthread_t *fp; 56 int err = 0; 57 int i; 58 59 ASSERT(MUTEX_HELD(&pidlock)); 60 61 /* skip kernel processes */ 62 if (pp->p_flag & SSYS) { 63 *obind = PBIND_NONE; 64 return (0); 65 } 66 67 mutex_enter(&pp->p_lock); 68 tp = pp->p_tlist; 69 if (tp != NULL) { 70 fp = tp; 71 do { 72 i = cpu_bind_thread(tp, bind, obind, error); 73 if (err == 0) 74 err = i; 75 } while ((tp = tp->t_forw) != fp); 76 } 77 78 mutex_exit(&pp->p_lock); 79 return (err); 80 } 81 82 /* 83 * Bind all the processes of a task to a CPU. 84 */ 85 static int 86 cpu_bind_task(task_t *tk, processorid_t bind, processorid_t *obind, 87 int *error) 88 { 89 proc_t *p; 90 int err = 0; 91 int i; 92 93 ASSERT(MUTEX_HELD(&pidlock)); 94 95 if ((p = tk->tk_memb_list) == NULL) 96 return (ESRCH); 97 98 do { 99 i = cpu_bind_process(p, bind, obind, error); 100 if (err == 0) 101 err = i; 102 } while ((p = p->p_tasknext) != tk->tk_memb_list); 103 104 return (err); 105 } 106 107 /* 108 * Bind all the processes in a project to a CPU. 109 */ 110 static int 111 cpu_bind_project(kproject_t *kpj, processorid_t bind, processorid_t *obind, 112 int *error) 113 { 114 proc_t *p; 115 int err = 0; 116 int i; 117 118 ASSERT(MUTEX_HELD(&pidlock)); 119 120 for (p = practive; p != NULL; p = p->p_next) { 121 if (p->p_tlist == NULL) 122 continue; 123 if (p->p_task->tk_proj == kpj) { 124 i = cpu_bind_process(p, bind, obind, error); 125 if (err == 0) 126 err = i; 127 } 128 } 129 return (err); 130 } 131 132 /* 133 * Bind all the processes in a zone to a CPU. 134 */ 135 int 136 cpu_bind_zone(zone_t *zptr, processorid_t bind, processorid_t *obind, 137 int *error) 138 { 139 proc_t *p; 140 int err = 0; 141 int i; 142 143 ASSERT(MUTEX_HELD(&pidlock)); 144 145 for (p = practive; p != NULL; p = p->p_next) { 146 if (p->p_tlist == NULL) 147 continue; 148 if (p->p_zone == zptr) { 149 i = cpu_bind_process(p, bind, obind, error); 150 if (err == 0) 151 err = i; 152 } 153 } 154 return (err); 155 } 156 157 /* 158 * Bind all the processes in a process contract to a CPU. 159 */ 160 int 161 cpu_bind_contract(cont_process_t *ctp, processorid_t bind, processorid_t *obind, 162 int *error) 163 { 164 proc_t *p; 165 int err = 0; 166 int i; 167 168 ASSERT(MUTEX_HELD(&pidlock)); 169 170 for (p = practive; p != NULL; p = p->p_next) { 171 if (p->p_tlist == NULL) 172 continue; 173 if (p->p_ct_process == ctp) { 174 i = cpu_bind_process(p, bind, obind, error); 175 if (err == 0) 176 err = i; 177 } 178 } 179 return (err); 180 } 181 182 /* 183 * processor_bind(2) - Processor binding interfaces. 184 */ 185 int 186 processor_bind(idtype_t idtype, id_t id, processorid_t bind, 187 processorid_t *obindp) 188 { 189 processorid_t obind = PBIND_NONE; 190 int ret = 0; 191 int err = 0; 192 cpu_t *cp; 193 kthread_id_t tp; 194 proc_t *pp; 195 task_t *tk; 196 kproject_t *kpj; 197 zone_t *zptr; 198 contract_t *ct; 199 200 /* 201 * Since we might be making a binding to a processor, hold the 202 * cpu_lock so that the processor cannot be taken offline while 203 * we do this. 204 */ 205 mutex_enter(&cpu_lock); 206 207 /* 208 * Check to be sure binding processor ID is valid. 209 */ 210 switch (bind) { 211 default: 212 if ((cp = cpu_get(bind)) == NULL || 213 (cp->cpu_flags & (CPU_QUIESCED | CPU_OFFLINE))) 214 ret = EINVAL; 215 else if ((cp->cpu_flags & CPU_READY) == 0) 216 ret = EIO; 217 break; 218 219 case PBIND_NONE: 220 case PBIND_QUERY: 221 break; 222 } 223 224 if (ret) { 225 mutex_exit(&cpu_lock); 226 return (set_errno(ret)); 227 } 228 229 switch (idtype) { 230 case P_LWPID: 231 pp = curproc; 232 mutex_enter(&pp->p_lock); 233 if (id == P_MYID) { 234 ret = cpu_bind_thread(curthread, bind, &obind, &err); 235 } else { 236 int found = 0; 237 238 tp = pp->p_tlist; 239 do { 240 if (tp->t_tid == id) { 241 ret = cpu_bind_thread(tp, 242 bind, &obind, &err); 243 found = 1; 244 break; 245 } 246 } while ((tp = tp->t_forw) != pp->p_tlist); 247 if (!found) 248 ret = ESRCH; 249 } 250 mutex_exit(&pp->p_lock); 251 break; 252 253 case P_PID: 254 /* 255 * Note. Cannot use dotoprocs here because it doesn't find 256 * system class processes, which are legal to query. 257 */ 258 mutex_enter(&pidlock); 259 if (id == P_MYID) { 260 ret = cpu_bind_process(curproc, bind, &obind, &err); 261 } else if ((pp = prfind(id)) != NULL) { 262 ret = cpu_bind_process(pp, bind, &obind, &err); 263 } else { 264 ret = ESRCH; 265 } 266 mutex_exit(&pidlock); 267 break; 268 269 case P_TASKID: 270 mutex_enter(&pidlock); 271 if (id == P_MYID) { 272 proc_t *p = curproc; 273 id = p->p_task->tk_tkid; 274 } 275 276 if ((tk = task_hold_by_id(id)) != NULL) { 277 ret = cpu_bind_task(tk, bind, &obind, &err); 278 mutex_exit(&pidlock); 279 task_rele(tk); 280 } else { 281 mutex_exit(&pidlock); 282 ret = ESRCH; 283 } 284 break; 285 286 case P_PROJID: 287 pp = curproc; 288 if (id == P_MYID) 289 id = curprojid(); 290 if ((kpj = project_hold_by_id(id, pp->p_zone, 291 PROJECT_HOLD_FIND)) == NULL) { 292 ret = ESRCH; 293 } else { 294 mutex_enter(&pidlock); 295 ret = cpu_bind_project(kpj, bind, &obind, &err); 296 mutex_exit(&pidlock); 297 project_rele(kpj); 298 } 299 break; 300 301 case P_ZONEID: 302 if (id == P_MYID) 303 id = getzoneid(); 304 305 if ((zptr = zone_find_by_id(id)) == NULL) { 306 ret = ESRCH; 307 } else { 308 mutex_enter(&pidlock); 309 ret = cpu_bind_zone(zptr, bind, &obind, &err); 310 mutex_exit(&pidlock); 311 zone_rele(zptr); 312 } 313 break; 314 315 case P_CTID: 316 if (id == P_MYID) 317 id = PRCTID(curproc); 318 319 if ((ct = contract_type_ptr(process_type, id, 320 curproc->p_zone->zone_uniqid)) == NULL) { 321 ret = ESRCH; 322 } else { 323 mutex_enter(&pidlock); 324 ret = cpu_bind_contract(ct->ct_data, 325 bind, &obind, &err); 326 mutex_exit(&pidlock); 327 contract_rele(ct); 328 } 329 break; 330 331 case P_CPUID: 332 if (id == P_MYID || bind != PBIND_NONE || cpu_get(id) == NULL) 333 ret = EINVAL; 334 else 335 ret = cpu_unbind(id); 336 break; 337 338 case P_ALL: 339 if (id == P_MYID || bind != PBIND_NONE) { 340 ret = EINVAL; 341 } else { 342 int i; 343 cpu_t *cp = cpu_list; 344 do { 345 if ((cp->cpu_flags & CPU_EXISTS) == 0) 346 continue; 347 i = cpu_unbind(cp->cpu_id); 348 if (ret == 0) 349 ret = i; 350 } while ((cp = cp->cpu_next) != cpu_list); 351 } 352 break; 353 354 default: 355 /* 356 * Spec says this is invalid, even though we could 357 * handle other idtypes. 358 */ 359 ret = EINVAL; 360 break; 361 } 362 mutex_exit(&cpu_lock); 363 364 /* 365 * If no search error occurred, see if any permissions errors did. 366 */ 367 if (ret == 0) 368 ret = err; 369 370 if (ret == 0 && obindp != NULL) 371 if (copyout((caddr_t)&obind, (caddr_t)obindp, 372 sizeof (obind)) == -1) 373 ret = EFAULT; 374 return (ret ? set_errno(ret) : 0); /* return success or failure */ 375 } 376