1139804Simp/*-
2103571Salfred * Copyright (c) 2002 Alfred Perlstein <alfred@FreeBSD.org>
3145855Srwatson * Copyright (c) 2003-2005 SPARTA, Inc.
4142498Srwatson * Copyright (c) 2005 Robert N. M. Watson
5103571Salfred * All rights reserved.
6103571Salfred *
7145855Srwatson * This software was developed for the FreeBSD Project in part by Network
8145855Srwatson * Associates Laboratories, the Security Research Division of Network
9145855Srwatson * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
10145855Srwatson * as part of the DARPA CHATS research program.
11145855Srwatson *
12103571Salfred * Redistribution and use in source and binary forms, with or without
13103571Salfred * modification, are permitted provided that the following conditions
14103571Salfred * are met:
15103571Salfred * 1. Redistributions of source code must retain the above copyright
16103571Salfred *    notice, this list of conditions and the following disclaimer.
17103571Salfred * 2. Redistributions in binary form must reproduce the above copyright
18103571Salfred *    notice, this list of conditions and the following disclaimer in the
19103571Salfred *    documentation and/or other materials provided with the distribution.
20103571Salfred *
21103571Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22103571Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23103571Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24103571Salfred * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25103571Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26103571Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27103571Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28103571Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29103571Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30103571Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31103571Salfred * SUCH DAMAGE.
32103571Salfred */
33103571Salfred
34116182Sobrien#include <sys/cdefs.h>
35116182Sobrien__FBSDID("$FreeBSD$");
36116182Sobrien
37205324Skib#include "opt_compat.h"
38103571Salfred#include "opt_posix.h"
39103571Salfred
40103571Salfred#include <sys/param.h>
41224778Srwatson#include <sys/capability.h>
42180059Sjhb#include <sys/condvar.h>
43180059Sjhb#include <sys/fcntl.h>
44180059Sjhb#include <sys/file.h>
45180059Sjhb#include <sys/filedesc.h>
46180059Sjhb#include <sys/fnv_hash.h>
47103571Salfred#include <sys/kernel.h>
48164184Strhodes#include <sys/ksem.h>
49180059Sjhb#include <sys/lock.h>
50180059Sjhb#include <sys/malloc.h>
51180059Sjhb#include <sys/module.h>
52180059Sjhb#include <sys/mutex.h>
53164033Srwatson#include <sys/priv.h>
54103571Salfred#include <sys/proc.h>
55164184Strhodes#include <sys/posix4.h>
56180059Sjhb#include <sys/_semaphore.h>
57180059Sjhb#include <sys/stat.h>
58103571Salfred#include <sys/syscall.h>
59180059Sjhb#include <sys/syscallsubr.h>
60180059Sjhb#include <sys/sysctl.h>
61103571Salfred#include <sys/sysent.h>
62180059Sjhb#include <sys/sysproto.h>
63180059Sjhb#include <sys/systm.h>
64180059Sjhb#include <sys/sx.h>
65180059Sjhb#include <sys/vnode.h>
66103571Salfred
67163606Srwatson#include <security/mac/mac_framework.h>
68163606Srwatson
69219030SnetchildFEATURE(p1003_1b_semaphores, "POSIX P1003.1B semaphores support");
70180059Sjhb/*
71180059Sjhb * TODO
72180059Sjhb *
73180059Sjhb * - Resource limits?
74180059Sjhb * - Replace global sem_lock with mtx_pool locks?
75180059Sjhb * - Add a MAC check_create() hook for creating new named semaphores.
76180059Sjhb */
77103571Salfred
78103571Salfred#ifndef SEM_MAX
79179054Srwatson#define	SEM_MAX	30
80103571Salfred#endif
81103571Salfred
82180059Sjhb#ifdef SEM_DEBUG
83180059Sjhb#define	DP(x)	printf x
84180059Sjhb#else
85180059Sjhb#define	DP(x)
86180059Sjhb#endif
87103571Salfred
88180059Sjhbstruct ksem_mapping {
89180059Sjhb	char		*km_path;
90180059Sjhb	Fnv32_t		km_fnv;
91180059Sjhb	struct ksem	*km_ksem;
92180059Sjhb	LIST_ENTRY(ksem_mapping) km_link;
93180059Sjhb};
94103571Salfred
95180059Sjhbstatic MALLOC_DEFINE(M_KSEM, "ksem", "semaphore file descriptor");
96180059Sjhbstatic LIST_HEAD(, ksem_mapping) *ksem_dictionary;
97180059Sjhbstatic struct sx ksem_dict_lock;
98180059Sjhbstatic struct mtx ksem_count_lock;
99180059Sjhbstatic struct mtx sem_lock;
100180059Sjhbstatic u_long ksem_hash;
101180059Sjhbstatic int ksem_dead;
102179054Srwatson
103180059Sjhb#define	KSEM_HASH(fnv)	(&ksem_dictionary[(fnv) & ksem_hash])
104103571Salfred
105103571Salfredstatic int nsems = 0;
106103571SalfredSYSCTL_DECL(_p1003_1b);
107180059SjhbSYSCTL_INT(_p1003_1b, OID_AUTO, nsems, CTLFLAG_RD, &nsems, 0,
108180059Sjhb    "Number of active kernel POSIX semaphores");
109103571Salfred
110180059Sjhbstatic int	kern_sem_wait(struct thread *td, semid_t id, int tryflag,
111180059Sjhb		    struct timespec *abstime);
112180059Sjhbstatic int	ksem_access(struct ksem *ks, struct ucred *ucred);
113180059Sjhbstatic struct ksem *ksem_alloc(struct ucred *ucred, mode_t mode,
114180059Sjhb		    unsigned int value);
115180059Sjhbstatic int	ksem_create(struct thread *td, const char *path,
116180059Sjhb		    semid_t *semidp, mode_t mode, unsigned int value,
117205324Skib		    int flags, int compat32);
118180059Sjhbstatic void	ksem_drop(struct ksem *ks);
119255219Spjdstatic int	ksem_get(struct thread *td, semid_t id, cap_rights_t *rightsp,
120224778Srwatson    struct file **fpp);
121180059Sjhbstatic struct ksem *ksem_hold(struct ksem *ks);
122180059Sjhbstatic void	ksem_insert(char *path, Fnv32_t fnv, struct ksem *ks);
123180059Sjhbstatic struct ksem *ksem_lookup(char *path, Fnv32_t fnv);
124180059Sjhbstatic void	ksem_module_destroy(void);
125180059Sjhbstatic int	ksem_module_init(void);
126180059Sjhbstatic int	ksem_remove(char *path, Fnv32_t fnv, struct ucred *ucred);
127180059Sjhbstatic int	sem_modload(struct module *module, int cmd, void *arg);
128112564Sjhb
129180059Sjhbstatic fo_rdwr_t	ksem_read;
130180059Sjhbstatic fo_rdwr_t	ksem_write;
131180059Sjhbstatic fo_truncate_t	ksem_truncate;
132180059Sjhbstatic fo_ioctl_t	ksem_ioctl;
133180059Sjhbstatic fo_poll_t	ksem_poll;
134180059Sjhbstatic fo_kqfilter_t	ksem_kqfilter;
135180059Sjhbstatic fo_stat_t	ksem_stat;
136180059Sjhbstatic fo_close_t	ksem_closef;
137224914Skibstatic fo_chmod_t	ksem_chmod;
138224914Skibstatic fo_chown_t	ksem_chown;
139104596Salfred
140180059Sjhb/* File descriptor operations. */
141180059Sjhbstatic struct fileops ksem_ops = {
142180059Sjhb	.fo_read = ksem_read,
143180059Sjhb	.fo_write = ksem_write,
144180059Sjhb	.fo_truncate = ksem_truncate,
145180059Sjhb	.fo_ioctl = ksem_ioctl,
146180059Sjhb	.fo_poll = ksem_poll,
147180059Sjhb	.fo_kqfilter = ksem_kqfilter,
148180059Sjhb	.fo_stat = ksem_stat,
149180059Sjhb	.fo_close = ksem_closef,
150224914Skib	.fo_chmod = ksem_chmod,
151224914Skib	.fo_chown = ksem_chown,
152254356Sglebius	.fo_sendfile = invfo_sendfile,
153180059Sjhb	.fo_flags = DFLAG_PASSABLE
154180059Sjhb};
155180059Sjhb
156180059SjhbFEATURE(posix_sem, "POSIX semaphores");
157180059Sjhb
158180059Sjhbstatic int
159180059Sjhbksem_read(struct file *fp, struct uio *uio, struct ucred *active_cred,
160180059Sjhb    int flags, struct thread *td)
161103571Salfred{
162103571Salfred
163180059Sjhb	return (EOPNOTSUPP);
164103571Salfred}
165103571Salfred
166180059Sjhbstatic int
167180059Sjhbksem_write(struct file *fp, struct uio *uio, struct ucred *active_cred,
168180059Sjhb    int flags, struct thread *td)
169103571Salfred{
170103571Salfred
171180059Sjhb	return (EOPNOTSUPP);
172103571Salfred}
173103571Salfred
174180059Sjhbstatic int
175180059Sjhbksem_truncate(struct file *fp, off_t length, struct ucred *active_cred,
176180059Sjhb    struct thread *td)
177103571Salfred{
178103571Salfred
179180059Sjhb	return (EINVAL);
180103571Salfred}
181103571Salfred
182180059Sjhbstatic int
183180059Sjhbksem_ioctl(struct file *fp, u_long com, void *data,
184180059Sjhb    struct ucred *active_cred, struct thread *td)
185103571Salfred{
186103571Salfred
187180059Sjhb	return (EOPNOTSUPP);
188103571Salfred}
189103571Salfred
190105227Sphkstatic int
191180059Sjhbksem_poll(struct file *fp, int events, struct ucred *active_cred,
192180059Sjhb    struct thread *td)
193103571Salfred{
194180059Sjhb
195180059Sjhb	return (EOPNOTSUPP);
196180059Sjhb}
197180059Sjhb
198180059Sjhbstatic int
199180059Sjhbksem_kqfilter(struct file *fp, struct knote *kn)
200180059Sjhb{
201180059Sjhb
202180059Sjhb	return (EOPNOTSUPP);
203180059Sjhb}
204180059Sjhb
205180059Sjhbstatic int
206180059Sjhbksem_stat(struct file *fp, struct stat *sb, struct ucred *active_cred,
207180059Sjhb    struct thread *td)
208180059Sjhb{
209180059Sjhb	struct ksem *ks;
210180059Sjhb#ifdef MAC
211103571Salfred	int error;
212180059Sjhb#endif
213103571Salfred
214180059Sjhb	ks = fp->f_data;
215179054Srwatson
216145855Srwatson#ifdef MAC
217180059Sjhb	error = mac_posixsem_check_stat(active_cred, fp->f_cred, ks);
218180059Sjhb	if (error)
219180059Sjhb		return (error);
220145855Srwatson#endif
221180059Sjhb
222180059Sjhb	/*
223180059Sjhb	 * Attempt to return sanish values for fstat() on a semaphore
224180059Sjhb	 * file descriptor.
225180059Sjhb	 */
226180059Sjhb	bzero(sb, sizeof(*sb));
227180059Sjhb
228224914Skib	mtx_lock(&sem_lock);
229205792Sed	sb->st_atim = ks->ks_atime;
230205792Sed	sb->st_ctim = ks->ks_ctime;
231205792Sed	sb->st_mtim = ks->ks_mtime;
232224914Skib	sb->st_birthtim = ks->ks_birthtime;
233180059Sjhb	sb->st_uid = ks->ks_uid;
234180059Sjhb	sb->st_gid = ks->ks_gid;
235224914Skib	sb->st_mode = S_IFREG | ks->ks_mode;		/* XXX */
236224914Skib	mtx_unlock(&sem_lock);
237180059Sjhb
238180059Sjhb	return (0);
239103571Salfred}
240103571Salfred
241180059Sjhbstatic int
242224914Skibksem_chmod(struct file *fp, mode_t mode, struct ucred *active_cred,
243224914Skib    struct thread *td)
244224914Skib{
245224914Skib	struct ksem *ks;
246224914Skib	int error;
247224914Skib
248224914Skib	error = 0;
249224914Skib	ks = fp->f_data;
250224914Skib	mtx_lock(&sem_lock);
251224914Skib#ifdef MAC
252224914Skib	error = mac_posixsem_check_setmode(active_cred, ks, mode);
253224914Skib	if (error != 0)
254224914Skib		goto out;
255224914Skib#endif
256224914Skib	error = vaccess(VREG, ks->ks_mode, ks->ks_uid, ks->ks_gid, VADMIN,
257224914Skib	    active_cred, NULL);
258224914Skib	if (error != 0)
259224914Skib		goto out;
260224914Skib	ks->ks_mode = mode & ACCESSPERMS;
261224914Skibout:
262224914Skib	mtx_unlock(&sem_lock);
263224914Skib	return (error);
264224914Skib}
265224914Skib
266224914Skibstatic int
267224914Skibksem_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred,
268224914Skib    struct thread *td)
269224914Skib{
270224914Skib	struct ksem *ks;
271224914Skib	int error;
272224914Skib
273224935Skib	error = 0;
274224914Skib	ks = fp->f_data;
275224914Skib	mtx_lock(&sem_lock);
276224914Skib#ifdef MAC
277224914Skib	error = mac_posixsem_check_setowner(active_cred, ks, uid, gid);
278224914Skib	if (error != 0)
279224914Skib		goto out;
280224914Skib#endif
281224914Skib	if (uid == (uid_t)-1)
282224914Skib		uid = ks->ks_uid;
283224914Skib	if (gid == (gid_t)-1)
284224914Skib                 gid = ks->ks_gid;
285224914Skib	if (((uid != ks->ks_uid && uid != active_cred->cr_uid) ||
286224914Skib	    (gid != ks->ks_gid && !groupmember(gid, active_cred))) &&
287224914Skib	    (error = priv_check_cred(active_cred, PRIV_VFS_CHOWN, 0)))
288224914Skib		goto out;
289224914Skib	ks->ks_uid = uid;
290224914Skib	ks->ks_gid = gid;
291224914Skibout:
292224914Skib	mtx_unlock(&sem_lock);
293224914Skib	return (error);
294224914Skib}
295224914Skib
296224914Skibstatic int
297180059Sjhbksem_closef(struct file *fp, struct thread *td)
298103571Salfred{
299180059Sjhb	struct ksem *ks;
300103571Salfred
301180059Sjhb	ks = fp->f_data;
302180059Sjhb	fp->f_data = NULL;
303180059Sjhb	ksem_drop(ks);
304180059Sjhb
305180059Sjhb	return (0);
306103571Salfred}
307103571Salfred
308180059Sjhb/*
309180059Sjhb * ksem object management including creation and reference counting
310180059Sjhb * routines.
311180059Sjhb */
312180059Sjhbstatic struct ksem *
313180059Sjhbksem_alloc(struct ucred *ucred, mode_t mode, unsigned int value)
314103571Salfred{
315103571Salfred	struct ksem *ks;
316103571Salfred
317180059Sjhb	mtx_lock(&ksem_count_lock);
318180059Sjhb	if (nsems == p31b_getcfg(CTL_P1003_1B_SEM_NSEMS_MAX) || ksem_dead) {
319180059Sjhb		mtx_unlock(&ksem_count_lock);
320180059Sjhb		return (NULL);
321103571Salfred	}
322180059Sjhb	nsems++;
323180059Sjhb	mtx_unlock(&ksem_count_lock);
324180059Sjhb	ks = malloc(sizeof(*ks), M_KSEM, M_WAITOK | M_ZERO);
325180059Sjhb	ks->ks_uid = ucred->cr_uid;
326180059Sjhb	ks->ks_gid = ucred->cr_gid;
327180059Sjhb	ks->ks_mode = mode;
328180059Sjhb	ks->ks_value = value;
329180059Sjhb	cv_init(&ks->ks_cv, "ksem");
330180059Sjhb	vfs_timestamp(&ks->ks_birthtime);
331180059Sjhb	ks->ks_atime = ks->ks_mtime = ks->ks_ctime = ks->ks_birthtime;
332180059Sjhb	refcount_init(&ks->ks_ref, 1);
333180059Sjhb#ifdef MAC
334180059Sjhb	mac_posixsem_init(ks);
335180059Sjhb	mac_posixsem_create(ucred, ks);
336180059Sjhb#endif
337180059Sjhb
338180059Sjhb	return (ks);
339103571Salfred}
340103571Salfred
341180059Sjhbstatic struct ksem *
342180059Sjhbksem_hold(struct ksem *ks)
343180059Sjhb{
344180059Sjhb
345180059Sjhb	refcount_acquire(&ks->ks_ref);
346180059Sjhb	return (ks);
347180059Sjhb}
348180059Sjhb
349180059Sjhbstatic void
350180059Sjhbksem_drop(struct ksem *ks)
351180059Sjhb{
352180059Sjhb
353180059Sjhb	if (refcount_release(&ks->ks_ref)) {
354180059Sjhb#ifdef MAC
355180059Sjhb		mac_posixsem_destroy(ks);
356103571Salfred#endif
357180059Sjhb		cv_destroy(&ks->ks_cv);
358180059Sjhb		free(ks, M_KSEM);
359180059Sjhb		mtx_lock(&ksem_count_lock);
360180059Sjhb		nsems--;
361180059Sjhb		mtx_unlock(&ksem_count_lock);
362180059Sjhb	}
363180059Sjhb}
364180059Sjhb
365180059Sjhb/*
366180059Sjhb * Determine if the credentials have sufficient permissions for read
367180059Sjhb * and write access.
368180059Sjhb */
369180059Sjhbstatic int
370180059Sjhbksem_access(struct ksem *ks, struct ucred *ucred)
371103571Salfred{
372103571Salfred	int error;
373103571Salfred
374180059Sjhb	error = vaccess(VREG, ks->ks_mode, ks->ks_uid, ks->ks_gid,
375180059Sjhb	    VREAD | VWRITE, ucred, NULL);
376103571Salfred	if (error)
377180059Sjhb		error = priv_check_cred(ucred, PRIV_SEM_WRITE, 0);
378103571Salfred	return (error);
379103571Salfred}
380103571Salfred
381180059Sjhb/*
382180059Sjhb * Dictionary management.  We maintain an in-kernel dictionary to map
383180059Sjhb * paths to semaphore objects.  We use the FNV hash on the path to
384180059Sjhb * store the mappings in a hash table.
385180059Sjhb */
386180059Sjhbstatic struct ksem *
387180059Sjhbksem_lookup(char *path, Fnv32_t fnv)
388103571Salfred{
389180059Sjhb	struct ksem_mapping *map;
390103571Salfred
391180059Sjhb	LIST_FOREACH(map, KSEM_HASH(fnv), km_link) {
392180059Sjhb		if (map->km_fnv != fnv)
393180059Sjhb			continue;
394180059Sjhb		if (strcmp(map->km_path, path) == 0)
395180059Sjhb			return (map->km_ksem);
396103571Salfred	}
397179054Srwatson
398180059Sjhb	return (NULL);
399180059Sjhb}
400179054Srwatson
401180059Sjhbstatic void
402180059Sjhbksem_insert(char *path, Fnv32_t fnv, struct ksem *ks)
403180059Sjhb{
404180059Sjhb	struct ksem_mapping *map;
405179054Srwatson
406180059Sjhb	map = malloc(sizeof(struct ksem_mapping), M_KSEM, M_WAITOK);
407180059Sjhb	map->km_path = path;
408180059Sjhb	map->km_fnv = fnv;
409180059Sjhb	map->km_ksem = ksem_hold(ks);
410250223Sjhb	ks->ks_path = path;
411180059Sjhb	LIST_INSERT_HEAD(KSEM_HASH(fnv), map, km_link);
412180059Sjhb}
413180059Sjhb
414180059Sjhbstatic int
415180059Sjhbksem_remove(char *path, Fnv32_t fnv, struct ucred *ucred)
416180059Sjhb{
417180059Sjhb	struct ksem_mapping *map;
418180059Sjhb	int error;
419180059Sjhb
420180059Sjhb	LIST_FOREACH(map, KSEM_HASH(fnv), km_link) {
421180059Sjhb		if (map->km_fnv != fnv)
422180059Sjhb			continue;
423180059Sjhb		if (strcmp(map->km_path, path) == 0) {
424145855Srwatson#ifdef MAC
425180059Sjhb			error = mac_posixsem_check_unlink(ucred, map->km_ksem);
426180059Sjhb			if (error)
427180059Sjhb				return (error);
428145855Srwatson#endif
429180059Sjhb			error = ksem_access(map->km_ksem, ucred);
430180059Sjhb			if (error)
431103571Salfred				return (error);
432250223Sjhb			map->km_ksem->ks_path = NULL;
433180059Sjhb			LIST_REMOVE(map, km_link);
434180059Sjhb			ksem_drop(map->km_ksem);
435180059Sjhb			free(map->km_path, M_KSEM);
436180059Sjhb			free(map, M_KSEM);
437180059Sjhb			return (0);
438103571Salfred		}
439103571Salfred	}
440180059Sjhb
441180059Sjhb	return (ENOENT);
442103571Salfred}
443103571Salfred
444250223Sjhbstatic void
445250223Sjhbksem_info_impl(struct ksem *ks, char *path, size_t size, uint32_t *value)
446250223Sjhb{
447250223Sjhb
448250223Sjhb	if (ks->ks_path == NULL)
449250223Sjhb		return;
450250223Sjhb	sx_slock(&ksem_dict_lock);
451250223Sjhb	if (ks->ks_path != NULL)
452250223Sjhb		strlcpy(path, ks->ks_path, size);
453250223Sjhb	if (value != NULL)
454250223Sjhb		*value = ks->ks_value;
455250223Sjhb	sx_sunlock(&ksem_dict_lock);
456250223Sjhb}
457250223Sjhb
458205324Skibstatic int
459205324Skibksem_create_copyout_semid(struct thread *td, semid_t *semidp, int fd,
460205324Skib    int compat32)
461205324Skib{
462205324Skib	semid_t semid;
463205324Skib#ifdef COMPAT_FREEBSD32
464205324Skib	int32_t semid32;
465205324Skib#endif
466205324Skib	void *ptr;
467205324Skib	size_t ptrs;
468205324Skib
469205324Skib#ifdef COMPAT_FREEBSD32
470205324Skib	if (compat32) {
471205324Skib		semid32 = fd;
472205324Skib		ptr = &semid32;
473205324Skib		ptrs = sizeof(semid32);
474205324Skib	} else {
475205324Skib#endif
476205324Skib		semid = fd;
477205324Skib		ptr = &semid;
478205324Skib		ptrs = sizeof(semid);
479205324Skib		compat32 = 0; /* silence gcc */
480205324Skib#ifdef COMPAT_FREEBSD32
481205324Skib	}
482205324Skib#endif
483205324Skib
484205324Skib	return (copyout(ptr, semidp, ptrs));
485205324Skib}
486205324Skib
487180059Sjhb/* Other helper routines. */
488105227Sphkstatic int
489180059Sjhbksem_create(struct thread *td, const char *name, semid_t *semidp, mode_t mode,
490205324Skib    unsigned int value, int flags, int compat32)
491103571Salfred{
492180059Sjhb	struct filedesc *fdp;
493180059Sjhb	struct ksem *ks;
494180059Sjhb	struct file *fp;
495180059Sjhb	char *path;
496180059Sjhb	Fnv32_t fnv;
497180059Sjhb	int error, fd;
498103571Salfred
499180059Sjhb	if (value > SEM_VALUE_MAX)
500180059Sjhb		return (EINVAL);
501180059Sjhb
502180059Sjhb	fdp = td->td_proc->p_fd;
503180059Sjhb	mode = (mode & ~fdp->fd_cmask) & ACCESSPERMS;
504249233Sjilles	error = falloc(td, &fp, &fd, O_CLOEXEC);
505180059Sjhb	if (error) {
506180059Sjhb		if (name == NULL)
507180059Sjhb			error = ENOSPC;
508180059Sjhb		return (error);
509180059Sjhb	}
510180059Sjhb
511164033Srwatson	/*
512180059Sjhb	 * Go ahead and copyout the file descriptor now.  This is a bit
513180059Sjhb	 * premature, but it is a lot easier to handle errors as opposed
514180059Sjhb	 * to later when we've possibly created a new semaphore, etc.
515164033Srwatson	 */
516205324Skib	error = ksem_create_copyout_semid(td, semidp, fd, compat32);
517180059Sjhb	if (error) {
518180059Sjhb		fdclose(fdp, fp, fd, td);
519180059Sjhb		fdrop(fp, td);
520180059Sjhb		return (error);
521180059Sjhb	}
522103571Salfred
523180059Sjhb	if (name == NULL) {
524180059Sjhb		/* Create an anonymous semaphore. */
525180059Sjhb		ks = ksem_alloc(td->td_ucred, mode, value);
526180059Sjhb		if (ks == NULL)
527180059Sjhb			error = ENOSPC;
528180059Sjhb		else
529180059Sjhb			ks->ks_flags |= KS_ANONYMOUS;
530180059Sjhb	} else {
531180059Sjhb		path = malloc(MAXPATHLEN, M_KSEM, M_WAITOK);
532180059Sjhb		error = copyinstr(name, path, MAXPATHLEN, NULL);
533103571Salfred
534180059Sjhb		/* Require paths to start with a '/' character. */
535180059Sjhb		if (error == 0 && path[0] != '/')
536180059Sjhb			error = EINVAL;
537180059Sjhb		if (error) {
538180059Sjhb			fdclose(fdp, fp, fd, td);
539180059Sjhb			fdrop(fp, td);
540180059Sjhb			free(path, M_KSEM);
541180059Sjhb			return (error);
542180059Sjhb		}
543180059Sjhb
544180059Sjhb		fnv = fnv_32_str(path, FNV1_32_INIT);
545180059Sjhb		sx_xlock(&ksem_dict_lock);
546180059Sjhb		ks = ksem_lookup(path, fnv);
547180059Sjhb		if (ks == NULL) {
548180059Sjhb			/* Object does not exist, create it if requested. */
549180059Sjhb			if (flags & O_CREAT) {
550180059Sjhb				ks = ksem_alloc(td->td_ucred, mode, value);
551180059Sjhb				if (ks == NULL)
552180059Sjhb					error = ENFILE;
553180059Sjhb				else {
554180059Sjhb					ksem_insert(path, fnv, ks);
555180059Sjhb					path = NULL;
556180059Sjhb				}
557180059Sjhb			} else
558180059Sjhb				error = ENOENT;
559180059Sjhb		} else {
560180059Sjhb			/*
561180059Sjhb			 * Object already exists, obtain a new
562180059Sjhb			 * reference if requested and permitted.
563180059Sjhb			 */
564180059Sjhb			if ((flags & (O_CREAT | O_EXCL)) ==
565180059Sjhb			    (O_CREAT | O_EXCL))
566180059Sjhb				error = EEXIST;
567180059Sjhb			else {
568175148Srwatson#ifdef MAC
569180059Sjhb				error = mac_posixsem_check_open(td->td_ucred,
570180059Sjhb				    ks);
571180059Sjhb				if (error == 0)
572175148Srwatson#endif
573180059Sjhb				error = ksem_access(ks, td->td_ucred);
574180059Sjhb			}
575180059Sjhb			if (error == 0)
576180059Sjhb				ksem_hold(ks);
577180059Sjhb#ifdef INVARIANTS
578180059Sjhb			else
579180059Sjhb				ks = NULL;
580180059Sjhb#endif
581180059Sjhb		}
582180059Sjhb		sx_xunlock(&ksem_dict_lock);
583180059Sjhb		if (path)
584180059Sjhb			free(path, M_KSEM);
585180059Sjhb	}
586103571Salfred
587180059Sjhb	if (error) {
588180059Sjhb		KASSERT(ks == NULL, ("ksem_create error with a ksem"));
589180059Sjhb		fdclose(fdp, fp, fd, td);
590180059Sjhb		fdrop(fp, td);
591180059Sjhb		return (error);
592180059Sjhb	}
593180059Sjhb	KASSERT(ks != NULL, ("ksem_create w/o a ksem"));
594103571Salfred
595180059Sjhb	finit(fp, FREAD | FWRITE, DTYPE_SEM, ks, &ksem_ops);
596180059Sjhb
597180059Sjhb	fdrop(fp, td);
598180059Sjhb
599180059Sjhb	return (0);
600103571Salfred}
601103571Salfred
602105227Sphkstatic int
603255219Spjdksem_get(struct thread *td, semid_t id, cap_rights_t *rightsp,
604255219Spjd    struct file **fpp)
605103571Salfred{
606180059Sjhb	struct ksem *ks;
607180059Sjhb	struct file *fp;
608180059Sjhb	int error;
609180059Sjhb
610255219Spjd	error = fget(td, id, rightsp, &fp);
611180059Sjhb	if (error)
612180059Sjhb		return (EINVAL);
613180059Sjhb	if (fp->f_type != DTYPE_SEM) {
614180059Sjhb		fdrop(fp, td);
615180059Sjhb		return (EINVAL);
616180059Sjhb	}
617180059Sjhb	ks = fp->f_data;
618180059Sjhb	if (ks->ks_flags & KS_DEAD) {
619180059Sjhb		fdrop(fp, td);
620180059Sjhb		return (EINVAL);
621180059Sjhb	}
622180059Sjhb	*fpp = fp;
623180059Sjhb	return (0);
624103571Salfred}
625103571Salfred
626180059Sjhb/* System calls. */
627180059Sjhb#ifndef _SYS_SYSPROTO_H_
628180059Sjhbstruct ksem_init_args {
629180059Sjhb	unsigned int	value;
630180059Sjhb	semid_t		*idp;
631180059Sjhb};
632180059Sjhb#endif
633180059Sjhbint
634225617Skmacysys_ksem_init(struct thread *td, struct ksem_init_args *uap)
635103571Salfred{
636103571Salfred
637180059Sjhb	return (ksem_create(td, NULL, uap->idp, S_IRWXU | S_IRWXG, uap->value,
638205324Skib	    0, 0));
639103571Salfred}
640103571Salfred
641180059Sjhb#ifndef _SYS_SYSPROTO_H_
642180059Sjhbstruct ksem_open_args {
643180059Sjhb	char		*name;
644180059Sjhb	int		oflag;
645180059Sjhb	mode_t		mode;
646180059Sjhb	unsigned int	value;
647180059Sjhb	semid_t		*idp;
648180059Sjhb};
649180059Sjhb#endif
650180059Sjhbint
651225617Skmacysys_ksem_open(struct thread *td, struct ksem_open_args *uap)
652103571Salfred{
653103571Salfred
654189735Sbms	DP((">>> ksem_open start, pid=%d\n", (int)td->td_proc->p_pid));
655189735Sbms
656180059Sjhb	if ((uap->oflag & ~(O_CREAT | O_EXCL)) != 0)
657180059Sjhb		return (EINVAL);
658180059Sjhb	return (ksem_create(td, uap->name, uap->idp, uap->mode, uap->value,
659205324Skib	    uap->oflag, 0));
660103571Salfred}
661103571Salfred
662103571Salfred#ifndef _SYS_SYSPROTO_H_
663103571Salfredstruct ksem_unlink_args {
664180059Sjhb	char		*name;
665103571Salfred};
666103571Salfred#endif
667103571Salfredint
668225617Skmacysys_ksem_unlink(struct thread *td, struct ksem_unlink_args *uap)
669103571Salfred{
670180059Sjhb	char *path;
671180059Sjhb	Fnv32_t fnv;
672103571Salfred	int error;
673103571Salfred
674180059Sjhb	path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
675180059Sjhb	error = copyinstr(uap->name, path, MAXPATHLEN, NULL);
676180059Sjhb	if (error) {
677180059Sjhb		free(path, M_TEMP);
678180059Sjhb		return (error);
679180059Sjhb	}
680103571Salfred
681180059Sjhb	fnv = fnv_32_str(path, FNV1_32_INIT);
682180059Sjhb	sx_xlock(&ksem_dict_lock);
683180059Sjhb	error = ksem_remove(path, fnv, td->td_ucred);
684180059Sjhb	sx_xunlock(&ksem_dict_lock);
685180059Sjhb	free(path, M_TEMP);
686103571Salfred
687103571Salfred	return (error);
688103571Salfred}
689103571Salfred
690103571Salfred#ifndef _SYS_SYSPROTO_H_
691103571Salfredstruct ksem_close_args {
692180059Sjhb	semid_t		id;
693103571Salfred};
694103571Salfred#endif
695103571Salfredint
696225617Skmacysys_ksem_close(struct thread *td, struct ksem_close_args *uap)
697103571Salfred{
698103571Salfred	struct ksem *ks;
699180059Sjhb	struct file *fp;
700103571Salfred	int error;
701103571Salfred
702224778Srwatson	/* No capability rights required to close a semaphore. */
703224778Srwatson	error = ksem_get(td, uap->id, 0, &fp);
704180059Sjhb	if (error)
705180059Sjhb		return (error);
706180059Sjhb	ks = fp->f_data;
707180059Sjhb	if (ks->ks_flags & KS_ANONYMOUS) {
708180059Sjhb		fdrop(fp, td);
709180059Sjhb		return (EINVAL);
710180059Sjhb	}
711180059Sjhb	error = kern_close(td, uap->id);
712180059Sjhb	fdrop(fp, td);
713109084Salfred	return (error);
714103571Salfred}
715103571Salfred
716103571Salfred#ifndef _SYS_SYSPROTO_H_
717103571Salfredstruct ksem_post_args {
718180059Sjhb	semid_t	id;
719103571Salfred};
720103571Salfred#endif
721103571Salfredint
722225617Skmacysys_ksem_post(struct thread *td, struct ksem_post_args *uap)
723103571Salfred{
724255219Spjd	cap_rights_t rights;
725180059Sjhb	struct file *fp;
726103571Salfred	struct ksem *ks;
727103571Salfred	int error;
728103571Salfred
729255219Spjd	error = ksem_get(td, uap->id,
730255219Spjd	    cap_rights_init(&rights, CAP_SEM_POST), &fp);
731180059Sjhb	if (error)
732180059Sjhb		return (error);
733180059Sjhb	ks = fp->f_data;
734180059Sjhb
735103571Salfred	mtx_lock(&sem_lock);
736145855Srwatson#ifdef MAC
737180059Sjhb	error = mac_posixsem_check_post(td->td_ucred, fp->f_cred, ks);
738145855Srwatson	if (error)
739145855Srwatson		goto err;
740145855Srwatson#endif
741103571Salfred	if (ks->ks_value == SEM_VALUE_MAX) {
742103571Salfred		error = EOVERFLOW;
743103571Salfred		goto err;
744103571Salfred	}
745103571Salfred	++ks->ks_value;
746103571Salfred	if (ks->ks_waiters > 0)
747103571Salfred		cv_signal(&ks->ks_cv);
748103571Salfred	error = 0;
749180059Sjhb	vfs_timestamp(&ks->ks_ctime);
750103571Salfrederr:
751103571Salfred	mtx_unlock(&sem_lock);
752180059Sjhb	fdrop(fp, td);
753103571Salfred	return (error);
754103571Salfred}
755103571Salfred
756103571Salfred#ifndef _SYS_SYSPROTO_H_
757103571Salfredstruct ksem_wait_args {
758180059Sjhb	semid_t		id;
759103571Salfred};
760103571Salfred#endif
761103571Salfredint
762225617Skmacysys_ksem_wait(struct thread *td, struct ksem_wait_args *uap)
763103571Salfred{
764103571Salfred
765125368Sdeischen	return (kern_sem_wait(td, uap->id, 0, NULL));
766103571Salfred}
767103571Salfred
768103571Salfred#ifndef _SYS_SYSPROTO_H_
769125368Sdeischenstruct ksem_timedwait_args {
770180059Sjhb	semid_t		id;
771151445Sstefanf	const struct timespec *abstime;
772125368Sdeischen};
773125368Sdeischen#endif
774125368Sdeischenint
775225617Skmacysys_ksem_timedwait(struct thread *td, struct ksem_timedwait_args *uap)
776125368Sdeischen{
777125368Sdeischen	struct timespec abstime;
778125368Sdeischen	struct timespec *ts;
779125368Sdeischen	int error;
780125368Sdeischen
781179054Srwatson	/*
782179054Srwatson	 * We allow a null timespec (wait forever).
783179054Srwatson	 */
784125368Sdeischen	if (uap->abstime == NULL)
785125368Sdeischen		ts = NULL;
786125368Sdeischen	else {
787125368Sdeischen		error = copyin(uap->abstime, &abstime, sizeof(abstime));
788125368Sdeischen		if (error != 0)
789125368Sdeischen			return (error);
790125368Sdeischen		if (abstime.tv_nsec >= 1000000000 || abstime.tv_nsec < 0)
791125368Sdeischen			return (EINVAL);
792125368Sdeischen		ts = &abstime;
793125368Sdeischen	}
794125368Sdeischen	return (kern_sem_wait(td, uap->id, 0, ts));
795125368Sdeischen}
796125368Sdeischen
797125368Sdeischen#ifndef _SYS_SYSPROTO_H_
798103571Salfredstruct ksem_trywait_args {
799180059Sjhb	semid_t		id;
800103571Salfred};
801103571Salfred#endif
802103571Salfredint
803225617Skmacysys_ksem_trywait(struct thread *td, struct ksem_trywait_args *uap)
804103571Salfred{
805103571Salfred
806125368Sdeischen	return (kern_sem_wait(td, uap->id, 1, NULL));
807103571Salfred}
808103571Salfred
809105227Sphkstatic int
810154659Srwatsonkern_sem_wait(struct thread *td, semid_t id, int tryflag,
811154659Srwatson    struct timespec *abstime)
812103571Salfred{
813125368Sdeischen	struct timespec ts1, ts2;
814125368Sdeischen	struct timeval tv;
815255219Spjd	cap_rights_t rights;
816180059Sjhb	struct file *fp;
817103571Salfred	struct ksem *ks;
818103571Salfred	int error;
819103571Salfred
820189735Sbms	DP((">>> kern_sem_wait entered! pid=%d\n", (int)td->td_proc->p_pid));
821255219Spjd	error = ksem_get(td, id, cap_rights_init(&rights, CAP_SEM_WAIT), &fp);
822180059Sjhb	if (error)
823180059Sjhb		return (error);
824180059Sjhb	ks = fp->f_data;
825103571Salfred	mtx_lock(&sem_lock);
826189735Sbms	DP((">>> kern_sem_wait critical section entered! pid=%d\n",
827189735Sbms	    (int)td->td_proc->p_pid));
828145855Srwatson#ifdef MAC
829180059Sjhb	error = mac_posixsem_check_wait(td->td_ucred, fp->f_cred, ks);
830145855Srwatson	if (error) {
831145855Srwatson		DP(("kern_sem_wait mac failed\n"));
832145855Srwatson		goto err;
833145855Srwatson	}
834145855Srwatson#endif
835104596Salfred	DP(("kern_sem_wait value = %d, tryflag %d\n", ks->ks_value, tryflag));
836180059Sjhb	vfs_timestamp(&ks->ks_atime);
837189736Sbms	while (ks->ks_value == 0) {
838103571Salfred		ks->ks_waiters++;
839125368Sdeischen		if (tryflag != 0)
840125368Sdeischen			error = EAGAIN;
841125368Sdeischen		else if (abstime == NULL)
842125368Sdeischen			error = cv_wait_sig(&ks->ks_cv, &sem_lock);
843125368Sdeischen		else {
844125368Sdeischen			for (;;) {
845125368Sdeischen				ts1 = *abstime;
846125368Sdeischen				getnanotime(&ts2);
847125368Sdeischen				timespecsub(&ts1, &ts2);
848125368Sdeischen				TIMESPEC_TO_TIMEVAL(&tv, &ts1);
849125368Sdeischen				if (tv.tv_sec < 0) {
850125368Sdeischen					error = ETIMEDOUT;
851125368Sdeischen					break;
852125368Sdeischen				}
853125368Sdeischen				error = cv_timedwait_sig(&ks->ks_cv,
854125368Sdeischen				    &sem_lock, tvtohz(&tv));
855125368Sdeischen				if (error != EWOULDBLOCK)
856125368Sdeischen					break;
857125368Sdeischen			}
858125368Sdeischen		}
859103571Salfred		ks->ks_waiters--;
860103571Salfred		if (error)
861103571Salfred			goto err;
862103571Salfred	}
863103571Salfred	ks->ks_value--;
864189735Sbms	DP(("kern_sem_wait value post-decrement = %d\n", ks->ks_value));
865103571Salfred	error = 0;
866103571Salfrederr:
867103571Salfred	mtx_unlock(&sem_lock);
868180059Sjhb	fdrop(fp, td);
869189735Sbms	DP(("<<< kern_sem_wait leaving, pid=%d, error = %d\n",
870189735Sbms	    (int)td->td_proc->p_pid, error));
871103571Salfred	return (error);
872103571Salfred}
873103571Salfred
874103571Salfred#ifndef _SYS_SYSPROTO_H_
875103571Salfredstruct ksem_getvalue_args {
876180059Sjhb	semid_t		id;
877180059Sjhb	int		*val;
878103571Salfred};
879103571Salfred#endif
880103571Salfredint
881225617Skmacysys_ksem_getvalue(struct thread *td, struct ksem_getvalue_args *uap)
882103571Salfred{
883255219Spjd	cap_rights_t rights;
884180059Sjhb	struct file *fp;
885103571Salfred	struct ksem *ks;
886103571Salfred	int error, val;
887103571Salfred
888255219Spjd	error = ksem_get(td, uap->id,
889255219Spjd	    cap_rights_init(&rights, CAP_SEM_GETVALUE), &fp);
890180059Sjhb	if (error)
891180059Sjhb		return (error);
892180059Sjhb	ks = fp->f_data;
893180059Sjhb
894103571Salfred	mtx_lock(&sem_lock);
895145855Srwatson#ifdef MAC
896180059Sjhb	error = mac_posixsem_check_getvalue(td->td_ucred, fp->f_cred, ks);
897145855Srwatson	if (error) {
898145855Srwatson		mtx_unlock(&sem_lock);
899180059Sjhb		fdrop(fp, td);
900145855Srwatson		return (error);
901145855Srwatson	}
902145855Srwatson#endif
903103571Salfred	val = ks->ks_value;
904180059Sjhb	vfs_timestamp(&ks->ks_atime);
905103571Salfred	mtx_unlock(&sem_lock);
906180059Sjhb	fdrop(fp, td);
907103571Salfred	error = copyout(&val, uap->val, sizeof(val));
908103571Salfred	return (error);
909103571Salfred}
910103571Salfred
911103571Salfred#ifndef _SYS_SYSPROTO_H_
912103571Salfredstruct ksem_destroy_args {
913180059Sjhb	semid_t		id;
914103571Salfred};
915103571Salfred#endif
916103571Salfredint
917225617Skmacysys_ksem_destroy(struct thread *td, struct ksem_destroy_args *uap)
918103571Salfred{
919180059Sjhb	struct file *fp;
920103571Salfred	struct ksem *ks;
921103571Salfred	int error;
922103571Salfred
923224778Srwatson	/* No capability rights required to close a semaphore. */
924224778Srwatson	error = ksem_get(td, uap->id, 0, &fp);
925180059Sjhb	if (error)
926180059Sjhb		return (error);
927180059Sjhb	ks = fp->f_data;
928180059Sjhb	if (!(ks->ks_flags & KS_ANONYMOUS)) {
929180059Sjhb		fdrop(fp, td);
930180059Sjhb		return (EINVAL);
931180059Sjhb	}
932103571Salfred	mtx_lock(&sem_lock);
933103571Salfred	if (ks->ks_waiters != 0) {
934180059Sjhb		mtx_unlock(&sem_lock);
935103571Salfred		error = EBUSY;
936103571Salfred		goto err;
937103571Salfred	}
938180059Sjhb	ks->ks_flags |= KS_DEAD;
939180059Sjhb	mtx_unlock(&sem_lock);
940180059Sjhb
941180059Sjhb	error = kern_close(td, uap->id);
942103571Salfrederr:
943180059Sjhb	fdrop(fp, td);
944103571Salfred	return (error);
945103571Salfred}
946103571Salfred
947205324Skibstatic struct syscall_helper_data ksem_syscalls[] = {
948205324Skib	SYSCALL_INIT_HELPER(ksem_init),
949205324Skib	SYSCALL_INIT_HELPER(ksem_open),
950205324Skib	SYSCALL_INIT_HELPER(ksem_unlink),
951205324Skib	SYSCALL_INIT_HELPER(ksem_close),
952205324Skib	SYSCALL_INIT_HELPER(ksem_post),
953205324Skib	SYSCALL_INIT_HELPER(ksem_wait),
954205324Skib	SYSCALL_INIT_HELPER(ksem_timedwait),
955205324Skib	SYSCALL_INIT_HELPER(ksem_trywait),
956205324Skib	SYSCALL_INIT_HELPER(ksem_getvalue),
957205324Skib	SYSCALL_INIT_HELPER(ksem_destroy),
958205324Skib	SYSCALL_INIT_LAST
959205324Skib};
960142498Srwatson
961205324Skib#ifdef COMPAT_FREEBSD32
962205324Skib#include <compat/freebsd32/freebsd32.h>
963205324Skib#include <compat/freebsd32/freebsd32_proto.h>
964205324Skib#include <compat/freebsd32/freebsd32_signal.h>
965205324Skib#include <compat/freebsd32/freebsd32_syscall.h>
966205324Skib#include <compat/freebsd32/freebsd32_util.h>
967142498Srwatson
968205324Skibint
969205324Skibfreebsd32_ksem_init(struct thread *td, struct freebsd32_ksem_init_args *uap)
970205324Skib{
971142498Srwatson
972205324Skib	return (ksem_create(td, NULL, uap->idp, S_IRWXU | S_IRWXG, uap->value,
973205324Skib	    0, 1));
974205324Skib}
975180059Sjhb
976205324Skibint
977205324Skibfreebsd32_ksem_open(struct thread *td, struct freebsd32_ksem_open_args *uap)
978205324Skib{
979205324Skib
980205324Skib	if ((uap->oflag & ~(O_CREAT | O_EXCL)) != 0)
981205324Skib		return (EINVAL);
982205324Skib	return (ksem_create(td, uap->name, uap->idp, uap->mode, uap->value,
983205324Skib	    uap->oflag, 1));
984205324Skib}
985205324Skib
986205324Skibint
987205324Skibfreebsd32_ksem_timedwait(struct thread *td,
988205324Skib    struct freebsd32_ksem_timedwait_args *uap)
989205324Skib{
990205324Skib	struct timespec32 abstime32;
991205324Skib	struct timespec *ts, abstime;
992205324Skib	int error;
993205324Skib
994205324Skib	/*
995205324Skib	 * We allow a null timespec (wait forever).
996205324Skib	 */
997205324Skib	if (uap->abstime == NULL)
998205324Skib		ts = NULL;
999205324Skib	else {
1000205324Skib		error = copyin(uap->abstime, &abstime32, sizeof(abstime32));
1001205324Skib		if (error != 0)
1002205324Skib			return (error);
1003205324Skib		CP(abstime32, abstime, tv_sec);
1004205324Skib		CP(abstime32, abstime, tv_nsec);
1005205324Skib		if (abstime.tv_nsec >= 1000000000 || abstime.tv_nsec < 0)
1006205324Skib			return (EINVAL);
1007205324Skib		ts = &abstime;
1008205324Skib	}
1009205324Skib	return (kern_sem_wait(td, uap->id, 0, ts));
1010205324Skib}
1011205324Skib
1012205324Skibstatic struct syscall_helper_data ksem32_syscalls[] = {
1013205324Skib	SYSCALL32_INIT_HELPER(freebsd32_ksem_init),
1014205324Skib	SYSCALL32_INIT_HELPER(freebsd32_ksem_open),
1015225617Skmacy	SYSCALL32_INIT_HELPER_COMPAT(ksem_unlink),
1016225617Skmacy	SYSCALL32_INIT_HELPER_COMPAT(ksem_close),
1017225617Skmacy	SYSCALL32_INIT_HELPER_COMPAT(ksem_post),
1018225617Skmacy	SYSCALL32_INIT_HELPER_COMPAT(ksem_wait),
1019205324Skib	SYSCALL32_INIT_HELPER(freebsd32_ksem_timedwait),
1020225617Skmacy	SYSCALL32_INIT_HELPER_COMPAT(ksem_trywait),
1021225617Skmacy	SYSCALL32_INIT_HELPER_COMPAT(ksem_getvalue),
1022225617Skmacy	SYSCALL32_INIT_HELPER_COMPAT(ksem_destroy),
1023205324Skib	SYSCALL_INIT_LAST
1024205324Skib};
1025205324Skib#endif
1026205324Skib
1027180059Sjhbstatic int
1028180059Sjhbksem_module_init(void)
1029142498Srwatson{
1030180059Sjhb	int error;
1031142498Srwatson
1032180059Sjhb	mtx_init(&sem_lock, "sem", NULL, MTX_DEF);
1033180059Sjhb	mtx_init(&ksem_count_lock, "ksem count", NULL, MTX_DEF);
1034180059Sjhb	sx_init(&ksem_dict_lock, "ksem dictionary");
1035180059Sjhb	ksem_dictionary = hashinit(1024, M_KSEM, &ksem_hash);
1036215541Sjhb	p31b_setcfg(CTL_P1003_1B_SEMAPHORES, 200112L);
1037180059Sjhb	p31b_setcfg(CTL_P1003_1B_SEM_NSEMS_MAX, SEM_MAX);
1038180059Sjhb	p31b_setcfg(CTL_P1003_1B_SEM_VALUE_MAX, SEM_VALUE_MAX);
1039250223Sjhb	ksem_info = ksem_info_impl;
1040179054Srwatson
1041205324Skib	error = syscall_helper_register(ksem_syscalls);
1042205324Skib	if (error)
1043205324Skib		return (error);
1044205324Skib#ifdef COMPAT_FREEBSD32
1045205324Skib	error = syscall32_helper_register(ksem32_syscalls);
1046205324Skib	if (error)
1047205324Skib		return (error);
1048205324Skib#endif
1049180059Sjhb	return (0);
1050142498Srwatson}
1051142498Srwatson
1052142498Srwatsonstatic void
1053180059Sjhbksem_module_destroy(void)
1054103571Salfred{
1055161302Snetchild
1056205324Skib#ifdef COMPAT_FREEBSD32
1057205324Skib	syscall32_helper_unregister(ksem32_syscalls);
1058205324Skib#endif
1059205324Skib	syscall_helper_unregister(ksem_syscalls);
1060103571Salfred
1061250223Sjhb	ksem_info = NULL;
1062215541Sjhb	p31b_setcfg(CTL_P1003_1B_SEMAPHORES, 0);
1063180059Sjhb	hashdestroy(ksem_dictionary, M_KSEM, ksem_hash);
1064180059Sjhb	sx_destroy(&ksem_dict_lock);
1065180059Sjhb	mtx_destroy(&ksem_count_lock);
1066180059Sjhb	mtx_destroy(&sem_lock);
1067208731Skib	p31b_unsetcfg(CTL_P1003_1B_SEM_VALUE_MAX);
1068208731Skib	p31b_unsetcfg(CTL_P1003_1B_SEM_NSEMS_MAX);
1069103571Salfred}
1070103571Salfred
1071103571Salfredstatic int
1072103571Salfredsem_modload(struct module *module, int cmd, void *arg)
1073103571Salfred{
1074103571Salfred        int error = 0;
1075103571Salfred
1076103571Salfred        switch (cmd) {
1077103571Salfred        case MOD_LOAD:
1078180059Sjhb		error = ksem_module_init();
1079180059Sjhb		if (error)
1080180059Sjhb			ksem_module_destroy();
1081103571Salfred                break;
1082179054Srwatson
1083103571Salfred        case MOD_UNLOAD:
1084180059Sjhb		mtx_lock(&ksem_count_lock);
1085103571Salfred		if (nsems != 0) {
1086103571Salfred			error = EOPNOTSUPP;
1087180059Sjhb			mtx_unlock(&ksem_count_lock);
1088103571Salfred			break;
1089103571Salfred		}
1090180059Sjhb		ksem_dead = 1;
1091180059Sjhb		mtx_unlock(&ksem_count_lock);
1092180059Sjhb		ksem_module_destroy();
1093103571Salfred                break;
1094179054Srwatson
1095103571Salfred        case MOD_SHUTDOWN:
1096103571Salfred                break;
1097103571Salfred        default:
1098103571Salfred                error = EINVAL;
1099103571Salfred                break;
1100103571Salfred        }
1101103571Salfred        return (error);
1102103571Salfred}
1103103571Salfred
1104103571Salfredstatic moduledata_t sem_mod = {
1105103571Salfred        "sem",
1106103571Salfred        &sem_modload,
1107103571Salfred        NULL
1108103571Salfred};
1109103571Salfred
1110103571SalfredDECLARE_MODULE(sem, sem_mod, SI_SUB_SYSV_SEM, SI_ORDER_FIRST);
1111103571SalfredMODULE_VERSION(sem, 1);
1112