sysv_sem.c revision 194832
1/*-
2 * Implementation of SVID semaphores
3 *
4 * Author:  Daniel Boulet
5 *
6 * This software is provided ``AS IS'' without any warranties of any kind.
7 */
8/*-
9 * Copyright (c) 2003-2005 McAfee, Inc.
10 * All rights reserved.
11 *
12 * This software was developed for the FreeBSD Project in part by McAfee
13 * Research, the Security Research Division of McAfee, Inc under DARPA/SPAWAR
14 * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS research
15 * program.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
19 * are met:
20 * 1. Redistributions of source code must retain the above copyright
21 *    notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 *    notice, this list of conditions and the following disclaimer in the
24 *    documentation and/or other materials provided with the distribution.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39#include <sys/cdefs.h>
40__FBSDID("$FreeBSD: head/sys/kern/sysv_sem.c 194832 2009-06-24 13:35:38Z jhb $");
41
42#include "opt_sysvipc.h"
43
44#include <sys/param.h>
45#include <sys/systm.h>
46#include <sys/sysproto.h>
47#include <sys/eventhandler.h>
48#include <sys/kernel.h>
49#include <sys/proc.h>
50#include <sys/lock.h>
51#include <sys/module.h>
52#include <sys/mutex.h>
53#include <sys/sem.h>
54#include <sys/syscall.h>
55#include <sys/syscallsubr.h>
56#include <sys/sysent.h>
57#include <sys/sysctl.h>
58#include <sys/uio.h>
59#include <sys/malloc.h>
60#include <sys/jail.h>
61
62#include <security/mac/mac_framework.h>
63
64static MALLOC_DEFINE(M_SEM, "sem", "SVID compatible semaphores");
65
66#ifdef SEM_DEBUG
67#define DPRINTF(a)	printf a
68#else
69#define DPRINTF(a)
70#endif
71
72static void seminit(void);
73static int sysvsem_modload(struct module *, int, void *);
74static int semunload(void);
75static void semexit_myhook(void *arg, struct proc *p);
76static int sysctl_sema(SYSCTL_HANDLER_ARGS);
77static int semvalid(int semid, struct semid_kernel *semakptr);
78
79#ifndef _SYS_SYSPROTO_H_
80struct __semctl_args;
81int __semctl(struct thread *td, struct __semctl_args *uap);
82struct semget_args;
83int semget(struct thread *td, struct semget_args *uap);
84struct semop_args;
85int semop(struct thread *td, struct semop_args *uap);
86#endif
87
88static struct sem_undo *semu_alloc(struct thread *td);
89static int semundo_adjust(struct thread *td, struct sem_undo **supptr,
90    int semid, int semseq, int semnum, int adjval);
91static void semundo_clear(int semid, int semnum);
92
93/* XXX casting to (sy_call_t *) is bogus, as usual. */
94static sy_call_t *semcalls[] = {
95	(sy_call_t *)__semctl, (sy_call_t *)semget,
96	(sy_call_t *)semop
97};
98
99static struct mtx	sem_mtx;	/* semaphore global lock */
100static struct mtx sem_undo_mtx;
101static int	semtot = 0;
102static struct semid_kernel *sema;	/* semaphore id pool */
103static struct mtx *sema_mtx;	/* semaphore id pool mutexes*/
104static struct sem *sem;		/* semaphore pool */
105LIST_HEAD(, sem_undo) semu_list;	/* list of active undo structures */
106LIST_HEAD(, sem_undo) semu_free_list;	/* list of free undo structures */
107static int	*semu;		/* undo structure pool */
108static eventhandler_tag semexit_tag;
109
110#define SEMUNDO_MTX		sem_undo_mtx
111#define SEMUNDO_LOCK()		mtx_lock(&SEMUNDO_MTX);
112#define SEMUNDO_UNLOCK()	mtx_unlock(&SEMUNDO_MTX);
113#define SEMUNDO_LOCKASSERT(how)	mtx_assert(&SEMUNDO_MTX, (how));
114
115struct sem {
116	u_short	semval;		/* semaphore value */
117	pid_t	sempid;		/* pid of last operation */
118	u_short	semncnt;	/* # awaiting semval > cval */
119	u_short	semzcnt;	/* # awaiting semval = 0 */
120};
121
122/*
123 * Undo structure (one per process)
124 */
125struct sem_undo {
126	LIST_ENTRY(sem_undo) un_next;	/* ptr to next active undo structure */
127	struct	proc *un_proc;		/* owner of this structure */
128	short	un_cnt;			/* # of active entries */
129	struct undo {
130		short	un_adjval;	/* adjust on exit values */
131		short	un_num;		/* semaphore # */
132		int	un_id;		/* semid */
133		unsigned short un_seq;
134	} un_ent[1];			/* undo entries */
135};
136
137/*
138 * Configuration parameters
139 */
140#ifndef SEMMNI
141#define SEMMNI	10		/* # of semaphore identifiers */
142#endif
143#ifndef SEMMNS
144#define SEMMNS	60		/* # of semaphores in system */
145#endif
146#ifndef SEMUME
147#define SEMUME	10		/* max # of undo entries per process */
148#endif
149#ifndef SEMMNU
150#define SEMMNU	30		/* # of undo structures in system */
151#endif
152
153/* shouldn't need tuning */
154#ifndef SEMMAP
155#define SEMMAP	30		/* # of entries in semaphore map */
156#endif
157#ifndef SEMMSL
158#define SEMMSL	SEMMNS		/* max # of semaphores per id */
159#endif
160#ifndef SEMOPM
161#define SEMOPM	100		/* max # of operations per semop call */
162#endif
163
164#define SEMVMX	32767		/* semaphore maximum value */
165#define SEMAEM	16384		/* adjust on exit max value */
166
167/*
168 * Due to the way semaphore memory is allocated, we have to ensure that
169 * SEMUSZ is properly aligned.
170 */
171
172#define SEM_ALIGN(bytes) (((bytes) + (sizeof(long) - 1)) & ~(sizeof(long) - 1))
173
174/* actual size of an undo structure */
175#define SEMUSZ	SEM_ALIGN(offsetof(struct sem_undo, un_ent[SEMUME]))
176
177/*
178 * Macro to find a particular sem_undo vector
179 */
180#define SEMU(ix) \
181	((struct sem_undo *)(((intptr_t)semu)+ix * seminfo.semusz))
182
183/*
184 * semaphore info struct
185 */
186struct seminfo seminfo = {
187                SEMMAP,         /* # of entries in semaphore map */
188                SEMMNI,         /* # of semaphore identifiers */
189                SEMMNS,         /* # of semaphores in system */
190                SEMMNU,         /* # of undo structures in system */
191                SEMMSL,         /* max # of semaphores per id */
192                SEMOPM,         /* max # of operations per semop call */
193                SEMUME,         /* max # of undo entries per process */
194                SEMUSZ,         /* size in bytes of undo structure */
195                SEMVMX,         /* semaphore maximum value */
196                SEMAEM          /* adjust on exit max value */
197};
198
199SYSCTL_INT(_kern_ipc, OID_AUTO, semmap, CTLFLAG_RW, &seminfo.semmap, 0,
200    "Number of entries in the semaphore map");
201SYSCTL_INT(_kern_ipc, OID_AUTO, semmni, CTLFLAG_RDTUN, &seminfo.semmni, 0,
202    "Number of semaphore identifiers");
203SYSCTL_INT(_kern_ipc, OID_AUTO, semmns, CTLFLAG_RDTUN, &seminfo.semmns, 0,
204    "Maximum number of semaphores in the system");
205SYSCTL_INT(_kern_ipc, OID_AUTO, semmnu, CTLFLAG_RDTUN, &seminfo.semmnu, 0,
206    "Maximum number of undo structures in the system");
207SYSCTL_INT(_kern_ipc, OID_AUTO, semmsl, CTLFLAG_RW, &seminfo.semmsl, 0,
208    "Max semaphores per id");
209SYSCTL_INT(_kern_ipc, OID_AUTO, semopm, CTLFLAG_RDTUN, &seminfo.semopm, 0,
210    "Max operations per semop call");
211SYSCTL_INT(_kern_ipc, OID_AUTO, semume, CTLFLAG_RDTUN, &seminfo.semume, 0,
212    "Max undo entries per process");
213SYSCTL_INT(_kern_ipc, OID_AUTO, semusz, CTLFLAG_RDTUN, &seminfo.semusz, 0,
214    "Size in bytes of undo structure");
215SYSCTL_INT(_kern_ipc, OID_AUTO, semvmx, CTLFLAG_RW, &seminfo.semvmx, 0,
216    "Semaphore maximum value");
217SYSCTL_INT(_kern_ipc, OID_AUTO, semaem, CTLFLAG_RW, &seminfo.semaem, 0,
218    "Adjust on exit max value");
219SYSCTL_PROC(_kern_ipc, OID_AUTO, sema, CTLFLAG_RD,
220    NULL, 0, sysctl_sema, "", "");
221
222static void
223seminit(void)
224{
225	int i;
226
227	TUNABLE_INT_FETCH("kern.ipc.semmap", &seminfo.semmap);
228	TUNABLE_INT_FETCH("kern.ipc.semmni", &seminfo.semmni);
229	TUNABLE_INT_FETCH("kern.ipc.semmns", &seminfo.semmns);
230	TUNABLE_INT_FETCH("kern.ipc.semmnu", &seminfo.semmnu);
231	TUNABLE_INT_FETCH("kern.ipc.semmsl", &seminfo.semmsl);
232	TUNABLE_INT_FETCH("kern.ipc.semopm", &seminfo.semopm);
233	TUNABLE_INT_FETCH("kern.ipc.semume", &seminfo.semume);
234	TUNABLE_INT_FETCH("kern.ipc.semusz", &seminfo.semusz);
235	TUNABLE_INT_FETCH("kern.ipc.semvmx", &seminfo.semvmx);
236	TUNABLE_INT_FETCH("kern.ipc.semaem", &seminfo.semaem);
237
238	sem = malloc(sizeof(struct sem) * seminfo.semmns, M_SEM, M_WAITOK);
239	sema = malloc(sizeof(struct semid_kernel) * seminfo.semmni, M_SEM,
240	    M_WAITOK);
241	sema_mtx = malloc(sizeof(struct mtx) * seminfo.semmni, M_SEM,
242	    M_WAITOK | M_ZERO);
243	semu = malloc(seminfo.semmnu * seminfo.semusz, M_SEM, M_WAITOK);
244
245	for (i = 0; i < seminfo.semmni; i++) {
246		sema[i].u.sem_base = 0;
247		sema[i].u.sem_perm.mode = 0;
248		sema[i].u.sem_perm.seq = 0;
249#ifdef MAC
250		mac_sysvsem_init(&sema[i]);
251#endif
252	}
253	for (i = 0; i < seminfo.semmni; i++)
254		mtx_init(&sema_mtx[i], "semid", NULL, MTX_DEF);
255	LIST_INIT(&semu_free_list);
256	for (i = 0; i < seminfo.semmnu; i++) {
257		struct sem_undo *suptr = SEMU(i);
258		suptr->un_proc = NULL;
259		LIST_INSERT_HEAD(&semu_free_list, suptr, un_next);
260	}
261	LIST_INIT(&semu_list);
262	mtx_init(&sem_mtx, "sem", NULL, MTX_DEF);
263	mtx_init(&sem_undo_mtx, "semu", NULL, MTX_DEF);
264	semexit_tag = EVENTHANDLER_REGISTER(process_exit, semexit_myhook, NULL,
265	    EVENTHANDLER_PRI_ANY);
266}
267
268static int
269semunload(void)
270{
271	int i;
272
273	/* XXXKIB */
274	if (semtot != 0)
275		return (EBUSY);
276
277	EVENTHANDLER_DEREGISTER(process_exit, semexit_tag);
278#ifdef MAC
279	for (i = 0; i < seminfo.semmni; i++)
280		mac_sysvsem_destroy(&sema[i]);
281#endif
282	free(sem, M_SEM);
283	free(sema, M_SEM);
284	free(semu, M_SEM);
285	for (i = 0; i < seminfo.semmni; i++)
286		mtx_destroy(&sema_mtx[i]);
287	free(sema_mtx, M_SEM);
288	mtx_destroy(&sem_mtx);
289	mtx_destroy(&sem_undo_mtx);
290	return (0);
291}
292
293static int
294sysvsem_modload(struct module *module, int cmd, void *arg)
295{
296	int error = 0;
297
298	switch (cmd) {
299	case MOD_LOAD:
300		seminit();
301		break;
302	case MOD_UNLOAD:
303		error = semunload();
304		break;
305	case MOD_SHUTDOWN:
306		break;
307	default:
308		error = EINVAL;
309		break;
310	}
311	return (error);
312}
313
314static moduledata_t sysvsem_mod = {
315	"sysvsem",
316	&sysvsem_modload,
317	NULL
318};
319
320SYSCALL_MODULE_HELPER(semsys);
321SYSCALL_MODULE_HELPER(__semctl);
322SYSCALL_MODULE_HELPER(semget);
323SYSCALL_MODULE_HELPER(semop);
324
325DECLARE_MODULE(sysvsem, sysvsem_mod, SI_SUB_SYSV_SEM, SI_ORDER_FIRST);
326MODULE_VERSION(sysvsem, 1);
327
328/*
329 * Entry point for all SEM calls.
330 */
331int
332semsys(td, uap)
333	struct thread *td;
334	/* XXX actually varargs. */
335	struct semsys_args /* {
336		int	which;
337		int	a2;
338		int	a3;
339		int	a4;
340		int	a5;
341	} */ *uap;
342{
343	int error;
344
345	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
346		return (ENOSYS);
347	if (uap->which < 0 ||
348	    uap->which >= sizeof(semcalls)/sizeof(semcalls[0]))
349		return (EINVAL);
350	error = (*semcalls[uap->which])(td, &uap->a2);
351	return (error);
352}
353
354/*
355 * Allocate a new sem_undo structure for a process
356 * (returns ptr to structure or NULL if no more room)
357 */
358
359static struct sem_undo *
360semu_alloc(struct thread *td)
361{
362	struct sem_undo *suptr;
363
364	SEMUNDO_LOCKASSERT(MA_OWNED);
365	if ((suptr = LIST_FIRST(&semu_free_list)) == NULL)
366		return (NULL);
367	LIST_REMOVE(suptr, un_next);
368	LIST_INSERT_HEAD(&semu_list, suptr, un_next);
369	suptr->un_cnt = 0;
370	suptr->un_proc = td->td_proc;
371	return (suptr);
372}
373
374static int
375semu_try_free(struct sem_undo *suptr)
376{
377
378	SEMUNDO_LOCKASSERT(MA_OWNED);
379
380	if (suptr->un_cnt != 0)
381		return (0);
382	LIST_REMOVE(suptr, un_next);
383	LIST_INSERT_HEAD(&semu_free_list, suptr, un_next);
384	return (1);
385}
386
387/*
388 * Adjust a particular entry for a particular proc
389 */
390
391static int
392semundo_adjust(struct thread *td, struct sem_undo **supptr, int semid,
393    int semseq, int semnum, int adjval)
394{
395	struct proc *p = td->td_proc;
396	struct sem_undo *suptr;
397	struct undo *sunptr;
398	int i;
399
400	SEMUNDO_LOCKASSERT(MA_OWNED);
401	/* Look for and remember the sem_undo if the caller doesn't provide
402	   it */
403
404	suptr = *supptr;
405	if (suptr == NULL) {
406		LIST_FOREACH(suptr, &semu_list, un_next) {
407			if (suptr->un_proc == p) {
408				*supptr = suptr;
409				break;
410			}
411		}
412		if (suptr == NULL) {
413			if (adjval == 0)
414				return(0);
415			suptr = semu_alloc(td);
416			if (suptr == NULL)
417				return (ENOSPC);
418			*supptr = suptr;
419		}
420	}
421
422	/*
423	 * Look for the requested entry and adjust it (delete if adjval becomes
424	 * 0).
425	 */
426	sunptr = &suptr->un_ent[0];
427	for (i = 0; i < suptr->un_cnt; i++, sunptr++) {
428		if (sunptr->un_id != semid || sunptr->un_num != semnum)
429			continue;
430		if (adjval != 0) {
431			adjval += sunptr->un_adjval;
432			if (adjval > seminfo.semaem || adjval < -seminfo.semaem)
433				return (ERANGE);
434		}
435		sunptr->un_adjval = adjval;
436		if (sunptr->un_adjval == 0) {
437			suptr->un_cnt--;
438			if (i < suptr->un_cnt)
439				suptr->un_ent[i] =
440				    suptr->un_ent[suptr->un_cnt];
441			if (suptr->un_cnt == 0)
442				semu_try_free(suptr);
443		}
444		return (0);
445	}
446
447	/* Didn't find the right entry - create it */
448	if (adjval == 0)
449		return (0);
450	if (adjval > seminfo.semaem || adjval < -seminfo.semaem)
451		return (ERANGE);
452	if (suptr->un_cnt != seminfo.semume) {
453		sunptr = &suptr->un_ent[suptr->un_cnt];
454		suptr->un_cnt++;
455		sunptr->un_adjval = adjval;
456		sunptr->un_id = semid;
457		sunptr->un_num = semnum;
458		sunptr->un_seq = semseq;
459	} else
460		return (EINVAL);
461	return (0);
462}
463
464static void
465semundo_clear(int semid, int semnum)
466{
467	struct sem_undo *suptr, *suptr1;
468	struct undo *sunptr;
469	int i;
470
471	SEMUNDO_LOCKASSERT(MA_OWNED);
472	LIST_FOREACH_SAFE(suptr, &semu_list, un_next, suptr1) {
473		sunptr = &suptr->un_ent[0];
474		for (i = 0; i < suptr->un_cnt; i++, sunptr++) {
475			if (sunptr->un_id != semid)
476				continue;
477			if (semnum == -1 || sunptr->un_num == semnum) {
478				suptr->un_cnt--;
479				if (i < suptr->un_cnt) {
480					suptr->un_ent[i] =
481					    suptr->un_ent[suptr->un_cnt];
482					continue;
483				}
484				semu_try_free(suptr);
485			}
486			if (semnum != -1)
487				break;
488		}
489	}
490}
491
492static int
493semvalid(int semid, struct semid_kernel *semakptr)
494{
495
496	return ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 ||
497	    semakptr->u.sem_perm.seq != IPCID_TO_SEQ(semid) ? EINVAL : 0);
498}
499
500/*
501 * Note that the user-mode half of this passes a union, not a pointer.
502 */
503#ifndef _SYS_SYSPROTO_H_
504struct __semctl_args {
505	int	semid;
506	int	semnum;
507	int	cmd;
508	union	semun *arg;
509};
510#endif
511int
512__semctl(struct thread *td, struct __semctl_args *uap)
513{
514	struct semid_ds dsbuf;
515	union semun arg, semun;
516	register_t rval;
517	int error;
518
519	switch (uap->cmd) {
520	case SEM_STAT:
521	case IPC_SET:
522	case IPC_STAT:
523	case GETALL:
524	case SETVAL:
525	case SETALL:
526		error = copyin(uap->arg, &arg, sizeof(arg));
527		if (error)
528			return (error);
529		break;
530	}
531
532	switch (uap->cmd) {
533	case SEM_STAT:
534	case IPC_STAT:
535		semun.buf = &dsbuf;
536		break;
537	case IPC_SET:
538		error = copyin(arg.buf, &dsbuf, sizeof(dsbuf));
539		if (error)
540			return (error);
541		semun.buf = &dsbuf;
542		break;
543	case GETALL:
544	case SETALL:
545		semun.array = arg.array;
546		break;
547	case SETVAL:
548		semun.val = arg.val;
549		break;
550	}
551
552	error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun,
553	    &rval);
554	if (error)
555		return (error);
556
557	switch (uap->cmd) {
558	case SEM_STAT:
559	case IPC_STAT:
560		error = copyout(&dsbuf, arg.buf, sizeof(dsbuf));
561		break;
562	}
563
564	if (error == 0)
565		td->td_retval[0] = rval;
566	return (error);
567}
568
569int
570kern_semctl(struct thread *td, int semid, int semnum, int cmd,
571    union semun *arg, register_t *rval)
572{
573	u_short *array;
574	struct ucred *cred = td->td_ucred;
575	int i, error;
576	struct semid_ds *sbuf;
577	struct semid_kernel *semakptr;
578	struct mtx *sema_mtxp;
579	u_short usval, count;
580	int semidx;
581
582	DPRINTF(("call to semctl(%d, %d, %d, 0x%p)\n",
583	    semid, semnum, cmd, arg));
584	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
585		return (ENOSYS);
586
587	array = NULL;
588
589	switch(cmd) {
590	case SEM_STAT:
591		/*
592		 * For this command we assume semid is an array index
593		 * rather than an IPC id.
594		 */
595		if (semid < 0 || semid >= seminfo.semmni)
596			return (EINVAL);
597		semakptr = &sema[semid];
598		sema_mtxp = &sema_mtx[semid];
599		mtx_lock(sema_mtxp);
600		if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) {
601			error = EINVAL;
602			goto done2;
603		}
604		if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
605			goto done2;
606#ifdef MAC
607		error = mac_sysvsem_check_semctl(cred, semakptr, cmd);
608		if (error != 0)
609			goto done2;
610#endif
611		bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds));
612		*rval = IXSEQ_TO_IPCID(semid, semakptr->u.sem_perm);
613		mtx_unlock(sema_mtxp);
614		return (0);
615	}
616
617	semidx = IPCID_TO_IX(semid);
618	if (semidx < 0 || semidx >= seminfo.semmni)
619		return (EINVAL);
620
621	semakptr = &sema[semidx];
622	sema_mtxp = &sema_mtx[semidx];
623	if (cmd == IPC_RMID)
624		mtx_lock(&sem_mtx);
625	mtx_lock(sema_mtxp);
626#ifdef MAC
627	error = mac_sysvsem_check_semctl(cred, semakptr, cmd);
628	if (error != 0)
629		goto done2;
630#endif
631
632	error = 0;
633	*rval = 0;
634
635	switch (cmd) {
636	case IPC_RMID:
637		if ((error = semvalid(semid, semakptr)) != 0)
638			goto done2;
639		if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M)))
640			goto done2;
641		semakptr->u.sem_perm.cuid = cred->cr_uid;
642		semakptr->u.sem_perm.uid = cred->cr_uid;
643		semakptr->u.sem_perm.mode = 0;
644		SEMUNDO_LOCK();
645		semundo_clear(semidx, -1);
646		SEMUNDO_UNLOCK();
647#ifdef MAC
648		mac_sysvsem_cleanup(semakptr);
649#endif
650		wakeup(semakptr);
651		for (i = 0; i < seminfo.semmni; i++) {
652			if ((sema[i].u.sem_perm.mode & SEM_ALLOC) &&
653			    sema[i].u.sem_base > semakptr->u.sem_base)
654				mtx_lock_flags(&sema_mtx[i], LOP_DUPOK);
655		}
656		for (i = semakptr->u.sem_base - sem; i < semtot; i++)
657			sem[i] = sem[i + semakptr->u.sem_nsems];
658		for (i = 0; i < seminfo.semmni; i++) {
659			if ((sema[i].u.sem_perm.mode & SEM_ALLOC) &&
660			    sema[i].u.sem_base > semakptr->u.sem_base) {
661				sema[i].u.sem_base -= semakptr->u.sem_nsems;
662				mtx_unlock(&sema_mtx[i]);
663			}
664		}
665		semtot -= semakptr->u.sem_nsems;
666		break;
667
668	case IPC_SET:
669		if ((error = semvalid(semid, semakptr)) != 0)
670			goto done2;
671		if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M)))
672			goto done2;
673		sbuf = arg->buf;
674		semakptr->u.sem_perm.uid = sbuf->sem_perm.uid;
675		semakptr->u.sem_perm.gid = sbuf->sem_perm.gid;
676		semakptr->u.sem_perm.mode = (semakptr->u.sem_perm.mode &
677		    ~0777) | (sbuf->sem_perm.mode & 0777);
678		semakptr->u.sem_ctime = time_second;
679		break;
680
681	case IPC_STAT:
682		if ((error = semvalid(semid, semakptr)) != 0)
683			goto done2;
684		if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
685			goto done2;
686		bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds));
687		break;
688
689	case GETNCNT:
690		if ((error = semvalid(semid, semakptr)) != 0)
691			goto done2;
692		if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
693			goto done2;
694		if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
695			error = EINVAL;
696			goto done2;
697		}
698		*rval = semakptr->u.sem_base[semnum].semncnt;
699		break;
700
701	case GETPID:
702		if ((error = semvalid(semid, semakptr)) != 0)
703			goto done2;
704		if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
705			goto done2;
706		if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
707			error = EINVAL;
708			goto done2;
709		}
710		*rval = semakptr->u.sem_base[semnum].sempid;
711		break;
712
713	case GETVAL:
714		if ((error = semvalid(semid, semakptr)) != 0)
715			goto done2;
716		if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
717			goto done2;
718		if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
719			error = EINVAL;
720			goto done2;
721		}
722		*rval = semakptr->u.sem_base[semnum].semval;
723		break;
724
725	case GETALL:
726		/*
727		 * Unfortunately, callers of this function don't know
728		 * in advance how many semaphores are in this set.
729		 * While we could just allocate the maximum size array
730		 * and pass the actual size back to the caller, that
731		 * won't work for SETALL since we can't copyin() more
732		 * data than the user specified as we may return a
733		 * spurious EFAULT.
734		 *
735		 * Note that the number of semaphores in a set is
736		 * fixed for the life of that set.  The only way that
737		 * the 'count' could change while are blocked in
738		 * malloc() is if this semaphore set were destroyed
739		 * and a new one created with the same index.
740		 * However, semvalid() will catch that due to the
741		 * sequence number unless exactly 0x8000 (or a
742		 * multiple thereof) semaphore sets for the same index
743		 * are created and destroyed while we are in malloc!
744		 *
745		 */
746		count = semakptr->u.sem_nsems;
747		mtx_unlock(sema_mtxp);
748		array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK);
749		mtx_lock(sema_mtxp);
750		if ((error = semvalid(semid, semakptr)) != 0)
751			goto done2;
752		KASSERT(count == semakptr->u.sem_nsems, ("nsems changed"));
753		if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
754			goto done2;
755		for (i = 0; i < semakptr->u.sem_nsems; i++)
756			array[i] = semakptr->u.sem_base[i].semval;
757		mtx_unlock(sema_mtxp);
758		error = copyout(array, arg->array, count * sizeof(*array));
759		mtx_lock(sema_mtxp);
760		break;
761
762	case GETZCNT:
763		if ((error = semvalid(semid, semakptr)) != 0)
764			goto done2;
765		if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
766			goto done2;
767		if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
768			error = EINVAL;
769			goto done2;
770		}
771		*rval = semakptr->u.sem_base[semnum].semzcnt;
772		break;
773
774	case SETVAL:
775		if ((error = semvalid(semid, semakptr)) != 0)
776			goto done2;
777		if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W)))
778			goto done2;
779		if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
780			error = EINVAL;
781			goto done2;
782		}
783		if (arg->val < 0 || arg->val > seminfo.semvmx) {
784			error = ERANGE;
785			goto done2;
786		}
787		semakptr->u.sem_base[semnum].semval = arg->val;
788		SEMUNDO_LOCK();
789		semundo_clear(semidx, semnum);
790		SEMUNDO_UNLOCK();
791		wakeup(semakptr);
792		break;
793
794	case SETALL:
795		/*
796		 * See comment on GETALL for why 'count' shouldn't change
797		 * and why we require a userland buffer.
798		 */
799		count = semakptr->u.sem_nsems;
800		mtx_unlock(sema_mtxp);
801		array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK);
802		error = copyin(arg->array, array, count * sizeof(*array));
803		mtx_lock(sema_mtxp);
804		if (error)
805			break;
806		if ((error = semvalid(semid, semakptr)) != 0)
807			goto done2;
808		KASSERT(count == semakptr->u.sem_nsems, ("nsems changed"));
809		if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W)))
810			goto done2;
811		for (i = 0; i < semakptr->u.sem_nsems; i++) {
812			usval = array[i];
813			if (usval > seminfo.semvmx) {
814				error = ERANGE;
815				break;
816			}
817			semakptr->u.sem_base[i].semval = usval;
818		}
819		SEMUNDO_LOCK();
820		semundo_clear(semidx, -1);
821		SEMUNDO_UNLOCK();
822		wakeup(semakptr);
823		break;
824
825	default:
826		error = EINVAL;
827		break;
828	}
829
830done2:
831	mtx_unlock(sema_mtxp);
832	if (cmd == IPC_RMID)
833		mtx_unlock(&sem_mtx);
834	if (array != NULL)
835		free(array, M_TEMP);
836	return(error);
837}
838
839#ifndef _SYS_SYSPROTO_H_
840struct semget_args {
841	key_t	key;
842	int	nsems;
843	int	semflg;
844};
845#endif
846int
847semget(struct thread *td, struct semget_args *uap)
848{
849	int semid, error = 0;
850	int key = uap->key;
851	int nsems = uap->nsems;
852	int semflg = uap->semflg;
853	struct ucred *cred = td->td_ucred;
854
855	DPRINTF(("semget(0x%x, %d, 0%o)\n", key, nsems, semflg));
856	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
857		return (ENOSYS);
858
859	mtx_lock(&sem_mtx);
860	if (key != IPC_PRIVATE) {
861		for (semid = 0; semid < seminfo.semmni; semid++) {
862			if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) &&
863			    sema[semid].u.sem_perm.key == key)
864				break;
865		}
866		if (semid < seminfo.semmni) {
867			DPRINTF(("found public key\n"));
868			if ((error = ipcperm(td, &sema[semid].u.sem_perm,
869			    semflg & 0700))) {
870				goto done2;
871			}
872			if (nsems > 0 && sema[semid].u.sem_nsems < nsems) {
873				DPRINTF(("too small\n"));
874				error = EINVAL;
875				goto done2;
876			}
877			if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) {
878				DPRINTF(("not exclusive\n"));
879				error = EEXIST;
880				goto done2;
881			}
882#ifdef MAC
883			error = mac_sysvsem_check_semget(cred, &sema[semid]);
884			if (error != 0)
885				goto done2;
886#endif
887			goto found;
888		}
889	}
890
891	DPRINTF(("need to allocate the semid_kernel\n"));
892	if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) {
893		if (nsems <= 0 || nsems > seminfo.semmsl) {
894			DPRINTF(("nsems out of range (0<%d<=%d)\n", nsems,
895			    seminfo.semmsl));
896			error = EINVAL;
897			goto done2;
898		}
899		if (nsems > seminfo.semmns - semtot) {
900			DPRINTF((
901			    "not enough semaphores left (need %d, got %d)\n",
902			    nsems, seminfo.semmns - semtot));
903			error = ENOSPC;
904			goto done2;
905		}
906		for (semid = 0; semid < seminfo.semmni; semid++) {
907			if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0)
908				break;
909		}
910		if (semid == seminfo.semmni) {
911			DPRINTF(("no more semid_kernel's available\n"));
912			error = ENOSPC;
913			goto done2;
914		}
915		DPRINTF(("semid %d is available\n", semid));
916		mtx_lock(&sema_mtx[semid]);
917		KASSERT((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0,
918		    ("Lost semaphore %d", semid));
919		sema[semid].u.sem_perm.key = key;
920		sema[semid].u.sem_perm.cuid = cred->cr_uid;
921		sema[semid].u.sem_perm.uid = cred->cr_uid;
922		sema[semid].u.sem_perm.cgid = cred->cr_gid;
923		sema[semid].u.sem_perm.gid = cred->cr_gid;
924		sema[semid].u.sem_perm.mode = (semflg & 0777) | SEM_ALLOC;
925		sema[semid].u.sem_perm.seq =
926		    (sema[semid].u.sem_perm.seq + 1) & 0x7fff;
927		sema[semid].u.sem_nsems = nsems;
928		sema[semid].u.sem_otime = 0;
929		sema[semid].u.sem_ctime = time_second;
930		sema[semid].u.sem_base = &sem[semtot];
931		semtot += nsems;
932		bzero(sema[semid].u.sem_base,
933		    sizeof(sema[semid].u.sem_base[0])*nsems);
934#ifdef MAC
935		mac_sysvsem_create(cred, &sema[semid]);
936#endif
937		mtx_unlock(&sema_mtx[semid]);
938		DPRINTF(("sembase = %p, next = %p\n",
939		    sema[semid].u.sem_base, &sem[semtot]));
940	} else {
941		DPRINTF(("didn't find it and wasn't asked to create it\n"));
942		error = ENOENT;
943		goto done2;
944	}
945
946found:
947	td->td_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].u.sem_perm);
948done2:
949	mtx_unlock(&sem_mtx);
950	return (error);
951}
952
953#ifndef _SYS_SYSPROTO_H_
954struct semop_args {
955	int	semid;
956	struct	sembuf *sops;
957	size_t	nsops;
958};
959#endif
960int
961semop(struct thread *td, struct semop_args *uap)
962{
963#define SMALL_SOPS	8
964	struct sembuf small_sops[SMALL_SOPS];
965	int semid = uap->semid;
966	size_t nsops = uap->nsops;
967	struct sembuf *sops;
968	struct semid_kernel *semakptr;
969	struct sembuf *sopptr = 0;
970	struct sem *semptr = 0;
971	struct sem_undo *suptr;
972	struct mtx *sema_mtxp;
973	size_t i, j, k;
974	int error;
975	int do_wakeup, do_undos;
976	unsigned short seq;
977
978#ifdef SEM_DEBUG
979	sops = NULL;
980#endif
981	DPRINTF(("call to semop(%d, %p, %u)\n", semid, sops, nsops));
982
983	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
984		return (ENOSYS);
985
986	semid = IPCID_TO_IX(semid);	/* Convert back to zero origin */
987
988	if (semid < 0 || semid >= seminfo.semmni)
989		return (EINVAL);
990
991	/* Allocate memory for sem_ops */
992	if (nsops <= SMALL_SOPS)
993		sops = small_sops;
994	else if (nsops <= seminfo.semopm)
995		sops = malloc(nsops * sizeof(*sops), M_TEMP, M_WAITOK);
996	else {
997		DPRINTF(("too many sops (max=%d, nsops=%d)\n", seminfo.semopm,
998		    nsops));
999		return (E2BIG);
1000	}
1001	if ((error = copyin(uap->sops, sops, nsops * sizeof(sops[0]))) != 0) {
1002		DPRINTF(("error = %d from copyin(%p, %p, %d)\n", error,
1003		    uap->sops, sops, nsops * sizeof(sops[0])));
1004		if (sops != small_sops)
1005			free(sops, M_SEM);
1006		return (error);
1007	}
1008
1009	semakptr = &sema[semid];
1010	sema_mtxp = &sema_mtx[semid];
1011	mtx_lock(sema_mtxp);
1012	if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) {
1013		error = EINVAL;
1014		goto done2;
1015	}
1016	seq = semakptr->u.sem_perm.seq;
1017	if (seq != IPCID_TO_SEQ(uap->semid)) {
1018		error = EINVAL;
1019		goto done2;
1020	}
1021	/*
1022	 * Initial pass thru sops to see what permissions are needed.
1023	 * Also perform any checks that don't need repeating on each
1024	 * attempt to satisfy the request vector.
1025	 */
1026	j = 0;		/* permission needed */
1027	do_undos = 0;
1028	for (i = 0; i < nsops; i++) {
1029		sopptr = &sops[i];
1030		if (sopptr->sem_num >= semakptr->u.sem_nsems) {
1031			error = EFBIG;
1032			goto done2;
1033		}
1034		if (sopptr->sem_flg & SEM_UNDO && sopptr->sem_op != 0)
1035			do_undos = 1;
1036		j |= (sopptr->sem_op == 0) ? SEM_R : SEM_A;
1037	}
1038
1039	if ((error = ipcperm(td, &semakptr->u.sem_perm, j))) {
1040		DPRINTF(("error = %d from ipaccess\n", error));
1041		goto done2;
1042	}
1043#ifdef MAC
1044	error = mac_sysvsem_check_semop(td->td_ucred, semakptr, j);
1045	if (error != 0)
1046		goto done2;
1047#endif
1048
1049	/*
1050	 * Loop trying to satisfy the vector of requests.
1051	 * If we reach a point where we must wait, any requests already
1052	 * performed are rolled back and we go to sleep until some other
1053	 * process wakes us up.  At this point, we start all over again.
1054	 *
1055	 * This ensures that from the perspective of other tasks, a set
1056	 * of requests is atomic (never partially satisfied).
1057	 */
1058	for (;;) {
1059		do_wakeup = 0;
1060		error = 0;	/* error return if necessary */
1061
1062		for (i = 0; i < nsops; i++) {
1063			sopptr = &sops[i];
1064			semptr = &semakptr->u.sem_base[sopptr->sem_num];
1065
1066			DPRINTF((
1067			    "semop:  semakptr=%p, sem_base=%p, "
1068			    "semptr=%p, sem[%d]=%d : op=%d, flag=%s\n",
1069			    semakptr, semakptr->u.sem_base, semptr,
1070			    sopptr->sem_num, semptr->semval, sopptr->sem_op,
1071			    (sopptr->sem_flg & IPC_NOWAIT) ?
1072			    "nowait" : "wait"));
1073
1074			if (sopptr->sem_op < 0) {
1075				if (semptr->semval + sopptr->sem_op < 0) {
1076					DPRINTF(("semop:  can't do it now\n"));
1077					break;
1078				} else {
1079					semptr->semval += sopptr->sem_op;
1080					if (semptr->semval == 0 &&
1081					    semptr->semzcnt > 0)
1082						do_wakeup = 1;
1083				}
1084			} else if (sopptr->sem_op == 0) {
1085				if (semptr->semval != 0) {
1086					DPRINTF(("semop:  not zero now\n"));
1087					break;
1088				}
1089			} else if (semptr->semval + sopptr->sem_op >
1090			    seminfo.semvmx) {
1091				error = ERANGE;
1092				break;
1093			} else {
1094				if (semptr->semncnt > 0)
1095					do_wakeup = 1;
1096				semptr->semval += sopptr->sem_op;
1097			}
1098		}
1099
1100		/*
1101		 * Did we get through the entire vector?
1102		 */
1103		if (i >= nsops)
1104			goto done;
1105
1106		/*
1107		 * No ... rollback anything that we've already done
1108		 */
1109		DPRINTF(("semop:  rollback 0 through %d\n", i-1));
1110		for (j = 0; j < i; j++)
1111			semakptr->u.sem_base[sops[j].sem_num].semval -=
1112			    sops[j].sem_op;
1113
1114		/* If we detected an error, return it */
1115		if (error != 0)
1116			goto done2;
1117
1118		/*
1119		 * If the request that we couldn't satisfy has the
1120		 * NOWAIT flag set then return with EAGAIN.
1121		 */
1122		if (sopptr->sem_flg & IPC_NOWAIT) {
1123			error = EAGAIN;
1124			goto done2;
1125		}
1126
1127		if (sopptr->sem_op == 0)
1128			semptr->semzcnt++;
1129		else
1130			semptr->semncnt++;
1131
1132		DPRINTF(("semop:  good night!\n"));
1133		error = msleep(semakptr, sema_mtxp, (PZERO - 4) | PCATCH,
1134		    "semwait", 0);
1135		DPRINTF(("semop:  good morning (error=%d)!\n", error));
1136		/* return code is checked below, after sem[nz]cnt-- */
1137
1138		/*
1139		 * Make sure that the semaphore still exists
1140		 */
1141		seq = semakptr->u.sem_perm.seq;
1142		if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 ||
1143		    seq != IPCID_TO_SEQ(uap->semid)) {
1144			error = EIDRM;
1145			goto done2;
1146		}
1147
1148		/*
1149		 * Renew the semaphore's pointer after wakeup since
1150		 * during msleep sem_base may have been modified and semptr
1151		 * is not valid any more
1152		 */
1153		semptr = &semakptr->u.sem_base[sopptr->sem_num];
1154
1155		/*
1156		 * The semaphore is still alive.  Readjust the count of
1157		 * waiting processes.
1158		 */
1159		if (sopptr->sem_op == 0)
1160			semptr->semzcnt--;
1161		else
1162			semptr->semncnt--;
1163
1164		/*
1165		 * Is it really morning, or was our sleep interrupted?
1166		 * (Delayed check of msleep() return code because we
1167		 * need to decrement sem[nz]cnt either way.)
1168		 */
1169		if (error != 0) {
1170			error = EINTR;
1171			goto done2;
1172		}
1173		DPRINTF(("semop:  good morning!\n"));
1174	}
1175
1176done:
1177	/*
1178	 * Process any SEM_UNDO requests.
1179	 */
1180	if (do_undos) {
1181		SEMUNDO_LOCK();
1182		suptr = NULL;
1183		for (i = 0; i < nsops; i++) {
1184			/*
1185			 * We only need to deal with SEM_UNDO's for non-zero
1186			 * op's.
1187			 */
1188			int adjval;
1189
1190			if ((sops[i].sem_flg & SEM_UNDO) == 0)
1191				continue;
1192			adjval = sops[i].sem_op;
1193			if (adjval == 0)
1194				continue;
1195			error = semundo_adjust(td, &suptr, semid, seq,
1196			    sops[i].sem_num, -adjval);
1197			if (error == 0)
1198				continue;
1199
1200			/*
1201			 * Oh-Oh!  We ran out of either sem_undo's or undo's.
1202			 * Rollback the adjustments to this point and then
1203			 * rollback the semaphore ups and down so we can return
1204			 * with an error with all structures restored.  We
1205			 * rollback the undo's in the exact reverse order that
1206			 * we applied them.  This guarantees that we won't run
1207			 * out of space as we roll things back out.
1208			 */
1209			for (j = 0; j < i; j++) {
1210				k = i - j - 1;
1211				if ((sops[k].sem_flg & SEM_UNDO) == 0)
1212					continue;
1213				adjval = sops[k].sem_op;
1214				if (adjval == 0)
1215					continue;
1216				if (semundo_adjust(td, &suptr, semid, seq,
1217				    sops[k].sem_num, adjval) != 0)
1218					panic("semop - can't undo undos");
1219			}
1220
1221			for (j = 0; j < nsops; j++)
1222				semakptr->u.sem_base[sops[j].sem_num].semval -=
1223				    sops[j].sem_op;
1224
1225			DPRINTF(("error = %d from semundo_adjust\n", error));
1226			SEMUNDO_UNLOCK();
1227			goto done2;
1228		} /* loop through the sops */
1229		SEMUNDO_UNLOCK();
1230	} /* if (do_undos) */
1231
1232	/* We're definitely done - set the sempid's and time */
1233	for (i = 0; i < nsops; i++) {
1234		sopptr = &sops[i];
1235		semptr = &semakptr->u.sem_base[sopptr->sem_num];
1236		semptr->sempid = td->td_proc->p_pid;
1237	}
1238	semakptr->u.sem_otime = time_second;
1239
1240	/*
1241	 * Do a wakeup if any semaphore was up'd whilst something was
1242	 * sleeping on it.
1243	 */
1244	if (do_wakeup) {
1245		DPRINTF(("semop:  doing wakeup\n"));
1246		wakeup(semakptr);
1247		DPRINTF(("semop:  back from wakeup\n"));
1248	}
1249	DPRINTF(("semop:  done\n"));
1250	td->td_retval[0] = 0;
1251done2:
1252	mtx_unlock(sema_mtxp);
1253	if (sops != small_sops)
1254		free(sops, M_SEM);
1255	return (error);
1256}
1257
1258/*
1259 * Go through the undo structures for this process and apply the adjustments to
1260 * semaphores.
1261 */
1262static void
1263semexit_myhook(void *arg, struct proc *p)
1264{
1265	struct sem_undo *suptr;
1266	struct semid_kernel *semakptr;
1267	struct mtx *sema_mtxp;
1268	int semid, semnum, adjval, ix;
1269	unsigned short seq;
1270
1271	/*
1272	 * Go through the chain of undo vectors looking for one
1273	 * associated with this process.
1274	 */
1275	SEMUNDO_LOCK();
1276	LIST_FOREACH(suptr, &semu_list, un_next) {
1277		if (suptr->un_proc == p)
1278			break;
1279	}
1280	if (suptr == NULL) {
1281		SEMUNDO_UNLOCK();
1282		return;
1283	}
1284	LIST_REMOVE(suptr, un_next);
1285
1286	DPRINTF(("proc @%p has undo structure with %d entries\n", p,
1287	    suptr->un_cnt));
1288
1289	/*
1290	 * If there are any active undo elements then process them.
1291	 */
1292	if (suptr->un_cnt > 0) {
1293		SEMUNDO_UNLOCK();
1294		for (ix = 0; ix < suptr->un_cnt; ix++) {
1295			semid = suptr->un_ent[ix].un_id;
1296			semnum = suptr->un_ent[ix].un_num;
1297			adjval = suptr->un_ent[ix].un_adjval;
1298			seq = suptr->un_ent[ix].un_seq;
1299			semakptr = &sema[semid];
1300			sema_mtxp = &sema_mtx[semid];
1301
1302			mtx_lock(sema_mtxp);
1303			if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 ||
1304			    (semakptr->u.sem_perm.seq != seq)) {
1305				mtx_unlock(sema_mtxp);
1306				continue;
1307			}
1308			if (semnum >= semakptr->u.sem_nsems)
1309				panic("semexit - semnum out of range");
1310
1311			DPRINTF((
1312			    "semexit:  %p id=%d num=%d(adj=%d) ; sem=%d\n",
1313			    suptr->un_proc, suptr->un_ent[ix].un_id,
1314			    suptr->un_ent[ix].un_num,
1315			    suptr->un_ent[ix].un_adjval,
1316			    semakptr->u.sem_base[semnum].semval));
1317
1318			if (adjval < 0 && semakptr->u.sem_base[semnum].semval <
1319			    -adjval)
1320				semakptr->u.sem_base[semnum].semval = 0;
1321			else
1322				semakptr->u.sem_base[semnum].semval += adjval;
1323
1324			wakeup(semakptr);
1325			DPRINTF(("semexit:  back from wakeup\n"));
1326			mtx_unlock(sema_mtxp);
1327		}
1328		SEMUNDO_LOCK();
1329	}
1330
1331	/*
1332	 * Deallocate the undo vector.
1333	 */
1334	DPRINTF(("removing vector\n"));
1335	suptr->un_proc = NULL;
1336	suptr->un_cnt = 0;
1337	LIST_INSERT_HEAD(&semu_free_list, suptr, un_next);
1338	SEMUNDO_UNLOCK();
1339}
1340
1341static int
1342sysctl_sema(SYSCTL_HANDLER_ARGS)
1343{
1344
1345	return (SYSCTL_OUT(req, sema,
1346	    sizeof(struct semid_kernel) * seminfo.semmni));
1347}
1348