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