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