1 /*- 2 * Implementation of SVID semaphores 3 * 4 * Author: Daniel Boulet 5 * 6 * This software is provided ``AS IS'' without any warranties of any kind. 7 */ 8 /*- 9 * Copyright (c) 2003-2005 McAfee, Inc. 10 * All rights reserved. 11 * 12 * This software was developed for the FreeBSD Project in part by McAfee 13 * Research, the Security Research Division of McAfee, Inc under DARPA/SPAWAR 14 * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS research 15 * program. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions 19 * are met: 20 * 1. Redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer. 22 * 2. Redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 __FBSDID("$FreeBSD$"); 41 42 #include "opt_sysvipc.h" 43 #include "opt_mac.h" 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/sysproto.h> 48 #include <sys/eventhandler.h> 49 #include <sys/kernel.h> 50 #include <sys/proc.h> 51 #include <sys/lock.h> 52 #include <sys/module.h> 53 #include <sys/mutex.h> 54 #include <sys/sem.h> 55 #include <sys/syscall.h> 56 #include <sys/syscallsubr.h> 57 #include <sys/sysent.h> 58 #include <sys/sysctl.h> 59 #include <sys/uio.h> 60 #include <sys/malloc.h> 61 #include <sys/jail.h> 62 #include <sys/mac.h> 63 64 static MALLOC_DEFINE(M_SEM, "sem", "SVID compatible semaphores"); 65 66 #ifdef SEM_DEBUG 67 #define DPRINTF(a) printf a 68 #else 69 #define DPRINTF(a) 70 #endif 71 #ifdef MAC_DEBUG 72 #define MPRINTF(a) printf a 73 #else 74 #define MPRINTF(a) 75 #endif 76 77 static void seminit(void); 78 static int sysvsem_modload(struct module *, int, void *); 79 static int semunload(void); 80 static void semexit_myhook(void *arg, struct proc *p); 81 static int sysctl_sema(SYSCTL_HANDLER_ARGS); 82 static int semvalid(int semid, struct semid_kernel *semakptr); 83 84 #ifndef _SYS_SYSPROTO_H_ 85 struct __semctl_args; 86 int __semctl(struct thread *td, struct __semctl_args *uap); 87 struct semget_args; 88 int semget(struct thread *td, struct semget_args *uap); 89 struct semop_args; 90 int semop(struct thread *td, struct semop_args *uap); 91 #endif 92 93 static struct sem_undo *semu_alloc(struct thread *td); 94 static int semundo_adjust(struct thread *td, struct sem_undo **supptr, 95 int semid, int semnum, int adjval); 96 static void semundo_clear(int semid, int semnum); 97 98 /* XXX casting to (sy_call_t *) is bogus, as usual. */ 99 static sy_call_t *semcalls[] = { 100 (sy_call_t *)__semctl, (sy_call_t *)semget, 101 (sy_call_t *)semop 102 }; 103 104 static struct mtx sem_mtx; /* semaphore global lock */ 105 static int semtot = 0; 106 static struct semid_kernel *sema; /* semaphore id pool */ 107 static struct mtx *sema_mtx; /* semaphore id pool mutexes*/ 108 static struct sem *sem; /* semaphore pool */ 109 SLIST_HEAD(, sem_undo) semu_list; /* list of active undo structures */ 110 static int *semu; /* undo structure pool */ 111 static eventhandler_tag semexit_tag; 112 113 #define SEMUNDO_MTX sem_mtx 114 #define SEMUNDO_LOCK() mtx_lock(&SEMUNDO_MTX); 115 #define SEMUNDO_UNLOCK() mtx_unlock(&SEMUNDO_MTX); 116 #define SEMUNDO_LOCKASSERT(how) mtx_assert(&SEMUNDO_MTX, (how)); 117 118 struct sem { 119 u_short semval; /* semaphore value */ 120 pid_t sempid; /* pid of last operation */ 121 u_short semncnt; /* # awaiting semval > cval */ 122 u_short semzcnt; /* # awaiting semval = 0 */ 123 }; 124 125 /* 126 * Undo structure (one per process) 127 */ 128 struct sem_undo { 129 SLIST_ENTRY(sem_undo) un_next; /* ptr to next active undo structure */ 130 struct proc *un_proc; /* owner of this structure */ 131 short un_cnt; /* # of active entries */ 132 struct undo { 133 short un_adjval; /* adjust on exit values */ 134 short un_num; /* semaphore # */ 135 int un_id; /* semid */ 136 } un_ent[1]; /* undo entries */ 137 }; 138 139 /* 140 * Configuration parameters 141 */ 142 #ifndef SEMMNI 143 #define SEMMNI 10 /* # of semaphore identifiers */ 144 #endif 145 #ifndef SEMMNS 146 #define SEMMNS 60 /* # of semaphores in system */ 147 #endif 148 #ifndef SEMUME 149 #define SEMUME 10 /* max # of undo entries per process */ 150 #endif 151 #ifndef SEMMNU 152 #define SEMMNU 30 /* # of undo structures in system */ 153 #endif 154 155 /* shouldn't need tuning */ 156 #ifndef SEMMAP 157 #define SEMMAP 30 /* # of entries in semaphore map */ 158 #endif 159 #ifndef SEMMSL 160 #define SEMMSL SEMMNS /* max # of semaphores per id */ 161 #endif 162 #ifndef SEMOPM 163 #define SEMOPM 100 /* max # of operations per semop call */ 164 #endif 165 166 #define SEMVMX 32767 /* semaphore maximum value */ 167 #define SEMAEM 16384 /* adjust on exit max value */ 168 169 /* 170 * Due to the way semaphore memory is allocated, we have to ensure that 171 * SEMUSZ is properly aligned. 172 */ 173 174 #define SEM_ALIGN(bytes) (((bytes) + (sizeof(long) - 1)) & ~(sizeof(long) - 1)) 175 176 /* actual size of an undo structure */ 177 #define SEMUSZ SEM_ALIGN(offsetof(struct sem_undo, un_ent[SEMUME])) 178 179 /* 180 * Macro to find a particular sem_undo vector 181 */ 182 #define SEMU(ix) \ 183 ((struct sem_undo *)(((intptr_t)semu)+ix * seminfo.semusz)) 184 185 /* 186 * semaphore info struct 187 */ 188 struct seminfo seminfo = { 189 SEMMAP, /* # of entries in semaphore map */ 190 SEMMNI, /* # of semaphore identifiers */ 191 SEMMNS, /* # of semaphores in system */ 192 SEMMNU, /* # of undo structures in system */ 193 SEMMSL, /* max # of semaphores per id */ 194 SEMOPM, /* max # of operations per semop call */ 195 SEMUME, /* max # of undo entries per process */ 196 SEMUSZ, /* size in bytes of undo structure */ 197 SEMVMX, /* semaphore maximum value */ 198 SEMAEM /* adjust on exit max value */ 199 }; 200 201 SYSCTL_INT(_kern_ipc, OID_AUTO, semmap, CTLFLAG_RW, &seminfo.semmap, 0, 202 "Number of entries in the semaphore map"); 203 SYSCTL_INT(_kern_ipc, OID_AUTO, semmni, CTLFLAG_RDTUN, &seminfo.semmni, 0, 204 "Number of semaphore identifiers"); 205 SYSCTL_INT(_kern_ipc, OID_AUTO, semmns, CTLFLAG_RDTUN, &seminfo.semmns, 0, 206 "Maximum number of semaphores in the system"); 207 SYSCTL_INT(_kern_ipc, OID_AUTO, semmnu, CTLFLAG_RDTUN, &seminfo.semmnu, 0, 208 "Maximum number of undo structures in the system"); 209 SYSCTL_INT(_kern_ipc, OID_AUTO, semmsl, CTLFLAG_RW, &seminfo.semmsl, 0, 210 "Max semaphores per id"); 211 SYSCTL_INT(_kern_ipc, OID_AUTO, semopm, CTLFLAG_RDTUN, &seminfo.semopm, 0, 212 "Max operations per semop call"); 213 SYSCTL_INT(_kern_ipc, OID_AUTO, semume, CTLFLAG_RDTUN, &seminfo.semume, 0, 214 "Max undo entries per process"); 215 SYSCTL_INT(_kern_ipc, OID_AUTO, semusz, CTLFLAG_RDTUN, &seminfo.semusz, 0, 216 "Size in bytes of undo structure"); 217 SYSCTL_INT(_kern_ipc, OID_AUTO, semvmx, CTLFLAG_RW, &seminfo.semvmx, 0, 218 "Semaphore maximum value"); 219 SYSCTL_INT(_kern_ipc, OID_AUTO, semaem, CTLFLAG_RW, &seminfo.semaem, 0, 220 "Adjust on exit max value"); 221 SYSCTL_PROC(_kern_ipc, OID_AUTO, sema, CTLFLAG_RD, 222 NULL, 0, sysctl_sema, "", ""); 223 224 static void 225 seminit(void) 226 { 227 int i; 228 229 TUNABLE_INT_FETCH("kern.ipc.semmap", &seminfo.semmap); 230 TUNABLE_INT_FETCH("kern.ipc.semmni", &seminfo.semmni); 231 TUNABLE_INT_FETCH("kern.ipc.semmns", &seminfo.semmns); 232 TUNABLE_INT_FETCH("kern.ipc.semmnu", &seminfo.semmnu); 233 TUNABLE_INT_FETCH("kern.ipc.semmsl", &seminfo.semmsl); 234 TUNABLE_INT_FETCH("kern.ipc.semopm", &seminfo.semopm); 235 TUNABLE_INT_FETCH("kern.ipc.semume", &seminfo.semume); 236 TUNABLE_INT_FETCH("kern.ipc.semusz", &seminfo.semusz); 237 TUNABLE_INT_FETCH("kern.ipc.semvmx", &seminfo.semvmx); 238 TUNABLE_INT_FETCH("kern.ipc.semaem", &seminfo.semaem); 239 240 sem = malloc(sizeof(struct sem) * seminfo.semmns, M_SEM, M_WAITOK); 241 sema = malloc(sizeof(struct semid_kernel) * seminfo.semmni, M_SEM, 242 M_WAITOK); 243 sema_mtx = malloc(sizeof(struct mtx) * seminfo.semmni, M_SEM, 244 M_WAITOK | M_ZERO); 245 semu = malloc(seminfo.semmnu * seminfo.semusz, M_SEM, M_WAITOK); 246 247 for (i = 0; i < seminfo.semmni; i++) { 248 sema[i].u.sem_base = 0; 249 sema[i].u.sem_perm.mode = 0; 250 sema[i].u.sem_perm.seq = 0; 251 #ifdef MAC 252 mac_init_sysv_sem(&sema[i]); 253 #endif 254 } 255 for (i = 0; i < seminfo.semmni; i++) 256 mtx_init(&sema_mtx[i], "semid", NULL, MTX_DEF); 257 for (i = 0; i < seminfo.semmnu; i++) { 258 struct sem_undo *suptr = SEMU(i); 259 suptr->un_proc = NULL; 260 } 261 SLIST_INIT(&semu_list); 262 mtx_init(&sem_mtx, "sem", NULL, MTX_DEF); 263 semexit_tag = EVENTHANDLER_REGISTER(process_exit, semexit_myhook, NULL, 264 EVENTHANDLER_PRI_ANY); 265 } 266 267 static int 268 semunload(void) 269 { 270 int i; 271 272 if (semtot != 0) 273 return (EBUSY); 274 275 EVENTHANDLER_DEREGISTER(process_exit, semexit_tag); 276 #ifdef MAC 277 for (i = 0; i < seminfo.semmni; i++) 278 mac_destroy_sysv_sem(&sema[i]); 279 #endif 280 free(sem, M_SEM); 281 free(sema, M_SEM); 282 free(semu, M_SEM); 283 for (i = 0; i < seminfo.semmni; i++) 284 mtx_destroy(&sema_mtx[i]); 285 mtx_destroy(&sem_mtx); 286 return (0); 287 } 288 289 static int 290 sysvsem_modload(struct module *module, int cmd, void *arg) 291 { 292 int error = 0; 293 294 switch (cmd) { 295 case MOD_LOAD: 296 seminit(); 297 break; 298 case MOD_UNLOAD: 299 error = semunload(); 300 break; 301 case MOD_SHUTDOWN: 302 break; 303 default: 304 error = EINVAL; 305 break; 306 } 307 return (error); 308 } 309 310 static moduledata_t sysvsem_mod = { 311 "sysvsem", 312 &sysvsem_modload, 313 NULL 314 }; 315 316 SYSCALL_MODULE_HELPER(semsys); 317 SYSCALL_MODULE_HELPER(__semctl); 318 SYSCALL_MODULE_HELPER(semget); 319 SYSCALL_MODULE_HELPER(semop); 320 321 DECLARE_MODULE(sysvsem, sysvsem_mod, 322 SI_SUB_SYSV_SEM, SI_ORDER_FIRST); 323 MODULE_VERSION(sysvsem, 1); 324 325 /* 326 * Entry point for all SEM calls 327 * 328 * MPSAFE 329 */ 330 int 331 semsys(td, uap) 332 struct thread *td; 333 /* XXX actually varargs. */ 334 struct semsys_args /* { 335 int which; 336 int a2; 337 int a3; 338 int a4; 339 int a5; 340 } */ *uap; 341 { 342 int error; 343 344 if (!jail_sysvipc_allowed && jailed(td->td_ucred)) 345 return (ENOSYS); 346 if (uap->which < 0 || 347 uap->which >= sizeof(semcalls)/sizeof(semcalls[0])) 348 return (EINVAL); 349 error = (*semcalls[uap->which])(td, &uap->a2); 350 return (error); 351 } 352 353 /* 354 * Allocate a new sem_undo structure for a process 355 * (returns ptr to structure or NULL if no more room) 356 */ 357 358 static struct sem_undo * 359 semu_alloc(td) 360 struct thread *td; 361 { 362 int i; 363 struct sem_undo *suptr; 364 struct sem_undo **supptr; 365 int attempt; 366 367 SEMUNDO_LOCKASSERT(MA_OWNED); 368 /* 369 * Try twice to allocate something. 370 * (we'll purge an empty structure after the first pass so 371 * two passes are always enough) 372 */ 373 374 for (attempt = 0; attempt < 2; attempt++) { 375 /* 376 * Look for a free structure. 377 * Fill it in and return it if we find one. 378 */ 379 380 for (i = 0; i < seminfo.semmnu; i++) { 381 suptr = SEMU(i); 382 if (suptr->un_proc == NULL) { 383 SLIST_INSERT_HEAD(&semu_list, suptr, un_next); 384 suptr->un_cnt = 0; 385 suptr->un_proc = td->td_proc; 386 return(suptr); 387 } 388 } 389 390 /* 391 * We didn't find a free one, if this is the first attempt 392 * then try to free a structure. 393 */ 394 395 if (attempt == 0) { 396 /* All the structures are in use - try to free one */ 397 int did_something = 0; 398 399 SLIST_FOREACH_PREVPTR(suptr, supptr, &semu_list, 400 un_next) { 401 if (suptr->un_cnt == 0) { 402 suptr->un_proc = NULL; 403 did_something = 1; 404 *supptr = SLIST_NEXT(suptr, un_next); 405 break; 406 } 407 } 408 409 /* If we didn't free anything then just give-up */ 410 if (!did_something) 411 return(NULL); 412 } else { 413 /* 414 * The second pass failed even though we freed 415 * something after the first pass! 416 * This is IMPOSSIBLE! 417 */ 418 panic("semu_alloc - second attempt failed"); 419 } 420 } 421 return (NULL); 422 } 423 424 /* 425 * Adjust a particular entry for a particular proc 426 */ 427 428 static int 429 semundo_adjust(td, supptr, semid, semnum, adjval) 430 struct thread *td; 431 struct sem_undo **supptr; 432 int semid, semnum; 433 int adjval; 434 { 435 struct proc *p = td->td_proc; 436 struct sem_undo *suptr; 437 struct undo *sunptr; 438 int i; 439 440 SEMUNDO_LOCKASSERT(MA_OWNED); 441 /* Look for and remember the sem_undo if the caller doesn't provide 442 it */ 443 444 suptr = *supptr; 445 if (suptr == NULL) { 446 SLIST_FOREACH(suptr, &semu_list, un_next) { 447 if (suptr->un_proc == p) { 448 *supptr = suptr; 449 break; 450 } 451 } 452 if (suptr == NULL) { 453 if (adjval == 0) 454 return(0); 455 suptr = semu_alloc(td); 456 if (suptr == NULL) 457 return(ENOSPC); 458 *supptr = suptr; 459 } 460 } 461 462 /* 463 * Look for the requested entry and adjust it (delete if adjval becomes 464 * 0). 465 */ 466 sunptr = &suptr->un_ent[0]; 467 for (i = 0; i < suptr->un_cnt; i++, sunptr++) { 468 if (sunptr->un_id != semid || sunptr->un_num != semnum) 469 continue; 470 if (adjval != 0) { 471 adjval += sunptr->un_adjval; 472 if (adjval > seminfo.semaem || adjval < -seminfo.semaem) 473 return (ERANGE); 474 } 475 sunptr->un_adjval = adjval; 476 if (sunptr->un_adjval == 0) { 477 suptr->un_cnt--; 478 if (i < suptr->un_cnt) 479 suptr->un_ent[i] = 480 suptr->un_ent[suptr->un_cnt]; 481 } 482 return(0); 483 } 484 485 /* Didn't find the right entry - create it */ 486 if (adjval == 0) 487 return(0); 488 if (adjval > seminfo.semaem || adjval < -seminfo.semaem) 489 return (ERANGE); 490 if (suptr->un_cnt != seminfo.semume) { 491 sunptr = &suptr->un_ent[suptr->un_cnt]; 492 suptr->un_cnt++; 493 sunptr->un_adjval = adjval; 494 sunptr->un_id = semid; sunptr->un_num = semnum; 495 } else 496 return(EINVAL); 497 return(0); 498 } 499 500 static void 501 semundo_clear(semid, semnum) 502 int semid, semnum; 503 { 504 struct sem_undo *suptr; 505 506 SEMUNDO_LOCKASSERT(MA_OWNED); 507 SLIST_FOREACH(suptr, &semu_list, un_next) { 508 struct undo *sunptr = &suptr->un_ent[0]; 509 int i = 0; 510 511 while (i < suptr->un_cnt) { 512 if (sunptr->un_id == semid) { 513 if (semnum == -1 || sunptr->un_num == semnum) { 514 suptr->un_cnt--; 515 if (i < suptr->un_cnt) { 516 suptr->un_ent[i] = 517 suptr->un_ent[suptr->un_cnt]; 518 continue; 519 } 520 } 521 if (semnum != -1) 522 break; 523 } 524 i++, sunptr++; 525 } 526 } 527 } 528 529 static int 530 semvalid(semid, semakptr) 531 int semid; 532 struct semid_kernel *semakptr; 533 { 534 535 return ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 536 semakptr->u.sem_perm.seq != IPCID_TO_SEQ(semid) ? EINVAL : 0); 537 } 538 539 /* 540 * Note that the user-mode half of this passes a union, not a pointer 541 */ 542 #ifndef _SYS_SYSPROTO_H_ 543 struct __semctl_args { 544 int semid; 545 int semnum; 546 int cmd; 547 union semun *arg; 548 }; 549 #endif 550 551 /* 552 * MPSAFE 553 */ 554 int 555 __semctl(td, uap) 556 struct thread *td; 557 struct __semctl_args *uap; 558 { 559 struct semid_ds dsbuf; 560 union semun arg, semun; 561 register_t rval; 562 int error; 563 564 switch (uap->cmd) { 565 case SEM_STAT: 566 case IPC_SET: 567 case IPC_STAT: 568 case GETALL: 569 case SETVAL: 570 case SETALL: 571 error = copyin(uap->arg, &arg, sizeof(arg)); 572 if (error) 573 return (error); 574 break; 575 } 576 577 switch (uap->cmd) { 578 case SEM_STAT: 579 case IPC_STAT: 580 semun.buf = &dsbuf; 581 break; 582 case IPC_SET: 583 error = copyin(arg.buf, &dsbuf, sizeof(dsbuf)); 584 if (error) 585 return (error); 586 semun.buf = &dsbuf; 587 break; 588 case GETALL: 589 case SETALL: 590 semun.array = arg.array; 591 break; 592 case SETVAL: 593 semun.val = arg.val; 594 break; 595 } 596 597 error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 598 &rval); 599 if (error) 600 return (error); 601 602 switch (uap->cmd) { 603 case SEM_STAT: 604 case IPC_STAT: 605 error = copyout(&dsbuf, arg.buf, sizeof(dsbuf)); 606 break; 607 } 608 609 if (error == 0) 610 td->td_retval[0] = rval; 611 return (error); 612 } 613 614 int 615 kern_semctl(struct thread *td, int semid, int semnum, int cmd, 616 union semun *arg, register_t *rval) 617 { 618 u_short *array; 619 struct ucred *cred = td->td_ucred; 620 int i, error; 621 struct semid_ds *sbuf; 622 struct semid_kernel *semakptr; 623 struct mtx *sema_mtxp; 624 u_short usval, count; 625 int semidx; 626 627 DPRINTF(("call to semctl(%d, %d, %d, 0x%p)\n", 628 semid, semnum, cmd, arg)); 629 if (!jail_sysvipc_allowed && jailed(td->td_ucred)) 630 return (ENOSYS); 631 632 array = NULL; 633 634 switch(cmd) { 635 case SEM_STAT: 636 /* 637 * For this command we assume semid is an array index 638 * rather than an IPC id. 639 */ 640 if (semid < 0 || semid >= seminfo.semmni) 641 return (EINVAL); 642 semakptr = &sema[semid]; 643 sema_mtxp = &sema_mtx[semid]; 644 mtx_lock(sema_mtxp); 645 if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) { 646 error = EINVAL; 647 goto done2; 648 } 649 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 650 goto done2; 651 #ifdef MAC 652 error = mac_check_sysv_semctl(cred, semakptr, cmd); 653 if (error != 0) { 654 MPRINTF(("mac_check_sysv_semctl returned %d\n", 655 error)); 656 goto done2; 657 } 658 #endif 659 bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds)); 660 *rval = IXSEQ_TO_IPCID(semid, semakptr->u.sem_perm); 661 mtx_unlock(sema_mtxp); 662 return (0); 663 } 664 665 semidx = IPCID_TO_IX(semid); 666 if (semidx < 0 || semidx >= seminfo.semmni) 667 return (EINVAL); 668 669 semakptr = &sema[semidx]; 670 sema_mtxp = &sema_mtx[semidx]; 671 mtx_lock(sema_mtxp); 672 #ifdef MAC 673 error = mac_check_sysv_semctl(cred, semakptr, cmd); 674 if (error != 0) { 675 MPRINTF(("mac_check_sysv_semctl returned %d\n", error)); 676 goto done2; 677 } 678 #endif 679 680 error = 0; 681 *rval = 0; 682 683 switch (cmd) { 684 case IPC_RMID: 685 if ((error = semvalid(semid, semakptr)) != 0) 686 goto done2; 687 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M))) 688 goto done2; 689 semakptr->u.sem_perm.cuid = cred->cr_uid; 690 semakptr->u.sem_perm.uid = cred->cr_uid; 691 semtot -= semakptr->u.sem_nsems; 692 for (i = semakptr->u.sem_base - sem; i < semtot; i++) 693 sem[i] = sem[i + semakptr->u.sem_nsems]; 694 for (i = 0; i < seminfo.semmni; i++) { 695 if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && 696 sema[i].u.sem_base > semakptr->u.sem_base) 697 sema[i].u.sem_base -= semakptr->u.sem_nsems; 698 } 699 semakptr->u.sem_perm.mode = 0; 700 #ifdef MAC 701 mac_cleanup_sysv_sem(semakptr); 702 #endif 703 SEMUNDO_LOCK(); 704 semundo_clear(semidx, -1); 705 SEMUNDO_UNLOCK(); 706 wakeup(semakptr); 707 break; 708 709 case IPC_SET: 710 if ((error = semvalid(semid, semakptr)) != 0) 711 goto done2; 712 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M))) 713 goto done2; 714 sbuf = arg->buf; 715 semakptr->u.sem_perm.uid = sbuf->sem_perm.uid; 716 semakptr->u.sem_perm.gid = sbuf->sem_perm.gid; 717 semakptr->u.sem_perm.mode = (semakptr->u.sem_perm.mode & 718 ~0777) | (sbuf->sem_perm.mode & 0777); 719 semakptr->u.sem_ctime = time_second; 720 break; 721 722 case IPC_STAT: 723 if ((error = semvalid(semid, semakptr)) != 0) 724 goto done2; 725 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 726 goto done2; 727 bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds)); 728 break; 729 730 case GETNCNT: 731 if ((error = semvalid(semid, semakptr)) != 0) 732 goto done2; 733 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 734 goto done2; 735 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 736 error = EINVAL; 737 goto done2; 738 } 739 *rval = semakptr->u.sem_base[semnum].semncnt; 740 break; 741 742 case GETPID: 743 if ((error = semvalid(semid, semakptr)) != 0) 744 goto done2; 745 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 746 goto done2; 747 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 748 error = EINVAL; 749 goto done2; 750 } 751 *rval = semakptr->u.sem_base[semnum].sempid; 752 break; 753 754 case GETVAL: 755 if ((error = semvalid(semid, semakptr)) != 0) 756 goto done2; 757 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 758 goto done2; 759 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 760 error = EINVAL; 761 goto done2; 762 } 763 *rval = semakptr->u.sem_base[semnum].semval; 764 break; 765 766 case GETALL: 767 /* 768 * Unfortunately, callers of this function don't know 769 * in advance how many semaphores are in this set. 770 * While we could just allocate the maximum size array 771 * and pass the actual size back to the caller, that 772 * won't work for SETALL since we can't copyin() more 773 * data than the user specified as we may return a 774 * spurious EFAULT. 775 * 776 * Note that the number of semaphores in a set is 777 * fixed for the life of that set. The only way that 778 * the 'count' could change while are blocked in 779 * malloc() is if this semaphore set were destroyed 780 * and a new one created with the same index. 781 * However, semvalid() will catch that due to the 782 * sequence number unless exactly 0x8000 (or a 783 * multiple thereof) semaphore sets for the same index 784 * are created and destroyed while we are in malloc! 785 * 786 */ 787 count = semakptr->u.sem_nsems; 788 mtx_unlock(sema_mtxp); 789 array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK); 790 mtx_lock(sema_mtxp); 791 if ((error = semvalid(semid, semakptr)) != 0) 792 goto done2; 793 KASSERT(count == semakptr->u.sem_nsems, ("nsems changed")); 794 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 795 goto done2; 796 for (i = 0; i < semakptr->u.sem_nsems; i++) 797 array[i] = semakptr->u.sem_base[i].semval; 798 mtx_unlock(sema_mtxp); 799 error = copyout(array, arg->array, count * sizeof(*array)); 800 mtx_lock(sema_mtxp); 801 break; 802 803 case GETZCNT: 804 if ((error = semvalid(semid, semakptr)) != 0) 805 goto done2; 806 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 807 goto done2; 808 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 809 error = EINVAL; 810 goto done2; 811 } 812 *rval = semakptr->u.sem_base[semnum].semzcnt; 813 break; 814 815 case SETVAL: 816 if ((error = semvalid(semid, semakptr)) != 0) 817 goto done2; 818 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W))) 819 goto done2; 820 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 821 error = EINVAL; 822 goto done2; 823 } 824 if (arg->val < 0 || arg->val > seminfo.semvmx) { 825 error = ERANGE; 826 goto done2; 827 } 828 semakptr->u.sem_base[semnum].semval = arg->val; 829 SEMUNDO_LOCK(); 830 semundo_clear(semidx, semnum); 831 SEMUNDO_UNLOCK(); 832 wakeup(semakptr); 833 break; 834 835 case SETALL: 836 /* 837 * See comment on GETALL for why 'count' shouldn't change 838 * and why we require a userland buffer. 839 */ 840 count = semakptr->u.sem_nsems; 841 mtx_unlock(sema_mtxp); 842 array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK); 843 error = copyin(arg->array, array, count * sizeof(*array)); 844 if (error) 845 break; 846 mtx_lock(sema_mtxp); 847 if ((error = semvalid(semid, semakptr)) != 0) 848 goto done2; 849 KASSERT(count == semakptr->u.sem_nsems, ("nsems changed")); 850 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W))) 851 goto done2; 852 for (i = 0; i < semakptr->u.sem_nsems; i++) { 853 usval = array[i]; 854 if (usval > seminfo.semvmx) { 855 error = ERANGE; 856 break; 857 } 858 semakptr->u.sem_base[i].semval = usval; 859 } 860 SEMUNDO_LOCK(); 861 semundo_clear(semidx, -1); 862 SEMUNDO_UNLOCK(); 863 wakeup(semakptr); 864 break; 865 866 default: 867 error = EINVAL; 868 break; 869 } 870 871 done2: 872 mtx_unlock(sema_mtxp); 873 if (array != NULL) 874 free(array, M_TEMP); 875 return(error); 876 } 877 878 #ifndef _SYS_SYSPROTO_H_ 879 struct semget_args { 880 key_t key; 881 int nsems; 882 int semflg; 883 }; 884 #endif 885 886 /* 887 * MPSAFE 888 */ 889 int 890 semget(td, uap) 891 struct thread *td; 892 struct semget_args *uap; 893 { 894 int semid, error = 0; 895 int key = uap->key; 896 int nsems = uap->nsems; 897 int semflg = uap->semflg; 898 struct ucred *cred = td->td_ucred; 899 900 DPRINTF(("semget(0x%x, %d, 0%o)\n", key, nsems, semflg)); 901 if (!jail_sysvipc_allowed && jailed(td->td_ucred)) 902 return (ENOSYS); 903 904 mtx_lock(&Giant); 905 if (key != IPC_PRIVATE) { 906 for (semid = 0; semid < seminfo.semmni; semid++) { 907 if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) && 908 sema[semid].u.sem_perm.key == key) 909 break; 910 } 911 if (semid < seminfo.semmni) { 912 DPRINTF(("found public key\n")); 913 if ((error = ipcperm(td, &sema[semid].u.sem_perm, 914 semflg & 0700))) { 915 goto done2; 916 } 917 if (nsems > 0 && sema[semid].u.sem_nsems < nsems) { 918 DPRINTF(("too small\n")); 919 error = EINVAL; 920 goto done2; 921 } 922 if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) { 923 DPRINTF(("not exclusive\n")); 924 error = EEXIST; 925 goto done2; 926 } 927 #ifdef MAC 928 error = mac_check_sysv_semget(cred, &sema[semid]); 929 if (error != 0) { 930 MPRINTF(("mac_check_sysv_semget returned %d\n", 931 error)); 932 goto done2; 933 } 934 #endif 935 goto found; 936 } 937 } 938 939 DPRINTF(("need to allocate the semid_kernel\n")); 940 if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) { 941 if (nsems <= 0 || nsems > seminfo.semmsl) { 942 DPRINTF(("nsems out of range (0<%d<=%d)\n", nsems, 943 seminfo.semmsl)); 944 error = EINVAL; 945 goto done2; 946 } 947 if (nsems > seminfo.semmns - semtot) { 948 DPRINTF(( 949 "not enough semaphores left (need %d, got %d)\n", 950 nsems, seminfo.semmns - semtot)); 951 error = ENOSPC; 952 goto done2; 953 } 954 for (semid = 0; semid < seminfo.semmni; semid++) { 955 if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0) 956 break; 957 } 958 if (semid == seminfo.semmni) { 959 DPRINTF(("no more semid_kernel's available\n")); 960 error = ENOSPC; 961 goto done2; 962 } 963 DPRINTF(("semid %d is available\n", semid)); 964 sema[semid].u.sem_perm.key = key; 965 sema[semid].u.sem_perm.cuid = cred->cr_uid; 966 sema[semid].u.sem_perm.uid = cred->cr_uid; 967 sema[semid].u.sem_perm.cgid = cred->cr_gid; 968 sema[semid].u.sem_perm.gid = cred->cr_gid; 969 sema[semid].u.sem_perm.mode = (semflg & 0777) | SEM_ALLOC; 970 sema[semid].u.sem_perm.seq = 971 (sema[semid].u.sem_perm.seq + 1) & 0x7fff; 972 sema[semid].u.sem_nsems = nsems; 973 sema[semid].u.sem_otime = 0; 974 sema[semid].u.sem_ctime = time_second; 975 sema[semid].u.sem_base = &sem[semtot]; 976 semtot += nsems; 977 bzero(sema[semid].u.sem_base, 978 sizeof(sema[semid].u.sem_base[0])*nsems); 979 #ifdef MAC 980 mac_create_sysv_sem(cred, &sema[semid]); 981 #endif 982 DPRINTF(("sembase = %p, next = %p\n", 983 sema[semid].u.sem_base, &sem[semtot])); 984 } else { 985 DPRINTF(("didn't find it and wasn't asked to create it\n")); 986 error = ENOENT; 987 goto done2; 988 } 989 990 found: 991 td->td_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].u.sem_perm); 992 done2: 993 mtx_unlock(&Giant); 994 return (error); 995 } 996 997 #ifndef _SYS_SYSPROTO_H_ 998 struct semop_args { 999 int semid; 1000 struct sembuf *sops; 1001 size_t nsops; 1002 }; 1003 #endif 1004 1005 /* 1006 * MPSAFE 1007 */ 1008 int 1009 semop(td, uap) 1010 struct thread *td; 1011 struct semop_args *uap; 1012 { 1013 #define SMALL_SOPS 8 1014 struct sembuf small_sops[SMALL_SOPS]; 1015 int semid = uap->semid; 1016 size_t nsops = uap->nsops; 1017 struct sembuf *sops; 1018 struct semid_kernel *semakptr; 1019 struct sembuf *sopptr = 0; 1020 struct sem *semptr = 0; 1021 struct sem_undo *suptr; 1022 struct mtx *sema_mtxp; 1023 size_t i, j, k; 1024 int error; 1025 int do_wakeup, do_undos; 1026 1027 #ifdef SEM_DEBUG 1028 sops = NULL; 1029 #endif 1030 DPRINTF(("call to semop(%d, %p, %u)\n", semid, sops, nsops)); 1031 1032 if (!jail_sysvipc_allowed && jailed(td->td_ucred)) 1033 return (ENOSYS); 1034 1035 semid = IPCID_TO_IX(semid); /* Convert back to zero origin */ 1036 1037 if (semid < 0 || semid >= seminfo.semmni) 1038 return (EINVAL); 1039 1040 /* Allocate memory for sem_ops */ 1041 if (nsops <= SMALL_SOPS) 1042 sops = small_sops; 1043 else if (nsops <= seminfo.semopm) 1044 sops = malloc(nsops * sizeof(*sops), M_TEMP, M_WAITOK); 1045 else { 1046 DPRINTF(("too many sops (max=%d, nsops=%d)\n", seminfo.semopm, 1047 nsops)); 1048 return (E2BIG); 1049 } 1050 if ((error = copyin(uap->sops, sops, nsops * sizeof(sops[0]))) != 0) { 1051 DPRINTF(("error = %d from copyin(%p, %p, %d)\n", error, 1052 uap->sops, sops, nsops * sizeof(sops[0]))); 1053 if (sops != small_sops) 1054 free(sops, M_SEM); 1055 return (error); 1056 } 1057 1058 semakptr = &sema[semid]; 1059 sema_mtxp = &sema_mtx[semid]; 1060 mtx_lock(sema_mtxp); 1061 if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) { 1062 error = EINVAL; 1063 goto done2; 1064 } 1065 if (semakptr->u.sem_perm.seq != IPCID_TO_SEQ(uap->semid)) { 1066 error = EINVAL; 1067 goto done2; 1068 } 1069 /* 1070 * Initial pass thru sops to see what permissions are needed. 1071 * Also perform any checks that don't need repeating on each 1072 * attempt to satisfy the request vector. 1073 */ 1074 j = 0; /* permission needed */ 1075 do_undos = 0; 1076 for (i = 0; i < nsops; i++) { 1077 sopptr = &sops[i]; 1078 if (sopptr->sem_num >= semakptr->u.sem_nsems) { 1079 error = EFBIG; 1080 goto done2; 1081 } 1082 if (sopptr->sem_flg & SEM_UNDO && sopptr->sem_op != 0) 1083 do_undos = 1; 1084 j |= (sopptr->sem_op == 0) ? SEM_R : SEM_A; 1085 } 1086 1087 if ((error = ipcperm(td, &semakptr->u.sem_perm, j))) { 1088 DPRINTF(("error = %d from ipaccess\n", error)); 1089 goto done2; 1090 } 1091 #ifdef MAC 1092 error = mac_check_sysv_semop(td->td_ucred, semakptr, j); 1093 if (error != 0) { 1094 MPRINTF(("mac_check_sysv_semop returned %d\n", error)); 1095 goto done2; 1096 } 1097 #endif 1098 1099 /* 1100 * Loop trying to satisfy the vector of requests. 1101 * If we reach a point where we must wait, any requests already 1102 * performed are rolled back and we go to sleep until some other 1103 * process wakes us up. At this point, we start all over again. 1104 * 1105 * This ensures that from the perspective of other tasks, a set 1106 * of requests is atomic (never partially satisfied). 1107 */ 1108 for (;;) { 1109 do_wakeup = 0; 1110 error = 0; /* error return if necessary */ 1111 1112 for (i = 0; i < nsops; i++) { 1113 sopptr = &sops[i]; 1114 semptr = &semakptr->u.sem_base[sopptr->sem_num]; 1115 1116 DPRINTF(( 1117 "semop: semakptr=%p, sem_base=%p, " 1118 "semptr=%p, sem[%d]=%d : op=%d, flag=%s\n", 1119 semakptr, semakptr->u.sem_base, semptr, 1120 sopptr->sem_num, semptr->semval, sopptr->sem_op, 1121 (sopptr->sem_flg & IPC_NOWAIT) ? 1122 "nowait" : "wait")); 1123 1124 if (sopptr->sem_op < 0) { 1125 if (semptr->semval + sopptr->sem_op < 0) { 1126 DPRINTF(("semop: can't do it now\n")); 1127 break; 1128 } else { 1129 semptr->semval += sopptr->sem_op; 1130 if (semptr->semval == 0 && 1131 semptr->semzcnt > 0) 1132 do_wakeup = 1; 1133 } 1134 } else if (sopptr->sem_op == 0) { 1135 if (semptr->semval != 0) { 1136 DPRINTF(("semop: not zero now\n")); 1137 break; 1138 } 1139 } else if (semptr->semval + sopptr->sem_op > 1140 seminfo.semvmx) { 1141 error = ERANGE; 1142 break; 1143 } else { 1144 if (semptr->semncnt > 0) 1145 do_wakeup = 1; 1146 semptr->semval += sopptr->sem_op; 1147 } 1148 } 1149 1150 /* 1151 * Did we get through the entire vector? 1152 */ 1153 if (i >= nsops) 1154 goto done; 1155 1156 /* 1157 * No ... rollback anything that we've already done 1158 */ 1159 DPRINTF(("semop: rollback 0 through %d\n", i-1)); 1160 for (j = 0; j < i; j++) 1161 semakptr->u.sem_base[sops[j].sem_num].semval -= 1162 sops[j].sem_op; 1163 1164 /* If we detected an error, return it */ 1165 if (error != 0) 1166 goto done2; 1167 1168 /* 1169 * If the request that we couldn't satisfy has the 1170 * NOWAIT flag set then return with EAGAIN. 1171 */ 1172 if (sopptr->sem_flg & IPC_NOWAIT) { 1173 error = EAGAIN; 1174 goto done2; 1175 } 1176 1177 if (sopptr->sem_op == 0) 1178 semptr->semzcnt++; 1179 else 1180 semptr->semncnt++; 1181 1182 DPRINTF(("semop: good night!\n")); 1183 error = msleep(semakptr, sema_mtxp, (PZERO - 4) | PCATCH, 1184 "semwait", 0); 1185 DPRINTF(("semop: good morning (error=%d)!\n", error)); 1186 /* return code is checked below, after sem[nz]cnt-- */ 1187 1188 /* 1189 * Make sure that the semaphore still exists 1190 */ 1191 if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 1192 semakptr->u.sem_perm.seq != IPCID_TO_SEQ(uap->semid)) { 1193 error = EIDRM; 1194 goto done2; 1195 } 1196 1197 /* 1198 * The semaphore is still alive. Readjust the count of 1199 * waiting processes. 1200 */ 1201 if (sopptr->sem_op == 0) 1202 semptr->semzcnt--; 1203 else 1204 semptr->semncnt--; 1205 1206 /* 1207 * Is it really morning, or was our sleep interrupted? 1208 * (Delayed check of msleep() return code because we 1209 * need to decrement sem[nz]cnt either way.) 1210 */ 1211 if (error != 0) { 1212 error = EINTR; 1213 goto done2; 1214 } 1215 DPRINTF(("semop: good morning!\n")); 1216 } 1217 1218 done: 1219 /* 1220 * Process any SEM_UNDO requests. 1221 */ 1222 if (do_undos) { 1223 SEMUNDO_LOCK(); 1224 suptr = NULL; 1225 for (i = 0; i < nsops; i++) { 1226 /* 1227 * We only need to deal with SEM_UNDO's for non-zero 1228 * op's. 1229 */ 1230 int adjval; 1231 1232 if ((sops[i].sem_flg & SEM_UNDO) == 0) 1233 continue; 1234 adjval = sops[i].sem_op; 1235 if (adjval == 0) 1236 continue; 1237 error = semundo_adjust(td, &suptr, semid, 1238 sops[i].sem_num, -adjval); 1239 if (error == 0) 1240 continue; 1241 1242 /* 1243 * Oh-Oh! We ran out of either sem_undo's or undo's. 1244 * Rollback the adjustments to this point and then 1245 * rollback the semaphore ups and down so we can return 1246 * with an error with all structures restored. We 1247 * rollback the undo's in the exact reverse order that 1248 * we applied them. This guarantees that we won't run 1249 * out of space as we roll things back out. 1250 */ 1251 for (j = 0; j < i; j++) { 1252 k = i - j - 1; 1253 if ((sops[k].sem_flg & SEM_UNDO) == 0) 1254 continue; 1255 adjval = sops[k].sem_op; 1256 if (adjval == 0) 1257 continue; 1258 if (semundo_adjust(td, &suptr, semid, 1259 sops[k].sem_num, adjval) != 0) 1260 panic("semop - can't undo undos"); 1261 } 1262 1263 for (j = 0; j < nsops; j++) 1264 semakptr->u.sem_base[sops[j].sem_num].semval -= 1265 sops[j].sem_op; 1266 1267 DPRINTF(("error = %d from semundo_adjust\n", error)); 1268 SEMUNDO_UNLOCK(); 1269 goto done2; 1270 } /* loop through the sops */ 1271 SEMUNDO_UNLOCK(); 1272 } /* if (do_undos) */ 1273 1274 /* We're definitely done - set the sempid's and time */ 1275 for (i = 0; i < nsops; i++) { 1276 sopptr = &sops[i]; 1277 semptr = &semakptr->u.sem_base[sopptr->sem_num]; 1278 semptr->sempid = td->td_proc->p_pid; 1279 } 1280 semakptr->u.sem_otime = time_second; 1281 1282 /* 1283 * Do a wakeup if any semaphore was up'd whilst something was 1284 * sleeping on it. 1285 */ 1286 if (do_wakeup) { 1287 DPRINTF(("semop: doing wakeup\n")); 1288 wakeup(semakptr); 1289 DPRINTF(("semop: back from wakeup\n")); 1290 } 1291 DPRINTF(("semop: done\n")); 1292 td->td_retval[0] = 0; 1293 done2: 1294 mtx_unlock(sema_mtxp); 1295 if (sops != small_sops) 1296 free(sops, M_SEM); 1297 return (error); 1298 } 1299 1300 /* 1301 * Go through the undo structures for this process and apply the adjustments to 1302 * semaphores. 1303 */ 1304 static void 1305 semexit_myhook(arg, p) 1306 void *arg; 1307 struct proc *p; 1308 { 1309 struct sem_undo *suptr; 1310 struct sem_undo **supptr; 1311 1312 /* 1313 * Go through the chain of undo vectors looking for one 1314 * associated with this process. 1315 */ 1316 SEMUNDO_LOCK(); 1317 SLIST_FOREACH_PREVPTR(suptr, supptr, &semu_list, un_next) { 1318 if (suptr->un_proc == p) 1319 break; 1320 } 1321 SEMUNDO_UNLOCK(); 1322 1323 if (suptr == NULL) 1324 return; 1325 1326 DPRINTF(("proc @%p has undo structure with %d entries\n", p, 1327 suptr->un_cnt)); 1328 1329 /* 1330 * If there are any active undo elements then process them. 1331 */ 1332 if (suptr->un_cnt > 0) { 1333 int ix; 1334 1335 for (ix = 0; ix < suptr->un_cnt; ix++) { 1336 int semid = suptr->un_ent[ix].un_id; 1337 int semnum = suptr->un_ent[ix].un_num; 1338 int adjval = suptr->un_ent[ix].un_adjval; 1339 struct semid_kernel *semakptr; 1340 struct mtx *sema_mtxp; 1341 1342 semakptr = &sema[semid]; 1343 sema_mtxp = &sema_mtx[semid]; 1344 mtx_lock(sema_mtxp); 1345 SEMUNDO_LOCK(); 1346 if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) 1347 panic("semexit - semid not allocated"); 1348 if (semnum >= semakptr->u.sem_nsems) 1349 panic("semexit - semnum out of range"); 1350 1351 DPRINTF(( 1352 "semexit: %p id=%d num=%d(adj=%d) ; sem=%d\n", 1353 suptr->un_proc, suptr->un_ent[ix].un_id, 1354 suptr->un_ent[ix].un_num, 1355 suptr->un_ent[ix].un_adjval, 1356 semakptr->u.sem_base[semnum].semval)); 1357 1358 if (adjval < 0) { 1359 if (semakptr->u.sem_base[semnum].semval < 1360 -adjval) 1361 semakptr->u.sem_base[semnum].semval = 0; 1362 else 1363 semakptr->u.sem_base[semnum].semval += 1364 adjval; 1365 } else 1366 semakptr->u.sem_base[semnum].semval += adjval; 1367 1368 wakeup(semakptr); 1369 DPRINTF(("semexit: back from wakeup\n")); 1370 mtx_unlock(sema_mtxp); 1371 SEMUNDO_UNLOCK(); 1372 } 1373 } 1374 1375 /* 1376 * Deallocate the undo vector. 1377 */ 1378 DPRINTF(("removing vector\n")); 1379 suptr->un_proc = NULL; 1380 *supptr = SLIST_NEXT(suptr, un_next); 1381 } 1382 1383 static int 1384 sysctl_sema(SYSCTL_HANDLER_ARGS) 1385 { 1386 1387 return (SYSCTL_OUT(req, sema, 1388 sizeof(struct semid_kernel) * seminfo.semmni)); 1389 } 1390