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