Deleted Added
sdiff udiff text old ( 77461 ) new ( 82607 )
full compact
1/* $FreeBSD: head/sys/kern/sysv_sem.c 77461 2001-05-30 03:28:59Z dd $ */
2
3/*
4 * Implementation of SVID semaphores
5 *
6 * Author: Daniel Boulet
7 *
8 * This software is provided ``AS IS'' without any warranties of any kind.
9 */
10
11#include "opt_sysvipc.h"
12
13#include <sys/param.h>
14#include <sys/systm.h>
15#include <sys/sysproto.h>
16#include <sys/kernel.h>
17#include <sys/proc.h>
18#include <sys/sem.h>
19#include <sys/syscall.h>
20#include <sys/sysent.h>
21#include <sys/sysctl.h>
22#include <sys/malloc.h>
23#include <sys/jail.h>
24
25static MALLOC_DEFINE(M_SEM, "sem", "SVID compatible semaphores");

--- 213 unchanged lines hidden (view full) ---

239SYSCALL_MODULE_HELPER(semop, 3);
240
241DECLARE_MODULE(sysvsem, sysvsem_mod,
242 SI_SUB_SYSV_SEM, SI_ORDER_FIRST);
243MODULE_VERSION(sysvsem, 1);
244
245/*
246 * Entry point for all SEM calls
247 */
248int
249semsys(p, uap)
250 struct proc *p;
251 /* XXX actually varargs. */
252 struct semsys_args /* {
253 u_int which;
254 int a2;
255 int a3;
256 int a4;
257 int a5;
258 } */ *uap;
259{
260
261 if (!jail_sysvipc_allowed && jailed(p->p_ucred))
262 return (ENOSYS);
263
264 if (uap->which >= sizeof(semcalls)/sizeof(semcalls[0]))
265 return (EINVAL);
266 return ((*semcalls[uap->which])(p, &uap->a2));
267}
268
269/*
270 * Allocate a new sem_undo structure for a process
271 * (returns ptr to structure or NULL if no more room)
272 */
273
274static struct sem_undo *

--- 168 unchanged lines hidden (view full) ---

443struct __semctl_args {
444 int semid;
445 int semnum;
446 int cmd;
447 union semun *arg;
448};
449#endif
450
451int
452__semctl(p, uap)
453 struct proc *p;
454 register struct __semctl_args *uap;
455{
456 int semid = uap->semid;
457 int semnum = uap->semnum;
458 int cmd = uap->cmd;
459 union semun *arg = uap->arg;
460 union semun real_arg;
461 struct ucred *cred = p->p_ucred;
462 int i, rval, eval;
463 struct semid_ds sbuf;
464 register struct semid_ds *semaptr;
465
466#ifdef SEM_DEBUG
467 printf("call to semctl(%d, %d, %d, 0x%x)\n", semid, semnum, cmd, arg);
468#endif
469
470 if (!jail_sysvipc_allowed && jailed(p->p_ucred))
471 return (ENOSYS);
472
473 semid = IPCID_TO_IX(semid);
474 if (semid < 0 || semid >= seminfo.semmsl)
475 return(EINVAL);
476
477 semaptr = &sema[semid];
478 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ||
479 semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid))
480 return(EINVAL);
481
482 eval = 0;
483 rval = 0;
484
485 switch (cmd) {
486 case IPC_RMID:
487 if ((eval = ipcperm(p, &semaptr->sem_perm, IPC_M)))
488 return(eval);
489 semaptr->sem_perm.cuid = cred->cr_uid;
490 semaptr->sem_perm.uid = cred->cr_uid;
491 semtot -= semaptr->sem_nsems;
492 for (i = semaptr->sem_base - sem; i < semtot; i++)
493 sem[i] = sem[i + semaptr->sem_nsems];
494 for (i = 0; i < seminfo.semmni; i++) {
495 if ((sema[i].sem_perm.mode & SEM_ALLOC) &&
496 sema[i].sem_base > semaptr->sem_base)
497 sema[i].sem_base -= semaptr->sem_nsems;
498 }
499 semaptr->sem_perm.mode = 0;
500 semundo_clear(semid, -1);
501 wakeup((caddr_t)semaptr);
502 break;
503
504 case IPC_SET:
505 if ((eval = ipcperm(p, &semaptr->sem_perm, IPC_M)))
506 return(eval);
507 if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
508 return(eval);
509 if ((eval = copyin(real_arg.buf, (caddr_t)&sbuf,
510 sizeof(sbuf))) != 0)
511 return(eval);
512 semaptr->sem_perm.uid = sbuf.sem_perm.uid;
513 semaptr->sem_perm.gid = sbuf.sem_perm.gid;
514 semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777) |
515 (sbuf.sem_perm.mode & 0777);
516 semaptr->sem_ctime = time_second;
517 break;
518
519 case IPC_STAT:
520 if ((eval = ipcperm(p, &semaptr->sem_perm, IPC_R)))
521 return(eval);
522 if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
523 return(eval);
524 eval = copyout((caddr_t)semaptr, real_arg.buf,
525 sizeof(struct semid_ds));
526 break;
527
528 case GETNCNT:
529 if ((eval = ipcperm(p, &semaptr->sem_perm, IPC_R)))
530 return(eval);
531 if (semnum < 0 || semnum >= semaptr->sem_nsems)
532 return(EINVAL);
533 rval = semaptr->sem_base[semnum].semncnt;
534 break;
535
536 case GETPID:
537 if ((eval = ipcperm(p, &semaptr->sem_perm, IPC_R)))
538 return(eval);
539 if (semnum < 0 || semnum >= semaptr->sem_nsems)
540 return(EINVAL);
541 rval = semaptr->sem_base[semnum].sempid;
542 break;
543
544 case GETVAL:
545 if ((eval = ipcperm(p, &semaptr->sem_perm, IPC_R)))
546 return(eval);
547 if (semnum < 0 || semnum >= semaptr->sem_nsems)
548 return(EINVAL);
549 rval = semaptr->sem_base[semnum].semval;
550 break;
551
552 case GETALL:
553 if ((eval = ipcperm(p, &semaptr->sem_perm, IPC_R)))
554 return(eval);
555 if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
556 return(eval);
557 for (i = 0; i < semaptr->sem_nsems; i++) {
558 eval = copyout((caddr_t)&semaptr->sem_base[i].semval,
559 &real_arg.array[i], sizeof(real_arg.array[0]));
560 if (eval != 0)
561 break;
562 }
563 break;
564
565 case GETZCNT:
566 if ((eval = ipcperm(p, &semaptr->sem_perm, IPC_R)))
567 return(eval);
568 if (semnum < 0 || semnum >= semaptr->sem_nsems)
569 return(EINVAL);
570 rval = semaptr->sem_base[semnum].semzcnt;
571 break;
572
573 case SETVAL:
574 if ((eval = ipcperm(p, &semaptr->sem_perm, IPC_W)))
575 return(eval);
576 if (semnum < 0 || semnum >= semaptr->sem_nsems)
577 return(EINVAL);
578 if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
579 return(eval);
580 semaptr->sem_base[semnum].semval = real_arg.val;
581 semundo_clear(semid, semnum);
582 wakeup((caddr_t)semaptr);
583 break;
584
585 case SETALL:
586 if ((eval = ipcperm(p, &semaptr->sem_perm, IPC_W)))
587 return(eval);
588 if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
589 return(eval);
590 for (i = 0; i < semaptr->sem_nsems; i++) {
591 eval = copyin(&real_arg.array[i],
592 (caddr_t)&semaptr->sem_base[i].semval,
593 sizeof(real_arg.array[0]));
594 if (eval != 0)
595 break;
596 }
597 semundo_clear(semid, -1);
598 wakeup((caddr_t)semaptr);
599 break;
600
601 default:
602 return(EINVAL);
603 }
604
605 if (eval == 0)
606 p->p_retval[0] = rval;
607 return(eval);
608}
609
610#ifndef _SYS_SYSPROTO_H_
611struct semget_args {
612 key_t key;
613 int nsems;
614 int semflg;
615};
616#endif
617
618int
619semget(p, uap)
620 struct proc *p;
621 register struct semget_args *uap;
622{
623 int semid, eval;
624 int key = uap->key;
625 int nsems = uap->nsems;
626 int semflg = uap->semflg;
627 struct ucred *cred = p->p_ucred;
628
629#ifdef SEM_DEBUG
630 printf("semget(0x%x, %d, 0%o)\n", key, nsems, semflg);
631#endif
632
633 if (!jail_sysvipc_allowed && jailed(p->p_ucred))
634 return (ENOSYS);
635
636 if (key != IPC_PRIVATE) {
637 for (semid = 0; semid < seminfo.semmni; semid++) {
638 if ((sema[semid].sem_perm.mode & SEM_ALLOC) &&
639 sema[semid].sem_perm.key == key)
640 break;
641 }
642 if (semid < seminfo.semmni) {
643#ifdef SEM_DEBUG
644 printf("found public key\n");
645#endif
646 if ((eval = ipcperm(p, &sema[semid].sem_perm,
647 semflg & 0700)))
648 return(eval);
649 if (nsems > 0 && sema[semid].sem_nsems < nsems) {
650#ifdef SEM_DEBUG
651 printf("too small\n");
652#endif
653 return(EINVAL);
654 }
655 if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) {
656#ifdef SEM_DEBUG
657 printf("not exclusive\n");
658#endif
659 return(EEXIST);
660 }
661 goto found;
662 }
663 }
664
665#ifdef SEM_DEBUG
666 printf("need to allocate the semid_ds\n");
667#endif
668 if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) {
669 if (nsems <= 0 || nsems > seminfo.semmsl) {
670#ifdef SEM_DEBUG
671 printf("nsems out of range (0<%d<=%d)\n", nsems,
672 seminfo.semmsl);
673#endif
674 return(EINVAL);
675 }
676 if (nsems > seminfo.semmns - semtot) {
677#ifdef SEM_DEBUG
678 printf("not enough semaphores left (need %d, got %d)\n",
679 nsems, seminfo.semmns - semtot);
680#endif
681 return(ENOSPC);
682 }
683 for (semid = 0; semid < seminfo.semmni; semid++) {
684 if ((sema[semid].sem_perm.mode & SEM_ALLOC) == 0)
685 break;
686 }
687 if (semid == seminfo.semmni) {
688#ifdef SEM_DEBUG
689 printf("no more semid_ds's available\n");
690#endif
691 return(ENOSPC);
692 }
693#ifdef SEM_DEBUG
694 printf("semid %d is available\n", semid);
695#endif
696 sema[semid].sem_perm.key = key;
697 sema[semid].sem_perm.cuid = cred->cr_uid;
698 sema[semid].sem_perm.uid = cred->cr_uid;
699 sema[semid].sem_perm.cgid = cred->cr_gid;

--- 11 unchanged lines hidden (view full) ---

711#ifdef SEM_DEBUG
712 printf("sembase = 0x%x, next = 0x%x\n", sema[semid].sem_base,
713 &sem[semtot]);
714#endif
715 } else {
716#ifdef SEM_DEBUG
717 printf("didn't find it and wasn't asked to create it\n");
718#endif
719 return(ENOENT);
720 }
721
722found:
723 p->p_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].sem_perm);
724 return(0);
725}
726
727#ifndef _SYS_SYSPROTO_H_
728struct semop_args {
729 int semid;
730 struct sembuf *sops;
731 int nsops;
732};
733#endif
734
735int
736semop(p, uap)
737 struct proc *p;
738 register struct semop_args *uap;
739{
740 int semid = uap->semid;
741 int nsops = uap->nsops;
742 struct sembuf sops[MAX_SOPS];
743 register struct semid_ds *semaptr;
744 register struct sembuf *sopptr;
745 register struct sem *semptr;
746 struct sem_undo *suptr = NULL;
747 int i, j, eval;
748 int do_wakeup, do_undos;
749
750#ifdef SEM_DEBUG
751 printf("call to semop(%d, 0x%x, %d)\n", semid, sops, nsops);
752#endif
753
754 if (!jail_sysvipc_allowed && jailed(p->p_ucred))
755 return (ENOSYS);
756
757 semid = IPCID_TO_IX(semid); /* Convert back to zero origin */
758
759 if (semid < 0 || semid >= seminfo.semmsl)
760 return(EINVAL);
761
762 semaptr = &sema[semid];
763 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0)
764 return(EINVAL);
765 if (semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid))
766 return(EINVAL);
767
768 if ((eval = ipcperm(p, &semaptr->sem_perm, IPC_W))) {
769#ifdef SEM_DEBUG
770 printf("eval = %d from ipaccess\n", eval);
771#endif
772 return(eval);
773 }
774
775 if (nsops > MAX_SOPS) {
776#ifdef SEM_DEBUG
777 printf("too many sops (max=%d, nsops=%d)\n", MAX_SOPS, nsops);
778#endif
779 return(E2BIG);
780 }
781
782 if ((eval = copyin(uap->sops, &sops, nsops * sizeof(sops[0]))) != 0) {
783#ifdef SEM_DEBUG
784 printf("eval = %d from copyin(%08x, %08x, %d)\n", eval,
785 uap->sops, &sops, nsops * sizeof(sops[0]));
786#endif
787 return(eval);
788 }
789
790 /*
791 * Loop trying to satisfy the vector of requests.
792 * If we reach a point where we must wait, any requests already
793 * performed are rolled back and we go to sleep until some other
794 * process wakes us up. At this point, we start all over again.
795 *
796 * This ensures that from the perspective of other tasks, a set
797 * of requests is atomic (never partially satisfied).
798 */
799 do_undos = 0;
800
801 for (;;) {
802 do_wakeup = 0;
803
804 for (i = 0; i < nsops; i++) {
805 sopptr = &sops[i];
806
807 if (sopptr->sem_num >= semaptr->sem_nsems)
808 return(EFBIG);
809
810 semptr = &semaptr->sem_base[sopptr->sem_num];
811
812#ifdef SEM_DEBUG
813 printf("semop: semaptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n",
814 semaptr, semaptr->sem_base, semptr,
815 sopptr->sem_num, semptr->semval, sopptr->sem_op,
816 (sopptr->sem_flg & IPC_NOWAIT) ? "nowait" : "wait");

--- 44 unchanged lines hidden (view full) ---

861 for (j = 0; j < i; j++)
862 semaptr->sem_base[sops[j].sem_num].semval -=
863 sops[j].sem_op;
864
865 /*
866 * If the request that we couldn't satisfy has the
867 * NOWAIT flag set then return with EAGAIN.
868 */
869 if (sopptr->sem_flg & IPC_NOWAIT)
870 return(EAGAIN);
871
872 if (sopptr->sem_op == 0)
873 semptr->semzcnt++;
874 else
875 semptr->semncnt++;
876
877#ifdef SEM_DEBUG
878 printf("semop: good night!\n");
879#endif
880 eval = tsleep((caddr_t)semaptr, (PZERO - 4) | PCATCH,
881 "semwait", 0);
882#ifdef SEM_DEBUG
883 printf("semop: good morning (eval=%d)!\n", eval);
884#endif
885
886 suptr = NULL; /* sem_undo may have been reallocated */
887
888 if (eval != 0)
889 return(EINTR);
890#ifdef SEM_DEBUG
891 printf("semop: good morning!\n");
892#endif
893
894 /*
895 * Make sure that the semaphore still exists
896 */
897 if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ||
898 semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid))
899 return(EIDRM);
900
901 /*
902 * The semaphore is still alive. Readjust the count of
903 * waiting processes.
904 */
905 if (sopptr->sem_op == 0)
906 semptr->semzcnt--;
907 else

--- 12 unchanged lines hidden (view full) ---

920 */
921 int adjval;
922
923 if ((sops[i].sem_flg & SEM_UNDO) == 0)
924 continue;
925 adjval = sops[i].sem_op;
926 if (adjval == 0)
927 continue;
928 eval = semundo_adjust(p, &suptr, semid,
929 sops[i].sem_num, -adjval);
930 if (eval == 0)
931 continue;
932
933 /*
934 * Oh-Oh! We ran out of either sem_undo's or undo's.
935 * Rollback the adjustments to this point and then
936 * rollback the semaphore ups and down so we can return
937 * with an error with all structures restored. We
938 * rollback the undo's in the exact reverse order that

--- 11 unchanged lines hidden (view full) ---

950 panic("semop - can't undo undos");
951 }
952
953 for (j = 0; j < nsops; j++)
954 semaptr->sem_base[sops[j].sem_num].semval -=
955 sops[j].sem_op;
956
957#ifdef SEM_DEBUG
958 printf("eval = %d from semundo_adjust\n", eval);
959#endif
960 return(eval);
961 } /* loop through the sops */
962 } /* if (do_undos) */
963
964 /* We're definitely done - set the sempid's */
965 for (i = 0; i < nsops; i++) {
966 sopptr = &sops[i];
967 semptr = &semaptr->sem_base[sopptr->sem_num];
968 semptr->sempid = p->p_pid;

--- 8 unchanged lines hidden (view full) ---

977#ifdef SEM_DEBUG
978 printf("semop: back from wakeup\n");
979#endif
980 }
981#ifdef SEM_DEBUG
982 printf("semop: done\n");
983#endif
984 p->p_retval[0] = 0;
985 return(0);
986}
987
988/*
989 * Go through the undo structures for this process and apply the adjustments to
990 * semaphores.
991 */
992static void
993semexit_myhook(p)

--- 86 unchanged lines hidden ---