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