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: stable/10/sys/kern/uipc_sem.c 325783 2017-11-13 23:21:17Z jamie $");
36116182Sobrien
37205324Skib#include "opt_compat.h"
38103571Salfred#include "opt_posix.h"
39103571Salfred
40103571Salfred#include <sys/param.h>
41280258Srwatson#include <sys/capsicum.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>
47325783Sjamie#include <sys/jail.h>
48103571Salfred#include <sys/kernel.h>
49164184Strhodes#include <sys/ksem.h>
50180059Sjhb#include <sys/lock.h>
51180059Sjhb#include <sys/malloc.h>
52180059Sjhb#include <sys/module.h>
53180059Sjhb#include <sys/mutex.h>
54164033Srwatson#include <sys/priv.h>
55103571Salfred#include <sys/proc.h>
56164184Strhodes#include <sys/posix4.h>
57180059Sjhb#include <sys/_semaphore.h>
58180059Sjhb#include <sys/stat.h>
59103571Salfred#include <sys/syscall.h>
60180059Sjhb#include <sys/syscallsubr.h>
61180059Sjhb#include <sys/sysctl.h>
62103571Salfred#include <sys/sysent.h>
63180059Sjhb#include <sys/sysproto.h>
64180059Sjhb#include <sys/systm.h>
65180059Sjhb#include <sys/sx.h>
66180059Sjhb#include <sys/vnode.h>
67103571Salfred
68163606Srwatson#include <security/mac/mac_framework.h>
69163606Srwatson
70219030SnetchildFEATURE(p1003_1b_semaphores, "POSIX P1003.1B semaphores support");
71180059Sjhb/*
72180059Sjhb * TODO
73180059Sjhb *
74180059Sjhb * - Resource limits?
75180059Sjhb * - Replace global sem_lock with mtx_pool locks?
76180059Sjhb * - Add a MAC check_create() hook for creating new named semaphores.
77180059Sjhb */
78103571Salfred
79103571Salfred#ifndef SEM_MAX
80179054Srwatson#define	SEM_MAX	30
81103571Salfred#endif
82103571Salfred
83180059Sjhb#ifdef SEM_DEBUG
84180059Sjhb#define	DP(x)	printf x
85180059Sjhb#else
86180059Sjhb#define	DP(x)
87180059Sjhb#endif
88103571Salfred
89180059Sjhbstruct ksem_mapping {
90180059Sjhb	char		*km_path;
91180059Sjhb	Fnv32_t		km_fnv;
92180059Sjhb	struct ksem	*km_ksem;
93180059Sjhb	LIST_ENTRY(ksem_mapping) km_link;
94180059Sjhb};
95103571Salfred
96180059Sjhbstatic MALLOC_DEFINE(M_KSEM, "ksem", "semaphore file descriptor");
97180059Sjhbstatic LIST_HEAD(, ksem_mapping) *ksem_dictionary;
98180059Sjhbstatic struct sx ksem_dict_lock;
99180059Sjhbstatic struct mtx ksem_count_lock;
100180059Sjhbstatic struct mtx sem_lock;
101180059Sjhbstatic u_long ksem_hash;
102180059Sjhbstatic int ksem_dead;
103179054Srwatson
104180059Sjhb#define	KSEM_HASH(fnv)	(&ksem_dictionary[(fnv) & ksem_hash])
105103571Salfred
106103571Salfredstatic int nsems = 0;
107103571SalfredSYSCTL_DECL(_p1003_1b);
108180059SjhbSYSCTL_INT(_p1003_1b, OID_AUTO, nsems, CTLFLAG_RD, &nsems, 0,
109180059Sjhb    "Number of active kernel POSIX semaphores");
110103571Salfred
111180059Sjhbstatic int	kern_sem_wait(struct thread *td, semid_t id, int tryflag,
112180059Sjhb		    struct timespec *abstime);
113180059Sjhbstatic int	ksem_access(struct ksem *ks, struct ucred *ucred);
114180059Sjhbstatic struct ksem *ksem_alloc(struct ucred *ucred, mode_t mode,
115180059Sjhb		    unsigned int value);
116180059Sjhbstatic int	ksem_create(struct thread *td, const char *path,
117180059Sjhb		    semid_t *semidp, mode_t mode, unsigned int value,
118205324Skib		    int flags, int compat32);
119180059Sjhbstatic void	ksem_drop(struct ksem *ks);
120255219Spjdstatic int	ksem_get(struct thread *td, semid_t id, cap_rights_t *rightsp,
121224778Srwatson    struct file **fpp);
122180059Sjhbstatic struct ksem *ksem_hold(struct ksem *ks);
123180059Sjhbstatic void	ksem_insert(char *path, Fnv32_t fnv, struct ksem *ks);
124180059Sjhbstatic struct ksem *ksem_lookup(char *path, Fnv32_t fnv);
125180059Sjhbstatic void	ksem_module_destroy(void);
126180059Sjhbstatic int	ksem_module_init(void);
127180059Sjhbstatic int	ksem_remove(char *path, Fnv32_t fnv, struct ucred *ucred);
128180059Sjhbstatic int	sem_modload(struct module *module, int cmd, void *arg);
129112564Sjhb
130180059Sjhbstatic fo_rdwr_t	ksem_read;
131180059Sjhbstatic fo_rdwr_t	ksem_write;
132180059Sjhbstatic fo_truncate_t	ksem_truncate;
133180059Sjhbstatic fo_ioctl_t	ksem_ioctl;
134180059Sjhbstatic fo_poll_t	ksem_poll;
135180059Sjhbstatic fo_kqfilter_t	ksem_kqfilter;
136180059Sjhbstatic fo_stat_t	ksem_stat;
137180059Sjhbstatic fo_close_t	ksem_closef;
138224914Skibstatic fo_chmod_t	ksem_chmod;
139224914Skibstatic fo_chown_t	ksem_chown;
140104596Salfred
141180059Sjhb/* File descriptor operations. */
142180059Sjhbstatic struct fileops ksem_ops = {
143180059Sjhb	.fo_read = ksem_read,
144180059Sjhb	.fo_write = ksem_write,
145180059Sjhb	.fo_truncate = ksem_truncate,
146180059Sjhb	.fo_ioctl = ksem_ioctl,
147180059Sjhb	.fo_poll = ksem_poll,
148180059Sjhb	.fo_kqfilter = ksem_kqfilter,
149180059Sjhb	.fo_stat = ksem_stat,
150180059Sjhb	.fo_close = ksem_closef,
151224914Skib	.fo_chmod = ksem_chmod,
152224914Skib	.fo_chown = ksem_chown,
153254356Sglebius	.fo_sendfile = invfo_sendfile,
154180059Sjhb	.fo_flags = DFLAG_PASSABLE
155180059Sjhb};
156180059Sjhb
157180059SjhbFEATURE(posix_sem, "POSIX semaphores");
158180059Sjhb
159180059Sjhbstatic int
160180059Sjhbksem_read(struct file *fp, struct uio *uio, struct ucred *active_cred,
161180059Sjhb    int flags, struct thread *td)
162103571Salfred{
163103571Salfred
164180059Sjhb	return (EOPNOTSUPP);
165103571Salfred}
166103571Salfred
167180059Sjhbstatic int
168180059Sjhbksem_write(struct file *fp, struct uio *uio, struct ucred *active_cred,
169180059Sjhb    int flags, struct thread *td)
170103571Salfred{
171103571Salfred
172180059Sjhb	return (EOPNOTSUPP);
173103571Salfred}
174103571Salfred
175180059Sjhbstatic int
176180059Sjhbksem_truncate(struct file *fp, off_t length, struct ucred *active_cred,
177180059Sjhb    struct thread *td)
178103571Salfred{
179103571Salfred
180180059Sjhb	return (EINVAL);
181103571Salfred}
182103571Salfred
183180059Sjhbstatic int
184180059Sjhbksem_ioctl(struct file *fp, u_long com, void *data,
185180059Sjhb    struct ucred *active_cred, struct thread *td)
186103571Salfred{
187103571Salfred
188180059Sjhb	return (EOPNOTSUPP);
189103571Salfred}
190103571Salfred
191105227Sphkstatic int
192180059Sjhbksem_poll(struct file *fp, int events, struct ucred *active_cred,
193180059Sjhb    struct thread *td)
194103571Salfred{
195180059Sjhb
196180059Sjhb	return (EOPNOTSUPP);
197180059Sjhb}
198180059Sjhb
199180059Sjhbstatic int
200180059Sjhbksem_kqfilter(struct file *fp, struct knote *kn)
201180059Sjhb{
202180059Sjhb
203180059Sjhb	return (EOPNOTSUPP);
204180059Sjhb}
205180059Sjhb
206180059Sjhbstatic int
207180059Sjhbksem_stat(struct file *fp, struct stat *sb, struct ucred *active_cred,
208180059Sjhb    struct thread *td)
209180059Sjhb{
210180059Sjhb	struct ksem *ks;
211180059Sjhb#ifdef MAC
212103571Salfred	int error;
213180059Sjhb#endif
214103571Salfred
215180059Sjhb	ks = fp->f_data;
216179054Srwatson
217145855Srwatson#ifdef MAC
218180059Sjhb	error = mac_posixsem_check_stat(active_cred, fp->f_cred, ks);
219180059Sjhb	if (error)
220180059Sjhb		return (error);
221145855Srwatson#endif
222180059Sjhb
223180059Sjhb	/*
224180059Sjhb	 * Attempt to return sanish values for fstat() on a semaphore
225180059Sjhb	 * file descriptor.
226180059Sjhb	 */
227180059Sjhb	bzero(sb, sizeof(*sb));
228180059Sjhb
229224914Skib	mtx_lock(&sem_lock);
230205792Sed	sb->st_atim = ks->ks_atime;
231205792Sed	sb->st_ctim = ks->ks_ctime;
232205792Sed	sb->st_mtim = ks->ks_mtime;
233224914Skib	sb->st_birthtim = ks->ks_birthtime;
234180059Sjhb	sb->st_uid = ks->ks_uid;
235180059Sjhb	sb->st_gid = ks->ks_gid;
236224914Skib	sb->st_mode = S_IFREG | ks->ks_mode;		/* XXX */
237224914Skib	mtx_unlock(&sem_lock);
238180059Sjhb
239180059Sjhb	return (0);
240103571Salfred}
241103571Salfred
242180059Sjhbstatic int
243224914Skibksem_chmod(struct file *fp, mode_t mode, struct ucred *active_cred,
244224914Skib    struct thread *td)
245224914Skib{
246224914Skib	struct ksem *ks;
247224914Skib	int error;
248224914Skib
249224914Skib	error = 0;
250224914Skib	ks = fp->f_data;
251224914Skib	mtx_lock(&sem_lock);
252224914Skib#ifdef MAC
253224914Skib	error = mac_posixsem_check_setmode(active_cred, ks, mode);
254224914Skib	if (error != 0)
255224914Skib		goto out;
256224914Skib#endif
257224914Skib	error = vaccess(VREG, ks->ks_mode, ks->ks_uid, ks->ks_gid, VADMIN,
258224914Skib	    active_cred, NULL);
259224914Skib	if (error != 0)
260224914Skib		goto out;
261224914Skib	ks->ks_mode = mode & ACCESSPERMS;
262224914Skibout:
263224914Skib	mtx_unlock(&sem_lock);
264224914Skib	return (error);
265224914Skib}
266224914Skib
267224914Skibstatic int
268224914Skibksem_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred,
269224914Skib    struct thread *td)
270224914Skib{
271224914Skib	struct ksem *ks;
272224914Skib	int error;
273224914Skib
274224935Skib	error = 0;
275224914Skib	ks = fp->f_data;
276224914Skib	mtx_lock(&sem_lock);
277224914Skib#ifdef MAC
278224914Skib	error = mac_posixsem_check_setowner(active_cred, ks, uid, gid);
279224914Skib	if (error != 0)
280224914Skib		goto out;
281224914Skib#endif
282224914Skib	if (uid == (uid_t)-1)
283224914Skib		uid = ks->ks_uid;
284224914Skib	if (gid == (gid_t)-1)
285224914Skib                 gid = ks->ks_gid;
286224914Skib	if (((uid != ks->ks_uid && uid != active_cred->cr_uid) ||
287224914Skib	    (gid != ks->ks_gid && !groupmember(gid, active_cred))) &&
288224914Skib	    (error = priv_check_cred(active_cred, PRIV_VFS_CHOWN, 0)))
289224914Skib		goto out;
290224914Skib	ks->ks_uid = uid;
291224914Skib	ks->ks_gid = gid;
292224914Skibout:
293224914Skib	mtx_unlock(&sem_lock);
294224914Skib	return (error);
295224914Skib}
296224914Skib
297224914Skibstatic int
298180059Sjhbksem_closef(struct file *fp, struct thread *td)
299103571Salfred{
300180059Sjhb	struct ksem *ks;
301103571Salfred
302180059Sjhb	ks = fp->f_data;
303180059Sjhb	fp->f_data = NULL;
304180059Sjhb	ksem_drop(ks);
305180059Sjhb
306180059Sjhb	return (0);
307103571Salfred}
308103571Salfred
309180059Sjhb/*
310180059Sjhb * ksem object management including creation and reference counting
311180059Sjhb * routines.
312180059Sjhb */
313180059Sjhbstatic struct ksem *
314180059Sjhbksem_alloc(struct ucred *ucred, mode_t mode, unsigned int value)
315103571Salfred{
316103571Salfred	struct ksem *ks;
317103571Salfred
318180059Sjhb	mtx_lock(&ksem_count_lock);
319180059Sjhb	if (nsems == p31b_getcfg(CTL_P1003_1B_SEM_NSEMS_MAX) || ksem_dead) {
320180059Sjhb		mtx_unlock(&ksem_count_lock);
321180059Sjhb		return (NULL);
322103571Salfred	}
323180059Sjhb	nsems++;
324180059Sjhb	mtx_unlock(&ksem_count_lock);
325180059Sjhb	ks = malloc(sizeof(*ks), M_KSEM, M_WAITOK | M_ZERO);
326180059Sjhb	ks->ks_uid = ucred->cr_uid;
327180059Sjhb	ks->ks_gid = ucred->cr_gid;
328180059Sjhb	ks->ks_mode = mode;
329180059Sjhb	ks->ks_value = value;
330180059Sjhb	cv_init(&ks->ks_cv, "ksem");
331180059Sjhb	vfs_timestamp(&ks->ks_birthtime);
332180059Sjhb	ks->ks_atime = ks->ks_mtime = ks->ks_ctime = ks->ks_birthtime;
333180059Sjhb	refcount_init(&ks->ks_ref, 1);
334180059Sjhb#ifdef MAC
335180059Sjhb	mac_posixsem_init(ks);
336180059Sjhb	mac_posixsem_create(ucred, ks);
337180059Sjhb#endif
338180059Sjhb
339180059Sjhb	return (ks);
340103571Salfred}
341103571Salfred
342180059Sjhbstatic struct ksem *
343180059Sjhbksem_hold(struct ksem *ks)
344180059Sjhb{
345180059Sjhb
346180059Sjhb	refcount_acquire(&ks->ks_ref);
347180059Sjhb	return (ks);
348180059Sjhb}
349180059Sjhb
350180059Sjhbstatic void
351180059Sjhbksem_drop(struct ksem *ks)
352180059Sjhb{
353180059Sjhb
354180059Sjhb	if (refcount_release(&ks->ks_ref)) {
355180059Sjhb#ifdef MAC
356180059Sjhb		mac_posixsem_destroy(ks);
357103571Salfred#endif
358180059Sjhb		cv_destroy(&ks->ks_cv);
359180059Sjhb		free(ks, M_KSEM);
360180059Sjhb		mtx_lock(&ksem_count_lock);
361180059Sjhb		nsems--;
362180059Sjhb		mtx_unlock(&ksem_count_lock);
363180059Sjhb	}
364180059Sjhb}
365180059Sjhb
366180059Sjhb/*
367180059Sjhb * Determine if the credentials have sufficient permissions for read
368180059Sjhb * and write access.
369180059Sjhb */
370180059Sjhbstatic int
371180059Sjhbksem_access(struct ksem *ks, struct ucred *ucred)
372103571Salfred{
373103571Salfred	int error;
374103571Salfred
375180059Sjhb	error = vaccess(VREG, ks->ks_mode, ks->ks_uid, ks->ks_gid,
376180059Sjhb	    VREAD | VWRITE, ucred, NULL);
377103571Salfred	if (error)
378180059Sjhb		error = priv_check_cred(ucred, PRIV_SEM_WRITE, 0);
379103571Salfred	return (error);
380103571Salfred}
381103571Salfred
382180059Sjhb/*
383180059Sjhb * Dictionary management.  We maintain an in-kernel dictionary to map
384180059Sjhb * paths to semaphore objects.  We use the FNV hash on the path to
385180059Sjhb * store the mappings in a hash table.
386180059Sjhb */
387180059Sjhbstatic struct ksem *
388180059Sjhbksem_lookup(char *path, Fnv32_t fnv)
389103571Salfred{
390180059Sjhb	struct ksem_mapping *map;
391103571Salfred
392180059Sjhb	LIST_FOREACH(map, KSEM_HASH(fnv), km_link) {
393180059Sjhb		if (map->km_fnv != fnv)
394180059Sjhb			continue;
395180059Sjhb		if (strcmp(map->km_path, path) == 0)
396180059Sjhb			return (map->km_ksem);
397103571Salfred	}
398179054Srwatson
399180059Sjhb	return (NULL);
400180059Sjhb}
401179054Srwatson
402180059Sjhbstatic void
403180059Sjhbksem_insert(char *path, Fnv32_t fnv, struct ksem *ks)
404180059Sjhb{
405180059Sjhb	struct ksem_mapping *map;
406179054Srwatson
407180059Sjhb	map = malloc(sizeof(struct ksem_mapping), M_KSEM, M_WAITOK);
408180059Sjhb	map->km_path = path;
409180059Sjhb	map->km_fnv = fnv;
410180059Sjhb	map->km_ksem = ksem_hold(ks);
411250223Sjhb	ks->ks_path = path;
412180059Sjhb	LIST_INSERT_HEAD(KSEM_HASH(fnv), map, km_link);
413180059Sjhb}
414180059Sjhb
415180059Sjhbstatic int
416180059Sjhbksem_remove(char *path, Fnv32_t fnv, struct ucred *ucred)
417180059Sjhb{
418180059Sjhb	struct ksem_mapping *map;
419180059Sjhb	int error;
420180059Sjhb
421180059Sjhb	LIST_FOREACH(map, KSEM_HASH(fnv), km_link) {
422180059Sjhb		if (map->km_fnv != fnv)
423180059Sjhb			continue;
424180059Sjhb		if (strcmp(map->km_path, path) == 0) {
425145855Srwatson#ifdef MAC
426180059Sjhb			error = mac_posixsem_check_unlink(ucred, map->km_ksem);
427180059Sjhb			if (error)
428180059Sjhb				return (error);
429145855Srwatson#endif
430180059Sjhb			error = ksem_access(map->km_ksem, ucred);
431180059Sjhb			if (error)
432103571Salfred				return (error);
433250223Sjhb			map->km_ksem->ks_path = NULL;
434180059Sjhb			LIST_REMOVE(map, km_link);
435180059Sjhb			ksem_drop(map->km_ksem);
436180059Sjhb			free(map->km_path, M_KSEM);
437180059Sjhb			free(map, M_KSEM);
438180059Sjhb			return (0);
439103571Salfred		}
440103571Salfred	}
441180059Sjhb
442180059Sjhb	return (ENOENT);
443103571Salfred}
444103571Salfred
445250223Sjhbstatic void
446250223Sjhbksem_info_impl(struct ksem *ks, char *path, size_t size, uint32_t *value)
447250223Sjhb{
448325783Sjamie	const char *ks_path, *pr_path;
449325783Sjamie	size_t pr_pathlen;
450250223Sjhb
451250223Sjhb	if (ks->ks_path == NULL)
452250223Sjhb		return;
453250223Sjhb	sx_slock(&ksem_dict_lock);
454325783Sjamie	ks_path = ks->ks_path;
455325783Sjamie	if (ks_path != NULL) {
456325783Sjamie		pr_path = curthread->td_ucred->cr_prison->pr_path;
457325783Sjamie		if (strcmp(pr_path, "/") != 0) {
458325783Sjamie			/* Return the jail-rooted pathname. */
459325783Sjamie			pr_pathlen = strlen(pr_path);
460325783Sjamie			if (strncmp(ks_path, pr_path, pr_pathlen) == 0 &&
461325783Sjamie			    ks_path[pr_pathlen] == '/')
462325783Sjamie				ks_path += pr_pathlen;
463325783Sjamie		}
464325783Sjamie		strlcpy(path, ks_path, size);
465325783Sjamie	}
466250223Sjhb	if (value != NULL)
467250223Sjhb		*value = ks->ks_value;
468250223Sjhb	sx_sunlock(&ksem_dict_lock);
469250223Sjhb}
470250223Sjhb
471205324Skibstatic int
472205324Skibksem_create_copyout_semid(struct thread *td, semid_t *semidp, int fd,
473205324Skib    int compat32)
474205324Skib{
475205324Skib	semid_t semid;
476205324Skib#ifdef COMPAT_FREEBSD32
477205324Skib	int32_t semid32;
478205324Skib#endif
479205324Skib	void *ptr;
480205324Skib	size_t ptrs;
481205324Skib
482205324Skib#ifdef COMPAT_FREEBSD32
483205324Skib	if (compat32) {
484205324Skib		semid32 = fd;
485205324Skib		ptr = &semid32;
486205324Skib		ptrs = sizeof(semid32);
487205324Skib	} else {
488205324Skib#endif
489205324Skib		semid = fd;
490205324Skib		ptr = &semid;
491205324Skib		ptrs = sizeof(semid);
492205324Skib		compat32 = 0; /* silence gcc */
493205324Skib#ifdef COMPAT_FREEBSD32
494205324Skib	}
495205324Skib#endif
496205324Skib
497205324Skib	return (copyout(ptr, semidp, ptrs));
498205324Skib}
499205324Skib
500180059Sjhb/* Other helper routines. */
501105227Sphkstatic int
502180059Sjhbksem_create(struct thread *td, const char *name, semid_t *semidp, mode_t mode,
503205324Skib    unsigned int value, int flags, int compat32)
504103571Salfred{
505180059Sjhb	struct filedesc *fdp;
506180059Sjhb	struct ksem *ks;
507180059Sjhb	struct file *fp;
508180059Sjhb	char *path;
509325783Sjamie	const char *pr_path;
510325783Sjamie	size_t pr_pathlen;
511180059Sjhb	Fnv32_t fnv;
512180059Sjhb	int error, fd;
513103571Salfred
514180059Sjhb	if (value > SEM_VALUE_MAX)
515180059Sjhb		return (EINVAL);
516180059Sjhb
517180059Sjhb	fdp = td->td_proc->p_fd;
518180059Sjhb	mode = (mode & ~fdp->fd_cmask) & ACCESSPERMS;
519249233Sjilles	error = falloc(td, &fp, &fd, O_CLOEXEC);
520180059Sjhb	if (error) {
521180059Sjhb		if (name == NULL)
522180059Sjhb			error = ENOSPC;
523180059Sjhb		return (error);
524180059Sjhb	}
525180059Sjhb
526164033Srwatson	/*
527180059Sjhb	 * Go ahead and copyout the file descriptor now.  This is a bit
528180059Sjhb	 * premature, but it is a lot easier to handle errors as opposed
529180059Sjhb	 * to later when we've possibly created a new semaphore, etc.
530164033Srwatson	 */
531205324Skib	error = ksem_create_copyout_semid(td, semidp, fd, compat32);
532180059Sjhb	if (error) {
533321020Sdchagin		fdclose(td, fp, fd);
534180059Sjhb		fdrop(fp, td);
535180059Sjhb		return (error);
536180059Sjhb	}
537103571Salfred
538180059Sjhb	if (name == NULL) {
539180059Sjhb		/* Create an anonymous semaphore. */
540180059Sjhb		ks = ksem_alloc(td->td_ucred, mode, value);
541180059Sjhb		if (ks == NULL)
542180059Sjhb			error = ENOSPC;
543180059Sjhb		else
544180059Sjhb			ks->ks_flags |= KS_ANONYMOUS;
545180059Sjhb	} else {
546180059Sjhb		path = malloc(MAXPATHLEN, M_KSEM, M_WAITOK);
547325783Sjamie		pr_path = td->td_ucred->cr_prison->pr_path;
548103571Salfred
549325783Sjamie		/* Construct a full pathname for jailed callers. */
550325783Sjamie		pr_pathlen = strcmp(pr_path, "/") == 0 ? 0
551325783Sjamie		    : strlcpy(path, pr_path, MAXPATHLEN);
552325783Sjamie		error = copyinstr(name, path + pr_pathlen,
553325783Sjamie		    MAXPATHLEN - pr_pathlen, NULL);
554325783Sjamie
555180059Sjhb		/* Require paths to start with a '/' character. */
556325783Sjamie		if (error == 0 && path[pr_pathlen] != '/')
557180059Sjhb			error = EINVAL;
558180059Sjhb		if (error) {
559321020Sdchagin			fdclose(td, fp, fd);
560180059Sjhb			fdrop(fp, td);
561180059Sjhb			free(path, M_KSEM);
562180059Sjhb			return (error);
563180059Sjhb		}
564180059Sjhb
565180059Sjhb		fnv = fnv_32_str(path, FNV1_32_INIT);
566180059Sjhb		sx_xlock(&ksem_dict_lock);
567180059Sjhb		ks = ksem_lookup(path, fnv);
568180059Sjhb		if (ks == NULL) {
569180059Sjhb			/* Object does not exist, create it if requested. */
570180059Sjhb			if (flags & O_CREAT) {
571180059Sjhb				ks = ksem_alloc(td->td_ucred, mode, value);
572180059Sjhb				if (ks == NULL)
573180059Sjhb					error = ENFILE;
574180059Sjhb				else {
575180059Sjhb					ksem_insert(path, fnv, ks);
576180059Sjhb					path = NULL;
577180059Sjhb				}
578180059Sjhb			} else
579180059Sjhb				error = ENOENT;
580180059Sjhb		} else {
581180059Sjhb			/*
582180059Sjhb			 * Object already exists, obtain a new
583180059Sjhb			 * reference if requested and permitted.
584180059Sjhb			 */
585180059Sjhb			if ((flags & (O_CREAT | O_EXCL)) ==
586180059Sjhb			    (O_CREAT | O_EXCL))
587180059Sjhb				error = EEXIST;
588180059Sjhb			else {
589175148Srwatson#ifdef MAC
590180059Sjhb				error = mac_posixsem_check_open(td->td_ucred,
591180059Sjhb				    ks);
592180059Sjhb				if (error == 0)
593175148Srwatson#endif
594180059Sjhb				error = ksem_access(ks, td->td_ucred);
595180059Sjhb			}
596180059Sjhb			if (error == 0)
597180059Sjhb				ksem_hold(ks);
598180059Sjhb#ifdef INVARIANTS
599180059Sjhb			else
600180059Sjhb				ks = NULL;
601180059Sjhb#endif
602180059Sjhb		}
603180059Sjhb		sx_xunlock(&ksem_dict_lock);
604180059Sjhb		if (path)
605180059Sjhb			free(path, M_KSEM);
606180059Sjhb	}
607103571Salfred
608180059Sjhb	if (error) {
609180059Sjhb		KASSERT(ks == NULL, ("ksem_create error with a ksem"));
610321020Sdchagin		fdclose(td, fp, fd);
611180059Sjhb		fdrop(fp, td);
612180059Sjhb		return (error);
613180059Sjhb	}
614180059Sjhb	KASSERT(ks != NULL, ("ksem_create w/o a ksem"));
615103571Salfred
616180059Sjhb	finit(fp, FREAD | FWRITE, DTYPE_SEM, ks, &ksem_ops);
617180059Sjhb
618180059Sjhb	fdrop(fp, td);
619180059Sjhb
620180059Sjhb	return (0);
621103571Salfred}
622103571Salfred
623105227Sphkstatic int
624255219Spjdksem_get(struct thread *td, semid_t id, cap_rights_t *rightsp,
625255219Spjd    struct file **fpp)
626103571Salfred{
627180059Sjhb	struct ksem *ks;
628180059Sjhb	struct file *fp;
629180059Sjhb	int error;
630180059Sjhb
631255219Spjd	error = fget(td, id, rightsp, &fp);
632180059Sjhb	if (error)
633180059Sjhb		return (EINVAL);
634180059Sjhb	if (fp->f_type != DTYPE_SEM) {
635180059Sjhb		fdrop(fp, td);
636180059Sjhb		return (EINVAL);
637180059Sjhb	}
638180059Sjhb	ks = fp->f_data;
639180059Sjhb	if (ks->ks_flags & KS_DEAD) {
640180059Sjhb		fdrop(fp, td);
641180059Sjhb		return (EINVAL);
642180059Sjhb	}
643180059Sjhb	*fpp = fp;
644180059Sjhb	return (0);
645103571Salfred}
646103571Salfred
647180059Sjhb/* System calls. */
648180059Sjhb#ifndef _SYS_SYSPROTO_H_
649180059Sjhbstruct ksem_init_args {
650180059Sjhb	unsigned int	value;
651180059Sjhb	semid_t		*idp;
652180059Sjhb};
653180059Sjhb#endif
654180059Sjhbint
655225617Skmacysys_ksem_init(struct thread *td, struct ksem_init_args *uap)
656103571Salfred{
657103571Salfred
658180059Sjhb	return (ksem_create(td, NULL, uap->idp, S_IRWXU | S_IRWXG, uap->value,
659205324Skib	    0, 0));
660103571Salfred}
661103571Salfred
662180059Sjhb#ifndef _SYS_SYSPROTO_H_
663180059Sjhbstruct ksem_open_args {
664180059Sjhb	char		*name;
665180059Sjhb	int		oflag;
666180059Sjhb	mode_t		mode;
667180059Sjhb	unsigned int	value;
668180059Sjhb	semid_t		*idp;
669180059Sjhb};
670180059Sjhb#endif
671180059Sjhbint
672225617Skmacysys_ksem_open(struct thread *td, struct ksem_open_args *uap)
673103571Salfred{
674103571Salfred
675189735Sbms	DP((">>> ksem_open start, pid=%d\n", (int)td->td_proc->p_pid));
676189735Sbms
677180059Sjhb	if ((uap->oflag & ~(O_CREAT | O_EXCL)) != 0)
678180059Sjhb		return (EINVAL);
679180059Sjhb	return (ksem_create(td, uap->name, uap->idp, uap->mode, uap->value,
680205324Skib	    uap->oflag, 0));
681103571Salfred}
682103571Salfred
683103571Salfred#ifndef _SYS_SYSPROTO_H_
684103571Salfredstruct ksem_unlink_args {
685180059Sjhb	char		*name;
686103571Salfred};
687103571Salfred#endif
688103571Salfredint
689225617Skmacysys_ksem_unlink(struct thread *td, struct ksem_unlink_args *uap)
690103571Salfred{
691180059Sjhb	char *path;
692325783Sjamie	const char *pr_path;
693325783Sjamie	size_t pr_pathlen;
694180059Sjhb	Fnv32_t fnv;
695103571Salfred	int error;
696103571Salfred
697180059Sjhb	path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
698325783Sjamie	pr_path = td->td_ucred->cr_prison->pr_path;
699325783Sjamie	pr_pathlen = strcmp(pr_path, "/") == 0 ? 0
700325783Sjamie	    : strlcpy(path, pr_path, MAXPATHLEN);
701325783Sjamie	error = copyinstr(uap->name, path + pr_pathlen, MAXPATHLEN - pr_pathlen,
702325783Sjamie	    NULL);
703180059Sjhb	if (error) {
704180059Sjhb		free(path, M_TEMP);
705180059Sjhb		return (error);
706180059Sjhb	}
707103571Salfred
708180059Sjhb	fnv = fnv_32_str(path, FNV1_32_INIT);
709180059Sjhb	sx_xlock(&ksem_dict_lock);
710180059Sjhb	error = ksem_remove(path, fnv, td->td_ucred);
711180059Sjhb	sx_xunlock(&ksem_dict_lock);
712180059Sjhb	free(path, M_TEMP);
713103571Salfred
714103571Salfred	return (error);
715103571Salfred}
716103571Salfred
717103571Salfred#ifndef _SYS_SYSPROTO_H_
718103571Salfredstruct ksem_close_args {
719180059Sjhb	semid_t		id;
720103571Salfred};
721103571Salfred#endif
722103571Salfredint
723225617Skmacysys_ksem_close(struct thread *td, struct ksem_close_args *uap)
724103571Salfred{
725103571Salfred	struct ksem *ks;
726180059Sjhb	struct file *fp;
727103571Salfred	int error;
728103571Salfred
729224778Srwatson	/* No capability rights required to close a semaphore. */
730224778Srwatson	error = ksem_get(td, uap->id, 0, &fp);
731180059Sjhb	if (error)
732180059Sjhb		return (error);
733180059Sjhb	ks = fp->f_data;
734180059Sjhb	if (ks->ks_flags & KS_ANONYMOUS) {
735180059Sjhb		fdrop(fp, td);
736180059Sjhb		return (EINVAL);
737180059Sjhb	}
738180059Sjhb	error = kern_close(td, uap->id);
739180059Sjhb	fdrop(fp, td);
740109084Salfred	return (error);
741103571Salfred}
742103571Salfred
743103571Salfred#ifndef _SYS_SYSPROTO_H_
744103571Salfredstruct ksem_post_args {
745180059Sjhb	semid_t	id;
746103571Salfred};
747103571Salfred#endif
748103571Salfredint
749225617Skmacysys_ksem_post(struct thread *td, struct ksem_post_args *uap)
750103571Salfred{
751255219Spjd	cap_rights_t rights;
752180059Sjhb	struct file *fp;
753103571Salfred	struct ksem *ks;
754103571Salfred	int error;
755103571Salfred
756255219Spjd	error = ksem_get(td, uap->id,
757255219Spjd	    cap_rights_init(&rights, CAP_SEM_POST), &fp);
758180059Sjhb	if (error)
759180059Sjhb		return (error);
760180059Sjhb	ks = fp->f_data;
761180059Sjhb
762103571Salfred	mtx_lock(&sem_lock);
763145855Srwatson#ifdef MAC
764180059Sjhb	error = mac_posixsem_check_post(td->td_ucred, fp->f_cred, ks);
765145855Srwatson	if (error)
766145855Srwatson		goto err;
767145855Srwatson#endif
768103571Salfred	if (ks->ks_value == SEM_VALUE_MAX) {
769103571Salfred		error = EOVERFLOW;
770103571Salfred		goto err;
771103571Salfred	}
772103571Salfred	++ks->ks_value;
773103571Salfred	if (ks->ks_waiters > 0)
774103571Salfred		cv_signal(&ks->ks_cv);
775103571Salfred	error = 0;
776180059Sjhb	vfs_timestamp(&ks->ks_ctime);
777103571Salfrederr:
778103571Salfred	mtx_unlock(&sem_lock);
779180059Sjhb	fdrop(fp, td);
780103571Salfred	return (error);
781103571Salfred}
782103571Salfred
783103571Salfred#ifndef _SYS_SYSPROTO_H_
784103571Salfredstruct ksem_wait_args {
785180059Sjhb	semid_t		id;
786103571Salfred};
787103571Salfred#endif
788103571Salfredint
789225617Skmacysys_ksem_wait(struct thread *td, struct ksem_wait_args *uap)
790103571Salfred{
791103571Salfred
792125368Sdeischen	return (kern_sem_wait(td, uap->id, 0, NULL));
793103571Salfred}
794103571Salfred
795103571Salfred#ifndef _SYS_SYSPROTO_H_
796125368Sdeischenstruct ksem_timedwait_args {
797180059Sjhb	semid_t		id;
798151445Sstefanf	const struct timespec *abstime;
799125368Sdeischen};
800125368Sdeischen#endif
801125368Sdeischenint
802225617Skmacysys_ksem_timedwait(struct thread *td, struct ksem_timedwait_args *uap)
803125368Sdeischen{
804125368Sdeischen	struct timespec abstime;
805125368Sdeischen	struct timespec *ts;
806125368Sdeischen	int error;
807125368Sdeischen
808179054Srwatson	/*
809179054Srwatson	 * We allow a null timespec (wait forever).
810179054Srwatson	 */
811125368Sdeischen	if (uap->abstime == NULL)
812125368Sdeischen		ts = NULL;
813125368Sdeischen	else {
814125368Sdeischen		error = copyin(uap->abstime, &abstime, sizeof(abstime));
815125368Sdeischen		if (error != 0)
816125368Sdeischen			return (error);
817125368Sdeischen		if (abstime.tv_nsec >= 1000000000 || abstime.tv_nsec < 0)
818125368Sdeischen			return (EINVAL);
819125368Sdeischen		ts = &abstime;
820125368Sdeischen	}
821125368Sdeischen	return (kern_sem_wait(td, uap->id, 0, ts));
822125368Sdeischen}
823125368Sdeischen
824125368Sdeischen#ifndef _SYS_SYSPROTO_H_
825103571Salfredstruct ksem_trywait_args {
826180059Sjhb	semid_t		id;
827103571Salfred};
828103571Salfred#endif
829103571Salfredint
830225617Skmacysys_ksem_trywait(struct thread *td, struct ksem_trywait_args *uap)
831103571Salfred{
832103571Salfred
833125368Sdeischen	return (kern_sem_wait(td, uap->id, 1, NULL));
834103571Salfred}
835103571Salfred
836105227Sphkstatic int
837154659Srwatsonkern_sem_wait(struct thread *td, semid_t id, int tryflag,
838154659Srwatson    struct timespec *abstime)
839103571Salfred{
840125368Sdeischen	struct timespec ts1, ts2;
841125368Sdeischen	struct timeval tv;
842255219Spjd	cap_rights_t rights;
843180059Sjhb	struct file *fp;
844103571Salfred	struct ksem *ks;
845103571Salfred	int error;
846103571Salfred
847189735Sbms	DP((">>> kern_sem_wait entered! pid=%d\n", (int)td->td_proc->p_pid));
848255219Spjd	error = ksem_get(td, id, cap_rights_init(&rights, CAP_SEM_WAIT), &fp);
849180059Sjhb	if (error)
850180059Sjhb		return (error);
851180059Sjhb	ks = fp->f_data;
852103571Salfred	mtx_lock(&sem_lock);
853189735Sbms	DP((">>> kern_sem_wait critical section entered! pid=%d\n",
854189735Sbms	    (int)td->td_proc->p_pid));
855145855Srwatson#ifdef MAC
856180059Sjhb	error = mac_posixsem_check_wait(td->td_ucred, fp->f_cred, ks);
857145855Srwatson	if (error) {
858145855Srwatson		DP(("kern_sem_wait mac failed\n"));
859145855Srwatson		goto err;
860145855Srwatson	}
861145855Srwatson#endif
862104596Salfred	DP(("kern_sem_wait value = %d, tryflag %d\n", ks->ks_value, tryflag));
863180059Sjhb	vfs_timestamp(&ks->ks_atime);
864189736Sbms	while (ks->ks_value == 0) {
865103571Salfred		ks->ks_waiters++;
866125368Sdeischen		if (tryflag != 0)
867125368Sdeischen			error = EAGAIN;
868125368Sdeischen		else if (abstime == NULL)
869125368Sdeischen			error = cv_wait_sig(&ks->ks_cv, &sem_lock);
870125368Sdeischen		else {
871125368Sdeischen			for (;;) {
872125368Sdeischen				ts1 = *abstime;
873125368Sdeischen				getnanotime(&ts2);
874125368Sdeischen				timespecsub(&ts1, &ts2);
875125368Sdeischen				TIMESPEC_TO_TIMEVAL(&tv, &ts1);
876125368Sdeischen				if (tv.tv_sec < 0) {
877125368Sdeischen					error = ETIMEDOUT;
878125368Sdeischen					break;
879125368Sdeischen				}
880125368Sdeischen				error = cv_timedwait_sig(&ks->ks_cv,
881125368Sdeischen				    &sem_lock, tvtohz(&tv));
882125368Sdeischen				if (error != EWOULDBLOCK)
883125368Sdeischen					break;
884125368Sdeischen			}
885125368Sdeischen		}
886103571Salfred		ks->ks_waiters--;
887103571Salfred		if (error)
888103571Salfred			goto err;
889103571Salfred	}
890103571Salfred	ks->ks_value--;
891189735Sbms	DP(("kern_sem_wait value post-decrement = %d\n", ks->ks_value));
892103571Salfred	error = 0;
893103571Salfrederr:
894103571Salfred	mtx_unlock(&sem_lock);
895180059Sjhb	fdrop(fp, td);
896189735Sbms	DP(("<<< kern_sem_wait leaving, pid=%d, error = %d\n",
897189735Sbms	    (int)td->td_proc->p_pid, error));
898103571Salfred	return (error);
899103571Salfred}
900103571Salfred
901103571Salfred#ifndef _SYS_SYSPROTO_H_
902103571Salfredstruct ksem_getvalue_args {
903180059Sjhb	semid_t		id;
904180059Sjhb	int		*val;
905103571Salfred};
906103571Salfred#endif
907103571Salfredint
908225617Skmacysys_ksem_getvalue(struct thread *td, struct ksem_getvalue_args *uap)
909103571Salfred{
910255219Spjd	cap_rights_t rights;
911180059Sjhb	struct file *fp;
912103571Salfred	struct ksem *ks;
913103571Salfred	int error, val;
914103571Salfred
915255219Spjd	error = ksem_get(td, uap->id,
916255219Spjd	    cap_rights_init(&rights, CAP_SEM_GETVALUE), &fp);
917180059Sjhb	if (error)
918180059Sjhb		return (error);
919180059Sjhb	ks = fp->f_data;
920180059Sjhb
921103571Salfred	mtx_lock(&sem_lock);
922145855Srwatson#ifdef MAC
923180059Sjhb	error = mac_posixsem_check_getvalue(td->td_ucred, fp->f_cred, ks);
924145855Srwatson	if (error) {
925145855Srwatson		mtx_unlock(&sem_lock);
926180059Sjhb		fdrop(fp, td);
927145855Srwatson		return (error);
928145855Srwatson	}
929145855Srwatson#endif
930103571Salfred	val = ks->ks_value;
931180059Sjhb	vfs_timestamp(&ks->ks_atime);
932103571Salfred	mtx_unlock(&sem_lock);
933180059Sjhb	fdrop(fp, td);
934103571Salfred	error = copyout(&val, uap->val, sizeof(val));
935103571Salfred	return (error);
936103571Salfred}
937103571Salfred
938103571Salfred#ifndef _SYS_SYSPROTO_H_
939103571Salfredstruct ksem_destroy_args {
940180059Sjhb	semid_t		id;
941103571Salfred};
942103571Salfred#endif
943103571Salfredint
944225617Skmacysys_ksem_destroy(struct thread *td, struct ksem_destroy_args *uap)
945103571Salfred{
946180059Sjhb	struct file *fp;
947103571Salfred	struct ksem *ks;
948103571Salfred	int error;
949103571Salfred
950224778Srwatson	/* No capability rights required to close a semaphore. */
951224778Srwatson	error = ksem_get(td, uap->id, 0, &fp);
952180059Sjhb	if (error)
953180059Sjhb		return (error);
954180059Sjhb	ks = fp->f_data;
955180059Sjhb	if (!(ks->ks_flags & KS_ANONYMOUS)) {
956180059Sjhb		fdrop(fp, td);
957180059Sjhb		return (EINVAL);
958180059Sjhb	}
959103571Salfred	mtx_lock(&sem_lock);
960103571Salfred	if (ks->ks_waiters != 0) {
961180059Sjhb		mtx_unlock(&sem_lock);
962103571Salfred		error = EBUSY;
963103571Salfred		goto err;
964103571Salfred	}
965180059Sjhb	ks->ks_flags |= KS_DEAD;
966180059Sjhb	mtx_unlock(&sem_lock);
967180059Sjhb
968180059Sjhb	error = kern_close(td, uap->id);
969103571Salfrederr:
970180059Sjhb	fdrop(fp, td);
971103571Salfred	return (error);
972103571Salfred}
973103571Salfred
974205324Skibstatic struct syscall_helper_data ksem_syscalls[] = {
975205324Skib	SYSCALL_INIT_HELPER(ksem_init),
976205324Skib	SYSCALL_INIT_HELPER(ksem_open),
977205324Skib	SYSCALL_INIT_HELPER(ksem_unlink),
978205324Skib	SYSCALL_INIT_HELPER(ksem_close),
979205324Skib	SYSCALL_INIT_HELPER(ksem_post),
980205324Skib	SYSCALL_INIT_HELPER(ksem_wait),
981205324Skib	SYSCALL_INIT_HELPER(ksem_timedwait),
982205324Skib	SYSCALL_INIT_HELPER(ksem_trywait),
983205324Skib	SYSCALL_INIT_HELPER(ksem_getvalue),
984205324Skib	SYSCALL_INIT_HELPER(ksem_destroy),
985205324Skib	SYSCALL_INIT_LAST
986205324Skib};
987142498Srwatson
988205324Skib#ifdef COMPAT_FREEBSD32
989205324Skib#include <compat/freebsd32/freebsd32.h>
990205324Skib#include <compat/freebsd32/freebsd32_proto.h>
991205324Skib#include <compat/freebsd32/freebsd32_signal.h>
992205324Skib#include <compat/freebsd32/freebsd32_syscall.h>
993205324Skib#include <compat/freebsd32/freebsd32_util.h>
994142498Srwatson
995205324Skibint
996205324Skibfreebsd32_ksem_init(struct thread *td, struct freebsd32_ksem_init_args *uap)
997205324Skib{
998142498Srwatson
999205324Skib	return (ksem_create(td, NULL, uap->idp, S_IRWXU | S_IRWXG, uap->value,
1000205324Skib	    0, 1));
1001205324Skib}
1002180059Sjhb
1003205324Skibint
1004205324Skibfreebsd32_ksem_open(struct thread *td, struct freebsd32_ksem_open_args *uap)
1005205324Skib{
1006205324Skib
1007205324Skib	if ((uap->oflag & ~(O_CREAT | O_EXCL)) != 0)
1008205324Skib		return (EINVAL);
1009205324Skib	return (ksem_create(td, uap->name, uap->idp, uap->mode, uap->value,
1010205324Skib	    uap->oflag, 1));
1011205324Skib}
1012205324Skib
1013205324Skibint
1014205324Skibfreebsd32_ksem_timedwait(struct thread *td,
1015205324Skib    struct freebsd32_ksem_timedwait_args *uap)
1016205324Skib{
1017205324Skib	struct timespec32 abstime32;
1018205324Skib	struct timespec *ts, abstime;
1019205324Skib	int error;
1020205324Skib
1021205324Skib	/*
1022205324Skib	 * We allow a null timespec (wait forever).
1023205324Skib	 */
1024205324Skib	if (uap->abstime == NULL)
1025205324Skib		ts = NULL;
1026205324Skib	else {
1027205324Skib		error = copyin(uap->abstime, &abstime32, sizeof(abstime32));
1028205324Skib		if (error != 0)
1029205324Skib			return (error);
1030205324Skib		CP(abstime32, abstime, tv_sec);
1031205324Skib		CP(abstime32, abstime, tv_nsec);
1032205324Skib		if (abstime.tv_nsec >= 1000000000 || abstime.tv_nsec < 0)
1033205324Skib			return (EINVAL);
1034205324Skib		ts = &abstime;
1035205324Skib	}
1036205324Skib	return (kern_sem_wait(td, uap->id, 0, ts));
1037205324Skib}
1038205324Skib
1039205324Skibstatic struct syscall_helper_data ksem32_syscalls[] = {
1040205324Skib	SYSCALL32_INIT_HELPER(freebsd32_ksem_init),
1041205324Skib	SYSCALL32_INIT_HELPER(freebsd32_ksem_open),
1042225617Skmacy	SYSCALL32_INIT_HELPER_COMPAT(ksem_unlink),
1043225617Skmacy	SYSCALL32_INIT_HELPER_COMPAT(ksem_close),
1044225617Skmacy	SYSCALL32_INIT_HELPER_COMPAT(ksem_post),
1045225617Skmacy	SYSCALL32_INIT_HELPER_COMPAT(ksem_wait),
1046205324Skib	SYSCALL32_INIT_HELPER(freebsd32_ksem_timedwait),
1047225617Skmacy	SYSCALL32_INIT_HELPER_COMPAT(ksem_trywait),
1048225617Skmacy	SYSCALL32_INIT_HELPER_COMPAT(ksem_getvalue),
1049225617Skmacy	SYSCALL32_INIT_HELPER_COMPAT(ksem_destroy),
1050205324Skib	SYSCALL_INIT_LAST
1051205324Skib};
1052205324Skib#endif
1053205324Skib
1054180059Sjhbstatic int
1055180059Sjhbksem_module_init(void)
1056142498Srwatson{
1057180059Sjhb	int error;
1058142498Srwatson
1059180059Sjhb	mtx_init(&sem_lock, "sem", NULL, MTX_DEF);
1060180059Sjhb	mtx_init(&ksem_count_lock, "ksem count", NULL, MTX_DEF);
1061180059Sjhb	sx_init(&ksem_dict_lock, "ksem dictionary");
1062180059Sjhb	ksem_dictionary = hashinit(1024, M_KSEM, &ksem_hash);
1063215541Sjhb	p31b_setcfg(CTL_P1003_1B_SEMAPHORES, 200112L);
1064180059Sjhb	p31b_setcfg(CTL_P1003_1B_SEM_NSEMS_MAX, SEM_MAX);
1065180059Sjhb	p31b_setcfg(CTL_P1003_1B_SEM_VALUE_MAX, SEM_VALUE_MAX);
1066250223Sjhb	ksem_info = ksem_info_impl;
1067179054Srwatson
1068205324Skib	error = syscall_helper_register(ksem_syscalls);
1069205324Skib	if (error)
1070205324Skib		return (error);
1071205324Skib#ifdef COMPAT_FREEBSD32
1072205324Skib	error = syscall32_helper_register(ksem32_syscalls);
1073205324Skib	if (error)
1074205324Skib		return (error);
1075205324Skib#endif
1076180059Sjhb	return (0);
1077142498Srwatson}
1078142498Srwatson
1079142498Srwatsonstatic void
1080180059Sjhbksem_module_destroy(void)
1081103571Salfred{
1082161302Snetchild
1083205324Skib#ifdef COMPAT_FREEBSD32
1084205324Skib	syscall32_helper_unregister(ksem32_syscalls);
1085205324Skib#endif
1086205324Skib	syscall_helper_unregister(ksem_syscalls);
1087103571Salfred
1088250223Sjhb	ksem_info = NULL;
1089215541Sjhb	p31b_setcfg(CTL_P1003_1B_SEMAPHORES, 0);
1090180059Sjhb	hashdestroy(ksem_dictionary, M_KSEM, ksem_hash);
1091180059Sjhb	sx_destroy(&ksem_dict_lock);
1092180059Sjhb	mtx_destroy(&ksem_count_lock);
1093180059Sjhb	mtx_destroy(&sem_lock);
1094208731Skib	p31b_unsetcfg(CTL_P1003_1B_SEM_VALUE_MAX);
1095208731Skib	p31b_unsetcfg(CTL_P1003_1B_SEM_NSEMS_MAX);
1096103571Salfred}
1097103571Salfred
1098103571Salfredstatic int
1099103571Salfredsem_modload(struct module *module, int cmd, void *arg)
1100103571Salfred{
1101103571Salfred        int error = 0;
1102103571Salfred
1103103571Salfred        switch (cmd) {
1104103571Salfred        case MOD_LOAD:
1105180059Sjhb		error = ksem_module_init();
1106180059Sjhb		if (error)
1107180059Sjhb			ksem_module_destroy();
1108103571Salfred                break;
1109179054Srwatson
1110103571Salfred        case MOD_UNLOAD:
1111180059Sjhb		mtx_lock(&ksem_count_lock);
1112103571Salfred		if (nsems != 0) {
1113103571Salfred			error = EOPNOTSUPP;
1114180059Sjhb			mtx_unlock(&ksem_count_lock);
1115103571Salfred			break;
1116103571Salfred		}
1117180059Sjhb		ksem_dead = 1;
1118180059Sjhb		mtx_unlock(&ksem_count_lock);
1119180059Sjhb		ksem_module_destroy();
1120103571Salfred                break;
1121179054Srwatson
1122103571Salfred        case MOD_SHUTDOWN:
1123103571Salfred                break;
1124103571Salfred        default:
1125103571Salfred                error = EINVAL;
1126103571Salfred                break;
1127103571Salfred        }
1128103571Salfred        return (error);
1129103571Salfred}
1130103571Salfred
1131103571Salfredstatic moduledata_t sem_mod = {
1132103571Salfred        "sem",
1133103571Salfred        &sem_modload,
1134103571Salfred        NULL
1135103571Salfred};
1136103571Salfred
1137103571SalfredDECLARE_MODULE(sem, sem_mod, SI_SUB_SYSV_SEM, SI_ORDER_FIRST);
1138103571SalfredMODULE_VERSION(sem, 1);
1139