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