xref: /illumos-gate/usr/src/uts/common/syscall/sem.c (revision 7c478bd95313f5f23a4c958a745db2134aa0324)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate /*
34*7c478bd9Sstevel@tonic-gate  * Inter-Process Communication Semaphore Facility.
35*7c478bd9Sstevel@tonic-gate  *
36*7c478bd9Sstevel@tonic-gate  * See os/ipc.c for a description of common IPC functionality.
37*7c478bd9Sstevel@tonic-gate  *
38*7c478bd9Sstevel@tonic-gate  * Resource controls
39*7c478bd9Sstevel@tonic-gate  * -----------------
40*7c478bd9Sstevel@tonic-gate  *
41*7c478bd9Sstevel@tonic-gate  * Control:      project.max-sem-ids (rc_project_semmni)
42*7c478bd9Sstevel@tonic-gate  * Description:  Maximum number of semaphore ids allowed a project.
43*7c478bd9Sstevel@tonic-gate  *
44*7c478bd9Sstevel@tonic-gate  *   When semget() is used to allocate a semaphore set, one id is
45*7c478bd9Sstevel@tonic-gate  *   allocated.  If the id allocation doesn't succeed, semget() fails
46*7c478bd9Sstevel@tonic-gate  *   and errno is set to ENOSPC.  Upon successful semctl(, IPC_RMID)
47*7c478bd9Sstevel@tonic-gate  *   the id is deallocated.
48*7c478bd9Sstevel@tonic-gate  *
49*7c478bd9Sstevel@tonic-gate  * Control:      process.max-sem-nsems (rc_process_semmsl)
50*7c478bd9Sstevel@tonic-gate  * Description:  Maximum number of semaphores allowed per semaphore set.
51*7c478bd9Sstevel@tonic-gate  *
52*7c478bd9Sstevel@tonic-gate  *   When semget() is used to allocate a semaphore set, the size of the
53*7c478bd9Sstevel@tonic-gate  *   set is compared with this limit.  If the number of semaphores
54*7c478bd9Sstevel@tonic-gate  *   exceeds the limit, semget() fails and errno is set to EINVAL.
55*7c478bd9Sstevel@tonic-gate  *
56*7c478bd9Sstevel@tonic-gate  * Control:      process.max-sem-ops (rc_process_semopm)
57*7c478bd9Sstevel@tonic-gate  * Description:  Maximum number of semaphore operations allowed per
58*7c478bd9Sstevel@tonic-gate  *               semop call.
59*7c478bd9Sstevel@tonic-gate  *
60*7c478bd9Sstevel@tonic-gate  *   When semget() successfully allocates a semaphore set, the minimum
61*7c478bd9Sstevel@tonic-gate  *   enforced value of this limit is used to initialize the
62*7c478bd9Sstevel@tonic-gate  *   "system-imposed maximum" number of operations a semop() call for
63*7c478bd9Sstevel@tonic-gate  *   this set can perform.
64*7c478bd9Sstevel@tonic-gate  *
65*7c478bd9Sstevel@tonic-gate  * Undo structures
66*7c478bd9Sstevel@tonic-gate  * ---------------
67*7c478bd9Sstevel@tonic-gate  *
68*7c478bd9Sstevel@tonic-gate  * Removing the undo structure tunables involved a serious redesign of
69*7c478bd9Sstevel@tonic-gate  * how they were implemented.  There is now one undo structure for
70*7c478bd9Sstevel@tonic-gate  * every process/semaphore array combination (lazily allocated, of
71*7c478bd9Sstevel@tonic-gate  * course), and each is equal in size to the semaphore it corresponds
72*7c478bd9Sstevel@tonic-gate  * to.  To avoid scalability and performance problems, the undo
73*7c478bd9Sstevel@tonic-gate  * structures are stored in two places: a per-process AVL tree sorted
74*7c478bd9Sstevel@tonic-gate  * by ksemid pointer (p_semacct, protected by p_lock) and an unsorted
75*7c478bd9Sstevel@tonic-gate  * per-semaphore linked list (sem_undos, protected by the semaphore's
76*7c478bd9Sstevel@tonic-gate  * ID lock).  The former is used by semop, where a lookup is performed
77*7c478bd9Sstevel@tonic-gate  * once and cached if SEM_UNDO is specified for any of the operations,
78*7c478bd9Sstevel@tonic-gate  * and at process exit where the undoable operations are rolled back.
79*7c478bd9Sstevel@tonic-gate  * The latter is used when removing the semaphore, so the undo
80*7c478bd9Sstevel@tonic-gate  * structures can be removed from the appropriate processes' trees.
81*7c478bd9Sstevel@tonic-gate  *
82*7c478bd9Sstevel@tonic-gate  * The undo structure itself contains pointers to the ksemid and proc
83*7c478bd9Sstevel@tonic-gate  * to which it corresponds, a list node, an AVL node, and an array of
84*7c478bd9Sstevel@tonic-gate  * adjust-on-exit (AOE) values.  When an undo structure is allocated it
85*7c478bd9Sstevel@tonic-gate  * is immediately added to both the process's tree and the semaphore's
86*7c478bd9Sstevel@tonic-gate  * list.  Lastly, the reference count on the semaphore is increased.
87*7c478bd9Sstevel@tonic-gate  *
88*7c478bd9Sstevel@tonic-gate  * Avoiding a lock ordering violation between p_lock and the ID lock,
89*7c478bd9Sstevel@tonic-gate  * wont to occur when there is a race between a process exiting and the
90*7c478bd9Sstevel@tonic-gate  * removal of a semaphore, mandates the delicate dance that exists
91*7c478bd9Sstevel@tonic-gate  * between semexit and sem_rmid.
92*7c478bd9Sstevel@tonic-gate  *
93*7c478bd9Sstevel@tonic-gate  * sem_rmid, holding the ID lock, iterates through all undo structures
94*7c478bd9Sstevel@tonic-gate  * and for each takes the appropriate process's p_lock and checks to
95*7c478bd9Sstevel@tonic-gate  * see if p_semacct is NULL.  If it is, it skips that undo structure
96*7c478bd9Sstevel@tonic-gate  * and continues to the next.  Otherwise, it removes the undo structure
97*7c478bd9Sstevel@tonic-gate  * from both the AVL tree and the semaphore's list, and releases the
98*7c478bd9Sstevel@tonic-gate  * hold that the undo structure had on the semaphore.
99*7c478bd9Sstevel@tonic-gate  *
100*7c478bd9Sstevel@tonic-gate  * The important other half of this is semexit, which will immediately
101*7c478bd9Sstevel@tonic-gate  * take p_lock, obtain the AVL pointer, clear p_semacct, and drop
102*7c478bd9Sstevel@tonic-gate  * p_lock.  From this point on it is semexit's responsibility to clean
103*7c478bd9Sstevel@tonic-gate  * up all undo structures found in the tree -- a coexecuting sem_rmid
104*7c478bd9Sstevel@tonic-gate  * will see the NULL p_semacct and skip that undo structure.  It walks
105*7c478bd9Sstevel@tonic-gate  * the AVL tree (using avl_destroy_nodes) and for each undo structure
106*7c478bd9Sstevel@tonic-gate  * takes the appropriate semaphore's ID lock (always legal since the
107*7c478bd9Sstevel@tonic-gate  * undo structure has a hold on the semaphore), updates all semaphores
108*7c478bd9Sstevel@tonic-gate  * with non-zero AOE values, and removes the structure from the
109*7c478bd9Sstevel@tonic-gate  * semaphore's list.  It then drops the structure's reference on the
110*7c478bd9Sstevel@tonic-gate  * semaphore, drops the ID lock, and frees the undo structure.
111*7c478bd9Sstevel@tonic-gate  */
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
114*7c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
115*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
116*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
117*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
118*7c478bd9Sstevel@tonic-gate #include <sys/cred.h>
119*7c478bd9Sstevel@tonic-gate #include <sys/vmem.h>
120*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
121*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
122*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
123*7c478bd9Sstevel@tonic-gate #include <sys/ipc.h>
124*7c478bd9Sstevel@tonic-gate #include <sys/ipc_impl.h>
125*7c478bd9Sstevel@tonic-gate #include <sys/sem.h>
126*7c478bd9Sstevel@tonic-gate #include <sys/sem_impl.h>
127*7c478bd9Sstevel@tonic-gate #include <sys/user.h>
128*7c478bd9Sstevel@tonic-gate #include <sys/proc.h>
129*7c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
130*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
131*7c478bd9Sstevel@tonic-gate #include <sys/var.h>
132*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
133*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
134*7c478bd9Sstevel@tonic-gate #include <sys/syscall.h>
135*7c478bd9Sstevel@tonic-gate #include <sys/avl.h>
136*7c478bd9Sstevel@tonic-gate #include <sys/list.h>
137*7c478bd9Sstevel@tonic-gate #include <sys/zone.h>
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate #include <c2/audit.h>
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate extern rctl_hndl_t rc_project_semmni;
142*7c478bd9Sstevel@tonic-gate extern rctl_hndl_t rc_process_semmsl;
143*7c478bd9Sstevel@tonic-gate extern rctl_hndl_t rc_process_semopm;
144*7c478bd9Sstevel@tonic-gate static ipc_service_t *sem_svc;
145*7c478bd9Sstevel@tonic-gate static zone_key_t sem_zone_key;
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate /*
148*7c478bd9Sstevel@tonic-gate  * The following tunables are obsolete.  Though for compatibility we
149*7c478bd9Sstevel@tonic-gate  * still read and interpret seminfo_semmsl, seminfo_semopm and
150*7c478bd9Sstevel@tonic-gate  * seminfo_semmni (see os/project.c and os/rctl_proc.c), the preferred
151*7c478bd9Sstevel@tonic-gate  * mechanism for administrating the IPC Semaphore facility is through
152*7c478bd9Sstevel@tonic-gate  * the resource controls described at the top of this file.
153*7c478bd9Sstevel@tonic-gate  */
154*7c478bd9Sstevel@tonic-gate int seminfo_semaem = 16384;	/* (obsolete) */
155*7c478bd9Sstevel@tonic-gate int seminfo_semmap = 10;	/* (obsolete) */
156*7c478bd9Sstevel@tonic-gate int seminfo_semmni = 10;	/* (obsolete) */
157*7c478bd9Sstevel@tonic-gate int seminfo_semmns = 60;	/* (obsolete) */
158*7c478bd9Sstevel@tonic-gate int seminfo_semmnu = 30;	/* (obsolete) */
159*7c478bd9Sstevel@tonic-gate int seminfo_semmsl = 25;	/* (obsolete) */
160*7c478bd9Sstevel@tonic-gate int seminfo_semopm = 10;	/* (obsolete) */
161*7c478bd9Sstevel@tonic-gate int seminfo_semume = 10;	/* (obsolete) */
162*7c478bd9Sstevel@tonic-gate int seminfo_semusz = 96;	/* (obsolete) */
163*7c478bd9Sstevel@tonic-gate int seminfo_semvmx = 32767;	/* (obsolete) */
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate #define	SEM_MAXUCOPS	4096	/* max # of unchecked ops per semop call */
166*7c478bd9Sstevel@tonic-gate #define	SEM_UNDOSZ(n)	(sizeof (struct sem_undo) + (n - 1) * sizeof (int))
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate static int semsys(int opcode, uintptr_t a0, uintptr_t a1,
169*7c478bd9Sstevel@tonic-gate     uintptr_t a2, uintptr_t a3);
170*7c478bd9Sstevel@tonic-gate static void sem_dtor(kipc_perm_t *);
171*7c478bd9Sstevel@tonic-gate static void sem_rmid(kipc_perm_t *);
172*7c478bd9Sstevel@tonic-gate static void sem_remove_zone(zoneid_t, void *);
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate static struct sysent ipcsem_sysent = {
175*7c478bd9Sstevel@tonic-gate 	5,
176*7c478bd9Sstevel@tonic-gate 	SE_NOUNLOAD | SE_ARGC | SE_32RVAL1,
177*7c478bd9Sstevel@tonic-gate 	semsys
178*7c478bd9Sstevel@tonic-gate };
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate /*
181*7c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
182*7c478bd9Sstevel@tonic-gate  */
183*7c478bd9Sstevel@tonic-gate static struct modlsys modlsys = {
184*7c478bd9Sstevel@tonic-gate 	&mod_syscallops, "System V semaphore facility", &ipcsem_sysent
185*7c478bd9Sstevel@tonic-gate };
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
188*7c478bd9Sstevel@tonic-gate static struct modlsys modlsys32 = {
189*7c478bd9Sstevel@tonic-gate 	&mod_syscallops32, "32-bit System V semaphore facility", &ipcsem_sysent
190*7c478bd9Sstevel@tonic-gate };
191*7c478bd9Sstevel@tonic-gate #endif
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
194*7c478bd9Sstevel@tonic-gate 	MODREV_1,
195*7c478bd9Sstevel@tonic-gate 	&modlsys,
196*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
197*7c478bd9Sstevel@tonic-gate 	&modlsys32,
198*7c478bd9Sstevel@tonic-gate #endif
199*7c478bd9Sstevel@tonic-gate 	NULL
200*7c478bd9Sstevel@tonic-gate };
201*7c478bd9Sstevel@tonic-gate 
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate int
204*7c478bd9Sstevel@tonic-gate _init(void)
205*7c478bd9Sstevel@tonic-gate {
206*7c478bd9Sstevel@tonic-gate 	int result;
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate 	sem_svc = ipcs_create("semids", rc_project_semmni, sizeof (ksemid_t),
209*7c478bd9Sstevel@tonic-gate 	    sem_dtor, sem_rmid, AT_IPC_SEM,
210*7c478bd9Sstevel@tonic-gate 	    offsetof(kproject_data_t, kpd_semmni));
211*7c478bd9Sstevel@tonic-gate 	zone_key_create(&sem_zone_key, NULL, sem_remove_zone, NULL);
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate 	if ((result = mod_install(&modlinkage)) == 0)
214*7c478bd9Sstevel@tonic-gate 		return (0);
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate 	(void) zone_key_delete(sem_zone_key);
217*7c478bd9Sstevel@tonic-gate 	ipcs_destroy(sem_svc);
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate 	return (result);
220*7c478bd9Sstevel@tonic-gate }
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate int
223*7c478bd9Sstevel@tonic-gate _fini(void)
224*7c478bd9Sstevel@tonic-gate {
225*7c478bd9Sstevel@tonic-gate 	return (EBUSY);
226*7c478bd9Sstevel@tonic-gate }
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate int
229*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
230*7c478bd9Sstevel@tonic-gate {
231*7c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
232*7c478bd9Sstevel@tonic-gate }
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate static void
235*7c478bd9Sstevel@tonic-gate sem_dtor(kipc_perm_t *perm)
236*7c478bd9Sstevel@tonic-gate {
237*7c478bd9Sstevel@tonic-gate 	ksemid_t *sp = (ksemid_t *)perm;
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 	kmem_free(sp->sem_base,
240*7c478bd9Sstevel@tonic-gate 	    P2ROUNDUP(sp->sem_nsems * sizeof (struct sem), 64));
241*7c478bd9Sstevel@tonic-gate 	list_destroy(&sp->sem_undos);
242*7c478bd9Sstevel@tonic-gate }
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate /*
245*7c478bd9Sstevel@tonic-gate  * sem_undo_add - Create or update adjust on exit entry.
246*7c478bd9Sstevel@tonic-gate  */
247*7c478bd9Sstevel@tonic-gate static int
248*7c478bd9Sstevel@tonic-gate sem_undo_add(short val, ushort_t num, struct sem_undo *undo)
249*7c478bd9Sstevel@tonic-gate {
250*7c478bd9Sstevel@tonic-gate 	int newval = undo->un_aoe[num] - val;
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate 	if (newval > USHRT_MAX || newval < -USHRT_MAX)
253*7c478bd9Sstevel@tonic-gate 		return (ERANGE);
254*7c478bd9Sstevel@tonic-gate 	undo->un_aoe[num] = newval;
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 	return (0);
257*7c478bd9Sstevel@tonic-gate }
258*7c478bd9Sstevel@tonic-gate 
259*7c478bd9Sstevel@tonic-gate /*
260*7c478bd9Sstevel@tonic-gate  * sem_undo_clear - clears all undo entries for specified semaphores
261*7c478bd9Sstevel@tonic-gate  *
262*7c478bd9Sstevel@tonic-gate  * Used when semaphores are reset by SETVAL or SETALL.
263*7c478bd9Sstevel@tonic-gate  */
264*7c478bd9Sstevel@tonic-gate static void
265*7c478bd9Sstevel@tonic-gate sem_undo_clear(ksemid_t *sp, ushort_t low, ushort_t high)
266*7c478bd9Sstevel@tonic-gate {
267*7c478bd9Sstevel@tonic-gate 	struct sem_undo *undo;
268*7c478bd9Sstevel@tonic-gate 	int i;
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate 	ASSERT(low <= high);
271*7c478bd9Sstevel@tonic-gate 	ASSERT(high < sp->sem_nsems);
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate 	for (undo = list_head(&sp->sem_undos); undo;
274*7c478bd9Sstevel@tonic-gate 	    undo = list_next(&sp->sem_undos, undo))
275*7c478bd9Sstevel@tonic-gate 		for (i = low; i <= high; i++)
276*7c478bd9Sstevel@tonic-gate 			undo->un_aoe[i] = 0;
277*7c478bd9Sstevel@tonic-gate }
278*7c478bd9Sstevel@tonic-gate 
279*7c478bd9Sstevel@tonic-gate /*
280*7c478bd9Sstevel@tonic-gate  * sem_rollback - roll back work done so far if unable to complete operation
281*7c478bd9Sstevel@tonic-gate  */
282*7c478bd9Sstevel@tonic-gate static void
283*7c478bd9Sstevel@tonic-gate sem_rollback(ksemid_t *sp, struct sembuf *op, int n, struct sem_undo *undo)
284*7c478bd9Sstevel@tonic-gate {
285*7c478bd9Sstevel@tonic-gate 	struct sem *semp;	/* semaphore ptr */
286*7c478bd9Sstevel@tonic-gate 
287*7c478bd9Sstevel@tonic-gate 	for (op += n - 1; n--; op--) {
288*7c478bd9Sstevel@tonic-gate 		if (op->sem_op == 0)
289*7c478bd9Sstevel@tonic-gate 			continue;
290*7c478bd9Sstevel@tonic-gate 		semp = &sp->sem_base[op->sem_num];
291*7c478bd9Sstevel@tonic-gate 		semp->semval -= op->sem_op;
292*7c478bd9Sstevel@tonic-gate 		if (op->sem_flg & SEM_UNDO) {
293*7c478bd9Sstevel@tonic-gate 			ASSERT(undo != NULL);
294*7c478bd9Sstevel@tonic-gate 			(void) sem_undo_add(-op->sem_op, op->sem_num, undo);
295*7c478bd9Sstevel@tonic-gate 		}
296*7c478bd9Sstevel@tonic-gate 	}
297*7c478bd9Sstevel@tonic-gate }
298*7c478bd9Sstevel@tonic-gate 
299*7c478bd9Sstevel@tonic-gate static void
300*7c478bd9Sstevel@tonic-gate sem_rmid(kipc_perm_t *perm)
301*7c478bd9Sstevel@tonic-gate {
302*7c478bd9Sstevel@tonic-gate 	ksemid_t *sp = (ksemid_t *)perm;
303*7c478bd9Sstevel@tonic-gate 	struct sem *semp;
304*7c478bd9Sstevel@tonic-gate 	struct sem_undo *undo;
305*7c478bd9Sstevel@tonic-gate 	size_t size = SEM_UNDOSZ(sp->sem_nsems);
306*7c478bd9Sstevel@tonic-gate 	int i;
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 	/*LINTED*/
309*7c478bd9Sstevel@tonic-gate 	while (undo = list_head(&sp->sem_undos)) {
310*7c478bd9Sstevel@tonic-gate 		list_remove(&sp->sem_undos, undo);
311*7c478bd9Sstevel@tonic-gate 		mutex_enter(&undo->un_proc->p_lock);
312*7c478bd9Sstevel@tonic-gate 		if (undo->un_proc->p_semacct == NULL) {
313*7c478bd9Sstevel@tonic-gate 			mutex_exit(&undo->un_proc->p_lock);
314*7c478bd9Sstevel@tonic-gate 			continue;
315*7c478bd9Sstevel@tonic-gate 		}
316*7c478bd9Sstevel@tonic-gate 		avl_remove(undo->un_proc->p_semacct, undo);
317*7c478bd9Sstevel@tonic-gate 		mutex_exit(&undo->un_proc->p_lock);
318*7c478bd9Sstevel@tonic-gate 		kmem_free(undo, size);
319*7c478bd9Sstevel@tonic-gate 		ipc_rele_locked(sem_svc, (kipc_perm_t *)sp);
320*7c478bd9Sstevel@tonic-gate 	}
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < sp->sem_nsems; i++) {
323*7c478bd9Sstevel@tonic-gate 		semp = &sp->sem_base[i];
324*7c478bd9Sstevel@tonic-gate 		semp->semval = semp->sempid = 0;
325*7c478bd9Sstevel@tonic-gate 		if (semp->semncnt) {
326*7c478bd9Sstevel@tonic-gate 			cv_broadcast(&semp->semncnt_cv);
327*7c478bd9Sstevel@tonic-gate 			semp->semncnt = 0;
328*7c478bd9Sstevel@tonic-gate 		}
329*7c478bd9Sstevel@tonic-gate 		if (semp->semzcnt) {
330*7c478bd9Sstevel@tonic-gate 			cv_broadcast(&semp->semzcnt_cv);
331*7c478bd9Sstevel@tonic-gate 			semp->semzcnt = 0;
332*7c478bd9Sstevel@tonic-gate 		}
333*7c478bd9Sstevel@tonic-gate 	}
334*7c478bd9Sstevel@tonic-gate }
335*7c478bd9Sstevel@tonic-gate 
336*7c478bd9Sstevel@tonic-gate /*
337*7c478bd9Sstevel@tonic-gate  * semctl - Semctl system call.
338*7c478bd9Sstevel@tonic-gate  */
339*7c478bd9Sstevel@tonic-gate static int
340*7c478bd9Sstevel@tonic-gate semctl(int semid, uint_t semnum, int cmd, uintptr_t arg)
341*7c478bd9Sstevel@tonic-gate {
342*7c478bd9Sstevel@tonic-gate 	ksemid_t		*sp;	/* ptr to semaphore header */
343*7c478bd9Sstevel@tonic-gate 	struct sem		*p;	/* ptr to semaphore */
344*7c478bd9Sstevel@tonic-gate 	unsigned int		i;	/* loop control */
345*7c478bd9Sstevel@tonic-gate 	ushort_t		*vals, *vp;
346*7c478bd9Sstevel@tonic-gate 	size_t			vsize = 0;
347*7c478bd9Sstevel@tonic-gate 	int			error = 0;
348*7c478bd9Sstevel@tonic-gate 	int			retval = 0;
349*7c478bd9Sstevel@tonic-gate 	struct cred		*cr;
350*7c478bd9Sstevel@tonic-gate 	kmutex_t		*lock;
351*7c478bd9Sstevel@tonic-gate 	model_t			mdl = get_udatamodel();
352*7c478bd9Sstevel@tonic-gate 	STRUCT_DECL(semid_ds, sid);
353*7c478bd9Sstevel@tonic-gate 	struct semid_ds64	ds64;
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate 	STRUCT_INIT(sid, mdl);
356*7c478bd9Sstevel@tonic-gate 	cr = CRED();
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate 	/*
359*7c478bd9Sstevel@tonic-gate 	 * Perform pre- or non-lookup actions (e.g. copyins, RMID).
360*7c478bd9Sstevel@tonic-gate 	 */
361*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
362*7c478bd9Sstevel@tonic-gate 	case IPC_SET:
363*7c478bd9Sstevel@tonic-gate 		if (copyin((void *)arg, STRUCT_BUF(sid), STRUCT_SIZE(sid)))
364*7c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
365*7c478bd9Sstevel@tonic-gate 		break;
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate 	case IPC_SET64:
368*7c478bd9Sstevel@tonic-gate 		if (copyin((void *)arg, &ds64, sizeof (struct semid_ds64)))
369*7c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
370*7c478bd9Sstevel@tonic-gate 		break;
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate 	case SETALL:
373*7c478bd9Sstevel@tonic-gate 		if ((lock = ipc_lookup(sem_svc, semid,
374*7c478bd9Sstevel@tonic-gate 		    (kipc_perm_t **)&sp)) == NULL)
375*7c478bd9Sstevel@tonic-gate 			return (set_errno(EINVAL));
376*7c478bd9Sstevel@tonic-gate 		vsize = sp->sem_nsems * sizeof (*vals);
377*7c478bd9Sstevel@tonic-gate 		mutex_exit(lock);
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 		/* allocate space to hold all semaphore values */
380*7c478bd9Sstevel@tonic-gate 		vals = kmem_alloc(vsize, KM_SLEEP);
381*7c478bd9Sstevel@tonic-gate 
382*7c478bd9Sstevel@tonic-gate 		if (copyin((void *)arg, vals, vsize)) {
383*7c478bd9Sstevel@tonic-gate 			kmem_free(vals, vsize);
384*7c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
385*7c478bd9Sstevel@tonic-gate 		}
386*7c478bd9Sstevel@tonic-gate 		break;
387*7c478bd9Sstevel@tonic-gate 
388*7c478bd9Sstevel@tonic-gate 	case IPC_RMID:
389*7c478bd9Sstevel@tonic-gate 		if (error = ipc_rmid(sem_svc, semid, cr))
390*7c478bd9Sstevel@tonic-gate 			return (set_errno(error));
391*7c478bd9Sstevel@tonic-gate 		return (0);
392*7c478bd9Sstevel@tonic-gate 	}
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate 	if ((lock = ipc_lookup(sem_svc, semid, (kipc_perm_t **)&sp)) == NULL) {
395*7c478bd9Sstevel@tonic-gate 		if (vsize != 0)
396*7c478bd9Sstevel@tonic-gate 			kmem_free(vals, vsize);
397*7c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
398*7c478bd9Sstevel@tonic-gate 	}
399*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
400*7c478bd9Sstevel@tonic-gate 	/* Set ownership and permissions. */
401*7c478bd9Sstevel@tonic-gate 	case IPC_SET:
402*7c478bd9Sstevel@tonic-gate 
403*7c478bd9Sstevel@tonic-gate 		if (error = ipcperm_set(sem_svc, cr, &sp->sem_perm,
404*7c478bd9Sstevel@tonic-gate 		    &STRUCT_BUF(sid)->sem_perm, mdl)) {
405*7c478bd9Sstevel@tonic-gate 			mutex_exit(lock);
406*7c478bd9Sstevel@tonic-gate 			return (set_errno(error));
407*7c478bd9Sstevel@tonic-gate 		}
408*7c478bd9Sstevel@tonic-gate 		sp->sem_ctime = gethrestime_sec();
409*7c478bd9Sstevel@tonic-gate 		mutex_exit(lock);
410*7c478bd9Sstevel@tonic-gate 		return (0);
411*7c478bd9Sstevel@tonic-gate 
412*7c478bd9Sstevel@tonic-gate 	/* Get semaphore data structure. */
413*7c478bd9Sstevel@tonic-gate 	case IPC_STAT:
414*7c478bd9Sstevel@tonic-gate 
415*7c478bd9Sstevel@tonic-gate 		if (error = ipcperm_access(&sp->sem_perm, SEM_R, cr)) {
416*7c478bd9Sstevel@tonic-gate 			mutex_exit(lock);
417*7c478bd9Sstevel@tonic-gate 			return (set_errno(error));
418*7c478bd9Sstevel@tonic-gate 		}
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate 		ipcperm_stat(&STRUCT_BUF(sid)->sem_perm, &sp->sem_perm, mdl);
421*7c478bd9Sstevel@tonic-gate 		STRUCT_FSETP(sid, sem_base, NULL);	/* kernel addr */
422*7c478bd9Sstevel@tonic-gate 		STRUCT_FSET(sid, sem_nsems, sp->sem_nsems);
423*7c478bd9Sstevel@tonic-gate 		STRUCT_FSET(sid, sem_otime, sp->sem_otime);
424*7c478bd9Sstevel@tonic-gate 		STRUCT_FSET(sid, sem_ctime, sp->sem_ctime);
425*7c478bd9Sstevel@tonic-gate 		STRUCT_FSET(sid, sem_binary, sp->sem_binary);
426*7c478bd9Sstevel@tonic-gate 		mutex_exit(lock);
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate 		if (copyout(STRUCT_BUF(sid), (void *)arg, STRUCT_SIZE(sid)))
429*7c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
430*7c478bd9Sstevel@tonic-gate 		return (0);
431*7c478bd9Sstevel@tonic-gate 
432*7c478bd9Sstevel@tonic-gate 	case IPC_SET64:
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate 		if (error = ipcperm_set64(sem_svc, cr, &sp->sem_perm,
435*7c478bd9Sstevel@tonic-gate 		    &ds64.semx_perm)) {
436*7c478bd9Sstevel@tonic-gate 			mutex_exit(lock);
437*7c478bd9Sstevel@tonic-gate 			return (set_errno(error));
438*7c478bd9Sstevel@tonic-gate 		}
439*7c478bd9Sstevel@tonic-gate 		sp->sem_ctime = gethrestime_sec();
440*7c478bd9Sstevel@tonic-gate 		mutex_exit(lock);
441*7c478bd9Sstevel@tonic-gate 		return (0);
442*7c478bd9Sstevel@tonic-gate 
443*7c478bd9Sstevel@tonic-gate 	case IPC_STAT64:
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate 		ipcperm_stat64(&ds64.semx_perm, &sp->sem_perm);
446*7c478bd9Sstevel@tonic-gate 		ds64.semx_nsems = sp->sem_nsems;
447*7c478bd9Sstevel@tonic-gate 		ds64.semx_otime = sp->sem_otime;
448*7c478bd9Sstevel@tonic-gate 		ds64.semx_ctime = sp->sem_ctime;
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 		mutex_exit(lock);
451*7c478bd9Sstevel@tonic-gate 		if (copyout(&ds64, (void *)arg, sizeof (struct semid_ds64)))
452*7c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate 		return (0);
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate 	/* Get # of processes sleeping for greater semval. */
457*7c478bd9Sstevel@tonic-gate 	case GETNCNT:
458*7c478bd9Sstevel@tonic-gate 		if (error = ipcperm_access(&sp->sem_perm, SEM_R, cr)) {
459*7c478bd9Sstevel@tonic-gate 			mutex_exit(lock);
460*7c478bd9Sstevel@tonic-gate 			return (set_errno(error));
461*7c478bd9Sstevel@tonic-gate 		}
462*7c478bd9Sstevel@tonic-gate 		if (semnum >= sp->sem_nsems) {
463*7c478bd9Sstevel@tonic-gate 			mutex_exit(lock);
464*7c478bd9Sstevel@tonic-gate 			return (set_errno(EINVAL));
465*7c478bd9Sstevel@tonic-gate 		}
466*7c478bd9Sstevel@tonic-gate 		retval = sp->sem_base[semnum].semncnt;
467*7c478bd9Sstevel@tonic-gate 		mutex_exit(lock);
468*7c478bd9Sstevel@tonic-gate 		return (retval);
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 	/* Get pid of last process to operate on semaphore. */
471*7c478bd9Sstevel@tonic-gate 	case GETPID:
472*7c478bd9Sstevel@tonic-gate 		if (error = ipcperm_access(&sp->sem_perm, SEM_R, cr)) {
473*7c478bd9Sstevel@tonic-gate 			mutex_exit(lock);
474*7c478bd9Sstevel@tonic-gate 			return (set_errno(error));
475*7c478bd9Sstevel@tonic-gate 		}
476*7c478bd9Sstevel@tonic-gate 		if (semnum >= sp->sem_nsems) {
477*7c478bd9Sstevel@tonic-gate 			mutex_exit(lock);
478*7c478bd9Sstevel@tonic-gate 			return (set_errno(EINVAL));
479*7c478bd9Sstevel@tonic-gate 		}
480*7c478bd9Sstevel@tonic-gate 		retval = sp->sem_base[semnum].sempid;
481*7c478bd9Sstevel@tonic-gate 		mutex_exit(lock);
482*7c478bd9Sstevel@tonic-gate 		return (retval);
483*7c478bd9Sstevel@tonic-gate 
484*7c478bd9Sstevel@tonic-gate 	/* Get semval of one semaphore. */
485*7c478bd9Sstevel@tonic-gate 	case GETVAL:
486*7c478bd9Sstevel@tonic-gate 		if (error = ipcperm_access(&sp->sem_perm, SEM_R, cr)) {
487*7c478bd9Sstevel@tonic-gate 			mutex_exit(lock);
488*7c478bd9Sstevel@tonic-gate 			return (set_errno(error));
489*7c478bd9Sstevel@tonic-gate 		}
490*7c478bd9Sstevel@tonic-gate 		if (semnum >= sp->sem_nsems) {
491*7c478bd9Sstevel@tonic-gate 			mutex_exit(lock);
492*7c478bd9Sstevel@tonic-gate 			return (set_errno(EINVAL));
493*7c478bd9Sstevel@tonic-gate 		}
494*7c478bd9Sstevel@tonic-gate 		retval = sp->sem_base[semnum].semval;
495*7c478bd9Sstevel@tonic-gate 		mutex_exit(lock);
496*7c478bd9Sstevel@tonic-gate 		return (retval);
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate 	/* Get all semvals in set. */
499*7c478bd9Sstevel@tonic-gate 	case GETALL:
500*7c478bd9Sstevel@tonic-gate 		if (error = ipcperm_access(&sp->sem_perm, SEM_R, cr)) {
501*7c478bd9Sstevel@tonic-gate 			mutex_exit(lock);
502*7c478bd9Sstevel@tonic-gate 			return (set_errno(error));
503*7c478bd9Sstevel@tonic-gate 		}
504*7c478bd9Sstevel@tonic-gate 
505*7c478bd9Sstevel@tonic-gate 		/* allocate space to hold all semaphore values */
506*7c478bd9Sstevel@tonic-gate 		vsize = sp->sem_nsems * sizeof (*vals);
507*7c478bd9Sstevel@tonic-gate 		vals = vp = kmem_alloc(vsize, KM_SLEEP);
508*7c478bd9Sstevel@tonic-gate 
509*7c478bd9Sstevel@tonic-gate 		for (i = sp->sem_nsems, p = sp->sem_base; i--; p++, vp++)
510*7c478bd9Sstevel@tonic-gate 			bcopy(&p->semval, vp, sizeof (p->semval));
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate 		mutex_exit(lock);
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate 		if (copyout((void *)vals, (void *)arg, vsize)) {
515*7c478bd9Sstevel@tonic-gate 			kmem_free(vals, vsize);
516*7c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
517*7c478bd9Sstevel@tonic-gate 		}
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 		kmem_free(vals, vsize);
520*7c478bd9Sstevel@tonic-gate 		return (0);
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate 	/* Get # of processes sleeping for semval to become zero. */
523*7c478bd9Sstevel@tonic-gate 	case GETZCNT:
524*7c478bd9Sstevel@tonic-gate 		if (error = ipcperm_access(&sp->sem_perm, SEM_R, cr)) {
525*7c478bd9Sstevel@tonic-gate 			mutex_exit(lock);
526*7c478bd9Sstevel@tonic-gate 			return (set_errno(error));
527*7c478bd9Sstevel@tonic-gate 		}
528*7c478bd9Sstevel@tonic-gate 		if (semnum >= sp->sem_nsems) {
529*7c478bd9Sstevel@tonic-gate 			mutex_exit(lock);
530*7c478bd9Sstevel@tonic-gate 			return (set_errno(EINVAL));
531*7c478bd9Sstevel@tonic-gate 		}
532*7c478bd9Sstevel@tonic-gate 		retval = sp->sem_base[semnum].semzcnt;
533*7c478bd9Sstevel@tonic-gate 		mutex_exit(lock);
534*7c478bd9Sstevel@tonic-gate 		return (retval);
535*7c478bd9Sstevel@tonic-gate 
536*7c478bd9Sstevel@tonic-gate 	/* Set semval of one semaphore. */
537*7c478bd9Sstevel@tonic-gate 	case SETVAL:
538*7c478bd9Sstevel@tonic-gate 		if (error = ipcperm_access(&sp->sem_perm, SEM_A, cr)) {
539*7c478bd9Sstevel@tonic-gate 			mutex_exit(lock);
540*7c478bd9Sstevel@tonic-gate 			return (set_errno(error));
541*7c478bd9Sstevel@tonic-gate 		}
542*7c478bd9Sstevel@tonic-gate 		if (semnum >= sp->sem_nsems) {
543*7c478bd9Sstevel@tonic-gate 			mutex_exit(lock);
544*7c478bd9Sstevel@tonic-gate 			return (set_errno(EINVAL));
545*7c478bd9Sstevel@tonic-gate 		}
546*7c478bd9Sstevel@tonic-gate 		if ((uint_t)arg > USHRT_MAX) {
547*7c478bd9Sstevel@tonic-gate 			mutex_exit(lock);
548*7c478bd9Sstevel@tonic-gate 			return (set_errno(ERANGE));
549*7c478bd9Sstevel@tonic-gate 		}
550*7c478bd9Sstevel@tonic-gate 		p = &sp->sem_base[semnum];
551*7c478bd9Sstevel@tonic-gate 		if ((p->semval = (ushort_t)arg) != 0) {
552*7c478bd9Sstevel@tonic-gate 			if (p->semncnt) {
553*7c478bd9Sstevel@tonic-gate 				cv_broadcast(&p->semncnt_cv);
554*7c478bd9Sstevel@tonic-gate 			}
555*7c478bd9Sstevel@tonic-gate 		} else if (p->semzcnt) {
556*7c478bd9Sstevel@tonic-gate 			cv_broadcast(&p->semzcnt_cv);
557*7c478bd9Sstevel@tonic-gate 		}
558*7c478bd9Sstevel@tonic-gate 		p->sempid = curproc->p_pid;
559*7c478bd9Sstevel@tonic-gate 		sem_undo_clear(sp, (ushort_t)semnum, (ushort_t)semnum);
560*7c478bd9Sstevel@tonic-gate 		mutex_exit(lock);
561*7c478bd9Sstevel@tonic-gate 		return (0);
562*7c478bd9Sstevel@tonic-gate 
563*7c478bd9Sstevel@tonic-gate 	/* Set semvals of all semaphores in set. */
564*7c478bd9Sstevel@tonic-gate 	case SETALL:
565*7c478bd9Sstevel@tonic-gate 		/* Check if semaphore set has been deleted and reallocated. */
566*7c478bd9Sstevel@tonic-gate 		if (sp->sem_nsems * sizeof (*vals) != vsize) {
567*7c478bd9Sstevel@tonic-gate 			error = set_errno(EINVAL);
568*7c478bd9Sstevel@tonic-gate 			goto seterr;
569*7c478bd9Sstevel@tonic-gate 		}
570*7c478bd9Sstevel@tonic-gate 		if (error = ipcperm_access(&sp->sem_perm, SEM_A, cr)) {
571*7c478bd9Sstevel@tonic-gate 			error = set_errno(error);
572*7c478bd9Sstevel@tonic-gate 			goto seterr;
573*7c478bd9Sstevel@tonic-gate 		}
574*7c478bd9Sstevel@tonic-gate 		sem_undo_clear(sp, 0, sp->sem_nsems - 1);
575*7c478bd9Sstevel@tonic-gate 		for (i = 0, p = sp->sem_base; i < sp->sem_nsems;
576*7c478bd9Sstevel@tonic-gate 		    (p++)->sempid = curproc->p_pid) {
577*7c478bd9Sstevel@tonic-gate 			if ((p->semval = vals[i++]) != 0) {
578*7c478bd9Sstevel@tonic-gate 				if (p->semncnt) {
579*7c478bd9Sstevel@tonic-gate 					cv_broadcast(&p->semncnt_cv);
580*7c478bd9Sstevel@tonic-gate 				}
581*7c478bd9Sstevel@tonic-gate 			} else if (p->semzcnt) {
582*7c478bd9Sstevel@tonic-gate 				cv_broadcast(&p->semzcnt_cv);
583*7c478bd9Sstevel@tonic-gate 			}
584*7c478bd9Sstevel@tonic-gate 		}
585*7c478bd9Sstevel@tonic-gate seterr:
586*7c478bd9Sstevel@tonic-gate 		mutex_exit(lock);
587*7c478bd9Sstevel@tonic-gate 		kmem_free(vals, vsize);
588*7c478bd9Sstevel@tonic-gate 		return (error);
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate 	default:
591*7c478bd9Sstevel@tonic-gate 		mutex_exit(lock);
592*7c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
593*7c478bd9Sstevel@tonic-gate 	}
594*7c478bd9Sstevel@tonic-gate 
595*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
596*7c478bd9Sstevel@tonic-gate }
597*7c478bd9Sstevel@tonic-gate 
598*7c478bd9Sstevel@tonic-gate /*
599*7c478bd9Sstevel@tonic-gate  * semexit - Called by exit() to clean up on process exit.
600*7c478bd9Sstevel@tonic-gate  */
601*7c478bd9Sstevel@tonic-gate void
602*7c478bd9Sstevel@tonic-gate semexit(proc_t *pp)
603*7c478bd9Sstevel@tonic-gate {
604*7c478bd9Sstevel@tonic-gate 	avl_tree_t	*tree;
605*7c478bd9Sstevel@tonic-gate 	struct sem_undo	*undo;
606*7c478bd9Sstevel@tonic-gate 	void		*cookie = NULL;
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate 	mutex_enter(&pp->p_lock);
609*7c478bd9Sstevel@tonic-gate 	tree = pp->p_semacct;
610*7c478bd9Sstevel@tonic-gate 	pp->p_semacct = NULL;
611*7c478bd9Sstevel@tonic-gate 	mutex_exit(&pp->p_lock);
612*7c478bd9Sstevel@tonic-gate 
613*7c478bd9Sstevel@tonic-gate 	while (undo = avl_destroy_nodes(tree, &cookie)) {
614*7c478bd9Sstevel@tonic-gate 		ksemid_t *sp = undo->un_sp;
615*7c478bd9Sstevel@tonic-gate 		size_t size = SEM_UNDOSZ(sp->sem_nsems);
616*7c478bd9Sstevel@tonic-gate 		int i;
617*7c478bd9Sstevel@tonic-gate 
618*7c478bd9Sstevel@tonic-gate 		(void) ipc_lock(sem_svc, sp->sem_perm.ipc_id);
619*7c478bd9Sstevel@tonic-gate 		if (!IPC_FREE(&sp->sem_perm)) {
620*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < sp->sem_nsems; i++) {
621*7c478bd9Sstevel@tonic-gate 				int adj = undo->un_aoe[i];
622*7c478bd9Sstevel@tonic-gate 				if (adj) {
623*7c478bd9Sstevel@tonic-gate 					struct sem *semp = &sp->sem_base[i];
624*7c478bd9Sstevel@tonic-gate 					int v = (int)semp->semval + adj;
625*7c478bd9Sstevel@tonic-gate 
626*7c478bd9Sstevel@tonic-gate 					if (v < 0 || v > USHRT_MAX)
627*7c478bd9Sstevel@tonic-gate 						continue;
628*7c478bd9Sstevel@tonic-gate 					semp->semval = (ushort_t)v;
629*7c478bd9Sstevel@tonic-gate 					if (v == 0 && semp->semzcnt)
630*7c478bd9Sstevel@tonic-gate 						cv_broadcast(&semp->semzcnt_cv);
631*7c478bd9Sstevel@tonic-gate 					if (adj > 0 && semp->semncnt)
632*7c478bd9Sstevel@tonic-gate 						cv_broadcast(&semp->semncnt_cv);
633*7c478bd9Sstevel@tonic-gate 				}
634*7c478bd9Sstevel@tonic-gate 			}
635*7c478bd9Sstevel@tonic-gate 			list_remove(&sp->sem_undos, undo);
636*7c478bd9Sstevel@tonic-gate 		}
637*7c478bd9Sstevel@tonic-gate 		ipc_rele(sem_svc, (kipc_perm_t *)sp);
638*7c478bd9Sstevel@tonic-gate 		kmem_free(undo, size);
639*7c478bd9Sstevel@tonic-gate 	}
640*7c478bd9Sstevel@tonic-gate 
641*7c478bd9Sstevel@tonic-gate 	avl_destroy(tree);
642*7c478bd9Sstevel@tonic-gate 	kmem_free(tree, sizeof (avl_tree_t));
643*7c478bd9Sstevel@tonic-gate }
644*7c478bd9Sstevel@tonic-gate 
645*7c478bd9Sstevel@tonic-gate /*
646*7c478bd9Sstevel@tonic-gate  * Remove all semaphores associated with a given zone.  Called by
647*7c478bd9Sstevel@tonic-gate  * zone_shutdown when the zone is halted.
648*7c478bd9Sstevel@tonic-gate  */
649*7c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
650*7c478bd9Sstevel@tonic-gate static void
651*7c478bd9Sstevel@tonic-gate sem_remove_zone(zoneid_t zoneid, void *arg)
652*7c478bd9Sstevel@tonic-gate {
653*7c478bd9Sstevel@tonic-gate 	ipc_remove_zone(sem_svc, zoneid);
654*7c478bd9Sstevel@tonic-gate }
655*7c478bd9Sstevel@tonic-gate 
656*7c478bd9Sstevel@tonic-gate /*
657*7c478bd9Sstevel@tonic-gate  * semget - Semget system call.
658*7c478bd9Sstevel@tonic-gate  */
659*7c478bd9Sstevel@tonic-gate static int
660*7c478bd9Sstevel@tonic-gate semget(key_t key, int nsems, int semflg)
661*7c478bd9Sstevel@tonic-gate {
662*7c478bd9Sstevel@tonic-gate 	ksemid_t	*sp;
663*7c478bd9Sstevel@tonic-gate 	kmutex_t	*lock;
664*7c478bd9Sstevel@tonic-gate 	int		id, error;
665*7c478bd9Sstevel@tonic-gate 	proc_t		*pp = curproc;
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate top:
668*7c478bd9Sstevel@tonic-gate 	if (error = ipc_get(sem_svc, key, semflg, (kipc_perm_t **)&sp, &lock))
669*7c478bd9Sstevel@tonic-gate 		return (set_errno(error));
670*7c478bd9Sstevel@tonic-gate 
671*7c478bd9Sstevel@tonic-gate 	if (!IPC_FREE(&sp->sem_perm)) {
672*7c478bd9Sstevel@tonic-gate 		/*
673*7c478bd9Sstevel@tonic-gate 		 * A semaphore with the requested key exists.
674*7c478bd9Sstevel@tonic-gate 		 */
675*7c478bd9Sstevel@tonic-gate 		if (!((nsems >= 0) && (nsems <= sp->sem_nsems))) {
676*7c478bd9Sstevel@tonic-gate 			mutex_exit(lock);
677*7c478bd9Sstevel@tonic-gate 			return (set_errno(EINVAL));
678*7c478bd9Sstevel@tonic-gate 		}
679*7c478bd9Sstevel@tonic-gate 	} else {
680*7c478bd9Sstevel@tonic-gate 		/*
681*7c478bd9Sstevel@tonic-gate 		 * This is a new semaphore set.  Finish initialization.
682*7c478bd9Sstevel@tonic-gate 		 */
683*7c478bd9Sstevel@tonic-gate 		if (nsems <= 0 || (rctl_test(rc_process_semmsl, pp->p_rctls, pp,
684*7c478bd9Sstevel@tonic-gate 		    nsems, RCA_SAFE) & RCT_DENY)) {
685*7c478bd9Sstevel@tonic-gate 			mutex_exit(lock);
686*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pp->p_lock);
687*7c478bd9Sstevel@tonic-gate 			ipc_cleanup(sem_svc, (kipc_perm_t *)sp);
688*7c478bd9Sstevel@tonic-gate 			return (set_errno(EINVAL));
689*7c478bd9Sstevel@tonic-gate 		}
690*7c478bd9Sstevel@tonic-gate 		mutex_exit(lock);
691*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pp->p_lock);
692*7c478bd9Sstevel@tonic-gate 
693*7c478bd9Sstevel@tonic-gate 		/*
694*7c478bd9Sstevel@tonic-gate 		 * We round the allocation up to coherency granularity
695*7c478bd9Sstevel@tonic-gate 		 * so that multiple semaphore allocations won't result
696*7c478bd9Sstevel@tonic-gate 		 * in the false sharing of their sem structures.
697*7c478bd9Sstevel@tonic-gate 		 */
698*7c478bd9Sstevel@tonic-gate 		sp->sem_base =
699*7c478bd9Sstevel@tonic-gate 		    kmem_zalloc(P2ROUNDUP(nsems * sizeof (struct sem), 64),
700*7c478bd9Sstevel@tonic-gate 		    KM_SLEEP);
701*7c478bd9Sstevel@tonic-gate 		sp->sem_binary = (nsems == 1);
702*7c478bd9Sstevel@tonic-gate 		sp->sem_nsems = (ushort_t)nsems;
703*7c478bd9Sstevel@tonic-gate 		sp->sem_ctime = gethrestime_sec();
704*7c478bd9Sstevel@tonic-gate 		sp->sem_otime = 0;
705*7c478bd9Sstevel@tonic-gate 		list_create(&sp->sem_undos, sizeof (struct sem_undo),
706*7c478bd9Sstevel@tonic-gate 		    offsetof(struct sem_undo, un_list));
707*7c478bd9Sstevel@tonic-gate 
708*7c478bd9Sstevel@tonic-gate 		if (error = ipc_commit_begin(sem_svc, key, semflg,
709*7c478bd9Sstevel@tonic-gate 		    (kipc_perm_t *)sp)) {
710*7c478bd9Sstevel@tonic-gate 			if (error == EAGAIN)
711*7c478bd9Sstevel@tonic-gate 				goto top;
712*7c478bd9Sstevel@tonic-gate 			return (set_errno(error));
713*7c478bd9Sstevel@tonic-gate 		}
714*7c478bd9Sstevel@tonic-gate 		sp->sem_maxops =
715*7c478bd9Sstevel@tonic-gate 		    rctl_enforced_value(rc_process_semopm, pp->p_rctls, pp);
716*7c478bd9Sstevel@tonic-gate 		if (rctl_test(rc_process_semmsl, pp->p_rctls, pp, nsems,
717*7c478bd9Sstevel@tonic-gate 		    RCA_SAFE) & RCT_DENY) {
718*7c478bd9Sstevel@tonic-gate 			ipc_cleanup(sem_svc, (kipc_perm_t *)sp);
719*7c478bd9Sstevel@tonic-gate 			return (set_errno(EINVAL));
720*7c478bd9Sstevel@tonic-gate 		}
721*7c478bd9Sstevel@tonic-gate 		lock = ipc_commit_end(sem_svc, &sp->sem_perm);
722*7c478bd9Sstevel@tonic-gate 	}
723*7c478bd9Sstevel@tonic-gate #ifdef C2_AUDIT
724*7c478bd9Sstevel@tonic-gate 	if (audit_active)
725*7c478bd9Sstevel@tonic-gate 		audit_ipcget(AT_IPC_SEM, (void *)sp);
726*7c478bd9Sstevel@tonic-gate #endif
727*7c478bd9Sstevel@tonic-gate 	id = sp->sem_perm.ipc_id;
728*7c478bd9Sstevel@tonic-gate 	mutex_exit(lock);
729*7c478bd9Sstevel@tonic-gate 	return (id);
730*7c478bd9Sstevel@tonic-gate }
731*7c478bd9Sstevel@tonic-gate 
732*7c478bd9Sstevel@tonic-gate /*
733*7c478bd9Sstevel@tonic-gate  * semids system call.
734*7c478bd9Sstevel@tonic-gate  */
735*7c478bd9Sstevel@tonic-gate static int
736*7c478bd9Sstevel@tonic-gate semids(int *buf, uint_t nids, uint_t *pnids)
737*7c478bd9Sstevel@tonic-gate {
738*7c478bd9Sstevel@tonic-gate 	int error;
739*7c478bd9Sstevel@tonic-gate 
740*7c478bd9Sstevel@tonic-gate 	if (error = ipc_ids(sem_svc, buf, nids, pnids))
741*7c478bd9Sstevel@tonic-gate 		return (set_errno(error));
742*7c478bd9Sstevel@tonic-gate 
743*7c478bd9Sstevel@tonic-gate 	return (0);
744*7c478bd9Sstevel@tonic-gate }
745*7c478bd9Sstevel@tonic-gate 
746*7c478bd9Sstevel@tonic-gate 
747*7c478bd9Sstevel@tonic-gate /*
748*7c478bd9Sstevel@tonic-gate  * Helper function for semop - copies in the provided timespec and
749*7c478bd9Sstevel@tonic-gate  * computes the absolute future time after which we must return.
750*7c478bd9Sstevel@tonic-gate  */
751*7c478bd9Sstevel@tonic-gate static int
752*7c478bd9Sstevel@tonic-gate compute_timeout(timespec_t **tsp, timespec_t *ts, timespec_t *now,
753*7c478bd9Sstevel@tonic-gate 	timespec_t *timeout)
754*7c478bd9Sstevel@tonic-gate {
755*7c478bd9Sstevel@tonic-gate 	model_t datamodel = get_udatamodel();
756*7c478bd9Sstevel@tonic-gate 
757*7c478bd9Sstevel@tonic-gate 	if (datamodel == DATAMODEL_NATIVE) {
758*7c478bd9Sstevel@tonic-gate 		if (copyin(timeout, ts, sizeof (timespec_t)))
759*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
760*7c478bd9Sstevel@tonic-gate 	} else {
761*7c478bd9Sstevel@tonic-gate 		timespec32_t ts32;
762*7c478bd9Sstevel@tonic-gate 
763*7c478bd9Sstevel@tonic-gate 		if (copyin(timeout, &ts32, sizeof (timespec32_t)))
764*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
765*7c478bd9Sstevel@tonic-gate 		TIMESPEC32_TO_TIMESPEC(ts, &ts32)
766*7c478bd9Sstevel@tonic-gate 	}
767*7c478bd9Sstevel@tonic-gate 
768*7c478bd9Sstevel@tonic-gate 	if (itimerspecfix(ts))
769*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
770*7c478bd9Sstevel@tonic-gate 
771*7c478bd9Sstevel@tonic-gate 	/*
772*7c478bd9Sstevel@tonic-gate 	 * Convert the timespec value into absolute time.
773*7c478bd9Sstevel@tonic-gate 	 */
774*7c478bd9Sstevel@tonic-gate 	timespecadd(ts, now);
775*7c478bd9Sstevel@tonic-gate 	*tsp = ts;
776*7c478bd9Sstevel@tonic-gate 
777*7c478bd9Sstevel@tonic-gate 	return (0);
778*7c478bd9Sstevel@tonic-gate }
779*7c478bd9Sstevel@tonic-gate 
780*7c478bd9Sstevel@tonic-gate /*
781*7c478bd9Sstevel@tonic-gate  * Undo structure comparator.  We sort based on ksemid_t pointer.
782*7c478bd9Sstevel@tonic-gate  */
783*7c478bd9Sstevel@tonic-gate static int
784*7c478bd9Sstevel@tonic-gate sem_undo_compar(const void *x, const void *y)
785*7c478bd9Sstevel@tonic-gate {
786*7c478bd9Sstevel@tonic-gate 	struct sem_undo *undo1 = (struct sem_undo *)x;
787*7c478bd9Sstevel@tonic-gate 	struct sem_undo *undo2 = (struct sem_undo *)y;
788*7c478bd9Sstevel@tonic-gate 
789*7c478bd9Sstevel@tonic-gate 	if (undo1->un_sp < undo2->un_sp)
790*7c478bd9Sstevel@tonic-gate 		return (-1);
791*7c478bd9Sstevel@tonic-gate 	if (undo1->un_sp > undo2->un_sp)
792*7c478bd9Sstevel@tonic-gate 		return (1);
793*7c478bd9Sstevel@tonic-gate 	return (0);
794*7c478bd9Sstevel@tonic-gate }
795*7c478bd9Sstevel@tonic-gate 
796*7c478bd9Sstevel@tonic-gate /*
797*7c478bd9Sstevel@tonic-gate  * Helper function for semop - creates an undo structure and adds it to
798*7c478bd9Sstevel@tonic-gate  * the process's avl tree and the semaphore's list.
799*7c478bd9Sstevel@tonic-gate  */
800*7c478bd9Sstevel@tonic-gate static int
801*7c478bd9Sstevel@tonic-gate sem_undo_alloc(proc_t *pp, ksemid_t *sp, kmutex_t **lock,
802*7c478bd9Sstevel@tonic-gate     struct sem_undo *template, struct sem_undo **un)
803*7c478bd9Sstevel@tonic-gate {
804*7c478bd9Sstevel@tonic-gate 	size_t size;
805*7c478bd9Sstevel@tonic-gate 	struct sem_undo *undo;
806*7c478bd9Sstevel@tonic-gate 	avl_tree_t *tree = NULL;
807*7c478bd9Sstevel@tonic-gate 	avl_index_t where;
808*7c478bd9Sstevel@tonic-gate 
809*7c478bd9Sstevel@tonic-gate 	mutex_exit(*lock);
810*7c478bd9Sstevel@tonic-gate 
811*7c478bd9Sstevel@tonic-gate 	size = SEM_UNDOSZ(sp->sem_nsems);
812*7c478bd9Sstevel@tonic-gate 	undo = kmem_zalloc(size, KM_SLEEP);
813*7c478bd9Sstevel@tonic-gate 	undo->un_proc = pp;
814*7c478bd9Sstevel@tonic-gate 	undo->un_sp = sp;
815*7c478bd9Sstevel@tonic-gate 
816*7c478bd9Sstevel@tonic-gate 	if (pp->p_semacct == NULL)
817*7c478bd9Sstevel@tonic-gate 		tree = kmem_alloc(sizeof (avl_tree_t), KM_SLEEP);
818*7c478bd9Sstevel@tonic-gate 
819*7c478bd9Sstevel@tonic-gate 	*lock = ipc_lock(sem_svc, sp->sem_perm.ipc_id);
820*7c478bd9Sstevel@tonic-gate 	if (IPC_FREE(&sp->sem_perm)) {
821*7c478bd9Sstevel@tonic-gate 		kmem_free(undo, size);
822*7c478bd9Sstevel@tonic-gate 		if (tree)
823*7c478bd9Sstevel@tonic-gate 			kmem_free(tree, sizeof (avl_tree_t));
824*7c478bd9Sstevel@tonic-gate 		return (EIDRM);
825*7c478bd9Sstevel@tonic-gate 	}
826*7c478bd9Sstevel@tonic-gate 
827*7c478bd9Sstevel@tonic-gate 	mutex_enter(&pp->p_lock);
828*7c478bd9Sstevel@tonic-gate 	if (tree) {
829*7c478bd9Sstevel@tonic-gate 		if (pp->p_semacct == NULL) {
830*7c478bd9Sstevel@tonic-gate 			avl_create(tree, sem_undo_compar,
831*7c478bd9Sstevel@tonic-gate 			    sizeof (struct sem_undo),
832*7c478bd9Sstevel@tonic-gate 			    offsetof(struct sem_undo, un_avl));
833*7c478bd9Sstevel@tonic-gate 			pp->p_semacct = tree;
834*7c478bd9Sstevel@tonic-gate 		} else {
835*7c478bd9Sstevel@tonic-gate 			kmem_free(tree, sizeof (avl_tree_t));
836*7c478bd9Sstevel@tonic-gate 		}
837*7c478bd9Sstevel@tonic-gate 	}
838*7c478bd9Sstevel@tonic-gate 
839*7c478bd9Sstevel@tonic-gate 	if (*un = avl_find(pp->p_semacct, template, &where)) {
840*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pp->p_lock);
841*7c478bd9Sstevel@tonic-gate 		kmem_free(undo, size);
842*7c478bd9Sstevel@tonic-gate 	} else {
843*7c478bd9Sstevel@tonic-gate 		*un = undo;
844*7c478bd9Sstevel@tonic-gate 		avl_insert(pp->p_semacct, undo, where);
845*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pp->p_lock);
846*7c478bd9Sstevel@tonic-gate 		list_insert_head(&sp->sem_undos, undo);
847*7c478bd9Sstevel@tonic-gate 		ipc_hold(sem_svc, (kipc_perm_t *)sp);
848*7c478bd9Sstevel@tonic-gate 	}
849*7c478bd9Sstevel@tonic-gate 
850*7c478bd9Sstevel@tonic-gate 
851*7c478bd9Sstevel@tonic-gate 	return (0);
852*7c478bd9Sstevel@tonic-gate }
853*7c478bd9Sstevel@tonic-gate 
854*7c478bd9Sstevel@tonic-gate /*
855*7c478bd9Sstevel@tonic-gate  * semop - Semop system call.
856*7c478bd9Sstevel@tonic-gate  */
857*7c478bd9Sstevel@tonic-gate static int
858*7c478bd9Sstevel@tonic-gate semop(int semid, struct sembuf *sops, size_t nsops, timespec_t *timeout)
859*7c478bd9Sstevel@tonic-gate {
860*7c478bd9Sstevel@tonic-gate 	ksemid_t	*sp = NULL;
861*7c478bd9Sstevel@tonic-gate 	kmutex_t	*lock;
862*7c478bd9Sstevel@tonic-gate 	struct sembuf	*op;	/* ptr to operation */
863*7c478bd9Sstevel@tonic-gate 	int		i;	/* loop control */
864*7c478bd9Sstevel@tonic-gate 	struct sem	*semp;	/* ptr to semaphore */
865*7c478bd9Sstevel@tonic-gate 	int 		error = 0;
866*7c478bd9Sstevel@tonic-gate 	struct sembuf	*uops;	/* ptr to copy of user ops */
867*7c478bd9Sstevel@tonic-gate 	struct sembuf 	x_sem;	/* avoid kmem_alloc's */
868*7c478bd9Sstevel@tonic-gate 	timespec_t	now, ts, *tsp = NULL;
869*7c478bd9Sstevel@tonic-gate 	int		timecheck = 0;
870*7c478bd9Sstevel@tonic-gate 	int		cvres, needundo, mode;
871*7c478bd9Sstevel@tonic-gate 	struct sem_undo	*undo;
872*7c478bd9Sstevel@tonic-gate 	proc_t		*pp = curproc;
873*7c478bd9Sstevel@tonic-gate 	int		held = 0;
874*7c478bd9Sstevel@tonic-gate 
875*7c478bd9Sstevel@tonic-gate 	CPU_STATS_ADDQ(CPU, sys, sema, 1); /* bump semaphore op count */
876*7c478bd9Sstevel@tonic-gate 
877*7c478bd9Sstevel@tonic-gate 	/*
878*7c478bd9Sstevel@tonic-gate 	 * To avoid the cost of copying in 'timeout' in the common
879*7c478bd9Sstevel@tonic-gate 	 * case, we could only grab the time here and defer the copyin
880*7c478bd9Sstevel@tonic-gate 	 * and associated computations until we are about to block.
881*7c478bd9Sstevel@tonic-gate 	 *
882*7c478bd9Sstevel@tonic-gate 	 * The down side to this is that we would then have to spin
883*7c478bd9Sstevel@tonic-gate 	 * some goto top nonsense to avoid the copyin behind the semid
884*7c478bd9Sstevel@tonic-gate 	 * lock.  As a common use of timed semaphores is as an explicit
885*7c478bd9Sstevel@tonic-gate 	 * blocking mechanism, this could incur a greater penalty.
886*7c478bd9Sstevel@tonic-gate 	 *
887*7c478bd9Sstevel@tonic-gate 	 * If we eventually decide that this would be a wise route to
888*7c478bd9Sstevel@tonic-gate 	 * take, the deferrable functionality is completely contained
889*7c478bd9Sstevel@tonic-gate 	 * in 'compute_timeout', and the interface is defined such that
890*7c478bd9Sstevel@tonic-gate 	 * we can legally not validate 'timeout' if it is unused.
891*7c478bd9Sstevel@tonic-gate 	 */
892*7c478bd9Sstevel@tonic-gate 	if (timeout != NULL) {
893*7c478bd9Sstevel@tonic-gate 		timecheck = timechanged;
894*7c478bd9Sstevel@tonic-gate 		gethrestime(&now);
895*7c478bd9Sstevel@tonic-gate 		if (error = compute_timeout(&tsp, &ts, &now, timeout))
896*7c478bd9Sstevel@tonic-gate 			return (set_errno(error));
897*7c478bd9Sstevel@tonic-gate 	}
898*7c478bd9Sstevel@tonic-gate 
899*7c478bd9Sstevel@tonic-gate 	/*
900*7c478bd9Sstevel@tonic-gate 	 * Allocate space to hold the vector of semaphore ops.  If
901*7c478bd9Sstevel@tonic-gate 	 * there is only 1 operation we use a preallocated buffer on
902*7c478bd9Sstevel@tonic-gate 	 * the stack for speed.
903*7c478bd9Sstevel@tonic-gate 	 *
904*7c478bd9Sstevel@tonic-gate 	 * Since we don't want to allow the user to allocate an
905*7c478bd9Sstevel@tonic-gate 	 * arbitrary amount of kernel memory, we need to check against
906*7c478bd9Sstevel@tonic-gate 	 * the number of operations allowed by the semaphore.  We only
907*7c478bd9Sstevel@tonic-gate 	 * bother doing this if the number of operations is larger than
908*7c478bd9Sstevel@tonic-gate 	 * SEM_MAXUCOPS.
909*7c478bd9Sstevel@tonic-gate 	 */
910*7c478bd9Sstevel@tonic-gate 	if (nsops == 1)
911*7c478bd9Sstevel@tonic-gate 		uops = &x_sem;
912*7c478bd9Sstevel@tonic-gate 	else if (nsops == 0)
913*7c478bd9Sstevel@tonic-gate 		return (0);
914*7c478bd9Sstevel@tonic-gate 	else if (nsops <= SEM_MAXUCOPS)
915*7c478bd9Sstevel@tonic-gate 		uops = kmem_alloc(nsops * sizeof (*uops), KM_SLEEP);
916*7c478bd9Sstevel@tonic-gate 
917*7c478bd9Sstevel@tonic-gate 	if (nsops > SEM_MAXUCOPS) {
918*7c478bd9Sstevel@tonic-gate 		if ((lock = ipc_lookup(sem_svc, semid,
919*7c478bd9Sstevel@tonic-gate 		    (kipc_perm_t **)&sp)) == NULL)
920*7c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
921*7c478bd9Sstevel@tonic-gate 
922*7c478bd9Sstevel@tonic-gate 		if (nsops > sp->sem_maxops) {
923*7c478bd9Sstevel@tonic-gate 			mutex_exit(lock);
924*7c478bd9Sstevel@tonic-gate 			return (set_errno(E2BIG));
925*7c478bd9Sstevel@tonic-gate 		}
926*7c478bd9Sstevel@tonic-gate 		held = 1;
927*7c478bd9Sstevel@tonic-gate 		ipc_hold(sem_svc, (kipc_perm_t *)sp);
928*7c478bd9Sstevel@tonic-gate 		mutex_exit(lock);
929*7c478bd9Sstevel@tonic-gate 
930*7c478bd9Sstevel@tonic-gate 		uops = kmem_alloc(nsops * sizeof (*uops), KM_SLEEP);
931*7c478bd9Sstevel@tonic-gate 		if (copyin(sops, uops, nsops * sizeof (*op))) {
932*7c478bd9Sstevel@tonic-gate 			error = EFAULT;
933*7c478bd9Sstevel@tonic-gate 			(void) ipc_lock(sem_svc, sp->sem_perm.ipc_id);
934*7c478bd9Sstevel@tonic-gate 			goto semoperr;
935*7c478bd9Sstevel@tonic-gate 		}
936*7c478bd9Sstevel@tonic-gate 
937*7c478bd9Sstevel@tonic-gate 		lock = ipc_lock(sem_svc, sp->sem_perm.ipc_id);
938*7c478bd9Sstevel@tonic-gate 		if (IPC_FREE(&sp->sem_perm)) {
939*7c478bd9Sstevel@tonic-gate 			error = EIDRM;
940*7c478bd9Sstevel@tonic-gate 			goto semoperr;
941*7c478bd9Sstevel@tonic-gate 		}
942*7c478bd9Sstevel@tonic-gate 	} else {
943*7c478bd9Sstevel@tonic-gate 		/*
944*7c478bd9Sstevel@tonic-gate 		 * This could be interleaved with the above code, but
945*7c478bd9Sstevel@tonic-gate 		 * keeping them separate improves readability.
946*7c478bd9Sstevel@tonic-gate 		 */
947*7c478bd9Sstevel@tonic-gate 		if (copyin(sops, uops, nsops * sizeof (*op))) {
948*7c478bd9Sstevel@tonic-gate 			error = EFAULT;
949*7c478bd9Sstevel@tonic-gate 			goto semoperr_unlocked;
950*7c478bd9Sstevel@tonic-gate 		}
951*7c478bd9Sstevel@tonic-gate 
952*7c478bd9Sstevel@tonic-gate 		if ((lock = ipc_lookup(sem_svc, semid,
953*7c478bd9Sstevel@tonic-gate 		    (kipc_perm_t **)&sp)) == NULL) {
954*7c478bd9Sstevel@tonic-gate 			error = EINVAL;
955*7c478bd9Sstevel@tonic-gate 			goto semoperr_unlocked;
956*7c478bd9Sstevel@tonic-gate 		}
957*7c478bd9Sstevel@tonic-gate 
958*7c478bd9Sstevel@tonic-gate 		if (nsops > sp->sem_maxops) {
959*7c478bd9Sstevel@tonic-gate 			error = E2BIG;
960*7c478bd9Sstevel@tonic-gate 			goto semoperr;
961*7c478bd9Sstevel@tonic-gate 		}
962*7c478bd9Sstevel@tonic-gate 	}
963*7c478bd9Sstevel@tonic-gate 
964*7c478bd9Sstevel@tonic-gate 	/*
965*7c478bd9Sstevel@tonic-gate 	 * Scan all operations.  Verify that sem #s are in range and
966*7c478bd9Sstevel@tonic-gate 	 * this process is allowed the requested operations.  If any
967*7c478bd9Sstevel@tonic-gate 	 * operations are marked SEM_UNDO, find (or allocate) the undo
968*7c478bd9Sstevel@tonic-gate 	 * structure for this process and semaphore.
969*7c478bd9Sstevel@tonic-gate 	 */
970*7c478bd9Sstevel@tonic-gate 	needundo = 0;
971*7c478bd9Sstevel@tonic-gate 	mode = 0;
972*7c478bd9Sstevel@tonic-gate 	for (i = 0, op = uops; i++ < nsops; op++) {
973*7c478bd9Sstevel@tonic-gate 		mode |= op->sem_op ? SEM_A : SEM_R;
974*7c478bd9Sstevel@tonic-gate 		if (op->sem_num >= sp->sem_nsems) {
975*7c478bd9Sstevel@tonic-gate 			error = EFBIG;
976*7c478bd9Sstevel@tonic-gate 			goto semoperr;
977*7c478bd9Sstevel@tonic-gate 		}
978*7c478bd9Sstevel@tonic-gate 		if ((op->sem_flg & SEM_UNDO) && op->sem_op)
979*7c478bd9Sstevel@tonic-gate 			needundo = 1;
980*7c478bd9Sstevel@tonic-gate 	}
981*7c478bd9Sstevel@tonic-gate 	if (error = ipcperm_access(&sp->sem_perm, mode, CRED()))
982*7c478bd9Sstevel@tonic-gate 		goto semoperr;
983*7c478bd9Sstevel@tonic-gate 
984*7c478bd9Sstevel@tonic-gate 	if (needundo) {
985*7c478bd9Sstevel@tonic-gate 		struct sem_undo template;
986*7c478bd9Sstevel@tonic-gate 
987*7c478bd9Sstevel@tonic-gate 		template.un_sp = sp;
988*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pp->p_lock);
989*7c478bd9Sstevel@tonic-gate 		if (pp->p_semacct)
990*7c478bd9Sstevel@tonic-gate 			undo = avl_find(pp->p_semacct, &template, NULL);
991*7c478bd9Sstevel@tonic-gate 		else
992*7c478bd9Sstevel@tonic-gate 			undo = NULL;
993*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pp->p_lock);
994*7c478bd9Sstevel@tonic-gate 		if (undo == NULL) {
995*7c478bd9Sstevel@tonic-gate 			if (error = sem_undo_alloc(pp, sp, &lock, &template,
996*7c478bd9Sstevel@tonic-gate 			    &undo))
997*7c478bd9Sstevel@tonic-gate 				goto semoperr;
998*7c478bd9Sstevel@tonic-gate 
999*7c478bd9Sstevel@tonic-gate 			/* sem_undo_alloc unlocks the semaphore */
1000*7c478bd9Sstevel@tonic-gate 			if (error = ipcperm_access(&sp->sem_perm, mode, CRED()))
1001*7c478bd9Sstevel@tonic-gate 				goto semoperr;
1002*7c478bd9Sstevel@tonic-gate 		}
1003*7c478bd9Sstevel@tonic-gate 	}
1004*7c478bd9Sstevel@tonic-gate 
1005*7c478bd9Sstevel@tonic-gate check:
1006*7c478bd9Sstevel@tonic-gate 	/*
1007*7c478bd9Sstevel@tonic-gate 	 * Loop waiting for the operations to be satisfied atomically.
1008*7c478bd9Sstevel@tonic-gate 	 * Actually, do the operations and undo them if a wait is needed
1009*7c478bd9Sstevel@tonic-gate 	 * or an error is detected.
1010*7c478bd9Sstevel@tonic-gate 	 */
1011*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < nsops; i++) {
1012*7c478bd9Sstevel@tonic-gate 		op = &uops[i];
1013*7c478bd9Sstevel@tonic-gate 		semp = &sp->sem_base[op->sem_num];
1014*7c478bd9Sstevel@tonic-gate 
1015*7c478bd9Sstevel@tonic-gate 		/*
1016*7c478bd9Sstevel@tonic-gate 		 * Raise the semaphore (i.e. sema_v)
1017*7c478bd9Sstevel@tonic-gate 		 */
1018*7c478bd9Sstevel@tonic-gate 		if (op->sem_op > 0) {
1019*7c478bd9Sstevel@tonic-gate 			if (op->sem_op + (int)semp->semval > USHRT_MAX ||
1020*7c478bd9Sstevel@tonic-gate 			    ((op->sem_flg & SEM_UNDO) &&
1021*7c478bd9Sstevel@tonic-gate 			    (error = sem_undo_add(op->sem_op, op->sem_num,
1022*7c478bd9Sstevel@tonic-gate 			    undo)))) {
1023*7c478bd9Sstevel@tonic-gate 				if (i)
1024*7c478bd9Sstevel@tonic-gate 					sem_rollback(sp, uops, i, undo);
1025*7c478bd9Sstevel@tonic-gate 				if (error == 0)
1026*7c478bd9Sstevel@tonic-gate 					error = ERANGE;
1027*7c478bd9Sstevel@tonic-gate 				goto semoperr;
1028*7c478bd9Sstevel@tonic-gate 			}
1029*7c478bd9Sstevel@tonic-gate 			semp->semval += op->sem_op;
1030*7c478bd9Sstevel@tonic-gate 			/*
1031*7c478bd9Sstevel@tonic-gate 			 * If we are only incrementing the semaphore value
1032*7c478bd9Sstevel@tonic-gate 			 * by one on a binary semaphore, we can cv_signal.
1033*7c478bd9Sstevel@tonic-gate 			 */
1034*7c478bd9Sstevel@tonic-gate 			if (semp->semncnt) {
1035*7c478bd9Sstevel@tonic-gate 				if (op->sem_op == 1 && sp->sem_binary)
1036*7c478bd9Sstevel@tonic-gate 					cv_signal(&semp->semncnt_cv);
1037*7c478bd9Sstevel@tonic-gate 				else
1038*7c478bd9Sstevel@tonic-gate 					cv_broadcast(&semp->semncnt_cv);
1039*7c478bd9Sstevel@tonic-gate 			}
1040*7c478bd9Sstevel@tonic-gate 			if (semp->semzcnt && !semp->semval)
1041*7c478bd9Sstevel@tonic-gate 				cv_broadcast(&semp->semzcnt_cv);
1042*7c478bd9Sstevel@tonic-gate 			continue;
1043*7c478bd9Sstevel@tonic-gate 		}
1044*7c478bd9Sstevel@tonic-gate 
1045*7c478bd9Sstevel@tonic-gate 		/*
1046*7c478bd9Sstevel@tonic-gate 		 * Lower the semaphore (i.e. sema_p)
1047*7c478bd9Sstevel@tonic-gate 		 */
1048*7c478bd9Sstevel@tonic-gate 		if (op->sem_op < 0) {
1049*7c478bd9Sstevel@tonic-gate 			if (semp->semval >= (unsigned)(-op->sem_op)) {
1050*7c478bd9Sstevel@tonic-gate 				if ((op->sem_flg & SEM_UNDO) &&
1051*7c478bd9Sstevel@tonic-gate 				    (error = sem_undo_add(op->sem_op,
1052*7c478bd9Sstevel@tonic-gate 				    op->sem_num, undo))) {
1053*7c478bd9Sstevel@tonic-gate 					if (i)
1054*7c478bd9Sstevel@tonic-gate 						sem_rollback(sp, uops, i, undo);
1055*7c478bd9Sstevel@tonic-gate 					goto semoperr;
1056*7c478bd9Sstevel@tonic-gate 				}
1057*7c478bd9Sstevel@tonic-gate 				semp->semval += op->sem_op;
1058*7c478bd9Sstevel@tonic-gate 				if (semp->semzcnt && !semp->semval)
1059*7c478bd9Sstevel@tonic-gate 					cv_broadcast(&semp->semzcnt_cv);
1060*7c478bd9Sstevel@tonic-gate 				continue;
1061*7c478bd9Sstevel@tonic-gate 			}
1062*7c478bd9Sstevel@tonic-gate 			if (i)
1063*7c478bd9Sstevel@tonic-gate 				sem_rollback(sp, uops, i, undo);
1064*7c478bd9Sstevel@tonic-gate 			if (op->sem_flg & IPC_NOWAIT) {
1065*7c478bd9Sstevel@tonic-gate 				error = EAGAIN;
1066*7c478bd9Sstevel@tonic-gate 				goto semoperr;
1067*7c478bd9Sstevel@tonic-gate 			}
1068*7c478bd9Sstevel@tonic-gate 
1069*7c478bd9Sstevel@tonic-gate 			/*
1070*7c478bd9Sstevel@tonic-gate 			 * Mark the semaphore set as not a binary type
1071*7c478bd9Sstevel@tonic-gate 			 * if we are decrementing the value by more than 1.
1072*7c478bd9Sstevel@tonic-gate 			 *
1073*7c478bd9Sstevel@tonic-gate 			 * V operations will resort to cv_broadcast
1074*7c478bd9Sstevel@tonic-gate 			 * for this set because there are too many weird
1075*7c478bd9Sstevel@tonic-gate 			 * cases that have to be caught.
1076*7c478bd9Sstevel@tonic-gate 			 */
1077*7c478bd9Sstevel@tonic-gate 			if (op->sem_op < -1)
1078*7c478bd9Sstevel@tonic-gate 				sp->sem_binary = 0;
1079*7c478bd9Sstevel@tonic-gate 			if (!held) {
1080*7c478bd9Sstevel@tonic-gate 				held = 1;
1081*7c478bd9Sstevel@tonic-gate 				ipc_hold(sem_svc, (kipc_perm_t *)sp);
1082*7c478bd9Sstevel@tonic-gate 			}
1083*7c478bd9Sstevel@tonic-gate 			semp->semncnt++;
1084*7c478bd9Sstevel@tonic-gate 			cvres = cv_waituntil_sig(&semp->semncnt_cv, lock,
1085*7c478bd9Sstevel@tonic-gate 				tsp, timecheck);
1086*7c478bd9Sstevel@tonic-gate 			lock = ipc_relock(sem_svc, sp->sem_perm.ipc_id, lock);
1087*7c478bd9Sstevel@tonic-gate 
1088*7c478bd9Sstevel@tonic-gate 			if (!IPC_FREE(&sp->sem_perm)) {
1089*7c478bd9Sstevel@tonic-gate 				ASSERT(semp->semncnt != 0);
1090*7c478bd9Sstevel@tonic-gate 				semp->semncnt--;
1091*7c478bd9Sstevel@tonic-gate 				if (cvres > 0)	/* normal wakeup */
1092*7c478bd9Sstevel@tonic-gate 					goto check;
1093*7c478bd9Sstevel@tonic-gate 			}
1094*7c478bd9Sstevel@tonic-gate 
1095*7c478bd9Sstevel@tonic-gate 			/* EINTR or EAGAIN overrides EIDRM */
1096*7c478bd9Sstevel@tonic-gate 			if (cvres == 0)
1097*7c478bd9Sstevel@tonic-gate 				error = EINTR;
1098*7c478bd9Sstevel@tonic-gate 			else if (cvres < 0)
1099*7c478bd9Sstevel@tonic-gate 				error = EAGAIN;
1100*7c478bd9Sstevel@tonic-gate 			else
1101*7c478bd9Sstevel@tonic-gate 				error = EIDRM;
1102*7c478bd9Sstevel@tonic-gate 			goto semoperr;
1103*7c478bd9Sstevel@tonic-gate 		}
1104*7c478bd9Sstevel@tonic-gate 
1105*7c478bd9Sstevel@tonic-gate 		/*
1106*7c478bd9Sstevel@tonic-gate 		 * Wait for zero value
1107*7c478bd9Sstevel@tonic-gate 		 */
1108*7c478bd9Sstevel@tonic-gate 		if (semp->semval) {
1109*7c478bd9Sstevel@tonic-gate 			if (i)
1110*7c478bd9Sstevel@tonic-gate 				sem_rollback(sp, uops, i, undo);
1111*7c478bd9Sstevel@tonic-gate 			if (op->sem_flg & IPC_NOWAIT) {
1112*7c478bd9Sstevel@tonic-gate 				error = EAGAIN;
1113*7c478bd9Sstevel@tonic-gate 				goto semoperr;
1114*7c478bd9Sstevel@tonic-gate 			}
1115*7c478bd9Sstevel@tonic-gate 
1116*7c478bd9Sstevel@tonic-gate 			if (!held) {
1117*7c478bd9Sstevel@tonic-gate 				held = 1;
1118*7c478bd9Sstevel@tonic-gate 				ipc_hold(sem_svc, (kipc_perm_t *)sp);
1119*7c478bd9Sstevel@tonic-gate 			}
1120*7c478bd9Sstevel@tonic-gate 			semp->semzcnt++;
1121*7c478bd9Sstevel@tonic-gate 			cvres = cv_waituntil_sig(&semp->semzcnt_cv, lock,
1122*7c478bd9Sstevel@tonic-gate 				tsp, timecheck);
1123*7c478bd9Sstevel@tonic-gate 			lock = ipc_relock(sem_svc, sp->sem_perm.ipc_id, lock);
1124*7c478bd9Sstevel@tonic-gate 
1125*7c478bd9Sstevel@tonic-gate 			/*
1126*7c478bd9Sstevel@tonic-gate 			 * Don't touch semp if the semaphores have been removed.
1127*7c478bd9Sstevel@tonic-gate 			 */
1128*7c478bd9Sstevel@tonic-gate 			if (!IPC_FREE(&sp->sem_perm)) {
1129*7c478bd9Sstevel@tonic-gate 				ASSERT(semp->semzcnt != 0);
1130*7c478bd9Sstevel@tonic-gate 				semp->semzcnt--;
1131*7c478bd9Sstevel@tonic-gate 				if (cvres > 0)	/* normal wakeup */
1132*7c478bd9Sstevel@tonic-gate 					goto check;
1133*7c478bd9Sstevel@tonic-gate 			}
1134*7c478bd9Sstevel@tonic-gate 
1135*7c478bd9Sstevel@tonic-gate 			/* EINTR or EAGAIN overrides EIDRM */
1136*7c478bd9Sstevel@tonic-gate 			if (cvres == 0)
1137*7c478bd9Sstevel@tonic-gate 				error = EINTR;
1138*7c478bd9Sstevel@tonic-gate 			else if (cvres < 0)
1139*7c478bd9Sstevel@tonic-gate 				error = EAGAIN;
1140*7c478bd9Sstevel@tonic-gate 			else
1141*7c478bd9Sstevel@tonic-gate 				error = EIDRM;
1142*7c478bd9Sstevel@tonic-gate 			goto semoperr;
1143*7c478bd9Sstevel@tonic-gate 		}
1144*7c478bd9Sstevel@tonic-gate 	}
1145*7c478bd9Sstevel@tonic-gate 
1146*7c478bd9Sstevel@tonic-gate 	/* All operations succeeded.  Update sempid for accessed semaphores. */
1147*7c478bd9Sstevel@tonic-gate 	for (i = 0, op = uops; i++ < nsops;
1148*7c478bd9Sstevel@tonic-gate 	    sp->sem_base[(op++)->sem_num].sempid = pp->p_pid)
1149*7c478bd9Sstevel@tonic-gate 		;
1150*7c478bd9Sstevel@tonic-gate 	sp->sem_otime = gethrestime_sec();
1151*7c478bd9Sstevel@tonic-gate 	if (held)
1152*7c478bd9Sstevel@tonic-gate 		ipc_rele(sem_svc, (kipc_perm_t *)sp);
1153*7c478bd9Sstevel@tonic-gate 	else
1154*7c478bd9Sstevel@tonic-gate 		mutex_exit(lock);
1155*7c478bd9Sstevel@tonic-gate 
1156*7c478bd9Sstevel@tonic-gate 	/* Before leaving, deallocate the buffer that held the user semops */
1157*7c478bd9Sstevel@tonic-gate 	if (nsops != 1)
1158*7c478bd9Sstevel@tonic-gate 		kmem_free(uops, sizeof (*uops) * nsops);
1159*7c478bd9Sstevel@tonic-gate 	return (0);
1160*7c478bd9Sstevel@tonic-gate 
1161*7c478bd9Sstevel@tonic-gate 	/*
1162*7c478bd9Sstevel@tonic-gate 	 * Error return labels
1163*7c478bd9Sstevel@tonic-gate 	 */
1164*7c478bd9Sstevel@tonic-gate semoperr:
1165*7c478bd9Sstevel@tonic-gate 	if (held)
1166*7c478bd9Sstevel@tonic-gate 		ipc_rele(sem_svc, (kipc_perm_t *)sp);
1167*7c478bd9Sstevel@tonic-gate 	else
1168*7c478bd9Sstevel@tonic-gate 		mutex_exit(lock);
1169*7c478bd9Sstevel@tonic-gate 
1170*7c478bd9Sstevel@tonic-gate semoperr_unlocked:
1171*7c478bd9Sstevel@tonic-gate 
1172*7c478bd9Sstevel@tonic-gate 	/* Before leaving, deallocate the buffer that held the user semops */
1173*7c478bd9Sstevel@tonic-gate 	if (nsops != 1)
1174*7c478bd9Sstevel@tonic-gate 		kmem_free(uops, sizeof (*uops) * nsops);
1175*7c478bd9Sstevel@tonic-gate 	return (set_errno(error));
1176*7c478bd9Sstevel@tonic-gate }
1177*7c478bd9Sstevel@tonic-gate 
1178*7c478bd9Sstevel@tonic-gate /*
1179*7c478bd9Sstevel@tonic-gate  * semsys - System entry point for semctl, semget, and semop system calls.
1180*7c478bd9Sstevel@tonic-gate  */
1181*7c478bd9Sstevel@tonic-gate static int
1182*7c478bd9Sstevel@tonic-gate semsys(int opcode, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4)
1183*7c478bd9Sstevel@tonic-gate {
1184*7c478bd9Sstevel@tonic-gate 	int error;
1185*7c478bd9Sstevel@tonic-gate 
1186*7c478bd9Sstevel@tonic-gate 	switch (opcode) {
1187*7c478bd9Sstevel@tonic-gate 	case SEMCTL:
1188*7c478bd9Sstevel@tonic-gate 		error = semctl((int)a1, (uint_t)a2, (int)a3, a4);
1189*7c478bd9Sstevel@tonic-gate 		break;
1190*7c478bd9Sstevel@tonic-gate 	case SEMGET:
1191*7c478bd9Sstevel@tonic-gate 		error = semget((key_t)a1, (int)a2, (int)a3);
1192*7c478bd9Sstevel@tonic-gate 		break;
1193*7c478bd9Sstevel@tonic-gate 	case SEMOP:
1194*7c478bd9Sstevel@tonic-gate 		error = semop((int)a1, (struct sembuf *)a2, (size_t)a3, 0);
1195*7c478bd9Sstevel@tonic-gate 		break;
1196*7c478bd9Sstevel@tonic-gate 	case SEMIDS:
1197*7c478bd9Sstevel@tonic-gate 		error = semids((int *)a1, (uint_t)a2, (uint_t *)a3);
1198*7c478bd9Sstevel@tonic-gate 		break;
1199*7c478bd9Sstevel@tonic-gate 	case SEMTIMEDOP:
1200*7c478bd9Sstevel@tonic-gate 		error = semop((int)a1, (struct sembuf *)a2, (size_t)a3,
1201*7c478bd9Sstevel@tonic-gate 		    (timespec_t *)a4);
1202*7c478bd9Sstevel@tonic-gate 		break;
1203*7c478bd9Sstevel@tonic-gate 	default:
1204*7c478bd9Sstevel@tonic-gate 		error = set_errno(EINVAL);
1205*7c478bd9Sstevel@tonic-gate 		break;
1206*7c478bd9Sstevel@tonic-gate 	}
1207*7c478bd9Sstevel@tonic-gate 	return (error);
1208*7c478bd9Sstevel@tonic-gate }
1209