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