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