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 2008 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 *error = EPERM; 65 return (0); 66 } 67 68 mutex_enter(&pp->p_lock); 69 tp = pp->p_tlist; 70 if (tp != NULL) { 71 fp = tp; 72 do { 73 i = cpu_bind_thread(tp, bind, obind, error); 74 if (err == 0) 75 err = i; 76 } while ((tp = tp->t_forw) != fp); 77 } 78 79 mutex_exit(&pp->p_lock); 80 return (err); 81 } 82 83 /* 84 * Bind all the processes of a task to a CPU. 85 */ 86 static int 87 cpu_bind_task(task_t *tk, processorid_t bind, processorid_t *obind, 88 int *error) 89 { 90 proc_t *p; 91 int err = 0; 92 int i; 93 94 ASSERT(MUTEX_HELD(&pidlock)); 95 96 if ((p = tk->tk_memb_list) == NULL) 97 return (ESRCH); 98 99 do { 100 i = cpu_bind_process(p, bind, obind, error); 101 if (err == 0) 102 err = i; 103 } while ((p = p->p_tasknext) != tk->tk_memb_list); 104 105 return (err); 106 } 107 108 /* 109 * Bind all the processes in a project to a CPU. 110 */ 111 static int 112 cpu_bind_project(kproject_t *kpj, processorid_t bind, processorid_t *obind, 113 int *error) 114 { 115 proc_t *p; 116 int err = 0; 117 int i; 118 119 ASSERT(MUTEX_HELD(&pidlock)); 120 121 for (p = practive; p != NULL; p = p->p_next) { 122 if (p->p_tlist == NULL) 123 continue; 124 if (p->p_task->tk_proj == kpj) { 125 i = cpu_bind_process(p, bind, obind, error); 126 if (err == 0) 127 err = i; 128 } 129 } 130 return (err); 131 } 132 133 /* 134 * Bind all the processes in a zone to a CPU. 135 */ 136 int 137 cpu_bind_zone(zone_t *zptr, processorid_t bind, processorid_t *obind, 138 int *error) 139 { 140 proc_t *p; 141 int err = 0; 142 int i; 143 144 ASSERT(MUTEX_HELD(&pidlock)); 145 146 for (p = practive; p != NULL; p = p->p_next) { 147 if (p->p_tlist == NULL) 148 continue; 149 if (p->p_zone == zptr) { 150 i = cpu_bind_process(p, bind, obind, error); 151 if (err == 0) 152 err = i; 153 } 154 } 155 return (err); 156 } 157 158 /* 159 * Bind all the processes in a process contract to a CPU. 160 */ 161 int 162 cpu_bind_contract(cont_process_t *ctp, processorid_t bind, processorid_t *obind, 163 int *error) 164 { 165 proc_t *p; 166 int err = 0; 167 int i; 168 169 ASSERT(MUTEX_HELD(&pidlock)); 170 171 for (p = practive; p != NULL; p = p->p_next) { 172 if (p->p_tlist == NULL) 173 continue; 174 if (p->p_ct_process == ctp) { 175 i = cpu_bind_process(p, bind, obind, error); 176 if (err == 0) 177 err = i; 178 } 179 } 180 return (err); 181 } 182 183 /* 184 * processor_bind(2) - Processor binding interfaces. 185 */ 186 int 187 processor_bind(idtype_t idtype, id_t id, processorid_t bind, 188 processorid_t *obindp) 189 { 190 processorid_t obind = PBIND_NONE; 191 int ret = 0; 192 int err = 0; 193 cpu_t *cp; 194 kthread_id_t tp; 195 proc_t *pp; 196 task_t *tk; 197 kproject_t *kpj; 198 zone_t *zptr; 199 contract_t *ct; 200 201 /* 202 * Since we might be making a binding to a processor, hold the 203 * cpu_lock so that the processor cannot be taken offline while 204 * we do this. 205 */ 206 mutex_enter(&cpu_lock); 207 208 /* 209 * Check to be sure binding processor ID is valid. 210 */ 211 switch (bind) { 212 default: 213 if ((cp = cpu_get(bind)) == NULL || 214 (cp->cpu_flags & (CPU_QUIESCED | CPU_OFFLINE))) 215 ret = EINVAL; 216 else if ((cp->cpu_flags & CPU_READY) == 0) 217 ret = EIO; 218 break; 219 220 case PBIND_NONE: 221 case PBIND_QUERY: 222 case PBIND_HARD: 223 case PBIND_SOFT: 224 case PBIND_QUERY_TYPE: 225 break; 226 } 227 228 if (ret) { 229 mutex_exit(&cpu_lock); 230 return (set_errno(ret)); 231 } 232 233 switch (idtype) { 234 case P_LWPID: 235 pp = curproc; 236 mutex_enter(&pp->p_lock); 237 if (id == P_MYID) { 238 ret = cpu_bind_thread(curthread, bind, &obind, &err); 239 } else { 240 int found = 0; 241 242 tp = pp->p_tlist; 243 do { 244 if (tp->t_tid == id) { 245 ret = cpu_bind_thread(tp, 246 bind, &obind, &err); 247 found = 1; 248 break; 249 } 250 } while ((tp = tp->t_forw) != pp->p_tlist); 251 if (!found) 252 ret = ESRCH; 253 } 254 mutex_exit(&pp->p_lock); 255 break; 256 257 case P_PID: 258 /* 259 * Note. Cannot use dotoprocs here because it doesn't find 260 * system class processes, which are legal to query. 261 */ 262 mutex_enter(&pidlock); 263 if (id == P_MYID) { 264 ret = cpu_bind_process(curproc, bind, &obind, &err); 265 } else if ((pp = prfind(id)) != NULL) { 266 ret = cpu_bind_process(pp, bind, &obind, &err); 267 } else { 268 ret = ESRCH; 269 } 270 mutex_exit(&pidlock); 271 break; 272 273 case P_TASKID: 274 mutex_enter(&pidlock); 275 if (id == P_MYID) { 276 proc_t *p = curproc; 277 id = p->p_task->tk_tkid; 278 } 279 280 if ((tk = task_hold_by_id(id)) != NULL) { 281 ret = cpu_bind_task(tk, bind, &obind, &err); 282 mutex_exit(&pidlock); 283 task_rele(tk); 284 } else { 285 mutex_exit(&pidlock); 286 ret = ESRCH; 287 } 288 break; 289 290 case P_PROJID: 291 pp = curproc; 292 if (id == P_MYID) 293 id = curprojid(); 294 if ((kpj = project_hold_by_id(id, pp->p_zone, 295 PROJECT_HOLD_FIND)) == NULL) { 296 ret = ESRCH; 297 } else { 298 mutex_enter(&pidlock); 299 ret = cpu_bind_project(kpj, bind, &obind, &err); 300 mutex_exit(&pidlock); 301 project_rele(kpj); 302 } 303 break; 304 305 case P_ZONEID: 306 if (id == P_MYID) 307 id = getzoneid(); 308 309 if ((zptr = zone_find_by_id(id)) == NULL) { 310 ret = ESRCH; 311 } else { 312 mutex_enter(&pidlock); 313 ret = cpu_bind_zone(zptr, bind, &obind, &err); 314 mutex_exit(&pidlock); 315 zone_rele(zptr); 316 } 317 break; 318 319 case P_CTID: 320 if (id == P_MYID) 321 id = PRCTID(curproc); 322 323 if ((ct = contract_type_ptr(process_type, id, 324 curproc->p_zone->zone_uniqid)) == NULL) { 325 ret = ESRCH; 326 } else { 327 mutex_enter(&pidlock); 328 ret = cpu_bind_contract(ct->ct_data, 329 bind, &obind, &err); 330 mutex_exit(&pidlock); 331 contract_rele(ct); 332 } 333 break; 334 335 case P_CPUID: 336 if (id == P_MYID || bind != PBIND_NONE || cpu_get(id) == NULL) 337 ret = EINVAL; 338 else 339 ret = cpu_unbind(id, B_TRUE); 340 break; 341 342 case P_ALL: 343 if (id == P_MYID || bind != PBIND_NONE) { 344 ret = EINVAL; 345 } else { 346 int i; 347 cpu_t *cp = cpu_list; 348 do { 349 if ((cp->cpu_flags & CPU_EXISTS) == 0) 350 continue; 351 i = cpu_unbind(cp->cpu_id, B_TRUE); 352 if (ret == 0) 353 ret = i; 354 } while ((cp = cp->cpu_next) != cpu_list); 355 } 356 break; 357 358 default: 359 /* 360 * Spec says this is invalid, even though we could 361 * handle other idtypes. 362 */ 363 ret = EINVAL; 364 break; 365 } 366 mutex_exit(&cpu_lock); 367 368 /* 369 * If no search error occurred, see if any permissions errors did. 370 */ 371 if (ret == 0) 372 ret = err; 373 374 if (ret == 0 && obindp != NULL) 375 if (copyout((caddr_t)&obind, (caddr_t)obindp, 376 sizeof (obind)) == -1) 377 ret = EFAULT; 378 return (ret ? set_errno(ret) : 0); /* return success or failure */ 379 } 380