sysv_sem.c revision 88633
150477Speter/* $FreeBSD: head/sys/kern/sysv_sem.c 88633 2001-12-29 07:13:47Z alfred $ */ 22729Sdfr 32729Sdfr/* 42729Sdfr * Implementation of SVID semaphores 52729Sdfr * 62729Sdfr * Author: Daniel Boulet 72729Sdfr * 82729Sdfr * This software is provided ``AS IS'' without any warranties of any kind. 92729Sdfr */ 102729Sdfr 1159839Speter#include "opt_sysvipc.h" 1259839Speter 132729Sdfr#include <sys/param.h> 142729Sdfr#include <sys/systm.h> 1511626Sbde#include <sys/sysproto.h> 162729Sdfr#include <sys/kernel.h> 172729Sdfr#include <sys/proc.h> 1882607Sdillon#include <sys/lock.h> 1982607Sdillon#include <sys/mutex.h> 202729Sdfr#include <sys/sem.h> 2169449Salfred#include <sys/syscall.h> 2211626Sbde#include <sys/sysent.h> 2359839Speter#include <sys/sysctl.h> 2459839Speter#include <sys/malloc.h> 2568024Srwatson#include <sys/jail.h> 262729Sdfr 2759839Speterstatic MALLOC_DEFINE(M_SEM, "sem", "SVID compatible semaphores"); 2859839Speter 2969449Salfredstatic void seminit __P((void)); 3069449Salfredstatic int sysvsem_modload __P((struct module *, int, void *)); 3169449Salfredstatic int semunload __P((void)); 3269449Salfredstatic void semexit_myhook __P((struct proc *p)); 3377461Sddstatic int sysctl_sema __P((SYSCTL_HANDLER_ARGS)); 3410358Sjulian 3512866Speter#ifndef _SYS_SYSPROTO_H_ 3612866Speterstruct __semctl_args; 3783366Sjulianint __semctl __P((struct thread *td, struct __semctl_args *uap)); 3811626Sbdestruct semget_args; 3983366Sjulianint semget __P((struct thread *td, struct semget_args *uap)); 4011626Sbdestruct semop_args; 4183366Sjulianint semop __P((struct thread *td, struct semop_args *uap)); 4212866Speter#endif 4311626Sbde 4483366Sjulianstatic struct sem_undo *semu_alloc __P((struct thread *td)); 4583366Sjulianstatic int semundo_adjust __P((struct thread *td, struct sem_undo **supptr, 4612819Sphk int semid, int semnum, int adjval)); 4712819Sphkstatic void semundo_clear __P((int semid, int semnum)); 4811626Sbde 4911626Sbde/* XXX casting to (sy_call_t *) is bogus, as usual. */ 5012819Sphkstatic sy_call_t *semcalls[] = { 5112866Speter (sy_call_t *)__semctl, (sy_call_t *)semget, 5259828Speter (sy_call_t *)semop 5311626Sbde}; 5411626Sbde 5512819Sphkstatic int semtot = 0; 5659839Speterstatic struct semid_ds *sema; /* semaphore id pool */ 5759839Speterstatic struct sem *sem; /* semaphore pool */ 5859839Speterstatic struct sem_undo *semu_list; /* list of active undo structures */ 5959839Speterstatic int *semu; /* undo structure pool */ 602729Sdfr 6159839Speterstruct sem { 6259839Speter u_short semval; /* semaphore value */ 6359839Speter pid_t sempid; /* pid of last operation */ 6459839Speter u_short semncnt; /* # awaiting semval > cval */ 6559839Speter u_short semzcnt; /* # awaiting semval = 0 */ 6659839Speter}; 6759839Speter 6859839Speter/* 6959839Speter * Undo structure (one per process) 7059839Speter */ 7159839Speterstruct sem_undo { 7259839Speter struct sem_undo *un_next; /* ptr to next active undo structure */ 7359839Speter struct proc *un_proc; /* owner of this structure */ 7459839Speter short un_cnt; /* # of active entries */ 7559839Speter struct undo { 7659839Speter short un_adjval; /* adjust on exit values */ 7759839Speter short un_num; /* semaphore # */ 7859839Speter int un_id; /* semid */ 7959839Speter } un_ent[1]; /* undo entries */ 8059839Speter}; 8159839Speter 8259839Speter/* 8359839Speter * Configuration parameters 8459839Speter */ 8559839Speter#ifndef SEMMNI 8659839Speter#define SEMMNI 10 /* # of semaphore identifiers */ 8759839Speter#endif 8859839Speter#ifndef SEMMNS 8959839Speter#define SEMMNS 60 /* # of semaphores in system */ 9059839Speter#endif 9159839Speter#ifndef SEMUME 9259839Speter#define SEMUME 10 /* max # of undo entries per process */ 9359839Speter#endif 9459839Speter#ifndef SEMMNU 9559839Speter#define SEMMNU 30 /* # of undo structures in system */ 9659839Speter#endif 9759839Speter 9859839Speter/* shouldn't need tuning */ 9959839Speter#ifndef SEMMAP 10059839Speter#define SEMMAP 30 /* # of entries in semaphore map */ 10159839Speter#endif 10259839Speter#ifndef SEMMSL 10359839Speter#define SEMMSL SEMMNS /* max # of semaphores per id */ 10459839Speter#endif 10559839Speter#ifndef SEMOPM 10659839Speter#define SEMOPM 100 /* max # of operations per semop call */ 10759839Speter#endif 10859839Speter 10959839Speter#define SEMVMX 32767 /* semaphore maximum value */ 11059839Speter#define SEMAEM 16384 /* adjust on exit max value */ 11159839Speter 11259839Speter/* 11359839Speter * Due to the way semaphore memory is allocated, we have to ensure that 11459839Speter * SEMUSZ is properly aligned. 11559839Speter */ 11659839Speter 11759839Speter#define SEM_ALIGN(bytes) (((bytes) + (sizeof(long) - 1)) & ~(sizeof(long) - 1)) 11859839Speter 11959839Speter/* actual size of an undo structure */ 12059839Speter#define SEMUSZ SEM_ALIGN(offsetof(struct sem_undo, un_ent[SEMUME])) 12159839Speter 12259839Speter/* 12359839Speter * Macro to find a particular sem_undo vector 12459839Speter */ 12559839Speter#define SEMU(ix) ((struct sem_undo *)(((intptr_t)semu)+ix * seminfo.semusz)) 12659839Speter 12759839Speter/* 12859839Speter * semaphore info struct 12959839Speter */ 13059839Speterstruct seminfo seminfo = { 13159839Speter SEMMAP, /* # of entries in semaphore map */ 13259839Speter SEMMNI, /* # of semaphore identifiers */ 13359839Speter SEMMNS, /* # of semaphores in system */ 13459839Speter SEMMNU, /* # of undo structures in system */ 13559839Speter SEMMSL, /* max # of semaphores per id */ 13659839Speter SEMOPM, /* max # of operations per semop call */ 13759839Speter SEMUME, /* max # of undo entries per process */ 13859839Speter SEMUSZ, /* size in bytes of undo structure */ 13959839Speter SEMVMX, /* semaphore maximum value */ 14059839Speter SEMAEM /* adjust on exit max value */ 14159839Speter}; 14259839Speter 14359839SpeterSYSCTL_DECL(_kern_ipc); 14459839SpeterSYSCTL_INT(_kern_ipc, OID_AUTO, semmap, CTLFLAG_RW, &seminfo.semmap, 0, ""); 14559839SpeterSYSCTL_INT(_kern_ipc, OID_AUTO, semmni, CTLFLAG_RD, &seminfo.semmni, 0, ""); 14659839SpeterSYSCTL_INT(_kern_ipc, OID_AUTO, semmns, CTLFLAG_RD, &seminfo.semmns, 0, ""); 14759839SpeterSYSCTL_INT(_kern_ipc, OID_AUTO, semmnu, CTLFLAG_RD, &seminfo.semmnu, 0, ""); 14859839SpeterSYSCTL_INT(_kern_ipc, OID_AUTO, semmsl, CTLFLAG_RW, &seminfo.semmsl, 0, ""); 14959839SpeterSYSCTL_INT(_kern_ipc, OID_AUTO, semopm, CTLFLAG_RD, &seminfo.semopm, 0, ""); 15059839SpeterSYSCTL_INT(_kern_ipc, OID_AUTO, semume, CTLFLAG_RD, &seminfo.semume, 0, ""); 15159839SpeterSYSCTL_INT(_kern_ipc, OID_AUTO, semusz, CTLFLAG_RD, &seminfo.semusz, 0, ""); 15259839SpeterSYSCTL_INT(_kern_ipc, OID_AUTO, semvmx, CTLFLAG_RW, &seminfo.semvmx, 0, ""); 15359839SpeterSYSCTL_INT(_kern_ipc, OID_AUTO, semaem, CTLFLAG_RW, &seminfo.semaem, 0, ""); 15477461SddSYSCTL_PROC(_kern_ipc, OID_AUTO, sema, CTLFLAG_RD, 15577461Sdd NULL, 0, sysctl_sema, "", ""); 15659839Speter 15759839Speter#if 0 15859839SpeterRO seminfo.semmap /* SEMMAP unused */ 15959839SpeterRO seminfo.semmni 16059839SpeterRO seminfo.semmns 16159839SpeterRO seminfo.semmnu /* undo entries per system */ 16259839SpeterRW seminfo.semmsl 16359839SpeterRO seminfo.semopm /* SEMOPM unused */ 16459839SpeterRO seminfo.semume 16559839SpeterRO seminfo.semusz /* param - derived from SEMUME for per-proc sizeof */ 16659839SpeterRO seminfo.semvmx /* SEMVMX unused - user param */ 16759839SpeterRO seminfo.semaem /* SEMAEM unused - user param */ 16859839Speter#endif 16959839Speter 17059839Speterstatic void 17169449Salfredseminit(void) 1722729Sdfr{ 1732729Sdfr register int i; 1742729Sdfr 17583413Smr TUNABLE_INT_FETCH("kern.ipc.semmap", &seminfo.semmap); 17683413Smr TUNABLE_INT_FETCH("kern.ipc.semmni", &seminfo.semmni); 17783413Smr TUNABLE_INT_FETCH("kern.ipc.semmns", &seminfo.semmns); 17883413Smr TUNABLE_INT_FETCH("kern.ipc.semmnu", &seminfo.semmnu); 17983413Smr TUNABLE_INT_FETCH("kern.ipc.semmsl", &seminfo.semmsl); 18083413Smr TUNABLE_INT_FETCH("kern.ipc.semopm", &seminfo.semopm); 18183413Smr TUNABLE_INT_FETCH("kern.ipc.semume", &seminfo.semume); 18283413Smr TUNABLE_INT_FETCH("kern.ipc.semusz", &seminfo.semusz); 18383413Smr TUNABLE_INT_FETCH("kern.ipc.semvmx", &seminfo.semvmx); 18483413Smr TUNABLE_INT_FETCH("kern.ipc.semaem", &seminfo.semaem); 18583413Smr 18659839Speter sem = malloc(sizeof(struct sem) * seminfo.semmns, M_SEM, M_WAITOK); 18759839Speter if (sem == NULL) 18859839Speter panic("sem is NULL"); 18959839Speter sema = malloc(sizeof(struct semid_ds) * seminfo.semmni, M_SEM, M_WAITOK); 1902729Sdfr if (sema == NULL) 1912729Sdfr panic("sema is NULL"); 19259839Speter semu = malloc(seminfo.semmnu * seminfo.semusz, M_SEM, M_WAITOK); 1932729Sdfr if (semu == NULL) 1942729Sdfr panic("semu is NULL"); 1952729Sdfr 1962729Sdfr for (i = 0; i < seminfo.semmni; i++) { 1972729Sdfr sema[i].sem_base = 0; 1982729Sdfr sema[i].sem_perm.mode = 0; 1992729Sdfr } 2002729Sdfr for (i = 0; i < seminfo.semmnu; i++) { 2012729Sdfr register struct sem_undo *suptr = SEMU(i); 2022729Sdfr suptr->un_proc = NULL; 2032729Sdfr } 2042729Sdfr semu_list = NULL; 20569449Salfred semexit_hook = &semexit_myhook; 2062729Sdfr} 2072729Sdfr 20869449Salfredstatic int 20969449Salfredsemunload(void) 21069449Salfred{ 21169449Salfred 21269449Salfred if (semtot != 0) 21369449Salfred return (EBUSY); 21469449Salfred 21569449Salfred free(sem, M_SEM); 21669449Salfred free(sema, M_SEM); 21769449Salfred free(semu, M_SEM); 21869449Salfred semexit_hook = NULL; 21969449Salfred return (0); 22069449Salfred} 22169449Salfred 22269449Salfredstatic int 22369449Salfredsysvsem_modload(struct module *module, int cmd, void *arg) 22469449Salfred{ 22569449Salfred int error = 0; 22669449Salfred 22769449Salfred switch (cmd) { 22869449Salfred case MOD_LOAD: 22969449Salfred seminit(); 23069449Salfred break; 23169449Salfred case MOD_UNLOAD: 23269449Salfred error = semunload(); 23369449Salfred break; 23469449Salfred case MOD_SHUTDOWN: 23569449Salfred break; 23669449Salfred default: 23769449Salfred error = EINVAL; 23869449Salfred break; 23969449Salfred } 24069449Salfred return (error); 24169449Salfred} 24269449Salfred 24371038Sdesstatic moduledata_t sysvsem_mod = { 24471038Sdes "sysvsem", 24569449Salfred &sysvsem_modload, 24669449Salfred NULL 24769449Salfred}; 24869449Salfred 24988633SalfredSYSCALL_MODULE_HELPER(semsys); 25088633SalfredSYSCALL_MODULE_HELPER(__semctl); 25188633SalfredSYSCALL_MODULE_HELPER(semget); 25288633SalfredSYSCALL_MODULE_HELPER(semop); 25369449Salfred 25471038SdesDECLARE_MODULE(sysvsem, sysvsem_mod, 25569449Salfred SI_SUB_SYSV_SEM, SI_ORDER_FIRST); 25671038SdesMODULE_VERSION(sysvsem, 1); 25769449Salfred 2582729Sdfr/* 2592729Sdfr * Entry point for all SEM calls 26082607Sdillon * 26182607Sdillon * MPSAFE 2622729Sdfr */ 2632729Sdfrint 26483366Sjuliansemsys(td, uap) 26583366Sjulian struct thread *td; 26611626Sbde /* XXX actually varargs. */ 26711626Sbde struct semsys_args /* { 26811626Sbde u_int which; 26911626Sbde int a2; 27011626Sbde int a3; 27111626Sbde int a4; 27211626Sbde int a5; 27311626Sbde } */ *uap; 2742729Sdfr{ 27582607Sdillon int error; 2762729Sdfr 27782607Sdillon mtx_lock(&Giant); 27883366Sjulian if (!jail_sysvipc_allowed && jailed(td->td_proc->p_ucred)) { 27982607Sdillon error = ENOSYS; 28082607Sdillon goto done2; 28182607Sdillon } 28282607Sdillon if (uap->which >= sizeof(semcalls)/sizeof(semcalls[0])) { 28382607Sdillon error = EINVAL; 28482607Sdillon goto done2; 28582607Sdillon } 28683366Sjulian error = (*semcalls[uap->which])(td, &uap->a2); 28782607Sdillondone2: 28882607Sdillon mtx_unlock(&Giant); 28982607Sdillon return (error); 2902729Sdfr} 2912729Sdfr 2922729Sdfr/* 2932729Sdfr * Allocate a new sem_undo structure for a process 2942729Sdfr * (returns ptr to structure or NULL if no more room) 2952729Sdfr */ 2962729Sdfr 29712819Sphkstatic struct sem_undo * 29883366Sjuliansemu_alloc(td) 29983366Sjulian struct thread *td; 3002729Sdfr{ 3012729Sdfr register int i; 3022729Sdfr register struct sem_undo *suptr; 3032729Sdfr register struct sem_undo **supptr; 3042729Sdfr int attempt; 3052729Sdfr 3062729Sdfr /* 3072729Sdfr * Try twice to allocate something. 3082729Sdfr * (we'll purge any empty structures after the first pass so 3092729Sdfr * two passes are always enough) 3102729Sdfr */ 3112729Sdfr 3122729Sdfr for (attempt = 0; attempt < 2; attempt++) { 3132729Sdfr /* 3142729Sdfr * Look for a free structure. 3152729Sdfr * Fill it in and return it if we find one. 3162729Sdfr */ 3172729Sdfr 3182729Sdfr for (i = 0; i < seminfo.semmnu; i++) { 3192729Sdfr suptr = SEMU(i); 3202729Sdfr if (suptr->un_proc == NULL) { 3212729Sdfr suptr->un_next = semu_list; 3222729Sdfr semu_list = suptr; 3232729Sdfr suptr->un_cnt = 0; 32483366Sjulian suptr->un_proc = td->td_proc; 3252729Sdfr return(suptr); 3262729Sdfr } 3272729Sdfr } 3282729Sdfr 3292729Sdfr /* 3302729Sdfr * We didn't find a free one, if this is the first attempt 3312729Sdfr * then try to free some structures. 3322729Sdfr */ 3332729Sdfr 3342729Sdfr if (attempt == 0) { 3352729Sdfr /* All the structures are in use - try to free some */ 3362729Sdfr int did_something = 0; 3372729Sdfr 3382729Sdfr supptr = &semu_list; 3392729Sdfr while ((suptr = *supptr) != NULL) { 3402729Sdfr if (suptr->un_cnt == 0) { 3412729Sdfr suptr->un_proc = NULL; 3422729Sdfr *supptr = suptr->un_next; 3432729Sdfr did_something = 1; 3442729Sdfr } else 3452729Sdfr supptr = &(suptr->un_next); 3462729Sdfr } 3472729Sdfr 3482729Sdfr /* If we didn't free anything then just give-up */ 3492729Sdfr if (!did_something) 3502729Sdfr return(NULL); 3512729Sdfr } else { 3522729Sdfr /* 3532729Sdfr * The second pass failed even though we freed 3542729Sdfr * something after the first pass! 3552729Sdfr * This is IMPOSSIBLE! 3562729Sdfr */ 3572729Sdfr panic("semu_alloc - second attempt failed"); 3582729Sdfr } 3592729Sdfr } 3602836Sdg return (NULL); 3612729Sdfr} 3622729Sdfr 3632729Sdfr/* 3642729Sdfr * Adjust a particular entry for a particular proc 3652729Sdfr */ 3662729Sdfr 36712819Sphkstatic int 36883366Sjuliansemundo_adjust(td, supptr, semid, semnum, adjval) 36983366Sjulian register struct thread *td; 3702729Sdfr struct sem_undo **supptr; 3712729Sdfr int semid, semnum; 3722729Sdfr int adjval; 3732729Sdfr{ 37483366Sjulian struct proc *p = td->td_proc; 3752729Sdfr register struct sem_undo *suptr; 3762729Sdfr register struct undo *sunptr; 3772729Sdfr int i; 3782729Sdfr 3792729Sdfr /* Look for and remember the sem_undo if the caller doesn't provide 3802729Sdfr it */ 3812729Sdfr 3822729Sdfr suptr = *supptr; 3832729Sdfr if (suptr == NULL) { 3842729Sdfr for (suptr = semu_list; suptr != NULL; 3852729Sdfr suptr = suptr->un_next) { 3862729Sdfr if (suptr->un_proc == p) { 3872729Sdfr *supptr = suptr; 3882729Sdfr break; 3892729Sdfr } 3902729Sdfr } 3912729Sdfr if (suptr == NULL) { 3922729Sdfr if (adjval == 0) 3932729Sdfr return(0); 39483366Sjulian suptr = semu_alloc(td); 3952729Sdfr if (suptr == NULL) 3962729Sdfr return(ENOSPC); 3972729Sdfr *supptr = suptr; 3982729Sdfr } 3992729Sdfr } 4002729Sdfr 4012729Sdfr /* 4022729Sdfr * Look for the requested entry and adjust it (delete if adjval becomes 4032729Sdfr * 0). 4042729Sdfr */ 4052729Sdfr sunptr = &suptr->un_ent[0]; 4062729Sdfr for (i = 0; i < suptr->un_cnt; i++, sunptr++) { 4072729Sdfr if (sunptr->un_id != semid || sunptr->un_num != semnum) 4082729Sdfr continue; 40984789Smr if (adjval != 0) { 41084789Smr adjval += sunptr->un_adjval; 41184789Smr if (adjval > seminfo.semaem || adjval < -seminfo.semaem) 41284789Smr return (ERANGE); 41384789Smr } 41484789Smr sunptr->un_adjval = adjval; 4152729Sdfr if (sunptr->un_adjval == 0) { 4162729Sdfr suptr->un_cnt--; 4172729Sdfr if (i < suptr->un_cnt) 4182729Sdfr suptr->un_ent[i] = 4192729Sdfr suptr->un_ent[suptr->un_cnt]; 4202729Sdfr } 4212729Sdfr return(0); 4222729Sdfr } 4232729Sdfr 4242729Sdfr /* Didn't find the right entry - create it */ 4252729Sdfr if (adjval == 0) 4262729Sdfr return(0); 42784789Smr if (adjval > seminfo.semaem || adjval < -seminfo.semaem) 42884789Smr return (ERANGE); 42941774Sdillon if (suptr->un_cnt != seminfo.semume) { 4302729Sdfr sunptr = &suptr->un_ent[suptr->un_cnt]; 4312729Sdfr suptr->un_cnt++; 4322729Sdfr sunptr->un_adjval = adjval; 4332729Sdfr sunptr->un_id = semid; sunptr->un_num = semnum; 4342729Sdfr } else 4352729Sdfr return(EINVAL); 4362729Sdfr return(0); 4372729Sdfr} 4382729Sdfr 43912819Sphkstatic void 4402729Sdfrsemundo_clear(semid, semnum) 4412729Sdfr int semid, semnum; 4422729Sdfr{ 4432729Sdfr register struct sem_undo *suptr; 4442729Sdfr 4452729Sdfr for (suptr = semu_list; suptr != NULL; suptr = suptr->un_next) { 4462729Sdfr register struct undo *sunptr = &suptr->un_ent[0]; 4472729Sdfr register int i = 0; 4482729Sdfr 4492729Sdfr while (i < suptr->un_cnt) { 4502729Sdfr if (sunptr->un_id == semid) { 4512729Sdfr if (semnum == -1 || sunptr->un_num == semnum) { 4522729Sdfr suptr->un_cnt--; 4532729Sdfr if (i < suptr->un_cnt) { 4542729Sdfr suptr->un_ent[i] = 4552729Sdfr suptr->un_ent[suptr->un_cnt]; 4562729Sdfr continue; 4572729Sdfr } 4582729Sdfr } 4592729Sdfr if (semnum != -1) 4602729Sdfr break; 4612729Sdfr } 4622729Sdfr i++, sunptr++; 4632729Sdfr } 4642729Sdfr } 4652729Sdfr} 4662729Sdfr 46712866Speter/* 46812866Speter * Note that the user-mode half of this passes a union, not a pointer 46912866Speter */ 47012866Speter#ifndef _SYS_SYSPROTO_H_ 47112866Speterstruct __semctl_args { 4722729Sdfr int semid; 4732729Sdfr int semnum; 4742729Sdfr int cmd; 4752729Sdfr union semun *arg; 4762729Sdfr}; 47712866Speter#endif 4782729Sdfr 47982607Sdillon/* 48082607Sdillon * MPSAFE 48182607Sdillon */ 48212866Speterint 48383366Sjulian__semctl(td, uap) 48483366Sjulian struct thread *td; 48512866Speter register struct __semctl_args *uap; 4862729Sdfr{ 4872729Sdfr int semid = uap->semid; 4882729Sdfr int semnum = uap->semnum; 4892729Sdfr int cmd = uap->cmd; 4902729Sdfr union semun *arg = uap->arg; 4912729Sdfr union semun real_arg; 49283366Sjulian struct ucred *cred = td->td_proc->p_ucred; 49382607Sdillon int i, rval, error; 4942729Sdfr struct semid_ds sbuf; 4952729Sdfr register struct semid_ds *semaptr; 49684789Smr u_short usval; 4972729Sdfr 4982729Sdfr#ifdef SEM_DEBUG 4992729Sdfr printf("call to semctl(%d, %d, %d, 0x%x)\n", semid, semnum, cmd, arg); 5002729Sdfr#endif 50182607Sdillon mtx_lock(&Giant); 50283366Sjulian if (!jail_sysvipc_allowed && jailed(td->td_proc->p_ucred)) { 50382607Sdillon error = ENOSYS; 50482607Sdillon goto done2; 50582607Sdillon } 50668024Srwatson 50783414Smr switch(cmd) { 50883414Smr case SEM_STAT: 50983414Smr if (semid < 0 || semid >= seminfo.semmsl) 51083414Smr return(EINVAL); 51183414Smr semaptr = &sema[semid]; 51283414Smr if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ) 51383414Smr return(EINVAL); 51483414Smr if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R))) 51583414Smr return(error); 51683414Smr if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0) 51783414Smr return(error); 51883414Smr error = copyout((caddr_t)semaptr, real_arg.buf, 51983414Smr sizeof(struct semid_ds)); 52083414Smr rval = IXSEQ_TO_IPCID(semid,semaptr->sem_perm); 52183414Smr if (error == 0) 52283414Smr td->td_retval[0] = rval; 52383414Smr goto done2; 52483414Smr } 52583414Smr 5262729Sdfr semid = IPCID_TO_IX(semid); 52782607Sdillon if (semid < 0 || semid >= seminfo.semmsl) { 52882607Sdillon error = EINVAL; 52982607Sdillon goto done2; 53082607Sdillon } 5312729Sdfr 5322729Sdfr semaptr = &sema[semid]; 5332729Sdfr if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 || 53482607Sdillon semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) { 53582607Sdillon error = EINVAL; 53682607Sdillon goto done2; 53782607Sdillon } 5382729Sdfr 53982607Sdillon error = 0; 5402729Sdfr rval = 0; 5412729Sdfr 5422729Sdfr switch (cmd) { 5432729Sdfr case IPC_RMID: 54483366Sjulian if ((error = ipcperm(td, &semaptr->sem_perm, IPC_M))) 54582607Sdillon goto done2; 5462729Sdfr semaptr->sem_perm.cuid = cred->cr_uid; 5472729Sdfr semaptr->sem_perm.uid = cred->cr_uid; 5482729Sdfr semtot -= semaptr->sem_nsems; 5492729Sdfr for (i = semaptr->sem_base - sem; i < semtot; i++) 5502729Sdfr sem[i] = sem[i + semaptr->sem_nsems]; 5512729Sdfr for (i = 0; i < seminfo.semmni; i++) { 5522729Sdfr if ((sema[i].sem_perm.mode & SEM_ALLOC) && 5532729Sdfr sema[i].sem_base > semaptr->sem_base) 5542729Sdfr sema[i].sem_base -= semaptr->sem_nsems; 5552729Sdfr } 5562729Sdfr semaptr->sem_perm.mode = 0; 5572729Sdfr semundo_clear(semid, -1); 5582729Sdfr wakeup((caddr_t)semaptr); 5592729Sdfr break; 5602729Sdfr 5612729Sdfr case IPC_SET: 56283366Sjulian if ((error = ipcperm(td, &semaptr->sem_perm, IPC_M))) 56382607Sdillon goto done2; 56482607Sdillon if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0) 56582607Sdillon goto done2; 56682607Sdillon if ((error = copyin(real_arg.buf, (caddr_t)&sbuf, 56782607Sdillon sizeof(sbuf))) != 0) { 56882607Sdillon goto done2; 56982607Sdillon } 5702729Sdfr semaptr->sem_perm.uid = sbuf.sem_perm.uid; 5712729Sdfr semaptr->sem_perm.gid = sbuf.sem_perm.gid; 5722729Sdfr semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777) | 5732729Sdfr (sbuf.sem_perm.mode & 0777); 57434961Sphk semaptr->sem_ctime = time_second; 5752729Sdfr break; 5762729Sdfr 5772729Sdfr case IPC_STAT: 57883366Sjulian if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R))) 57982607Sdillon goto done2; 58082607Sdillon if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0) 58182607Sdillon goto done2; 58282607Sdillon error = copyout((caddr_t)semaptr, real_arg.buf, 58382607Sdillon sizeof(struct semid_ds)); 5842729Sdfr break; 5852729Sdfr 5862729Sdfr case GETNCNT: 58783366Sjulian if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R))) 58882607Sdillon goto done2; 58982607Sdillon if (semnum < 0 || semnum >= semaptr->sem_nsems) { 59082607Sdillon error = EINVAL; 59182607Sdillon goto done2; 59282607Sdillon } 5932729Sdfr rval = semaptr->sem_base[semnum].semncnt; 5942729Sdfr break; 5952729Sdfr 5962729Sdfr case GETPID: 59783366Sjulian if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R))) 59882607Sdillon goto done2; 59982607Sdillon if (semnum < 0 || semnum >= semaptr->sem_nsems) { 60082607Sdillon error = EINVAL; 60182607Sdillon goto done2; 60282607Sdillon } 6032729Sdfr rval = semaptr->sem_base[semnum].sempid; 6042729Sdfr break; 6052729Sdfr 6062729Sdfr case GETVAL: 60783366Sjulian if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R))) 60882607Sdillon goto done2; 60982607Sdillon if (semnum < 0 || semnum >= semaptr->sem_nsems) { 61082607Sdillon error = EINVAL; 61182607Sdillon goto done2; 61282607Sdillon } 6132729Sdfr rval = semaptr->sem_base[semnum].semval; 6142729Sdfr break; 6152729Sdfr 6162729Sdfr case GETALL: 61783366Sjulian if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R))) 61882607Sdillon goto done2; 61982607Sdillon if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0) 62082607Sdillon goto done2; 6212729Sdfr for (i = 0; i < semaptr->sem_nsems; i++) { 62282607Sdillon error = copyout((caddr_t)&semaptr->sem_base[i].semval, 6232729Sdfr &real_arg.array[i], sizeof(real_arg.array[0])); 62482607Sdillon if (error != 0) 6252729Sdfr break; 6262729Sdfr } 6272729Sdfr break; 6282729Sdfr 6292729Sdfr case GETZCNT: 63083366Sjulian if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R))) 63182607Sdillon goto done2; 63282607Sdillon if (semnum < 0 || semnum >= semaptr->sem_nsems) { 63382607Sdillon error = EINVAL; 63482607Sdillon goto done2; 63582607Sdillon } 6362729Sdfr rval = semaptr->sem_base[semnum].semzcnt; 6372729Sdfr break; 6382729Sdfr 6392729Sdfr case SETVAL: 64083366Sjulian if ((error = ipcperm(td, &semaptr->sem_perm, IPC_W))) 64182607Sdillon goto done2; 64282607Sdillon if (semnum < 0 || semnum >= semaptr->sem_nsems) { 64382607Sdillon error = EINVAL; 64482607Sdillon goto done2; 64582607Sdillon } 64682607Sdillon if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0) 64782607Sdillon goto done2; 64884789Smr if (real_arg.val < 0 || real_arg.val > seminfo.semvmx) { 64984789Smr error = ERANGE; 65084789Smr goto done2; 65184789Smr } 6522729Sdfr semaptr->sem_base[semnum].semval = real_arg.val; 6532729Sdfr semundo_clear(semid, semnum); 6542729Sdfr wakeup((caddr_t)semaptr); 6552729Sdfr break; 6562729Sdfr 6572729Sdfr case SETALL: 65883366Sjulian if ((error = ipcperm(td, &semaptr->sem_perm, IPC_W))) 65982607Sdillon goto done2; 66082607Sdillon if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0) 66182607Sdillon goto done2; 6622729Sdfr for (i = 0; i < semaptr->sem_nsems; i++) { 66382607Sdillon error = copyin(&real_arg.array[i], 66484789Smr (caddr_t)&usval, sizeof(real_arg.array[0])); 66582607Sdillon if (error != 0) 6662729Sdfr break; 66784789Smr if (usval > seminfo.semvmx) { 66884789Smr error = ERANGE; 66984789Smr break; 67084789Smr } 67184789Smr semaptr->sem_base[i].semval = usval; 6722729Sdfr } 6732729Sdfr semundo_clear(semid, -1); 6742729Sdfr wakeup((caddr_t)semaptr); 6752729Sdfr break; 6762729Sdfr 6772729Sdfr default: 67882607Sdillon error = EINVAL; 67982607Sdillon break; 6802729Sdfr } 6812729Sdfr 68282607Sdillon if (error == 0) 68383366Sjulian td->td_retval[0] = rval; 68482607Sdillondone2: 68582607Sdillon mtx_unlock(&Giant); 68682607Sdillon return(error); 6872729Sdfr} 6882729Sdfr 68912866Speter#ifndef _SYS_SYSPROTO_H_ 6902729Sdfrstruct semget_args { 6912729Sdfr key_t key; 6922729Sdfr int nsems; 6932729Sdfr int semflg; 6942729Sdfr}; 69512866Speter#endif 6962729Sdfr 69782607Sdillon/* 69882607Sdillon * MPSAFE 69982607Sdillon */ 70012866Speterint 70183366Sjuliansemget(td, uap) 70283366Sjulian struct thread *td; 7032729Sdfr register struct semget_args *uap; 7042729Sdfr{ 70582607Sdillon int semid, error = 0; 7062729Sdfr int key = uap->key; 7072729Sdfr int nsems = uap->nsems; 7082729Sdfr int semflg = uap->semflg; 70983366Sjulian struct ucred *cred = td->td_proc->p_ucred; 7102729Sdfr 7112729Sdfr#ifdef SEM_DEBUG 7122729Sdfr printf("semget(0x%x, %d, 0%o)\n", key, nsems, semflg); 7132729Sdfr#endif 71482607Sdillon mtx_lock(&Giant); 71583366Sjulian if (!jail_sysvipc_allowed && jailed(td->td_proc->p_ucred)) { 71682607Sdillon error = ENOSYS; 71782607Sdillon goto done2; 71882607Sdillon } 71968024Srwatson 7202729Sdfr if (key != IPC_PRIVATE) { 7212729Sdfr for (semid = 0; semid < seminfo.semmni; semid++) { 7222729Sdfr if ((sema[semid].sem_perm.mode & SEM_ALLOC) && 7232729Sdfr sema[semid].sem_perm.key == key) 7242729Sdfr break; 7252729Sdfr } 7262729Sdfr if (semid < seminfo.semmni) { 7272729Sdfr#ifdef SEM_DEBUG 7282729Sdfr printf("found public key\n"); 7292729Sdfr#endif 73083366Sjulian if ((error = ipcperm(td, &sema[semid].sem_perm, 73182607Sdillon semflg & 0700))) { 73282607Sdillon goto done2; 73382607Sdillon } 7342729Sdfr if (nsems > 0 && sema[semid].sem_nsems < nsems) { 7352729Sdfr#ifdef SEM_DEBUG 7362729Sdfr printf("too small\n"); 7372729Sdfr#endif 73882607Sdillon error = EINVAL; 73982607Sdillon goto done2; 7402729Sdfr } 7412729Sdfr if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) { 7422729Sdfr#ifdef SEM_DEBUG 7432729Sdfr printf("not exclusive\n"); 7442729Sdfr#endif 74582607Sdillon error = EEXIST; 74682607Sdillon goto done2; 7472729Sdfr } 7482729Sdfr goto found; 7492729Sdfr } 7502729Sdfr } 7512729Sdfr 7522729Sdfr#ifdef SEM_DEBUG 7532729Sdfr printf("need to allocate the semid_ds\n"); 7542729Sdfr#endif 7552729Sdfr if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) { 7562729Sdfr if (nsems <= 0 || nsems > seminfo.semmsl) { 7572729Sdfr#ifdef SEM_DEBUG 7582729Sdfr printf("nsems out of range (0<%d<=%d)\n", nsems, 7592729Sdfr seminfo.semmsl); 7602729Sdfr#endif 76182607Sdillon error = EINVAL; 76282607Sdillon goto done2; 7632729Sdfr } 7642729Sdfr if (nsems > seminfo.semmns - semtot) { 7652729Sdfr#ifdef SEM_DEBUG 7662729Sdfr printf("not enough semaphores left (need %d, got %d)\n", 7672729Sdfr nsems, seminfo.semmns - semtot); 7682729Sdfr#endif 76982607Sdillon error = ENOSPC; 77082607Sdillon goto done2; 7712729Sdfr } 7722729Sdfr for (semid = 0; semid < seminfo.semmni; semid++) { 7732729Sdfr if ((sema[semid].sem_perm.mode & SEM_ALLOC) == 0) 7742729Sdfr break; 7752729Sdfr } 7762729Sdfr if (semid == seminfo.semmni) { 7772729Sdfr#ifdef SEM_DEBUG 7782729Sdfr printf("no more semid_ds's available\n"); 7792729Sdfr#endif 78082607Sdillon error = ENOSPC; 78182607Sdillon goto done2; 7822729Sdfr } 7832729Sdfr#ifdef SEM_DEBUG 7842729Sdfr printf("semid %d is available\n", semid); 7852729Sdfr#endif 7862729Sdfr sema[semid].sem_perm.key = key; 7872729Sdfr sema[semid].sem_perm.cuid = cred->cr_uid; 7882729Sdfr sema[semid].sem_perm.uid = cred->cr_uid; 7892729Sdfr sema[semid].sem_perm.cgid = cred->cr_gid; 7902729Sdfr sema[semid].sem_perm.gid = cred->cr_gid; 7912729Sdfr sema[semid].sem_perm.mode = (semflg & 0777) | SEM_ALLOC; 7922729Sdfr sema[semid].sem_perm.seq = 7932729Sdfr (sema[semid].sem_perm.seq + 1) & 0x7fff; 7942729Sdfr sema[semid].sem_nsems = nsems; 7952729Sdfr sema[semid].sem_otime = 0; 79634961Sphk sema[semid].sem_ctime = time_second; 7972729Sdfr sema[semid].sem_base = &sem[semtot]; 7982729Sdfr semtot += nsems; 7992729Sdfr bzero(sema[semid].sem_base, 8002729Sdfr sizeof(sema[semid].sem_base[0])*nsems); 8012729Sdfr#ifdef SEM_DEBUG 8022729Sdfr printf("sembase = 0x%x, next = 0x%x\n", sema[semid].sem_base, 8032729Sdfr &sem[semtot]); 8042729Sdfr#endif 8052729Sdfr } else { 8062729Sdfr#ifdef SEM_DEBUG 8072729Sdfr printf("didn't find it and wasn't asked to create it\n"); 8082729Sdfr#endif 80982607Sdillon error = ENOENT; 81082607Sdillon goto done2; 8112729Sdfr } 8122729Sdfr 8132729Sdfrfound: 81483366Sjulian td->td_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].sem_perm); 81582607Sdillondone2: 81682607Sdillon mtx_unlock(&Giant); 81782607Sdillon return (error); 8182729Sdfr} 8192729Sdfr 82012866Speter#ifndef _SYS_SYSPROTO_H_ 8212729Sdfrstruct semop_args { 8222729Sdfr int semid; 8232729Sdfr struct sembuf *sops; 82483292Sdd u_int nsops; 8252729Sdfr}; 82612866Speter#endif 8272729Sdfr 82882607Sdillon/* 82982607Sdillon * MPSAFE 83082607Sdillon */ 83112866Speterint 83283366Sjuliansemop(td, uap) 83383366Sjulian struct thread *td; 8342729Sdfr register struct semop_args *uap; 8352729Sdfr{ 8362729Sdfr int semid = uap->semid; 83783292Sdd u_int nsops = uap->nsops; 83884789Smr struct sembuf *sops = NULL; 8392729Sdfr register struct semid_ds *semaptr; 8402729Sdfr register struct sembuf *sopptr; 8412729Sdfr register struct sem *semptr; 84284789Smr struct sem_undo *suptr; 84384789Smr int i, j, error; 8443308Sphk int do_wakeup, do_undos; 8452729Sdfr 8462729Sdfr#ifdef SEM_DEBUG 84783292Sdd printf("call to semop(%d, 0x%x, %u)\n", semid, sops, nsops); 8482729Sdfr#endif 8492729Sdfr 85082607Sdillon mtx_lock(&Giant); 85183366Sjulian if (!jail_sysvipc_allowed && jailed(td->td_proc->p_ucred)) { 85282607Sdillon error = ENOSYS; 85382607Sdillon goto done2; 85482607Sdillon } 85582607Sdillon 8562729Sdfr semid = IPCID_TO_IX(semid); /* Convert back to zero origin */ 8572729Sdfr 85882607Sdillon if (semid < 0 || semid >= seminfo.semmsl) { 85982607Sdillon error = EINVAL; 86082607Sdillon goto done2; 86182607Sdillon } 8622729Sdfr 8632729Sdfr semaptr = &sema[semid]; 86482607Sdillon if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0) { 86582607Sdillon error = EINVAL; 86682607Sdillon goto done2; 86782607Sdillon } 86882607Sdillon if (semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) { 86982607Sdillon error = EINVAL; 87082607Sdillon goto done2; 87182607Sdillon } 87284789Smr if (nsops > seminfo.semopm) { 8732729Sdfr#ifdef SEM_DEBUG 87484789Smr printf("too many sops (max=%d, nsops=%d)\n", seminfo.semopm, 87584789Smr nsops); 8762729Sdfr#endif 87784789Smr error = E2BIG; 87882607Sdillon goto done2; 8792729Sdfr } 8802729Sdfr 88184789Smr /* Allocate memory for sem_ops */ 88284789Smr sops = malloc(nsops * sizeof(sops[0]), M_SEM, M_WAITOK); 88384789Smr if (!sops) 88484789Smr panic("Failed to allocate %d sem_ops", nsops); 88584789Smr 88684789Smr if ((error = copyin(uap->sops, sops, nsops * sizeof(sops[0]))) != 0) { 8872729Sdfr#ifdef SEM_DEBUG 88884789Smr printf("error = %d from copyin(%08x, %08x, %d)\n", error, 88984789Smr uap->sops, sops, nsops * sizeof(sops[0])); 8902729Sdfr#endif 89182607Sdillon goto done2; 8922729Sdfr } 8932729Sdfr 89484789Smr /* 89584789Smr * Initial pass thru sops to see what permissions are needed. 89684789Smr * Also perform any checks that don't need repeating on each 89784789Smr * attempt to satisfy the request vector. 89884789Smr */ 89984789Smr j = 0; /* permission needed */ 90084789Smr do_undos = 0; 90184789Smr for (i = 0; i < nsops; i++) { 90284789Smr sopptr = &sops[i]; 90384789Smr if (sopptr->sem_num >= semaptr->sem_nsems) { 90484789Smr error = EFBIG; 90584789Smr goto done2; 90684789Smr } 90784789Smr if (sopptr->sem_flg & SEM_UNDO && sopptr->sem_op != 0) 90884789Smr do_undos = 1; 90984789Smr j |= (sopptr->sem_op == 0) ? SEM_R : SEM_A; 91084789Smr } 91184789Smr 91284789Smr if ((error = ipcperm(td, &semaptr->sem_perm, j))) { 9132729Sdfr#ifdef SEM_DEBUG 91484789Smr printf("error = %d from ipaccess\n", error); 9152729Sdfr#endif 91682607Sdillon goto done2; 9172729Sdfr } 9182729Sdfr 9198876Srgrimes /* 9202729Sdfr * Loop trying to satisfy the vector of requests. 9212729Sdfr * If we reach a point where we must wait, any requests already 9222729Sdfr * performed are rolled back and we go to sleep until some other 9232729Sdfr * process wakes us up. At this point, we start all over again. 9242729Sdfr * 9252729Sdfr * This ensures that from the perspective of other tasks, a set 9262729Sdfr * of requests is atomic (never partially satisfied). 9272729Sdfr */ 9282729Sdfr for (;;) { 9292729Sdfr do_wakeup = 0; 93084789Smr error = 0; /* error return if necessary */ 9312729Sdfr 9322729Sdfr for (i = 0; i < nsops; i++) { 9332729Sdfr sopptr = &sops[i]; 9342729Sdfr semptr = &semaptr->sem_base[sopptr->sem_num]; 9352729Sdfr 9362729Sdfr#ifdef SEM_DEBUG 9372729Sdfr printf("semop: semaptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n", 9382729Sdfr semaptr, semaptr->sem_base, semptr, 9392729Sdfr sopptr->sem_num, semptr->semval, sopptr->sem_op, 9402729Sdfr (sopptr->sem_flg & IPC_NOWAIT) ? "nowait" : "wait"); 9412729Sdfr#endif 9422729Sdfr 9432729Sdfr if (sopptr->sem_op < 0) { 9442729Sdfr if (semptr->semval + sopptr->sem_op < 0) { 9452729Sdfr#ifdef SEM_DEBUG 9462729Sdfr printf("semop: can't do it now\n"); 9472729Sdfr#endif 9482729Sdfr break; 9492729Sdfr } else { 9502729Sdfr semptr->semval += sopptr->sem_op; 9512729Sdfr if (semptr->semval == 0 && 9522729Sdfr semptr->semzcnt > 0) 9532729Sdfr do_wakeup = 1; 9542729Sdfr } 9552729Sdfr } else if (sopptr->sem_op == 0) { 95684789Smr if (semptr->semval != 0) { 9572729Sdfr#ifdef SEM_DEBUG 9582729Sdfr printf("semop: not zero now\n"); 9592729Sdfr#endif 9602729Sdfr break; 9612729Sdfr } 96284789Smr } else if (semptr->semval + sopptr->sem_op > 96384789Smr seminfo.semvmx) { 96484789Smr error = ERANGE; 96584789Smr break; 9662729Sdfr } else { 9672729Sdfr if (semptr->semncnt > 0) 9682729Sdfr do_wakeup = 1; 9692729Sdfr semptr->semval += sopptr->sem_op; 9702729Sdfr } 9712729Sdfr } 9722729Sdfr 9732729Sdfr /* 9742729Sdfr * Did we get through the entire vector? 9752729Sdfr */ 9762729Sdfr if (i >= nsops) 9772729Sdfr goto done; 9782729Sdfr 9792729Sdfr /* 9802729Sdfr * No ... rollback anything that we've already done 9812729Sdfr */ 9822729Sdfr#ifdef SEM_DEBUG 9832729Sdfr printf("semop: rollback 0 through %d\n", i-1); 9842729Sdfr#endif 9852729Sdfr for (j = 0; j < i; j++) 9862729Sdfr semaptr->sem_base[sops[j].sem_num].semval -= 9872729Sdfr sops[j].sem_op; 9882729Sdfr 98984789Smr /* If we detected an error, return it */ 99084789Smr if (error != 0) 99184789Smr goto done2; 99284789Smr 9932729Sdfr /* 9942729Sdfr * If the request that we couldn't satisfy has the 9952729Sdfr * NOWAIT flag set then return with EAGAIN. 9962729Sdfr */ 99782607Sdillon if (sopptr->sem_flg & IPC_NOWAIT) { 99882607Sdillon error = EAGAIN; 99982607Sdillon goto done2; 100082607Sdillon } 10012729Sdfr 10022729Sdfr if (sopptr->sem_op == 0) 10032729Sdfr semptr->semzcnt++; 10042729Sdfr else 10052729Sdfr semptr->semncnt++; 10062729Sdfr 10072729Sdfr#ifdef SEM_DEBUG 10082729Sdfr printf("semop: good night!\n"); 10092729Sdfr#endif 101082607Sdillon error = tsleep((caddr_t)semaptr, (PZERO - 4) | PCATCH, 10112729Sdfr "semwait", 0); 10122729Sdfr#ifdef SEM_DEBUG 101382607Sdillon printf("semop: good morning (error=%d)!\n", error); 10142729Sdfr#endif 10152729Sdfr 101682607Sdillon if (error != 0) { 101782607Sdillon error = EINTR; 101882607Sdillon goto done2; 101982607Sdillon } 10202729Sdfr#ifdef SEM_DEBUG 10212729Sdfr printf("semop: good morning!\n"); 10222729Sdfr#endif 10232729Sdfr 10242729Sdfr /* 10252729Sdfr * Make sure that the semaphore still exists 10262729Sdfr */ 10272729Sdfr if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 || 102882607Sdillon semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) { 102982607Sdillon error = EIDRM; 103082607Sdillon goto done2; 103182607Sdillon } 10322729Sdfr 10332729Sdfr /* 10342729Sdfr * The semaphore is still alive. Readjust the count of 10352729Sdfr * waiting processes. 10362729Sdfr */ 10372729Sdfr if (sopptr->sem_op == 0) 10382729Sdfr semptr->semzcnt--; 10392729Sdfr else 10402729Sdfr semptr->semncnt--; 10412729Sdfr } 10422729Sdfr 10432729Sdfrdone: 10442729Sdfr /* 10452729Sdfr * Process any SEM_UNDO requests. 10462729Sdfr */ 10472729Sdfr if (do_undos) { 104884789Smr suptr = NULL; 10492729Sdfr for (i = 0; i < nsops; i++) { 10502729Sdfr /* 10512729Sdfr * We only need to deal with SEM_UNDO's for non-zero 10522729Sdfr * op's. 10532729Sdfr */ 10542729Sdfr int adjval; 10552729Sdfr 10562729Sdfr if ((sops[i].sem_flg & SEM_UNDO) == 0) 10572729Sdfr continue; 10582729Sdfr adjval = sops[i].sem_op; 10592729Sdfr if (adjval == 0) 10602729Sdfr continue; 106183366Sjulian error = semundo_adjust(td, &suptr, semid, 10622729Sdfr sops[i].sem_num, -adjval); 106382607Sdillon if (error == 0) 10642729Sdfr continue; 10652729Sdfr 10662729Sdfr /* 10672729Sdfr * Oh-Oh! We ran out of either sem_undo's or undo's. 10682729Sdfr * Rollback the adjustments to this point and then 10692729Sdfr * rollback the semaphore ups and down so we can return 10702729Sdfr * with an error with all structures restored. We 10712729Sdfr * rollback the undo's in the exact reverse order that 10722729Sdfr * we applied them. This guarantees that we won't run 10732729Sdfr * out of space as we roll things back out. 10742729Sdfr */ 10752729Sdfr for (j = i - 1; j >= 0; j--) { 10762729Sdfr if ((sops[j].sem_flg & SEM_UNDO) == 0) 10772729Sdfr continue; 10782729Sdfr adjval = sops[j].sem_op; 10792729Sdfr if (adjval == 0) 10802729Sdfr continue; 108183366Sjulian if (semundo_adjust(td, &suptr, semid, 10822729Sdfr sops[j].sem_num, adjval) != 0) 10832729Sdfr panic("semop - can't undo undos"); 10842729Sdfr } 10852729Sdfr 10862729Sdfr for (j = 0; j < nsops; j++) 10872729Sdfr semaptr->sem_base[sops[j].sem_num].semval -= 10882729Sdfr sops[j].sem_op; 10892729Sdfr 10902729Sdfr#ifdef SEM_DEBUG 109182607Sdillon printf("error = %d from semundo_adjust\n", error); 10922729Sdfr#endif 109382607Sdillon goto done2; 10942729Sdfr } /* loop through the sops */ 10952729Sdfr } /* if (do_undos) */ 10962729Sdfr 109784789Smr /* We're definitely done - set the sempid's and time */ 10982729Sdfr for (i = 0; i < nsops; i++) { 10992729Sdfr sopptr = &sops[i]; 11002729Sdfr semptr = &semaptr->sem_base[sopptr->sem_num]; 110183366Sjulian semptr->sempid = td->td_proc->p_pid; 11022729Sdfr } 110384789Smr semaptr->sem_otime = time_second; 11042729Sdfr 110584789Smr /* 110684789Smr * Do a wakeup if any semaphore was up'd whilst something was 110784789Smr * sleeping on it. 110884789Smr */ 11092729Sdfr if (do_wakeup) { 11102729Sdfr#ifdef SEM_DEBUG 11112729Sdfr printf("semop: doing wakeup\n"); 111258831Speter#endif 11132729Sdfr wakeup((caddr_t)semaptr); 111458831Speter#ifdef SEM_DEBUG 11152729Sdfr printf("semop: back from wakeup\n"); 11162729Sdfr#endif 11172729Sdfr } 11182729Sdfr#ifdef SEM_DEBUG 11192729Sdfr printf("semop: done\n"); 11202729Sdfr#endif 112183366Sjulian td->td_retval[0] = 0; 112282607Sdillondone2: 112384789Smr if (sops) 112484789Smr free(sops, M_SEM); 112582607Sdillon mtx_unlock(&Giant); 112682607Sdillon return (error); 11272729Sdfr} 11282729Sdfr 11292729Sdfr/* 11302729Sdfr * Go through the undo structures for this process and apply the adjustments to 11312729Sdfr * semaphores. 11322729Sdfr */ 113369449Salfredstatic void 113469449Salfredsemexit_myhook(p) 11352729Sdfr struct proc *p; 11362729Sdfr{ 11372729Sdfr register struct sem_undo *suptr; 11382729Sdfr register struct sem_undo **supptr; 11392729Sdfr 11402729Sdfr /* 11412729Sdfr * Go through the chain of undo vectors looking for one 11422729Sdfr * associated with this process. 11432729Sdfr */ 11442729Sdfr 11452729Sdfr for (supptr = &semu_list; (suptr = *supptr) != NULL; 11462729Sdfr supptr = &suptr->un_next) { 11472729Sdfr if (suptr->un_proc == p) 11482729Sdfr break; 11492729Sdfr } 11502729Sdfr 11512729Sdfr if (suptr == NULL) 115259828Speter return; 11532729Sdfr 11542729Sdfr#ifdef SEM_DEBUG 11552729Sdfr printf("proc @%08x has undo structure with %d entries\n", p, 11562729Sdfr suptr->un_cnt); 11572729Sdfr#endif 11582729Sdfr 11592729Sdfr /* 11602729Sdfr * If there are any active undo elements then process them. 11612729Sdfr */ 11622729Sdfr if (suptr->un_cnt > 0) { 11632729Sdfr int ix; 11642729Sdfr 11652729Sdfr for (ix = 0; ix < suptr->un_cnt; ix++) { 11662729Sdfr int semid = suptr->un_ent[ix].un_id; 11672729Sdfr int semnum = suptr->un_ent[ix].un_num; 11682729Sdfr int adjval = suptr->un_ent[ix].un_adjval; 11692729Sdfr struct semid_ds *semaptr; 11702729Sdfr 11712729Sdfr semaptr = &sema[semid]; 11722729Sdfr if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0) 11732729Sdfr panic("semexit - semid not allocated"); 11742729Sdfr if (semnum >= semaptr->sem_nsems) 11752729Sdfr panic("semexit - semnum out of range"); 11762729Sdfr 11772729Sdfr#ifdef SEM_DEBUG 11782729Sdfr printf("semexit: %08x id=%d num=%d(adj=%d) ; sem=%d\n", 11792729Sdfr suptr->un_proc, suptr->un_ent[ix].un_id, 11802729Sdfr suptr->un_ent[ix].un_num, 11812729Sdfr suptr->un_ent[ix].un_adjval, 11822729Sdfr semaptr->sem_base[semnum].semval); 11832729Sdfr#endif 11842729Sdfr 11852729Sdfr if (adjval < 0) { 11862729Sdfr if (semaptr->sem_base[semnum].semval < -adjval) 11872729Sdfr semaptr->sem_base[semnum].semval = 0; 11882729Sdfr else 11892729Sdfr semaptr->sem_base[semnum].semval += 11902729Sdfr adjval; 11912729Sdfr } else 11922729Sdfr semaptr->sem_base[semnum].semval += adjval; 11932729Sdfr 11942729Sdfr wakeup((caddr_t)semaptr); 11952729Sdfr#ifdef SEM_DEBUG 11962729Sdfr printf("semexit: back from wakeup\n"); 11972729Sdfr#endif 11982729Sdfr } 11992729Sdfr } 12002729Sdfr 12012729Sdfr /* 12022729Sdfr * Deallocate the undo vector. 12032729Sdfr */ 12042729Sdfr#ifdef SEM_DEBUG 12052729Sdfr printf("removing vector\n"); 12062729Sdfr#endif 12072729Sdfr suptr->un_proc = NULL; 12082729Sdfr *supptr = suptr->un_next; 12092729Sdfr} 121077461Sdd 121177461Sddstatic int 121277461Sddsysctl_sema(SYSCTL_HANDLER_ARGS) 121377461Sdd{ 121477461Sdd 121577461Sdd return (SYSCTL_OUT(req, sema, 121677461Sdd sizeof(struct semid_ds) * seminfo.semmni)); 121777461Sdd} 1218