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