sysv_sem.c revision 215281
1139804Simp/*- 22729Sdfr * Implementation of SVID semaphores 32729Sdfr * 42729Sdfr * Author: Daniel Boulet 52729Sdfr * 62729Sdfr * This software is provided ``AS IS'' without any warranties of any kind. 72729Sdfr */ 8140615Srwatson/*- 9140615Srwatson * Copyright (c) 2003-2005 McAfee, Inc. 10140615Srwatson * All rights reserved. 11140615Srwatson * 12140615Srwatson * This software was developed for the FreeBSD Project in part by McAfee 13140615Srwatson * Research, the Security Research Division of McAfee, Inc under DARPA/SPAWAR 14140615Srwatson * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS research 15140615Srwatson * program. 16140615Srwatson * 17140615Srwatson * Redistribution and use in source and binary forms, with or without 18140615Srwatson * modification, are permitted provided that the following conditions 19140615Srwatson * are met: 20140615Srwatson * 1. Redistributions of source code must retain the above copyright 21140615Srwatson * notice, this list of conditions and the following disclaimer. 22140615Srwatson * 2. Redistributions in binary form must reproduce the above copyright 23140615Srwatson * notice, this list of conditions and the following disclaimer in the 24140615Srwatson * documentation and/or other materials provided with the distribution. 25140615Srwatson * 26140615Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 27140615Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28140615Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29140615Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 30140615Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31140615Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32140615Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33140615Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34140615Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35140615Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36140615Srwatson * SUCH DAMAGE. 37140615Srwatson */ 382729Sdfr 39116182Sobrien#include <sys/cdefs.h> 40116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/sysv_sem.c 215281 2010-11-14 06:09:50Z brucec $"); 41116182Sobrien 42194894Sjhb#include "opt_compat.h" 4359839Speter#include "opt_sysvipc.h" 4459839Speter 452729Sdfr#include <sys/param.h> 462729Sdfr#include <sys/systm.h> 4711626Sbde#include <sys/sysproto.h> 48112564Sjhb#include <sys/eventhandler.h> 492729Sdfr#include <sys/kernel.h> 502729Sdfr#include <sys/proc.h> 5182607Sdillon#include <sys/lock.h> 52129882Sphk#include <sys/module.h> 5382607Sdillon#include <sys/mutex.h> 542729Sdfr#include <sys/sem.h> 5569449Salfred#include <sys/syscall.h> 56159991Sjhb#include <sys/syscallsubr.h> 5711626Sbde#include <sys/sysent.h> 5859839Speter#include <sys/sysctl.h> 59159991Sjhb#include <sys/uio.h> 6059839Speter#include <sys/malloc.h> 6168024Srwatson#include <sys/jail.h> 622729Sdfr 63163606Srwatson#include <security/mac/mac_framework.h> 64163606Srwatson 6559839Speterstatic MALLOC_DEFINE(M_SEM, "sem", "SVID compatible semaphores"); 6659839Speter 67100523Salfred#ifdef SEM_DEBUG 68100523Salfred#define DPRINTF(a) printf a 69100523Salfred#else 70100523Salfred#define DPRINTF(a) 71100523Salfred#endif 72100523Salfred 73205323Skibstatic int seminit(void); 7492723Salfredstatic int sysvsem_modload(struct module *, int, void *); 7592723Salfredstatic int semunload(void); 76112564Sjhbstatic void semexit_myhook(void *arg, struct proc *p); 7792723Salfredstatic int sysctl_sema(SYSCTL_HANDLER_ARGS); 78137613Srwatsonstatic int semvalid(int semid, struct semid_kernel *semakptr); 7910358Sjulian 8012866Speter#ifndef _SYS_SYSPROTO_H_ 8112866Speterstruct __semctl_args; 8292723Salfredint __semctl(struct thread *td, struct __semctl_args *uap); 8311626Sbdestruct semget_args; 8492723Salfredint semget(struct thread *td, struct semget_args *uap); 8511626Sbdestruct semop_args; 8692723Salfredint semop(struct thread *td, struct semop_args *uap); 8712866Speter#endif 8811626Sbde 8992723Salfredstatic struct sem_undo *semu_alloc(struct thread *td); 90122201Srwatsonstatic int semundo_adjust(struct thread *td, struct sem_undo **supptr, 91187223Skib int semid, int semseq, int semnum, int adjval); 9292723Salfredstatic void semundo_clear(int semid, int semnum); 9311626Sbde 94101774Salfredstatic struct mtx sem_mtx; /* semaphore global lock */ 95187223Skibstatic struct mtx sem_undo_mtx; 9612819Sphkstatic int semtot = 0; 97137613Srwatsonstatic struct semid_kernel *sema; /* semaphore id pool */ 98101774Salfredstatic struct mtx *sema_mtx; /* semaphore id pool mutexes*/ 9959839Speterstatic struct sem *sem; /* semaphore pool */ 100187223SkibLIST_HEAD(, sem_undo) semu_list; /* list of active undo structures */ 101187223SkibLIST_HEAD(, sem_undo) semu_free_list; /* list of free undo structures */ 10259839Speterstatic int *semu; /* undo structure pool */ 103112564Sjhbstatic eventhandler_tag semexit_tag; 1042729Sdfr 105187223Skib#define SEMUNDO_MTX sem_undo_mtx 106101774Salfred#define SEMUNDO_LOCK() mtx_lock(&SEMUNDO_MTX); 107101774Salfred#define SEMUNDO_UNLOCK() mtx_unlock(&SEMUNDO_MTX); 108101774Salfred#define SEMUNDO_LOCKASSERT(how) mtx_assert(&SEMUNDO_MTX, (how)); 109101774Salfred 11059839Speterstruct sem { 11159839Speter u_short semval; /* semaphore value */ 11259839Speter pid_t sempid; /* pid of last operation */ 11359839Speter u_short semncnt; /* # awaiting semval > cval */ 11459839Speter u_short semzcnt; /* # awaiting semval = 0 */ 11559839Speter}; 11659839Speter 11759839Speter/* 11859839Speter * Undo structure (one per process) 11959839Speter */ 12059839Speterstruct sem_undo { 121187223Skib LIST_ENTRY(sem_undo) un_next; /* ptr to next active undo structure */ 12259839Speter struct proc *un_proc; /* owner of this structure */ 12359839Speter short un_cnt; /* # of active entries */ 12459839Speter struct undo { 12559839Speter short un_adjval; /* adjust on exit values */ 12659839Speter short un_num; /* semaphore # */ 12759839Speter int un_id; /* semid */ 128187223Skib unsigned short un_seq; 12959839Speter } un_ent[1]; /* undo entries */ 13059839Speter}; 13159839Speter 13259839Speter/* 13359839Speter * Configuration parameters 13459839Speter */ 13559839Speter#ifndef SEMMNI 136209037Sivoras#define SEMMNI 50 /* # of semaphore identifiers */ 13759839Speter#endif 13859839Speter#ifndef SEMMNS 139209037Sivoras#define SEMMNS 340 /* # of semaphores in system */ 14059839Speter#endif 14159839Speter#ifndef SEMUME 142209037Sivoras#define SEMUME 50 /* max # of undo entries per process */ 14359839Speter#endif 14459839Speter#ifndef SEMMNU 145209037Sivoras#define SEMMNU 150 /* # of undo structures in system */ 14659839Speter#endif 14759839Speter 14859839Speter/* shouldn't need tuning */ 14959839Speter#ifndef SEMMAP 15059839Speter#define SEMMAP 30 /* # of entries in semaphore map */ 15159839Speter#endif 15259839Speter#ifndef SEMMSL 15359839Speter#define SEMMSL SEMMNS /* max # of semaphores per id */ 15459839Speter#endif 15559839Speter#ifndef SEMOPM 15659839Speter#define SEMOPM 100 /* max # of operations per semop call */ 15759839Speter#endif 15859839Speter 15959839Speter#define SEMVMX 32767 /* semaphore maximum value */ 16059839Speter#define SEMAEM 16384 /* adjust on exit max value */ 16159839Speter 16259839Speter/* 16359839Speter * Due to the way semaphore memory is allocated, we have to ensure that 16459839Speter * SEMUSZ is properly aligned. 16559839Speter */ 16659839Speter 16759839Speter#define SEM_ALIGN(bytes) (((bytes) + (sizeof(long) - 1)) & ~(sizeof(long) - 1)) 16859839Speter 16959839Speter/* actual size of an undo structure */ 17059839Speter#define SEMUSZ SEM_ALIGN(offsetof(struct sem_undo, un_ent[SEMUME])) 17159839Speter 17259839Speter/* 17359839Speter * Macro to find a particular sem_undo vector 17459839Speter */ 175101350Salfred#define SEMU(ix) \ 176101350Salfred ((struct sem_undo *)(((intptr_t)semu)+ix * seminfo.semusz)) 17759839Speter 17859839Speter/* 17959839Speter * semaphore info struct 18059839Speter */ 18159839Speterstruct seminfo seminfo = { 18259839Speter SEMMAP, /* # of entries in semaphore map */ 18359839Speter SEMMNI, /* # of semaphore identifiers */ 18459839Speter SEMMNS, /* # of semaphores in system */ 18559839Speter SEMMNU, /* # of undo structures in system */ 18659839Speter SEMMSL, /* max # of semaphores per id */ 18759839Speter SEMOPM, /* max # of operations per semop call */ 18859839Speter SEMUME, /* max # of undo entries per process */ 18959839Speter SEMUSZ, /* size in bytes of undo structure */ 19059839Speter SEMVMX, /* semaphore maximum value */ 19159839Speter SEMAEM /* adjust on exit max value */ 19259839Speter}; 19359839Speter 194141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semmap, CTLFLAG_RW, &seminfo.semmap, 0, 195141710Scsjp "Number of entries in the semaphore map"); 196141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semmni, CTLFLAG_RDTUN, &seminfo.semmni, 0, 197141710Scsjp "Number of semaphore identifiers"); 198141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semmns, CTLFLAG_RDTUN, &seminfo.semmns, 0, 199141710Scsjp "Maximum number of semaphores in the system"); 200141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semmnu, CTLFLAG_RDTUN, &seminfo.semmnu, 0, 201141710Scsjp "Maximum number of undo structures in the system"); 202141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semmsl, CTLFLAG_RW, &seminfo.semmsl, 0, 203141710Scsjp "Max semaphores per id"); 204141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semopm, CTLFLAG_RDTUN, &seminfo.semopm, 0, 205141710Scsjp "Max operations per semop call"); 206141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semume, CTLFLAG_RDTUN, &seminfo.semume, 0, 207141710Scsjp "Max undo entries per process"); 208141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semusz, CTLFLAG_RDTUN, &seminfo.semusz, 0, 209141710Scsjp "Size in bytes of undo structure"); 210141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semvmx, CTLFLAG_RW, &seminfo.semvmx, 0, 211141710Scsjp "Semaphore maximum value"); 212141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, semaem, CTLFLAG_RW, &seminfo.semaem, 0, 213141710Scsjp "Adjust on exit max value"); 21477461SddSYSCTL_PROC(_kern_ipc, OID_AUTO, sema, CTLFLAG_RD, 215215281Sbrucec NULL, 0, sysctl_sema, "", "Semaphore id pool"); 21659839Speter 217205323Skibstatic struct syscall_helper_data sem_syscalls[] = { 218205323Skib SYSCALL_INIT_HELPER(__semctl), 219205323Skib SYSCALL_INIT_HELPER(semget), 220205323Skib SYSCALL_INIT_HELPER(semop), 221205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 222205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 223205323Skib SYSCALL_INIT_HELPER(semsys), 224205323Skib SYSCALL_INIT_HELPER(freebsd7___semctl), 225205323Skib#endif 226205323Skib SYSCALL_INIT_LAST 227205323Skib}; 228205323Skib 229205323Skib#ifdef COMPAT_FREEBSD32 230205323Skib#include <compat/freebsd32/freebsd32.h> 231205323Skib#include <compat/freebsd32/freebsd32_ipc.h> 232205323Skib#include <compat/freebsd32/freebsd32_proto.h> 233205323Skib#include <compat/freebsd32/freebsd32_signal.h> 234205323Skib#include <compat/freebsd32/freebsd32_syscall.h> 235205323Skib#include <compat/freebsd32/freebsd32_util.h> 236205323Skib 237205323Skibstatic struct syscall_helper_data sem32_syscalls[] = { 238205323Skib SYSCALL32_INIT_HELPER(freebsd32_semctl), 239205323Skib SYSCALL32_INIT_HELPER(semget), 240205323Skib SYSCALL32_INIT_HELPER(semop), 241205323Skib SYSCALL32_INIT_HELPER(freebsd32_semsys), 242205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 243205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 244205323Skib SYSCALL32_INIT_HELPER(freebsd7_freebsd32_semctl), 245205323Skib#endif 246205323Skib SYSCALL_INIT_LAST 247205323Skib}; 248205323Skib#endif 249205323Skib 250205323Skibstatic int 25169449Salfredseminit(void) 2522729Sdfr{ 253205323Skib int i, error; 2542729Sdfr 25583413Smr TUNABLE_INT_FETCH("kern.ipc.semmap", &seminfo.semmap); 25683413Smr TUNABLE_INT_FETCH("kern.ipc.semmni", &seminfo.semmni); 25783413Smr TUNABLE_INT_FETCH("kern.ipc.semmns", &seminfo.semmns); 25883413Smr TUNABLE_INT_FETCH("kern.ipc.semmnu", &seminfo.semmnu); 25983413Smr TUNABLE_INT_FETCH("kern.ipc.semmsl", &seminfo.semmsl); 26083413Smr TUNABLE_INT_FETCH("kern.ipc.semopm", &seminfo.semopm); 26183413Smr TUNABLE_INT_FETCH("kern.ipc.semume", &seminfo.semume); 26283413Smr TUNABLE_INT_FETCH("kern.ipc.semusz", &seminfo.semusz); 26383413Smr TUNABLE_INT_FETCH("kern.ipc.semvmx", &seminfo.semvmx); 26483413Smr TUNABLE_INT_FETCH("kern.ipc.semaem", &seminfo.semaem); 26583413Smr 266111119Simp sem = malloc(sizeof(struct sem) * seminfo.semmns, M_SEM, M_WAITOK); 267137613Srwatson sema = malloc(sizeof(struct semid_kernel) * seminfo.semmni, M_SEM, 268111119Simp M_WAITOK); 269101774Salfred sema_mtx = malloc(sizeof(struct mtx) * seminfo.semmni, M_SEM, 270111119Simp M_WAITOK | M_ZERO); 271111119Simp semu = malloc(seminfo.semmnu * seminfo.semusz, M_SEM, M_WAITOK); 2722729Sdfr 2732729Sdfr for (i = 0; i < seminfo.semmni; i++) { 274137613Srwatson sema[i].u.sem_base = 0; 275137613Srwatson sema[i].u.sem_perm.mode = 0; 276137613Srwatson sema[i].u.sem_perm.seq = 0; 277140615Srwatson#ifdef MAC 278172930Srwatson mac_sysvsem_init(&sema[i]); 279140615Srwatson#endif 2802729Sdfr } 281101774Salfred for (i = 0; i < seminfo.semmni; i++) 282101774Salfred mtx_init(&sema_mtx[i], "semid", NULL, MTX_DEF); 283187223Skib LIST_INIT(&semu_free_list); 2842729Sdfr for (i = 0; i < seminfo.semmnu; i++) { 285101350Salfred struct sem_undo *suptr = SEMU(i); 2862729Sdfr suptr->un_proc = NULL; 287187223Skib LIST_INSERT_HEAD(&semu_free_list, suptr, un_next); 2882729Sdfr } 289187223Skib LIST_INIT(&semu_list); 290101774Salfred mtx_init(&sem_mtx, "sem", NULL, MTX_DEF); 291187223Skib mtx_init(&sem_undo_mtx, "semu", NULL, MTX_DEF); 292112564Sjhb semexit_tag = EVENTHANDLER_REGISTER(process_exit, semexit_myhook, NULL, 293112564Sjhb EVENTHANDLER_PRI_ANY); 294205323Skib 295205323Skib error = syscall_helper_register(sem_syscalls); 296205323Skib if (error != 0) 297205323Skib return (error); 298205323Skib#ifdef COMPAT_FREEBSD32 299205323Skib error = syscall32_helper_register(sem32_syscalls); 300205323Skib if (error != 0) 301205323Skib return (error); 302205323Skib#endif 303205323Skib return (0); 3042729Sdfr} 3052729Sdfr 30669449Salfredstatic int 30769449Salfredsemunload(void) 30869449Salfred{ 309101774Salfred int i; 31069449Salfred 311187223Skib /* XXXKIB */ 31269449Salfred if (semtot != 0) 31369449Salfred return (EBUSY); 31469449Salfred 315205323Skib#ifdef COMPAT_FREEBSD32 316205323Skib syscall32_helper_unregister(sem32_syscalls); 317205323Skib#endif 318205323Skib syscall_helper_unregister(sem_syscalls); 319112564Sjhb EVENTHANDLER_DEREGISTER(process_exit, semexit_tag); 320140615Srwatson#ifdef MAC 321140615Srwatson for (i = 0; i < seminfo.semmni; i++) 322172930Srwatson mac_sysvsem_destroy(&sema[i]); 323140615Srwatson#endif 32469449Salfred free(sem, M_SEM); 32569449Salfred free(sema, M_SEM); 32669449Salfred free(semu, M_SEM); 327101774Salfred for (i = 0; i < seminfo.semmni; i++) 328101774Salfred mtx_destroy(&sema_mtx[i]); 329190557Sbrueffer free(sema_mtx, M_SEM); 330101774Salfred mtx_destroy(&sem_mtx); 331187223Skib mtx_destroy(&sem_undo_mtx); 33269449Salfred return (0); 33369449Salfred} 33469449Salfred 33569449Salfredstatic int 33669449Salfredsysvsem_modload(struct module *module, int cmd, void *arg) 33769449Salfred{ 33869449Salfred int error = 0; 33969449Salfred 34069449Salfred switch (cmd) { 34169449Salfred case MOD_LOAD: 342205323Skib error = seminit(); 343205323Skib if (error != 0) 344205323Skib semunload(); 34569449Salfred break; 34669449Salfred case MOD_UNLOAD: 34769449Salfred error = semunload(); 34869449Salfred break; 34969449Salfred case MOD_SHUTDOWN: 35069449Salfred break; 35169449Salfred default: 35269449Salfred error = EINVAL; 35369449Salfred break; 35469449Salfred } 35569449Salfred return (error); 35669449Salfred} 35769449Salfred 35871038Sdesstatic moduledata_t sysvsem_mod = { 35971038Sdes "sysvsem", 36069449Salfred &sysvsem_modload, 36169449Salfred NULL 36269449Salfred}; 36369449Salfred 364194832SjhbDECLARE_MODULE(sysvsem, sysvsem_mod, SI_SUB_SYSV_SEM, SI_ORDER_FIRST); 36571038SdesMODULE_VERSION(sysvsem, 1); 36669449Salfred 3672729Sdfr/* 3682729Sdfr * Allocate a new sem_undo structure for a process 3692729Sdfr * (returns ptr to structure or NULL if no more room) 3702729Sdfr */ 3712729Sdfr 37212819Sphkstatic struct sem_undo * 373187223Skibsemu_alloc(struct thread *td) 3742729Sdfr{ 375101350Salfred struct sem_undo *suptr; 3762729Sdfr 377101774Salfred SEMUNDO_LOCKASSERT(MA_OWNED); 378187223Skib if ((suptr = LIST_FIRST(&semu_free_list)) == NULL) 379187223Skib return (NULL); 380187223Skib LIST_REMOVE(suptr, un_next); 381187223Skib LIST_INSERT_HEAD(&semu_list, suptr, un_next); 382187223Skib suptr->un_cnt = 0; 383187223Skib suptr->un_proc = td->td_proc; 384187223Skib return (suptr); 385187223Skib} 3862729Sdfr 387187223Skibstatic int 388187223Skibsemu_try_free(struct sem_undo *suptr) 389187223Skib{ 3902729Sdfr 391187223Skib SEMUNDO_LOCKASSERT(MA_OWNED); 3922729Sdfr 393187223Skib if (suptr->un_cnt != 0) 394187223Skib return (0); 395187223Skib LIST_REMOVE(suptr, un_next); 396187223Skib LIST_INSERT_HEAD(&semu_free_list, suptr, un_next); 397187223Skib return (1); 3982729Sdfr} 3992729Sdfr 4002729Sdfr/* 4012729Sdfr * Adjust a particular entry for a particular proc 4022729Sdfr */ 4032729Sdfr 40412819Sphkstatic int 405187223Skibsemundo_adjust(struct thread *td, struct sem_undo **supptr, int semid, 406187223Skib int semseq, int semnum, int adjval) 4072729Sdfr{ 40883366Sjulian struct proc *p = td->td_proc; 409101350Salfred struct sem_undo *suptr; 410101350Salfred struct undo *sunptr; 4112729Sdfr int i; 4122729Sdfr 413101774Salfred SEMUNDO_LOCKASSERT(MA_OWNED); 4142729Sdfr /* Look for and remember the sem_undo if the caller doesn't provide 4152729Sdfr it */ 4162729Sdfr 4172729Sdfr suptr = *supptr; 4182729Sdfr if (suptr == NULL) { 419187223Skib LIST_FOREACH(suptr, &semu_list, un_next) { 4202729Sdfr if (suptr->un_proc == p) { 4212729Sdfr *supptr = suptr; 4222729Sdfr break; 4232729Sdfr } 4242729Sdfr } 4252729Sdfr if (suptr == NULL) { 4262729Sdfr if (adjval == 0) 4272729Sdfr return(0); 42883366Sjulian suptr = semu_alloc(td); 4292729Sdfr if (suptr == NULL) 430187223Skib return (ENOSPC); 4312729Sdfr *supptr = suptr; 4322729Sdfr } 4332729Sdfr } 4342729Sdfr 4352729Sdfr /* 4362729Sdfr * Look for the requested entry and adjust it (delete if adjval becomes 4372729Sdfr * 0). 4382729Sdfr */ 4392729Sdfr sunptr = &suptr->un_ent[0]; 4402729Sdfr for (i = 0; i < suptr->un_cnt; i++, sunptr++) { 4412729Sdfr if (sunptr->un_id != semid || sunptr->un_num != semnum) 4422729Sdfr continue; 44384789Smr if (adjval != 0) { 44484789Smr adjval += sunptr->un_adjval; 44584789Smr if (adjval > seminfo.semaem || adjval < -seminfo.semaem) 44684789Smr return (ERANGE); 44784789Smr } 44884789Smr sunptr->un_adjval = adjval; 4492729Sdfr if (sunptr->un_adjval == 0) { 4502729Sdfr suptr->un_cnt--; 4512729Sdfr if (i < suptr->un_cnt) 4522729Sdfr suptr->un_ent[i] = 4532729Sdfr suptr->un_ent[suptr->un_cnt]; 454187223Skib if (suptr->un_cnt == 0) 455187223Skib semu_try_free(suptr); 4562729Sdfr } 457187223Skib return (0); 4582729Sdfr } 4592729Sdfr 4602729Sdfr /* Didn't find the right entry - create it */ 4612729Sdfr if (adjval == 0) 462187223Skib return (0); 46384789Smr if (adjval > seminfo.semaem || adjval < -seminfo.semaem) 46484789Smr return (ERANGE); 46541774Sdillon if (suptr->un_cnt != seminfo.semume) { 4662729Sdfr sunptr = &suptr->un_ent[suptr->un_cnt]; 4672729Sdfr suptr->un_cnt++; 4682729Sdfr sunptr->un_adjval = adjval; 469187223Skib sunptr->un_id = semid; 470187223Skib sunptr->un_num = semnum; 471187223Skib sunptr->un_seq = semseq; 4722729Sdfr } else 473187223Skib return (EINVAL); 474187223Skib return (0); 4752729Sdfr} 4762729Sdfr 47712819Sphkstatic void 478187223Skibsemundo_clear(int semid, int semnum) 4792729Sdfr{ 480187223Skib struct sem_undo *suptr, *suptr1; 481187223Skib struct undo *sunptr; 482187223Skib int i; 4832729Sdfr 484101774Salfred SEMUNDO_LOCKASSERT(MA_OWNED); 485187223Skib LIST_FOREACH_SAFE(suptr, &semu_list, un_next, suptr1) { 486187223Skib sunptr = &suptr->un_ent[0]; 487187223Skib for (i = 0; i < suptr->un_cnt; i++, sunptr++) { 488187223Skib if (sunptr->un_id != semid) 489187223Skib continue; 490187223Skib if (semnum == -1 || sunptr->un_num == semnum) { 491187223Skib suptr->un_cnt--; 492187223Skib if (i < suptr->un_cnt) { 493187223Skib suptr->un_ent[i] = 494187223Skib suptr->un_ent[suptr->un_cnt]; 495187223Skib continue; 4962729Sdfr } 497187223Skib semu_try_free(suptr); 4982729Sdfr } 499187223Skib if (semnum != -1) 500187223Skib break; 5012729Sdfr } 5022729Sdfr } 5032729Sdfr} 5042729Sdfr 505101774Salfredstatic int 506187223Skibsemvalid(int semid, struct semid_kernel *semakptr) 507101774Salfred{ 508101774Salfred 509137613Srwatson return ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 510137613Srwatson semakptr->u.sem_perm.seq != IPCID_TO_SEQ(semid) ? EINVAL : 0); 511101774Salfred} 512101774Salfred 51312866Speter/* 514167211Srwatson * Note that the user-mode half of this passes a union, not a pointer. 51512866Speter */ 51612866Speter#ifndef _SYS_SYSPROTO_H_ 51712866Speterstruct __semctl_args { 5182729Sdfr int semid; 5192729Sdfr int semnum; 5202729Sdfr int cmd; 5212729Sdfr union semun *arg; 5222729Sdfr}; 52312866Speter#endif 52412866Speterint 525187223Skib__semctl(struct thread *td, struct __semctl_args *uap) 5262729Sdfr{ 527160187Sjhb struct semid_ds dsbuf; 528160187Sjhb union semun arg, semun; 529160187Sjhb register_t rval; 530159991Sjhb int error; 531159991Sjhb 532159991Sjhb switch (uap->cmd) { 533159991Sjhb case SEM_STAT: 534159991Sjhb case IPC_SET: 535159991Sjhb case IPC_STAT: 536159991Sjhb case GETALL: 537159991Sjhb case SETVAL: 538159991Sjhb case SETALL: 539160187Sjhb error = copyin(uap->arg, &arg, sizeof(arg)); 540159991Sjhb if (error) 541159991Sjhb return (error); 542159991Sjhb break; 543160187Sjhb } 544160187Sjhb 545160187Sjhb switch (uap->cmd) { 546160187Sjhb case SEM_STAT: 547160187Sjhb case IPC_STAT: 548160187Sjhb semun.buf = &dsbuf; 549159991Sjhb break; 550160187Sjhb case IPC_SET: 551160187Sjhb error = copyin(arg.buf, &dsbuf, sizeof(dsbuf)); 552160187Sjhb if (error) 553160187Sjhb return (error); 554160187Sjhb semun.buf = &dsbuf; 555160187Sjhb break; 556160187Sjhb case GETALL: 557160187Sjhb case SETALL: 558160187Sjhb semun.array = arg.array; 559160187Sjhb break; 560160187Sjhb case SETVAL: 561160187Sjhb semun.val = arg.val; 562160187Sjhb break; 563159991Sjhb } 564160187Sjhb 565160187Sjhb error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 566160187Sjhb &rval); 567160187Sjhb if (error) 568160187Sjhb return (error); 569160187Sjhb 570160187Sjhb switch (uap->cmd) { 571160187Sjhb case SEM_STAT: 572160187Sjhb case IPC_STAT: 573160187Sjhb error = copyout(&dsbuf, arg.buf, sizeof(dsbuf)); 574160187Sjhb break; 575160187Sjhb } 576160187Sjhb 577160187Sjhb if (error == 0) 578160187Sjhb td->td_retval[0] = rval; 579160187Sjhb return (error); 580159991Sjhb} 581159991Sjhb 582159991Sjhbint 583160187Sjhbkern_semctl(struct thread *td, int semid, int semnum, int cmd, 584160187Sjhb union semun *arg, register_t *rval) 585159991Sjhb{ 586101774Salfred u_short *array; 58791406Sjhb struct ucred *cred = td->td_ucred; 588160187Sjhb int i, error; 589160187Sjhb struct semid_ds *sbuf; 590137613Srwatson struct semid_kernel *semakptr; 591101774Salfred struct mtx *sema_mtxp; 592101774Salfred u_short usval, count; 593160028Sjhb int semidx; 5942729Sdfr 595160293Skib DPRINTF(("call to semctl(%d, %d, %d, 0x%p)\n", 596100523Salfred semid, semnum, cmd, arg)); 597192895Sjamie if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) 59891703Sjhb return (ENOSYS); 59991703Sjhb 600101774Salfred array = NULL; 601101774Salfred 60283414Smr switch(cmd) { 60383414Smr case SEM_STAT: 604160028Sjhb /* 605160028Sjhb * For this command we assume semid is an array index 606160028Sjhb * rather than an IPC id. 607160028Sjhb */ 60891744Smaxim if (semid < 0 || semid >= seminfo.semmni) 609101774Salfred return (EINVAL); 610137613Srwatson semakptr = &sema[semid]; 611101774Salfred sema_mtxp = &sema_mtx[semid]; 612101774Salfred mtx_lock(sema_mtxp); 613137613Srwatson if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) { 614101774Salfred error = EINVAL; 615101774Salfred goto done2; 616101774Salfred } 617137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 618101774Salfred goto done2; 619140615Srwatson#ifdef MAC 620172930Srwatson error = mac_sysvsem_check_semctl(cred, semakptr, cmd); 621162468Srwatson if (error != 0) 622140615Srwatson goto done2; 623140615Srwatson#endif 624160187Sjhb bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds)); 625160187Sjhb *rval = IXSEQ_TO_IPCID(semid, semakptr->u.sem_perm); 626101774Salfred mtx_unlock(sema_mtxp); 627160187Sjhb return (0); 62883414Smr } 62983414Smr 630160028Sjhb semidx = IPCID_TO_IX(semid); 631160028Sjhb if (semidx < 0 || semidx >= seminfo.semmni) 632101774Salfred return (EINVAL); 6332729Sdfr 634160028Sjhb semakptr = &sema[semidx]; 635160028Sjhb sema_mtxp = &sema_mtx[semidx]; 636187223Skib if (cmd == IPC_RMID) 637187223Skib mtx_lock(&sem_mtx); 638160187Sjhb mtx_lock(sema_mtxp); 639140615Srwatson#ifdef MAC 640172930Srwatson error = mac_sysvsem_check_semctl(cred, semakptr, cmd); 641162468Srwatson if (error != 0) 642160187Sjhb goto done2; 643140615Srwatson#endif 644145230Srwatson 64582607Sdillon error = 0; 646160187Sjhb *rval = 0; 6472729Sdfr 6482729Sdfr switch (cmd) { 6492729Sdfr case IPC_RMID: 650159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 651101774Salfred goto done2; 652137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M))) 65382607Sdillon goto done2; 654137613Srwatson semakptr->u.sem_perm.cuid = cred->cr_uid; 655137613Srwatson semakptr->u.sem_perm.uid = cred->cr_uid; 656187223Skib semakptr->u.sem_perm.mode = 0; 657187223Skib SEMUNDO_LOCK(); 658187223Skib semundo_clear(semidx, -1); 659187223Skib SEMUNDO_UNLOCK(); 660187223Skib#ifdef MAC 661187223Skib mac_sysvsem_cleanup(semakptr); 662187223Skib#endif 663187223Skib wakeup(semakptr); 664187223Skib for (i = 0; i < seminfo.semmni; i++) { 665187223Skib if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && 666187223Skib sema[i].u.sem_base > semakptr->u.sem_base) 667187223Skib mtx_lock_flags(&sema_mtx[i], LOP_DUPOK); 668187223Skib } 669137613Srwatson for (i = semakptr->u.sem_base - sem; i < semtot; i++) 670137613Srwatson sem[i] = sem[i + semakptr->u.sem_nsems]; 6712729Sdfr for (i = 0; i < seminfo.semmni; i++) { 672137613Srwatson if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && 673187223Skib sema[i].u.sem_base > semakptr->u.sem_base) { 674137613Srwatson sema[i].u.sem_base -= semakptr->u.sem_nsems; 675187223Skib mtx_unlock(&sema_mtx[i]); 676187223Skib } 6772729Sdfr } 678187223Skib semtot -= semakptr->u.sem_nsems; 6792729Sdfr break; 6802729Sdfr 6812729Sdfr case IPC_SET: 682159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 683101774Salfred goto done2; 684137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M))) 685101774Salfred goto done2; 686160187Sjhb sbuf = arg->buf; 687160187Sjhb semakptr->u.sem_perm.uid = sbuf->sem_perm.uid; 688160187Sjhb semakptr->u.sem_perm.gid = sbuf->sem_perm.gid; 689137613Srwatson semakptr->u.sem_perm.mode = (semakptr->u.sem_perm.mode & 690160187Sjhb ~0777) | (sbuf->sem_perm.mode & 0777); 691137613Srwatson semakptr->u.sem_ctime = time_second; 6922729Sdfr break; 6932729Sdfr 6942729Sdfr case IPC_STAT: 695159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 696101774Salfred goto done2; 697137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 69882607Sdillon goto done2; 699160187Sjhb bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds)); 7002729Sdfr break; 7012729Sdfr 7022729Sdfr case GETNCNT: 703159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 704101774Salfred goto done2; 705137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 70682607Sdillon goto done2; 707137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 70882607Sdillon error = EINVAL; 70982607Sdillon goto done2; 71082607Sdillon } 711160187Sjhb *rval = semakptr->u.sem_base[semnum].semncnt; 7122729Sdfr break; 7132729Sdfr 7142729Sdfr case GETPID: 715159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 716101774Salfred goto done2; 717137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 71882607Sdillon goto done2; 719137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 72082607Sdillon error = EINVAL; 72182607Sdillon goto done2; 72282607Sdillon } 723160187Sjhb *rval = semakptr->u.sem_base[semnum].sempid; 7242729Sdfr break; 7252729Sdfr 7262729Sdfr case GETVAL: 727159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 728101774Salfred goto done2; 729137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 73082607Sdillon goto done2; 731137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 73282607Sdillon error = EINVAL; 73382607Sdillon goto done2; 73482607Sdillon } 735160187Sjhb *rval = semakptr->u.sem_base[semnum].semval; 7362729Sdfr break; 7372729Sdfr 7382729Sdfr case GETALL: 739159991Sjhb /* 740160187Sjhb * Unfortunately, callers of this function don't know 741160187Sjhb * in advance how many semaphores are in this set. 742160187Sjhb * While we could just allocate the maximum size array 743160187Sjhb * and pass the actual size back to the caller, that 744160187Sjhb * won't work for SETALL since we can't copyin() more 745160187Sjhb * data than the user specified as we may return a 746160187Sjhb * spurious EFAULT. 747160187Sjhb * 748160187Sjhb * Note that the number of semaphores in a set is 749160187Sjhb * fixed for the life of that set. The only way that 750160187Sjhb * the 'count' could change while are blocked in 751160187Sjhb * malloc() is if this semaphore set were destroyed 752160187Sjhb * and a new one created with the same index. 753160187Sjhb * However, semvalid() will catch that due to the 754160187Sjhb * sequence number unless exactly 0x8000 (or a 755160187Sjhb * multiple thereof) semaphore sets for the same index 756160187Sjhb * are created and destroyed while we are in malloc! 757160187Sjhb * 758159991Sjhb */ 759160187Sjhb count = semakptr->u.sem_nsems; 760160187Sjhb mtx_unlock(sema_mtxp); 761160187Sjhb array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK); 762101774Salfred mtx_lock(sema_mtxp); 763159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 764101774Salfred goto done2; 765160187Sjhb KASSERT(count == semakptr->u.sem_nsems, ("nsems changed")); 766137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 76782607Sdillon goto done2; 768137613Srwatson for (i = 0; i < semakptr->u.sem_nsems; i++) 769137613Srwatson array[i] = semakptr->u.sem_base[i].semval; 770101774Salfred mtx_unlock(sema_mtxp); 771160187Sjhb error = copyout(array, arg->array, count * sizeof(*array)); 772160187Sjhb mtx_lock(sema_mtxp); 7732729Sdfr break; 7742729Sdfr 7752729Sdfr case GETZCNT: 776159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 777101774Salfred goto done2; 778137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) 77982607Sdillon goto done2; 780137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 78182607Sdillon error = EINVAL; 78282607Sdillon goto done2; 78382607Sdillon } 784160187Sjhb *rval = semakptr->u.sem_base[semnum].semzcnt; 7852729Sdfr break; 7862729Sdfr 7872729Sdfr case SETVAL: 788159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 789101774Salfred goto done2; 790137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W))) 79182607Sdillon goto done2; 792137613Srwatson if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { 79382607Sdillon error = EINVAL; 79482607Sdillon goto done2; 79582607Sdillon } 796159991Sjhb if (arg->val < 0 || arg->val > seminfo.semvmx) { 79784789Smr error = ERANGE; 79884789Smr goto done2; 79984789Smr } 800159991Sjhb semakptr->u.sem_base[semnum].semval = arg->val; 801101774Salfred SEMUNDO_LOCK(); 802160028Sjhb semundo_clear(semidx, semnum); 803101774Salfred SEMUNDO_UNLOCK(); 804137613Srwatson wakeup(semakptr); 8052729Sdfr break; 8062729Sdfr 8072729Sdfr case SETALL: 808159991Sjhb /* 809160187Sjhb * See comment on GETALL for why 'count' shouldn't change 810160187Sjhb * and why we require a userland buffer. 811159991Sjhb */ 812137613Srwatson count = semakptr->u.sem_nsems; 813160187Sjhb mtx_unlock(sema_mtxp); 814111119Simp array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK); 815159991Sjhb error = copyin(arg->array, array, count * sizeof(*array)); 816171179Skib mtx_lock(sema_mtxp); 817101774Salfred if (error) 818101774Salfred break; 819159991Sjhb if ((error = semvalid(semid, semakptr)) != 0) 820101774Salfred goto done2; 821160187Sjhb KASSERT(count == semakptr->u.sem_nsems, ("nsems changed")); 822137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W))) 823101774Salfred goto done2; 824137613Srwatson for (i = 0; i < semakptr->u.sem_nsems; i++) { 825101774Salfred usval = array[i]; 82684789Smr if (usval > seminfo.semvmx) { 82784789Smr error = ERANGE; 82884789Smr break; 82984789Smr } 830137613Srwatson semakptr->u.sem_base[i].semval = usval; 8312729Sdfr } 832101774Salfred SEMUNDO_LOCK(); 833160028Sjhb semundo_clear(semidx, -1); 834101774Salfred SEMUNDO_UNLOCK(); 835137613Srwatson wakeup(semakptr); 8362729Sdfr break; 8372729Sdfr 8382729Sdfr default: 83982607Sdillon error = EINVAL; 84082607Sdillon break; 8412729Sdfr } 8422729Sdfr 84382607Sdillondone2: 844160187Sjhb mtx_unlock(sema_mtxp); 845187223Skib if (cmd == IPC_RMID) 846187223Skib mtx_unlock(&sem_mtx); 847101774Salfred if (array != NULL) 848101774Salfred free(array, M_TEMP); 84982607Sdillon return(error); 8502729Sdfr} 8512729Sdfr 85212866Speter#ifndef _SYS_SYSPROTO_H_ 8532729Sdfrstruct semget_args { 8542729Sdfr key_t key; 8552729Sdfr int nsems; 8562729Sdfr int semflg; 8572729Sdfr}; 85812866Speter#endif 85912866Speterint 860187223Skibsemget(struct thread *td, struct semget_args *uap) 8612729Sdfr{ 86282607Sdillon int semid, error = 0; 8632729Sdfr int key = uap->key; 8642729Sdfr int nsems = uap->nsems; 8652729Sdfr int semflg = uap->semflg; 86691703Sjhb struct ucred *cred = td->td_ucred; 8672729Sdfr 868100523Salfred DPRINTF(("semget(0x%x, %d, 0%o)\n", key, nsems, semflg)); 869192895Sjamie if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) 87091703Sjhb return (ENOSYS); 87191703Sjhb 872187223Skib mtx_lock(&sem_mtx); 8732729Sdfr if (key != IPC_PRIVATE) { 8742729Sdfr for (semid = 0; semid < seminfo.semmni; semid++) { 875137613Srwatson if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) && 876137613Srwatson sema[semid].u.sem_perm.key == key) 8772729Sdfr break; 8782729Sdfr } 8792729Sdfr if (semid < seminfo.semmni) { 880100523Salfred DPRINTF(("found public key\n")); 881137613Srwatson if ((error = ipcperm(td, &sema[semid].u.sem_perm, 88282607Sdillon semflg & 0700))) { 88382607Sdillon goto done2; 88482607Sdillon } 885137613Srwatson if (nsems > 0 && sema[semid].u.sem_nsems < nsems) { 886100523Salfred DPRINTF(("too small\n")); 88782607Sdillon error = EINVAL; 88882607Sdillon goto done2; 8892729Sdfr } 8902729Sdfr if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) { 891100523Salfred DPRINTF(("not exclusive\n")); 89282607Sdillon error = EEXIST; 89382607Sdillon goto done2; 8942729Sdfr } 895140615Srwatson#ifdef MAC 896172930Srwatson error = mac_sysvsem_check_semget(cred, &sema[semid]); 897162468Srwatson if (error != 0) 898140615Srwatson goto done2; 899140615Srwatson#endif 9002729Sdfr goto found; 9012729Sdfr } 9022729Sdfr } 9032729Sdfr 904137613Srwatson DPRINTF(("need to allocate the semid_kernel\n")); 9052729Sdfr if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) { 9062729Sdfr if (nsems <= 0 || nsems > seminfo.semmsl) { 907100523Salfred DPRINTF(("nsems out of range (0<%d<=%d)\n", nsems, 908100523Salfred seminfo.semmsl)); 90982607Sdillon error = EINVAL; 91082607Sdillon goto done2; 9112729Sdfr } 9122729Sdfr if (nsems > seminfo.semmns - semtot) { 913100523Salfred DPRINTF(( 914100523Salfred "not enough semaphores left (need %d, got %d)\n", 915100523Salfred nsems, seminfo.semmns - semtot)); 91682607Sdillon error = ENOSPC; 91782607Sdillon goto done2; 9182729Sdfr } 9192729Sdfr for (semid = 0; semid < seminfo.semmni; semid++) { 920137613Srwatson if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0) 9212729Sdfr break; 9222729Sdfr } 9232729Sdfr if (semid == seminfo.semmni) { 924137613Srwatson DPRINTF(("no more semid_kernel's available\n")); 92582607Sdillon error = ENOSPC; 92682607Sdillon goto done2; 9272729Sdfr } 928100523Salfred DPRINTF(("semid %d is available\n", semid)); 929187298Skib mtx_lock(&sema_mtx[semid]); 930187298Skib KASSERT((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0, 931187298Skib ("Lost semaphore %d", semid)); 932137613Srwatson sema[semid].u.sem_perm.key = key; 933137613Srwatson sema[semid].u.sem_perm.cuid = cred->cr_uid; 934137613Srwatson sema[semid].u.sem_perm.uid = cred->cr_uid; 935137613Srwatson sema[semid].u.sem_perm.cgid = cred->cr_gid; 936137613Srwatson sema[semid].u.sem_perm.gid = cred->cr_gid; 937137613Srwatson sema[semid].u.sem_perm.mode = (semflg & 0777) | SEM_ALLOC; 938137613Srwatson sema[semid].u.sem_perm.seq = 939137613Srwatson (sema[semid].u.sem_perm.seq + 1) & 0x7fff; 940137613Srwatson sema[semid].u.sem_nsems = nsems; 941137613Srwatson sema[semid].u.sem_otime = 0; 942137613Srwatson sema[semid].u.sem_ctime = time_second; 943137613Srwatson sema[semid].u.sem_base = &sem[semtot]; 9442729Sdfr semtot += nsems; 945137613Srwatson bzero(sema[semid].u.sem_base, 946137613Srwatson sizeof(sema[semid].u.sem_base[0])*nsems); 947140615Srwatson#ifdef MAC 948172930Srwatson mac_sysvsem_create(cred, &sema[semid]); 949140615Srwatson#endif 950187298Skib mtx_unlock(&sema_mtx[semid]); 951160293Skib DPRINTF(("sembase = %p, next = %p\n", 952137613Srwatson sema[semid].u.sem_base, &sem[semtot])); 9532729Sdfr } else { 954100523Salfred DPRINTF(("didn't find it and wasn't asked to create it\n")); 95582607Sdillon error = ENOENT; 95682607Sdillon goto done2; 9572729Sdfr } 9582729Sdfr 9592729Sdfrfound: 960137613Srwatson td->td_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].u.sem_perm); 96182607Sdillondone2: 962187223Skib mtx_unlock(&sem_mtx); 96382607Sdillon return (error); 9642729Sdfr} 9652729Sdfr 96612866Speter#ifndef _SYS_SYSPROTO_H_ 9672729Sdfrstruct semop_args { 9682729Sdfr int semid; 9692729Sdfr struct sembuf *sops; 970109829Salfred size_t nsops; 9712729Sdfr}; 97212866Speter#endif 97312866Speterint 974187223Skibsemop(struct thread *td, struct semop_args *uap) 9752729Sdfr{ 976123667Stjr#define SMALL_SOPS 8 977123667Stjr struct sembuf small_sops[SMALL_SOPS]; 9782729Sdfr int semid = uap->semid; 979109829Salfred size_t nsops = uap->nsops; 980105429Salfred struct sembuf *sops; 981137613Srwatson struct semid_kernel *semakptr; 982101350Salfred struct sembuf *sopptr = 0; 983101350Salfred struct sem *semptr = 0; 98484789Smr struct sem_undo *suptr; 985101774Salfred struct mtx *sema_mtxp; 986110040Stjr size_t i, j, k; 987109829Salfred int error; 9883308Sphk int do_wakeup, do_undos; 989187223Skib unsigned short seq; 9902729Sdfr 991160293Skib#ifdef SEM_DEBUG 992160293Skib sops = NULL; 993160293Skib#endif 994160293Skib DPRINTF(("call to semop(%d, %p, %u)\n", semid, sops, nsops)); 9952729Sdfr 996192895Sjamie if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) 99791703Sjhb return (ENOSYS); 99891703Sjhb 9992729Sdfr semid = IPCID_TO_IX(semid); /* Convert back to zero origin */ 10002729Sdfr 1001101774Salfred if (semid < 0 || semid >= seminfo.semmni) 1002137644Srwatson return (EINVAL); 1003101774Salfred 1004101774Salfred /* Allocate memory for sem_ops */ 1005123667Stjr if (nsops <= SMALL_SOPS) 1006123667Stjr sops = small_sops; 1007123667Stjr else if (nsops <= seminfo.semopm) 1008123667Stjr sops = malloc(nsops * sizeof(*sops), M_TEMP, M_WAITOK); 1009123667Stjr else { 1010101774Salfred DPRINTF(("too many sops (max=%d, nsops=%d)\n", seminfo.semopm, 1011101774Salfred nsops)); 1012101774Salfred return (E2BIG); 101382607Sdillon } 1014101774Salfred if ((error = copyin(uap->sops, sops, nsops * sizeof(sops[0]))) != 0) { 1015160293Skib DPRINTF(("error = %d from copyin(%p, %p, %d)\n", error, 1016101774Salfred uap->sops, sops, nsops * sizeof(sops[0]))); 1017123667Stjr if (sops != small_sops) 1018123667Stjr free(sops, M_SEM); 1019101774Salfred return (error); 1020101774Salfred } 10212729Sdfr 1022137613Srwatson semakptr = &sema[semid]; 1023101774Salfred sema_mtxp = &sema_mtx[semid]; 1024101774Salfred mtx_lock(sema_mtxp); 1025137613Srwatson if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) { 102682607Sdillon error = EINVAL; 102782607Sdillon goto done2; 102882607Sdillon } 1029187223Skib seq = semakptr->u.sem_perm.seq; 1030187223Skib if (seq != IPCID_TO_SEQ(uap->semid)) { 103182607Sdillon error = EINVAL; 103282607Sdillon goto done2; 103382607Sdillon } 103484789Smr /* 103584789Smr * Initial pass thru sops to see what permissions are needed. 103684789Smr * Also perform any checks that don't need repeating on each 103784789Smr * attempt to satisfy the request vector. 103884789Smr */ 103984789Smr j = 0; /* permission needed */ 104084789Smr do_undos = 0; 104184789Smr for (i = 0; i < nsops; i++) { 104284789Smr sopptr = &sops[i]; 1043137613Srwatson if (sopptr->sem_num >= semakptr->u.sem_nsems) { 104484789Smr error = EFBIG; 104584789Smr goto done2; 104684789Smr } 104784789Smr if (sopptr->sem_flg & SEM_UNDO && sopptr->sem_op != 0) 104884789Smr do_undos = 1; 104984789Smr j |= (sopptr->sem_op == 0) ? SEM_R : SEM_A; 105084789Smr } 105184789Smr 1052137613Srwatson if ((error = ipcperm(td, &semakptr->u.sem_perm, j))) { 1053100523Salfred DPRINTF(("error = %d from ipaccess\n", error)); 105482607Sdillon goto done2; 10552729Sdfr } 1056140615Srwatson#ifdef MAC 1057172930Srwatson error = mac_sysvsem_check_semop(td->td_ucred, semakptr, j); 1058162468Srwatson if (error != 0) 1059140615Srwatson goto done2; 1060140615Srwatson#endif 10612729Sdfr 10628876Srgrimes /* 10632729Sdfr * Loop trying to satisfy the vector of requests. 10642729Sdfr * If we reach a point where we must wait, any requests already 10652729Sdfr * performed are rolled back and we go to sleep until some other 10662729Sdfr * process wakes us up. At this point, we start all over again. 10672729Sdfr * 10682729Sdfr * This ensures that from the perspective of other tasks, a set 10692729Sdfr * of requests is atomic (never partially satisfied). 10702729Sdfr */ 10712729Sdfr for (;;) { 10722729Sdfr do_wakeup = 0; 107384789Smr error = 0; /* error return if necessary */ 10742729Sdfr 10752729Sdfr for (i = 0; i < nsops; i++) { 10762729Sdfr sopptr = &sops[i]; 1077137613Srwatson semptr = &semakptr->u.sem_base[sopptr->sem_num]; 10782729Sdfr 1079100523Salfred DPRINTF(( 1080160293Skib "semop: semakptr=%p, sem_base=%p, " 1081160293Skib "semptr=%p, sem[%d]=%d : op=%d, flag=%s\n", 1082137613Srwatson semakptr, semakptr->u.sem_base, semptr, 10832729Sdfr sopptr->sem_num, semptr->semval, sopptr->sem_op, 1084100523Salfred (sopptr->sem_flg & IPC_NOWAIT) ? 1085100523Salfred "nowait" : "wait")); 10862729Sdfr 10872729Sdfr if (sopptr->sem_op < 0) { 10882729Sdfr if (semptr->semval + sopptr->sem_op < 0) { 1089100523Salfred DPRINTF(("semop: can't do it now\n")); 10902729Sdfr break; 10912729Sdfr } else { 10922729Sdfr semptr->semval += sopptr->sem_op; 10932729Sdfr if (semptr->semval == 0 && 10942729Sdfr semptr->semzcnt > 0) 10952729Sdfr do_wakeup = 1; 10962729Sdfr } 10972729Sdfr } else if (sopptr->sem_op == 0) { 109884789Smr if (semptr->semval != 0) { 1099100523Salfred DPRINTF(("semop: not zero now\n")); 11002729Sdfr break; 11012729Sdfr } 110284789Smr } else if (semptr->semval + sopptr->sem_op > 110384789Smr seminfo.semvmx) { 110484789Smr error = ERANGE; 110584789Smr break; 11062729Sdfr } else { 11072729Sdfr if (semptr->semncnt > 0) 11082729Sdfr do_wakeup = 1; 11092729Sdfr semptr->semval += sopptr->sem_op; 11102729Sdfr } 11112729Sdfr } 11122729Sdfr 11132729Sdfr /* 11142729Sdfr * Did we get through the entire vector? 11152729Sdfr */ 11162729Sdfr if (i >= nsops) 11172729Sdfr goto done; 11182729Sdfr 11192729Sdfr /* 11202729Sdfr * No ... rollback anything that we've already done 11212729Sdfr */ 1122100523Salfred DPRINTF(("semop: rollback 0 through %d\n", i-1)); 11232729Sdfr for (j = 0; j < i; j++) 1124137613Srwatson semakptr->u.sem_base[sops[j].sem_num].semval -= 11252729Sdfr sops[j].sem_op; 11262729Sdfr 112784789Smr /* If we detected an error, return it */ 112884789Smr if (error != 0) 112984789Smr goto done2; 113084789Smr 11312729Sdfr /* 11322729Sdfr * If the request that we couldn't satisfy has the 11332729Sdfr * NOWAIT flag set then return with EAGAIN. 11342729Sdfr */ 113582607Sdillon if (sopptr->sem_flg & IPC_NOWAIT) { 113682607Sdillon error = EAGAIN; 113782607Sdillon goto done2; 113882607Sdillon } 11392729Sdfr 11402729Sdfr if (sopptr->sem_op == 0) 11412729Sdfr semptr->semzcnt++; 11422729Sdfr else 11432729Sdfr semptr->semncnt++; 11442729Sdfr 1145100523Salfred DPRINTF(("semop: good night!\n")); 1146137613Srwatson error = msleep(semakptr, sema_mtxp, (PZERO - 4) | PCATCH, 1147101774Salfred "semwait", 0); 1148100523Salfred DPRINTF(("semop: good morning (error=%d)!\n", error)); 1149127108Scperciva /* return code is checked below, after sem[nz]cnt-- */ 11502729Sdfr 11512729Sdfr /* 11522729Sdfr * Make sure that the semaphore still exists 11532729Sdfr */ 1154187223Skib seq = semakptr->u.sem_perm.seq; 1155137613Srwatson if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 1156187223Skib seq != IPCID_TO_SEQ(uap->semid)) { 115782607Sdillon error = EIDRM; 115882607Sdillon goto done2; 115982607Sdillon } 11602729Sdfr 11612729Sdfr /* 1162179879Sgonzo * Renew the semaphore's pointer after wakeup since 1163179879Sgonzo * during msleep sem_base may have been modified and semptr 1164179879Sgonzo * is not valid any more 1165179879Sgonzo */ 1166179879Sgonzo semptr = &semakptr->u.sem_base[sopptr->sem_num]; 1167179879Sgonzo 1168179879Sgonzo /* 11692729Sdfr * The semaphore is still alive. Readjust the count of 11702729Sdfr * waiting processes. 11712729Sdfr */ 11722729Sdfr if (sopptr->sem_op == 0) 11732729Sdfr semptr->semzcnt--; 11742729Sdfr else 11752729Sdfr semptr->semncnt--; 1176127108Scperciva 1177127108Scperciva /* 1178127108Scperciva * Is it really morning, or was our sleep interrupted? 1179127108Scperciva * (Delayed check of msleep() return code because we 1180127108Scperciva * need to decrement sem[nz]cnt either way.) 1181127108Scperciva */ 1182127108Scperciva if (error != 0) { 1183127108Scperciva error = EINTR; 1184127108Scperciva goto done2; 1185127108Scperciva } 1186127108Scperciva DPRINTF(("semop: good morning!\n")); 11872729Sdfr } 11882729Sdfr 11892729Sdfrdone: 11902729Sdfr /* 11912729Sdfr * Process any SEM_UNDO requests. 11922729Sdfr */ 11932729Sdfr if (do_undos) { 1194101774Salfred SEMUNDO_LOCK(); 119584789Smr suptr = NULL; 11962729Sdfr for (i = 0; i < nsops; i++) { 11972729Sdfr /* 11982729Sdfr * We only need to deal with SEM_UNDO's for non-zero 11992729Sdfr * op's. 12002729Sdfr */ 12012729Sdfr int adjval; 12022729Sdfr 12032729Sdfr if ((sops[i].sem_flg & SEM_UNDO) == 0) 12042729Sdfr continue; 12052729Sdfr adjval = sops[i].sem_op; 12062729Sdfr if (adjval == 0) 12072729Sdfr continue; 1208187223Skib error = semundo_adjust(td, &suptr, semid, seq, 12092729Sdfr sops[i].sem_num, -adjval); 121082607Sdillon if (error == 0) 12112729Sdfr continue; 12122729Sdfr 12132729Sdfr /* 12142729Sdfr * Oh-Oh! We ran out of either sem_undo's or undo's. 12152729Sdfr * Rollback the adjustments to this point and then 12162729Sdfr * rollback the semaphore ups and down so we can return 12172729Sdfr * with an error with all structures restored. We 12182729Sdfr * rollback the undo's in the exact reverse order that 12192729Sdfr * we applied them. This guarantees that we won't run 12202729Sdfr * out of space as we roll things back out. 12212729Sdfr */ 1222110040Stjr for (j = 0; j < i; j++) { 1223110040Stjr k = i - j - 1; 1224110040Stjr if ((sops[k].sem_flg & SEM_UNDO) == 0) 12252729Sdfr continue; 1226110040Stjr adjval = sops[k].sem_op; 12272729Sdfr if (adjval == 0) 12282729Sdfr continue; 1229187223Skib if (semundo_adjust(td, &suptr, semid, seq, 1230110040Stjr sops[k].sem_num, adjval) != 0) 12312729Sdfr panic("semop - can't undo undos"); 12322729Sdfr } 12332729Sdfr 12342729Sdfr for (j = 0; j < nsops; j++) 1235137613Srwatson semakptr->u.sem_base[sops[j].sem_num].semval -= 12362729Sdfr sops[j].sem_op; 12372729Sdfr 1238100523Salfred DPRINTF(("error = %d from semundo_adjust\n", error)); 1239101774Salfred SEMUNDO_UNLOCK(); 124082607Sdillon goto done2; 12412729Sdfr } /* loop through the sops */ 1242101774Salfred SEMUNDO_UNLOCK(); 12432729Sdfr } /* if (do_undos) */ 12442729Sdfr 124584789Smr /* We're definitely done - set the sempid's and time */ 12462729Sdfr for (i = 0; i < nsops; i++) { 12472729Sdfr sopptr = &sops[i]; 1248137613Srwatson semptr = &semakptr->u.sem_base[sopptr->sem_num]; 124983366Sjulian semptr->sempid = td->td_proc->p_pid; 12502729Sdfr } 1251137613Srwatson semakptr->u.sem_otime = time_second; 12522729Sdfr 125384789Smr /* 125484789Smr * Do a wakeup if any semaphore was up'd whilst something was 125584789Smr * sleeping on it. 125684789Smr */ 12572729Sdfr if (do_wakeup) { 1258100523Salfred DPRINTF(("semop: doing wakeup\n")); 1259137613Srwatson wakeup(semakptr); 1260100523Salfred DPRINTF(("semop: back from wakeup\n")); 12612729Sdfr } 1262100523Salfred DPRINTF(("semop: done\n")); 126383366Sjulian td->td_retval[0] = 0; 126482607Sdillondone2: 1265101774Salfred mtx_unlock(sema_mtxp); 1266123667Stjr if (sops != small_sops) 1267123667Stjr free(sops, M_SEM); 126882607Sdillon return (error); 12692729Sdfr} 12702729Sdfr 12712729Sdfr/* 12722729Sdfr * Go through the undo structures for this process and apply the adjustments to 12732729Sdfr * semaphores. 12742729Sdfr */ 127569449Salfredstatic void 1276187223Skibsemexit_myhook(void *arg, struct proc *p) 12772729Sdfr{ 1278101350Salfred struct sem_undo *suptr; 1279187223Skib struct semid_kernel *semakptr; 1280187223Skib struct mtx *sema_mtxp; 1281187223Skib int semid, semnum, adjval, ix; 1282187223Skib unsigned short seq; 12832729Sdfr 12842729Sdfr /* 12852729Sdfr * Go through the chain of undo vectors looking for one 12862729Sdfr * associated with this process. 12872729Sdfr */ 1288101774Salfred SEMUNDO_LOCK(); 1289187223Skib LIST_FOREACH(suptr, &semu_list, un_next) { 1290187223Skib if (suptr->un_proc == p) 12912729Sdfr break; 12922729Sdfr } 1293187223Skib if (suptr == NULL) { 1294187223Skib SEMUNDO_UNLOCK(); 129559828Speter return; 1296187223Skib } 1297187223Skib LIST_REMOVE(suptr, un_next); 12982729Sdfr 1299160293Skib DPRINTF(("proc @%p has undo structure with %d entries\n", p, 1300100523Salfred suptr->un_cnt)); 13012729Sdfr 13022729Sdfr /* 13032729Sdfr * If there are any active undo elements then process them. 13042729Sdfr */ 13052729Sdfr if (suptr->un_cnt > 0) { 1306187223Skib SEMUNDO_UNLOCK(); 13072729Sdfr for (ix = 0; ix < suptr->un_cnt; ix++) { 1308187223Skib semid = suptr->un_ent[ix].un_id; 1309187223Skib semnum = suptr->un_ent[ix].un_num; 1310187223Skib adjval = suptr->un_ent[ix].un_adjval; 1311187223Skib seq = suptr->un_ent[ix].un_seq; 1312137613Srwatson semakptr = &sema[semid]; 1313101774Salfred sema_mtxp = &sema_mtx[semid]; 1314187223Skib 1315101774Salfred mtx_lock(sema_mtxp); 1316187223Skib if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || 1317187223Skib (semakptr->u.sem_perm.seq != seq)) { 1318187223Skib mtx_unlock(sema_mtxp); 1319187223Skib continue; 1320187223Skib } 1321137613Srwatson if (semnum >= semakptr->u.sem_nsems) 13222729Sdfr panic("semexit - semnum out of range"); 13232729Sdfr 1324100523Salfred DPRINTF(( 1325160293Skib "semexit: %p id=%d num=%d(adj=%d) ; sem=%d\n", 13262729Sdfr suptr->un_proc, suptr->un_ent[ix].un_id, 13272729Sdfr suptr->un_ent[ix].un_num, 13282729Sdfr suptr->un_ent[ix].un_adjval, 1329137613Srwatson semakptr->u.sem_base[semnum].semval)); 13302729Sdfr 1331187223Skib if (adjval < 0 && semakptr->u.sem_base[semnum].semval < 1332187223Skib -adjval) 1333187223Skib semakptr->u.sem_base[semnum].semval = 0; 1334187223Skib else 1335137613Srwatson semakptr->u.sem_base[semnum].semval += adjval; 13362729Sdfr 1337137613Srwatson wakeup(semakptr); 1338100523Salfred DPRINTF(("semexit: back from wakeup\n")); 1339101774Salfred mtx_unlock(sema_mtxp); 13402729Sdfr } 1341187223Skib SEMUNDO_LOCK(); 13422729Sdfr } 13432729Sdfr 13442729Sdfr /* 13452729Sdfr * Deallocate the undo vector. 13462729Sdfr */ 1347100523Salfred DPRINTF(("removing vector\n")); 13482729Sdfr suptr->un_proc = NULL; 1349187223Skib suptr->un_cnt = 0; 1350187223Skib LIST_INSERT_HEAD(&semu_free_list, suptr, un_next); 1351167904Semaste SEMUNDO_UNLOCK(); 13522729Sdfr} 135377461Sdd 135477461Sddstatic int 135577461Sddsysctl_sema(SYSCTL_HANDLER_ARGS) 135677461Sdd{ 135777461Sdd 135877461Sdd return (SYSCTL_OUT(req, sema, 1359137613Srwatson sizeof(struct semid_kernel) * seminfo.semmni)); 136077461Sdd} 1361194894Sjhb 1362194894Sjhb#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1363194894Sjhb defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1364194894Sjhb 1365194894Sjhb/* XXX casting to (sy_call_t *) is bogus, as usual. */ 1366194894Sjhbstatic sy_call_t *semcalls[] = { 1367194910Sjhb (sy_call_t *)freebsd7___semctl, (sy_call_t *)semget, 1368194894Sjhb (sy_call_t *)semop 1369194894Sjhb}; 1370194894Sjhb 1371194894Sjhb/* 1372194894Sjhb * Entry point for all SEM calls. 1373194894Sjhb */ 1374194894Sjhbint 1375194894Sjhbsemsys(td, uap) 1376194894Sjhb struct thread *td; 1377194894Sjhb /* XXX actually varargs. */ 1378194894Sjhb struct semsys_args /* { 1379194894Sjhb int which; 1380194894Sjhb int a2; 1381194894Sjhb int a3; 1382194894Sjhb int a4; 1383194894Sjhb int a5; 1384194894Sjhb } */ *uap; 1385194894Sjhb{ 1386194894Sjhb int error; 1387194894Sjhb 1388194894Sjhb if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC)) 1389194894Sjhb return (ENOSYS); 1390194894Sjhb if (uap->which < 0 || 1391194894Sjhb uap->which >= sizeof(semcalls)/sizeof(semcalls[0])) 1392194894Sjhb return (EINVAL); 1393194894Sjhb error = (*semcalls[uap->which])(td, &uap->a2); 1394194894Sjhb return (error); 1395194894Sjhb} 1396194910Sjhb 1397205323Skib#ifndef CP 1398194910Sjhb#define CP(src, dst, fld) do { (dst).fld = (src).fld; } while (0) 1399205323Skib#endif 1400194910Sjhb 1401194910Sjhb#ifndef _SYS_SYSPROTO_H_ 1402194910Sjhbstruct freebsd7___semctl_args { 1403194910Sjhb int semid; 1404194910Sjhb int semnum; 1405194910Sjhb int cmd; 1406194910Sjhb union semun_old *arg; 1407194910Sjhb}; 1408194910Sjhb#endif 1409194910Sjhbint 1410194910Sjhbfreebsd7___semctl(struct thread *td, struct freebsd7___semctl_args *uap) 1411194910Sjhb{ 1412194910Sjhb struct semid_ds_old dsold; 1413194910Sjhb struct semid_ds dsbuf; 1414194910Sjhb union semun_old arg; 1415194910Sjhb union semun semun; 1416194910Sjhb register_t rval; 1417194910Sjhb int error; 1418194910Sjhb 1419194910Sjhb switch (uap->cmd) { 1420194910Sjhb case SEM_STAT: 1421194910Sjhb case IPC_SET: 1422194910Sjhb case IPC_STAT: 1423194910Sjhb case GETALL: 1424194910Sjhb case SETVAL: 1425194910Sjhb case SETALL: 1426194910Sjhb error = copyin(uap->arg, &arg, sizeof(arg)); 1427194910Sjhb if (error) 1428194910Sjhb return (error); 1429194910Sjhb break; 1430194910Sjhb } 1431194910Sjhb 1432194910Sjhb switch (uap->cmd) { 1433194910Sjhb case SEM_STAT: 1434194910Sjhb case IPC_STAT: 1435194910Sjhb semun.buf = &dsbuf; 1436194910Sjhb break; 1437194910Sjhb case IPC_SET: 1438194910Sjhb error = copyin(arg.buf, &dsold, sizeof(dsold)); 1439194910Sjhb if (error) 1440194910Sjhb return (error); 1441194910Sjhb ipcperm_old2new(&dsold.sem_perm, &dsbuf.sem_perm); 1442194910Sjhb CP(dsold, dsbuf, sem_base); 1443194910Sjhb CP(dsold, dsbuf, sem_nsems); 1444194910Sjhb CP(dsold, dsbuf, sem_otime); 1445194910Sjhb CP(dsold, dsbuf, sem_ctime); 1446194910Sjhb semun.buf = &dsbuf; 1447194910Sjhb break; 1448194910Sjhb case GETALL: 1449194910Sjhb case SETALL: 1450194910Sjhb semun.array = arg.array; 1451194910Sjhb break; 1452194910Sjhb case SETVAL: 1453194910Sjhb semun.val = arg.val; 1454194910Sjhb break; 1455194910Sjhb } 1456194910Sjhb 1457194910Sjhb error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1458194910Sjhb &rval); 1459194910Sjhb if (error) 1460194910Sjhb return (error); 1461194910Sjhb 1462194910Sjhb switch (uap->cmd) { 1463194910Sjhb case SEM_STAT: 1464194910Sjhb case IPC_STAT: 1465194910Sjhb bzero(&dsold, sizeof(dsold)); 1466194910Sjhb ipcperm_new2old(&dsbuf.sem_perm, &dsold.sem_perm); 1467194910Sjhb CP(dsbuf, dsold, sem_base); 1468194910Sjhb CP(dsbuf, dsold, sem_nsems); 1469194910Sjhb CP(dsbuf, dsold, sem_otime); 1470194910Sjhb CP(dsbuf, dsold, sem_ctime); 1471194910Sjhb error = copyout(&dsold, arg.buf, sizeof(dsold)); 1472194910Sjhb break; 1473194910Sjhb } 1474194910Sjhb 1475194910Sjhb if (error == 0) 1476194910Sjhb td->td_retval[0] = rval; 1477194910Sjhb return (error); 1478194910Sjhb} 1479194910Sjhb 1480205323Skib#endif /* COMPAT_FREEBSD{4,5,6,7} */ 1481194910Sjhb 1482205323Skib#ifdef COMPAT_FREEBSD32 1483205323Skib 1484205323Skibint 1485205323Skibfreebsd32_semsys(struct thread *td, struct freebsd32_semsys_args *uap) 1486205323Skib{ 1487205323Skib 1488205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1489205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1490205323Skib switch (uap->which) { 1491205323Skib case 0: 1492205323Skib return (freebsd7_freebsd32_semctl(td, 1493205323Skib (struct freebsd7_freebsd32_semctl_args *)&uap->a2)); 1494205323Skib default: 1495205323Skib return (semsys(td, (struct semsys_args *)uap)); 1496205323Skib } 1497205323Skib#else 1498205323Skib return (nosys(td, NULL)); 1499205323Skib#endif 1500205323Skib} 1501205323Skib 1502205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ 1503205323Skib defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) 1504205323Skibint 1505205323Skibfreebsd7_freebsd32_semctl(struct thread *td, 1506205323Skib struct freebsd7_freebsd32_semctl_args *uap) 1507205323Skib{ 1508205323Skib struct semid_ds32_old dsbuf32; 1509205323Skib struct semid_ds dsbuf; 1510205323Skib union semun semun; 1511205323Skib union semun32 arg; 1512205323Skib register_t rval; 1513205323Skib int error; 1514205323Skib 1515205323Skib switch (uap->cmd) { 1516205323Skib case SEM_STAT: 1517205323Skib case IPC_SET: 1518205323Skib case IPC_STAT: 1519205323Skib case GETALL: 1520205323Skib case SETVAL: 1521205323Skib case SETALL: 1522205323Skib error = copyin(uap->arg, &arg, sizeof(arg)); 1523205323Skib if (error) 1524205323Skib return (error); 1525205323Skib break; 1526205323Skib } 1527205323Skib 1528205323Skib switch (uap->cmd) { 1529205323Skib case SEM_STAT: 1530205323Skib case IPC_STAT: 1531205323Skib semun.buf = &dsbuf; 1532205323Skib break; 1533205323Skib case IPC_SET: 1534205323Skib error = copyin(PTRIN(arg.buf), &dsbuf32, sizeof(dsbuf32)); 1535205323Skib if (error) 1536205323Skib return (error); 1537205323Skib freebsd32_ipcperm_old_in(&dsbuf32.sem_perm, &dsbuf.sem_perm); 1538205323Skib PTRIN_CP(dsbuf32, dsbuf, sem_base); 1539205323Skib CP(dsbuf32, dsbuf, sem_nsems); 1540205323Skib CP(dsbuf32, dsbuf, sem_otime); 1541205323Skib CP(dsbuf32, dsbuf, sem_ctime); 1542205323Skib semun.buf = &dsbuf; 1543205323Skib break; 1544205323Skib case GETALL: 1545205323Skib case SETALL: 1546205323Skib semun.array = PTRIN(arg.array); 1547205323Skib break; 1548205323Skib case SETVAL: 1549205323Skib semun.val = arg.val; 1550205323Skib break; 1551205323Skib } 1552205323Skib 1553205323Skib error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1554205323Skib &rval); 1555205323Skib if (error) 1556205323Skib return (error); 1557205323Skib 1558205323Skib switch (uap->cmd) { 1559205323Skib case SEM_STAT: 1560205323Skib case IPC_STAT: 1561205323Skib bzero(&dsbuf32, sizeof(dsbuf32)); 1562205323Skib freebsd32_ipcperm_old_out(&dsbuf.sem_perm, &dsbuf32.sem_perm); 1563205323Skib PTROUT_CP(dsbuf, dsbuf32, sem_base); 1564205323Skib CP(dsbuf, dsbuf32, sem_nsems); 1565205323Skib CP(dsbuf, dsbuf32, sem_otime); 1566205323Skib CP(dsbuf, dsbuf32, sem_ctime); 1567205323Skib error = copyout(&dsbuf32, PTRIN(arg.buf), sizeof(dsbuf32)); 1568205323Skib break; 1569205323Skib } 1570205323Skib 1571205323Skib if (error == 0) 1572205323Skib td->td_retval[0] = rval; 1573205323Skib return (error); 1574205323Skib} 1575205323Skib#endif 1576205323Skib 1577205323Skibint 1578205323Skibfreebsd32_semctl(struct thread *td, struct freebsd32_semctl_args *uap) 1579205323Skib{ 1580205323Skib struct semid_ds32 dsbuf32; 1581205323Skib struct semid_ds dsbuf; 1582205323Skib union semun semun; 1583205323Skib union semun32 arg; 1584205323Skib register_t rval; 1585205323Skib int error; 1586205323Skib 1587205323Skib switch (uap->cmd) { 1588205323Skib case SEM_STAT: 1589205323Skib case IPC_SET: 1590205323Skib case IPC_STAT: 1591205323Skib case GETALL: 1592205323Skib case SETVAL: 1593205323Skib case SETALL: 1594205323Skib error = copyin(uap->arg, &arg, sizeof(arg)); 1595205323Skib if (error) 1596205323Skib return (error); 1597205323Skib break; 1598205323Skib } 1599205323Skib 1600205323Skib switch (uap->cmd) { 1601205323Skib case SEM_STAT: 1602205323Skib case IPC_STAT: 1603205323Skib semun.buf = &dsbuf; 1604205323Skib break; 1605205323Skib case IPC_SET: 1606205323Skib error = copyin(PTRIN(arg.buf), &dsbuf32, sizeof(dsbuf32)); 1607205323Skib if (error) 1608205323Skib return (error); 1609205323Skib freebsd32_ipcperm_in(&dsbuf32.sem_perm, &dsbuf.sem_perm); 1610205323Skib PTRIN_CP(dsbuf32, dsbuf, sem_base); 1611205323Skib CP(dsbuf32, dsbuf, sem_nsems); 1612205323Skib CP(dsbuf32, dsbuf, sem_otime); 1613205323Skib CP(dsbuf32, dsbuf, sem_ctime); 1614205323Skib semun.buf = &dsbuf; 1615205323Skib break; 1616205323Skib case GETALL: 1617205323Skib case SETALL: 1618205323Skib semun.array = PTRIN(arg.array); 1619205323Skib break; 1620205323Skib case SETVAL: 1621205323Skib semun.val = arg.val; 1622205323Skib break; 1623205323Skib } 1624205323Skib 1625205323Skib error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun, 1626205323Skib &rval); 1627205323Skib if (error) 1628205323Skib return (error); 1629205323Skib 1630205323Skib switch (uap->cmd) { 1631205323Skib case SEM_STAT: 1632205323Skib case IPC_STAT: 1633205323Skib bzero(&dsbuf32, sizeof(dsbuf32)); 1634205323Skib freebsd32_ipcperm_out(&dsbuf.sem_perm, &dsbuf32.sem_perm); 1635205323Skib PTROUT_CP(dsbuf, dsbuf32, sem_base); 1636205323Skib CP(dsbuf, dsbuf32, sem_nsems); 1637205323Skib CP(dsbuf, dsbuf32, sem_otime); 1638205323Skib CP(dsbuf, dsbuf32, sem_ctime); 1639205323Skib error = copyout(&dsbuf32, PTRIN(arg.buf), sizeof(dsbuf32)); 1640205323Skib break; 1641205323Skib } 1642205323Skib 1643205323Skib if (error == 0) 1644205323Skib td->td_retval[0] = rval; 1645205323Skib return (error); 1646205323Skib} 1647205323Skib 1648205323Skib#endif /* COMPAT_FREEBSD32 */ 1649