1 /* $OpenBSD: sysv_sem.c,v 1.36 2008/05/23 20:14:45 djm Exp $ */ 2 /* $NetBSD: sysv_sem.c,v 1.26 1996/02/09 19:00:25 christos Exp $ */ 3 4 /* 5 * Copyright (c) 2002,2003 Todd C. Miller <Todd.Miller@courtesan.com> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 * 19 * Sponsored in part by the Defense Advanced Research Projects 20 * Agency (DARPA) and Air Force Research Laboratory, Air Force 21 * Materiel Command, USAF, under agreement number F39502-99-1-0512. 22 */ 23 /* 24 * Implementation of SVID semaphores 25 * 26 * Author: Daniel Boulet 27 * 28 * This software is provided ``AS IS'' without any warranties of any kind. 29 */ 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/kernel.h> 34 #include <sys/proc.h> 35 #include <sys/sem.h> 36 #include <sys/sysctl.h> 37 #include <sys/malloc.h> 38 #include <sys/pool.h> 39 40 #include <sys/mount.h> 41 #include <sys/syscallargs.h> 42 43 #ifdef SEM_DEBUG 44 #define DPRINTF(x) printf x 45 #else 46 #define DPRINTF(x) 47 #endif 48 49 int semtot = 0; 50 int semutot = 0; 51 struct semid_ds **sema; /* semaphore id list */ 52 SLIST_HEAD(, sem_undo) semu_list; /* list of undo structures */ 53 struct pool sema_pool; /* pool for struct semid_ds */ 54 struct pool semu_pool; /* pool for struct sem_undo (SEMUSZ) */ 55 unsigned short *semseqs; /* array of sem sequence numbers */ 56 57 struct sem_undo *semu_alloc(struct proc *); 58 int semundo_adjust(struct proc *, struct sem_undo **, int, int, int); 59 void semundo_clear(int, int); 60 61 void 62 seminit(void) 63 { 64 65 pool_init(&sema_pool, sizeof(struct semid_ds), 0, 0, 0, "semapl", 66 &pool_allocator_nointr); 67 pool_init(&semu_pool, SEMUSZ, 0, 0, 0, "semupl", 68 &pool_allocator_nointr); 69 sema = malloc(seminfo.semmni * sizeof(struct semid_ds *), 70 M_SEM, M_WAITOK|M_ZERO); 71 semseqs = malloc(seminfo.semmni * sizeof(unsigned short), 72 M_SEM, M_WAITOK|M_ZERO); 73 SLIST_INIT(&semu_list); 74 } 75 76 /* 77 * Allocate a new sem_undo structure for a process 78 * (returns ptr to structure or NULL if no more room) 79 */ 80 struct sem_undo * 81 semu_alloc(struct proc *p) 82 { 83 struct sem_undo *suptr, *sutmp; 84 85 if (semutot == seminfo.semmnu) 86 return (NULL); /* no space */ 87 88 /* 89 * Allocate a semu w/o waiting if possible. 90 * If we do have to wait, we must check to verify that a semu 91 * with un_proc == p has not been allocated in the meantime. 92 */ 93 semutot++; 94 if ((suptr = pool_get(&semu_pool, 0)) == NULL) { 95 sutmp = pool_get(&semu_pool, PR_WAITOK); 96 SLIST_FOREACH(suptr, &semu_list, un_next) { 97 if (suptr->un_proc == p) { 98 pool_put(&semu_pool, sutmp); 99 semutot--; 100 return (suptr); 101 } 102 } 103 suptr = sutmp; 104 } 105 suptr->un_cnt = 0; 106 suptr->un_proc = p; 107 SLIST_INSERT_HEAD(&semu_list, suptr, un_next); 108 return (suptr); 109 } 110 111 /* 112 * Adjust a particular entry for a particular proc 113 */ 114 int 115 semundo_adjust(struct proc *p, struct sem_undo **supptr, int semid, int semnum, 116 int adjval) 117 { 118 struct sem_undo *suptr; 119 struct undo *sunptr; 120 int i; 121 122 /* 123 * Look for and remember the sem_undo if the caller doesn't provide it. 124 */ 125 suptr = *supptr; 126 if (suptr == NULL) { 127 SLIST_FOREACH(suptr, &semu_list, un_next) { 128 if (suptr->un_proc == p) { 129 *supptr = suptr; 130 break; 131 } 132 } 133 if (suptr == NULL) { 134 if (adjval == 0) 135 return (0); 136 suptr = semu_alloc(p); 137 if (suptr == NULL) 138 return (ENOSPC); 139 *supptr = suptr; 140 } 141 } 142 143 /* 144 * Look for the requested entry and adjust it 145 * (delete if adjval becomes 0). 146 */ 147 sunptr = &suptr->un_ent[0]; 148 for (i = 0; i < suptr->un_cnt; i++, sunptr++) { 149 if (sunptr->un_id != semid || sunptr->un_num != semnum) 150 continue; 151 if (adjval == 0) 152 sunptr->un_adjval = 0; 153 else 154 sunptr->un_adjval += adjval; 155 if (sunptr->un_adjval != 0) 156 return (0); 157 158 if (--suptr->un_cnt == 0) { 159 SLIST_REMOVE(&semu_list, suptr, sem_undo, un_next); 160 pool_put(&semu_pool, suptr); 161 semutot--; 162 } else if (i < suptr->un_cnt) 163 suptr->un_ent[i] = 164 suptr->un_ent[suptr->un_cnt]; 165 return (0); 166 } 167 168 /* Didn't find the right entry - create it */ 169 if (adjval == 0) 170 return (0); 171 if (suptr->un_cnt == SEMUME) 172 return (EINVAL); 173 174 sunptr = &suptr->un_ent[suptr->un_cnt]; 175 suptr->un_cnt++; 176 sunptr->un_adjval = adjval; 177 sunptr->un_id = semid; 178 sunptr->un_num = semnum; 179 return (0); 180 } 181 182 void 183 semundo_clear(int semid, int semnum) 184 { 185 struct sem_undo *suptr = SLIST_FIRST(&semu_list); 186 struct sem_undo *suprev = SLIST_END(&semu_list); 187 struct undo *sunptr; 188 int i; 189 190 while (suptr != SLIST_END(&semu_list)) { 191 sunptr = &suptr->un_ent[0]; 192 for (i = 0; i < suptr->un_cnt; i++, sunptr++) { 193 if (sunptr->un_id == semid) { 194 if (semnum == -1 || sunptr->un_num == semnum) { 195 suptr->un_cnt--; 196 if (i < suptr->un_cnt) { 197 suptr->un_ent[i] = 198 suptr->un_ent[suptr->un_cnt]; 199 i--, sunptr--; 200 } 201 } 202 if (semnum != -1) 203 break; 204 } 205 } 206 if (suptr->un_cnt == 0) { 207 struct sem_undo *sutmp = suptr; 208 209 if (suptr == SLIST_FIRST(&semu_list)) 210 SLIST_REMOVE_HEAD(&semu_list, un_next); 211 else 212 SLIST_REMOVE_NEXT(&semu_list, suprev, un_next); 213 suptr = SLIST_NEXT(suptr, un_next); 214 pool_put(&semu_pool, sutmp); 215 semutot--; 216 } else { 217 suprev = suptr; 218 suptr = SLIST_NEXT(suptr, un_next); 219 } 220 } 221 } 222 223 int 224 sys___semctl(struct proc *p, void *v, register_t *retval) 225 { 226 struct sys___semctl_args /* { 227 syscallarg(int) semid; 228 syscallarg(int) semnum; 229 syscallarg(int) cmd; 230 syscallarg(union semun *) arg; 231 } */ *uap = v; 232 union semun arg; 233 int error = 0, cmd = SCARG(uap, cmd); 234 235 switch (cmd) { 236 case IPC_SET: 237 case IPC_STAT: 238 case GETALL: 239 case SETVAL: 240 case SETALL: 241 error = copyin(SCARG(uap, arg), &arg, sizeof(arg)); 242 break; 243 } 244 if (error == 0) { 245 error = semctl1(p, SCARG(uap, semid), SCARG(uap, semnum), 246 cmd, &arg, retval, copyin, copyout); 247 } 248 return (error); 249 } 250 251 int 252 semctl1(struct proc *p, int semid, int semnum, int cmd, union semun *arg, 253 register_t *retval, int (*ds_copyin)(const void *, void *, size_t), 254 int (*ds_copyout)(const void *, void *, size_t)) 255 { 256 struct ucred *cred = p->p_ucred; 257 int i, ix, error = 0; 258 struct semid_ds sbuf; 259 struct semid_ds *semaptr; 260 261 DPRINTF(("call to semctl(%d, %d, %d, %p)\n", semid, semnum, cmd, arg)); 262 263 ix = IPCID_TO_IX(semid); 264 if (ix < 0 || ix >= seminfo.semmni) 265 return (EINVAL); 266 267 if ((semaptr = sema[ix]) == NULL || 268 semaptr->sem_perm.seq != IPCID_TO_SEQ(semid)) 269 return (EINVAL); 270 271 switch (cmd) { 272 case IPC_RMID: 273 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_M)) != 0) 274 return (error); 275 semaptr->sem_perm.cuid = cred->cr_uid; 276 semaptr->sem_perm.uid = cred->cr_uid; 277 semtot -= semaptr->sem_nsems; 278 free(semaptr->sem_base, M_SEM); 279 pool_put(&sema_pool, semaptr); 280 sema[ix] = NULL; 281 semundo_clear(ix, -1); 282 wakeup(&sema[ix]); 283 break; 284 285 case IPC_SET: 286 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_M))) 287 return (error); 288 if ((error = ds_copyin(arg->buf, &sbuf, sizeof(sbuf))) != 0) 289 return (error); 290 semaptr->sem_perm.uid = sbuf.sem_perm.uid; 291 semaptr->sem_perm.gid = sbuf.sem_perm.gid; 292 semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777) | 293 (sbuf.sem_perm.mode & 0777); 294 semaptr->sem_ctime = time_second; 295 break; 296 297 case IPC_STAT: 298 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 299 return (error); 300 error = ds_copyout(semaptr, arg->buf, sizeof(struct semid_ds)); 301 break; 302 303 case GETNCNT: 304 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 305 return (error); 306 if (semnum < 0 || semnum >= semaptr->sem_nsems) 307 return (EINVAL); 308 *retval = semaptr->sem_base[semnum].semncnt; 309 break; 310 311 case GETPID: 312 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 313 return (error); 314 if (semnum < 0 || semnum >= semaptr->sem_nsems) 315 return (EINVAL); 316 *retval = semaptr->sem_base[semnum].sempid; 317 break; 318 319 case GETVAL: 320 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 321 return (error); 322 if (semnum < 0 || semnum >= semaptr->sem_nsems) 323 return (EINVAL); 324 *retval = semaptr->sem_base[semnum].semval; 325 break; 326 327 case GETALL: 328 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 329 return (error); 330 for (i = 0; i < semaptr->sem_nsems; i++) { 331 error = ds_copyout(&semaptr->sem_base[i].semval, 332 &arg->array[i], sizeof(arg->array[0])); 333 if (error != 0) 334 break; 335 } 336 break; 337 338 case GETZCNT: 339 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R))) 340 return (error); 341 if (semnum < 0 || semnum >= semaptr->sem_nsems) 342 return (EINVAL); 343 *retval = semaptr->sem_base[semnum].semzcnt; 344 break; 345 346 case SETVAL: 347 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_W))) 348 return (error); 349 if (semnum < 0 || semnum >= semaptr->sem_nsems) 350 return (EINVAL); 351 semaptr->sem_base[semnum].semval = arg->val; 352 semundo_clear(ix, semnum); 353 wakeup(&sema[ix]); 354 break; 355 356 case SETALL: 357 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_W))) 358 return (error); 359 for (i = 0; i < semaptr->sem_nsems; i++) { 360 error = ds_copyin(&arg->array[i], 361 &semaptr->sem_base[i].semval, 362 sizeof(arg->array[0])); 363 if (error != 0) 364 break; 365 } 366 semundo_clear(ix, -1); 367 wakeup(&sema[ix]); 368 break; 369 370 default: 371 return (EINVAL); 372 } 373 374 return (error); 375 } 376 377 int 378 sys_semget(struct proc *p, void *v, register_t *retval) 379 { 380 struct sys_semget_args /* { 381 syscallarg(key_t) key; 382 syscallarg(int) nsems; 383 syscallarg(int) semflg; 384 } */ *uap = v; 385 int semid, error; 386 int key = SCARG(uap, key); 387 int nsems = SCARG(uap, nsems); 388 int semflg = SCARG(uap, semflg); 389 struct semid_ds *semaptr, *semaptr_new = NULL; 390 struct ucred *cred = p->p_ucred; 391 392 DPRINTF(("semget(0x%x, %d, 0%o)\n", key, nsems, semflg)); 393 394 /* 395 * Preallocate space for the new semaphore. If we are going 396 * to sleep, we want to sleep now to eliminate any race 397 * condition in allocating a semaphore with a specific key. 398 */ 399 if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) { 400 if (nsems <= 0 || nsems > seminfo.semmsl) { 401 DPRINTF(("nsems out of range (0<%d<=%d)\n", nsems, 402 seminfo.semmsl)); 403 return (EINVAL); 404 } 405 if (nsems > seminfo.semmns - semtot) { 406 DPRINTF(("not enough semaphores left (need %d, got %d)\n", 407 nsems, seminfo.semmns - semtot)); 408 return (ENOSPC); 409 } 410 semaptr_new = pool_get(&sema_pool, PR_WAITOK); 411 semaptr_new->sem_base = malloc(nsems * sizeof(struct sem), 412 M_SEM, M_WAITOK|M_ZERO); 413 } 414 415 if (key != IPC_PRIVATE) { 416 for (semid = 0, semaptr = NULL; semid < seminfo.semmni; semid++) { 417 if ((semaptr = sema[semid]) != NULL && 418 semaptr->sem_perm.key == key) { 419 DPRINTF(("found public key\n")); 420 if ((error = ipcperm(cred, &semaptr->sem_perm, 421 semflg & 0700))) 422 goto error; 423 if (nsems > 0 && semaptr->sem_nsems < nsems) { 424 DPRINTF(("too small\n")); 425 error = EINVAL; 426 goto error; 427 } 428 if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) { 429 DPRINTF(("not exclusive\n")); 430 error = EEXIST; 431 goto error; 432 } 433 goto found; 434 } 435 } 436 } 437 438 DPRINTF(("need to allocate the semid_ds\n")); 439 if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) { 440 for (semid = 0; semid < seminfo.semmni; semid++) { 441 if ((semaptr = sema[semid]) == NULL) 442 break; 443 } 444 if (semid == seminfo.semmni) { 445 DPRINTF(("no more semid_ds's available\n")); 446 error = ENOSPC; 447 goto error; 448 } 449 DPRINTF(("semid %d is available\n", semid)); 450 semaptr_new->sem_perm.key = key; 451 semaptr_new->sem_perm.cuid = cred->cr_uid; 452 semaptr_new->sem_perm.uid = cred->cr_uid; 453 semaptr_new->sem_perm.cgid = cred->cr_gid; 454 semaptr_new->sem_perm.gid = cred->cr_gid; 455 semaptr_new->sem_perm.mode = (semflg & 0777); 456 semaptr_new->sem_perm.seq = semseqs[semid] = 457 (semseqs[semid] + 1) & 0x7fff; 458 semaptr_new->sem_nsems = nsems; 459 semaptr_new->sem_otime = 0; 460 semaptr_new->sem_ctime = time_second; 461 sema[semid] = semaptr_new; 462 semtot += nsems; 463 } else { 464 DPRINTF(("didn't find it and wasn't asked to create it\n")); 465 return (ENOENT); 466 } 467 468 found: 469 *retval = IXSEQ_TO_IPCID(semid, sema[semid]->sem_perm); 470 return (0); 471 error: 472 if (semaptr_new != NULL) { 473 free(semaptr_new->sem_base, M_SEM); 474 pool_put(&sema_pool, semaptr_new); 475 } 476 return (error); 477 } 478 479 int 480 sys_semop(struct proc *p, void *v, register_t *retval) 481 { 482 struct sys_semop_args /* { 483 syscallarg(int) semid; 484 syscallarg(struct sembuf *) sops; 485 syscallarg(size_t) nsops; 486 } */ *uap = v; 487 #define NSOPS 8 488 struct sembuf sopbuf[NSOPS]; 489 int semid = SCARG(uap, semid); 490 size_t nsops = SCARG(uap, nsops); 491 struct sembuf *sops; 492 struct semid_ds *semaptr; 493 struct sembuf *sopptr = NULL; 494 struct sem *semptr = NULL; 495 struct sem_undo *suptr = NULL; 496 struct ucred *cred = p->p_ucred; 497 size_t i, j; 498 int do_wakeup, do_undos, error; 499 500 DPRINTF(("call to semop(%d, %p, %lu)\n", semid, SCARG(uap, sops), 501 (u_long)nsops)); 502 503 semid = IPCID_TO_IX(semid); /* Convert back to zero origin */ 504 505 if (semid < 0 || semid >= seminfo.semmni) 506 return (EINVAL); 507 508 if ((semaptr = sema[semid]) == NULL || 509 semaptr->sem_perm.seq != IPCID_TO_SEQ(SCARG(uap, semid))) 510 return (EINVAL); 511 512 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_W))) { 513 DPRINTF(("error = %d from ipaccess\n", error)); 514 return (error); 515 } 516 517 if (nsops == 0) { 518 *retval = 0; 519 return (0); 520 } else if (nsops > (size_t)seminfo.semopm) { 521 DPRINTF(("too many sops (max=%d, nsops=%lu)\n", seminfo.semopm, 522 (u_long)nsops)); 523 return (E2BIG); 524 } 525 526 if (nsops <= NSOPS) 527 sops = sopbuf; 528 else 529 sops = malloc(nsops * sizeof(struct sembuf), M_SEM, M_WAITOK); 530 error = copyin(SCARG(uap, sops), sops, nsops * sizeof(struct sembuf)); 531 if (error != 0) { 532 DPRINTF(("error = %d from copyin(%p, %p, %u)\n", error, 533 SCARG(uap, sops), &sops, nsops * sizeof(struct sembuf))); 534 goto done2; 535 } 536 537 /* 538 * Loop trying to satisfy the vector of requests. 539 * If we reach a point where we must wait, any requests already 540 * performed are rolled back and we go to sleep until some other 541 * process wakes us up. At this point, we start all over again. 542 * 543 * This ensures that from the perspective of other tasks, a set 544 * of requests is atomic (never partially satisfied). 545 */ 546 do_undos = 0; 547 548 for (;;) { 549 do_wakeup = 0; 550 551 for (i = 0; i < nsops; i++) { 552 sopptr = &sops[i]; 553 554 if (sopptr->sem_num >= semaptr->sem_nsems) { 555 error = EFBIG; 556 goto done2; 557 } 558 559 semptr = &semaptr->sem_base[sopptr->sem_num]; 560 561 DPRINTF(("semop: semaptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n", 562 semaptr, semaptr->sem_base, semptr, 563 sopptr->sem_num, semptr->semval, sopptr->sem_op, 564 (sopptr->sem_flg & IPC_NOWAIT) ? "nowait" : "wait")); 565 566 if (sopptr->sem_op < 0) { 567 if ((int)(semptr->semval + 568 sopptr->sem_op) < 0) { 569 DPRINTF(("semop: can't do it now\n")); 570 break; 571 } else { 572 semptr->semval += sopptr->sem_op; 573 if (semptr->semval == 0 && 574 semptr->semzcnt > 0) 575 do_wakeup = 1; 576 } 577 if (sopptr->sem_flg & SEM_UNDO) 578 do_undos = 1; 579 } else if (sopptr->sem_op == 0) { 580 if (semptr->semval > 0) { 581 DPRINTF(("semop: not zero now\n")); 582 break; 583 } 584 } else { 585 if (semptr->semncnt > 0) 586 do_wakeup = 1; 587 semptr->semval += sopptr->sem_op; 588 if (sopptr->sem_flg & SEM_UNDO) 589 do_undos = 1; 590 } 591 } 592 593 /* 594 * Did we get through the entire vector? 595 */ 596 if (i >= nsops) 597 goto done; 598 599 /* 600 * No ... rollback anything that we've already done 601 */ 602 DPRINTF(("semop: rollback 0 through %d\n", i - 1)); 603 for (j = 0; j < i; j++) 604 semaptr->sem_base[sops[j].sem_num].semval -= 605 sops[j].sem_op; 606 607 /* 608 * If the request that we couldn't satisfy has the 609 * NOWAIT flag set then return with EAGAIN. 610 */ 611 if (sopptr->sem_flg & IPC_NOWAIT) { 612 error = EAGAIN; 613 goto done2; 614 } 615 616 if (sopptr->sem_op == 0) 617 semptr->semzcnt++; 618 else 619 semptr->semncnt++; 620 621 DPRINTF(("semop: good night!\n")); 622 error = tsleep(&sema[semid], PLOCK | PCATCH, 623 "semwait", 0); 624 DPRINTF(("semop: good morning (error=%d)!\n", error)); 625 626 suptr = NULL; /* sem_undo may have been reallocated */ 627 628 /* 629 * Make sure that the semaphore still exists 630 */ 631 if (sema[semid] == NULL || 632 semaptr->sem_perm.seq != IPCID_TO_SEQ(SCARG(uap, semid))) { 633 error = EIDRM; 634 goto done2; 635 } 636 637 /* 638 * The semaphore is still alive. Readjust the count of 639 * waiting processes. 640 */ 641 if (sopptr->sem_op == 0) 642 semptr->semzcnt--; 643 else 644 semptr->semncnt--; 645 646 /* 647 * Is it really morning, or was our sleep interrupted? 648 * (Delayed check of tsleep() return code because we 649 * need to decrement sem[nz]cnt either way.) 650 */ 651 if (error != 0) { 652 error = EINTR; 653 goto done2; 654 } 655 DPRINTF(("semop: good morning!\n")); 656 } 657 658 done: 659 /* 660 * Process any SEM_UNDO requests. 661 */ 662 if (do_undos) { 663 for (i = 0; i < nsops; i++) { 664 /* 665 * We only need to deal with SEM_UNDO's for non-zero 666 * op's. 667 */ 668 int adjval; 669 670 if ((sops[i].sem_flg & SEM_UNDO) == 0) 671 continue; 672 adjval = sops[i].sem_op; 673 if (adjval == 0) 674 continue; 675 error = semundo_adjust(p, &suptr, semid, 676 sops[i].sem_num, -adjval); 677 if (error == 0) 678 continue; 679 680 /* 681 * Uh-Oh! We ran out of either sem_undo's or undo's. 682 * Rollback the adjustments to this point and then 683 * rollback the semaphore ups and down so we can return 684 * with an error with all structures restored. We 685 * rollback the undo's in the exact reverse order that 686 * we applied them. This guarantees that we won't run 687 * out of space as we roll things back out. 688 */ 689 if (i != 0) { 690 for (j = i - 1; j >= 0; j--) { 691 if ((sops[j].sem_flg & SEM_UNDO) == 0) 692 continue; 693 adjval = sops[j].sem_op; 694 if (adjval == 0) 695 continue; 696 if (semundo_adjust(p, &suptr, semid, 697 sops[j].sem_num, adjval) != 0) 698 panic("semop - can't undo undos"); 699 } 700 } 701 702 for (j = 0; j < nsops; j++) 703 semaptr->sem_base[sops[j].sem_num].semval -= 704 sops[j].sem_op; 705 706 DPRINTF(("error = %d from semundo_adjust\n", error)); 707 goto done2; 708 } /* loop through the sops */ 709 } /* if (do_undos) */ 710 711 /* We're definitely done - set the sempid's */ 712 for (i = 0; i < nsops; i++) { 713 sopptr = &sops[i]; 714 semptr = &semaptr->sem_base[sopptr->sem_num]; 715 semptr->sempid = p->p_pid; 716 } 717 718 semaptr->sem_otime = time_second; 719 720 /* Do a wakeup if any semaphore was up'd. */ 721 if (do_wakeup) { 722 DPRINTF(("semop: doing wakeup\n")); 723 wakeup(&sema[semid]); 724 DPRINTF(("semop: back from wakeup\n")); 725 } 726 DPRINTF(("semop: done\n")); 727 *retval = 0; 728 done2: 729 if (sops != sopbuf) 730 free(sops, M_SEM); 731 return (error); 732 } 733 734 /* 735 * Go through the undo structures for this process and apply the adjustments to 736 * semaphores. 737 */ 738 void 739 semexit(struct proc *p) 740 { 741 struct sem_undo *suptr; 742 struct sem_undo **supptr; 743 744 /* 745 * Go through the chain of undo vectors looking for one associated with 746 * this process. 747 */ 748 SLIST_FOREACH_PREVPTR(suptr, supptr, &semu_list, un_next) { 749 if (suptr->un_proc == p) 750 break; 751 } 752 753 /* 754 * If there is no undo vector, skip to the end. 755 */ 756 if (suptr == NULL) 757 return; 758 759 /* 760 * We now have an undo vector for this process. 761 */ 762 DPRINTF(("proc @%p has undo structure with %d entries\n", p, 763 suptr->un_cnt)); 764 765 /* 766 * If there are any active undo elements then process them. 767 */ 768 if (suptr->un_cnt > 0) { 769 int ix; 770 771 for (ix = 0; ix < suptr->un_cnt; ix++) { 772 int semid = suptr->un_ent[ix].un_id; 773 int semnum = suptr->un_ent[ix].un_num; 774 int adjval = suptr->un_ent[ix].un_adjval; 775 struct semid_ds *semaptr; 776 777 if ((semaptr = sema[semid]) == NULL) 778 panic("semexit - semid not allocated"); 779 if (semnum >= semaptr->sem_nsems) 780 panic("semexit - semnum out of range"); 781 782 DPRINTF(("semexit: %p id=%d num=%d(adj=%d) ; sem=%d\n", 783 suptr->un_proc, suptr->un_ent[ix].un_id, 784 suptr->un_ent[ix].un_num, 785 suptr->un_ent[ix].un_adjval, 786 semaptr->sem_base[semnum].semval)); 787 788 if (adjval < 0 && 789 semaptr->sem_base[semnum].semval < -adjval) 790 semaptr->sem_base[semnum].semval = 0; 791 else 792 semaptr->sem_base[semnum].semval += adjval; 793 794 wakeup(&sema[semid]); 795 DPRINTF(("semexit: back from wakeup\n")); 796 } 797 } 798 799 /* 800 * Deallocate the undo vector. 801 */ 802 DPRINTF(("removing vector\n")); 803 *supptr = SLIST_NEXT(suptr, un_next); 804 pool_put(&semu_pool, suptr); 805 semutot--; 806 } 807 808 /* 809 * Userland access to struct seminfo. 810 */ 811 int 812 sysctl_sysvsem(int *name, u_int namelen, void *oldp, size_t *oldlenp, 813 void *newp, size_t newlen) 814 { 815 int error, val; 816 struct semid_ds **sema_new; 817 unsigned short *newseqs; 818 819 if (namelen != 2) { 820 switch (name[0]) { 821 case KERN_SEMINFO_SEMMNI: 822 case KERN_SEMINFO_SEMMNS: 823 case KERN_SEMINFO_SEMMNU: 824 case KERN_SEMINFO_SEMMSL: 825 case KERN_SEMINFO_SEMOPM: 826 case KERN_SEMINFO_SEMUME: 827 case KERN_SEMINFO_SEMUSZ: 828 case KERN_SEMINFO_SEMVMX: 829 case KERN_SEMINFO_SEMAEM: 830 break; 831 default: 832 return (ENOTDIR); /* overloaded */ 833 } 834 } 835 836 switch (name[0]) { 837 case KERN_SEMINFO_SEMMNI: 838 val = seminfo.semmni; 839 if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &val)) || 840 val == seminfo.semmni) 841 return (error); 842 843 if (val < seminfo.semmni || val > 0xffff) 844 return (EINVAL); 845 846 /* Expand semsegs and semseqs arrays */ 847 sema_new = malloc(val * sizeof(struct semid_ds *), 848 M_SEM, M_WAITOK|M_ZERO); 849 bcopy(sema, sema_new, 850 seminfo.semmni * sizeof(struct semid_ds *)); 851 newseqs = malloc(val * sizeof(unsigned short), M_SEM, 852 M_WAITOK|M_ZERO); 853 bcopy(semseqs, newseqs, 854 seminfo.semmni * sizeof(unsigned short)); 855 free(sema, M_SEM); 856 free(semseqs, M_SEM); 857 sema = sema_new; 858 semseqs = newseqs; 859 seminfo.semmni = val; 860 return (0); 861 case KERN_SEMINFO_SEMMNS: 862 val = seminfo.semmns; 863 if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &val)) || 864 val == seminfo.semmns) 865 return (error); 866 if (val < seminfo.semmns || val > 0xffff) 867 return (EINVAL); /* can't decrease semmns */ 868 seminfo.semmns = val; 869 return (0); 870 case KERN_SEMINFO_SEMMNU: 871 val = seminfo.semmnu; 872 if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &val)) || 873 val == seminfo.semmnu) 874 return (error); 875 if (val < seminfo.semmnu) 876 return (EINVAL); /* can't decrease semmnu */ 877 seminfo.semmnu = val; 878 return (0); 879 case KERN_SEMINFO_SEMMSL: 880 val = seminfo.semmsl; 881 if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &val)) || 882 val == seminfo.semmsl) 883 return (error); 884 if (val < seminfo.semmsl || val > 0xffff) 885 return (EINVAL); /* can't decrease semmsl */ 886 seminfo.semmsl = val; 887 return (0); 888 case KERN_SEMINFO_SEMOPM: 889 val = seminfo.semopm; 890 if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &val)) || 891 val == seminfo.semopm) 892 return (error); 893 if (val <= 0) 894 return (EINVAL); /* semopm must be >= 1 */ 895 seminfo.semopm = val; 896 return (0); 897 case KERN_SEMINFO_SEMUME: 898 return (sysctl_rdint(oldp, oldlenp, newp, seminfo.semume)); 899 case KERN_SEMINFO_SEMUSZ: 900 return (sysctl_rdint(oldp, oldlenp, newp, seminfo.semusz)); 901 case KERN_SEMINFO_SEMVMX: 902 return (sysctl_rdint(oldp, oldlenp, newp, seminfo.semvmx)); 903 case KERN_SEMINFO_SEMAEM: 904 return (sysctl_rdint(oldp, oldlenp, newp, seminfo.semaem)); 905 default: 906 return (EOPNOTSUPP); 907 } 908 /* NOTREACHED */ 909 } 910