The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/uipc_sem.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2002 Alfred Perlstein <alfred@FreeBSD.org>
    3  * Copyright (c) 2003-2005 SPARTA, Inc.
    4  * Copyright (c) 2005 Robert N. M. Watson
    5  * All rights reserved.
    6  *
    7  * This software was developed for the FreeBSD Project in part by Network
    8  * Associates Laboratories, the Security Research Division of Network
    9  * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
   10  * as part of the DARPA CHATS research program.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31  * SUCH DAMAGE.
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __FBSDID("$FreeBSD: releng/10.0/sys/kern/uipc_sem.c 255219 2013-09-05 00:09:56Z pjd $");
   36 
   37 #include "opt_compat.h"
   38 #include "opt_posix.h"
   39 
   40 #include <sys/param.h>
   41 #include <sys/capability.h>
   42 #include <sys/condvar.h>
   43 #include <sys/fcntl.h>
   44 #include <sys/file.h>
   45 #include <sys/filedesc.h>
   46 #include <sys/fnv_hash.h>
   47 #include <sys/kernel.h>
   48 #include <sys/ksem.h>
   49 #include <sys/lock.h>
   50 #include <sys/malloc.h>
   51 #include <sys/module.h>
   52 #include <sys/mutex.h>
   53 #include <sys/priv.h>
   54 #include <sys/proc.h>
   55 #include <sys/posix4.h>
   56 #include <sys/_semaphore.h>
   57 #include <sys/stat.h>
   58 #include <sys/syscall.h>
   59 #include <sys/syscallsubr.h>
   60 #include <sys/sysctl.h>
   61 #include <sys/sysent.h>
   62 #include <sys/sysproto.h>
   63 #include <sys/systm.h>
   64 #include <sys/sx.h>
   65 #include <sys/vnode.h>
   66 
   67 #include <security/mac/mac_framework.h>
   68 
   69 FEATURE(p1003_1b_semaphores, "POSIX P1003.1B semaphores support");
   70 /*
   71  * TODO
   72  *
   73  * - Resource limits?
   74  * - Replace global sem_lock with mtx_pool locks?
   75  * - Add a MAC check_create() hook for creating new named semaphores.
   76  */
   77 
   78 #ifndef SEM_MAX
   79 #define SEM_MAX 30
   80 #endif
   81 
   82 #ifdef SEM_DEBUG
   83 #define DP(x)   printf x
   84 #else
   85 #define DP(x)
   86 #endif
   87 
   88 struct ksem_mapping {
   89         char            *km_path;
   90         Fnv32_t         km_fnv;
   91         struct ksem     *km_ksem;
   92         LIST_ENTRY(ksem_mapping) km_link;
   93 };
   94 
   95 static MALLOC_DEFINE(M_KSEM, "ksem", "semaphore file descriptor");
   96 static LIST_HEAD(, ksem_mapping) *ksem_dictionary;
   97 static struct sx ksem_dict_lock;
   98 static struct mtx ksem_count_lock;
   99 static struct mtx sem_lock;
  100 static u_long ksem_hash;
  101 static int ksem_dead;
  102 
  103 #define KSEM_HASH(fnv)  (&ksem_dictionary[(fnv) & ksem_hash])
  104 
  105 static int nsems = 0;
  106 SYSCTL_DECL(_p1003_1b);
  107 SYSCTL_INT(_p1003_1b, OID_AUTO, nsems, CTLFLAG_RD, &nsems, 0,
  108     "Number of active kernel POSIX semaphores");
  109 
  110 static int      kern_sem_wait(struct thread *td, semid_t id, int tryflag,
  111                     struct timespec *abstime);
  112 static int      ksem_access(struct ksem *ks, struct ucred *ucred);
  113 static struct ksem *ksem_alloc(struct ucred *ucred, mode_t mode,
  114                     unsigned int value);
  115 static int      ksem_create(struct thread *td, const char *path,
  116                     semid_t *semidp, mode_t mode, unsigned int value,
  117                     int flags, int compat32);
  118 static void     ksem_drop(struct ksem *ks);
  119 static int      ksem_get(struct thread *td, semid_t id, cap_rights_t *rightsp,
  120     struct file **fpp);
  121 static struct ksem *ksem_hold(struct ksem *ks);
  122 static void     ksem_insert(char *path, Fnv32_t fnv, struct ksem *ks);
  123 static struct ksem *ksem_lookup(char *path, Fnv32_t fnv);
  124 static void     ksem_module_destroy(void);
  125 static int      ksem_module_init(void);
  126 static int      ksem_remove(char *path, Fnv32_t fnv, struct ucred *ucred);
  127 static int      sem_modload(struct module *module, int cmd, void *arg);
  128 
  129 static fo_rdwr_t        ksem_read;
  130 static fo_rdwr_t        ksem_write;
  131 static fo_truncate_t    ksem_truncate;
  132 static fo_ioctl_t       ksem_ioctl;
  133 static fo_poll_t        ksem_poll;
  134 static fo_kqfilter_t    ksem_kqfilter;
  135 static fo_stat_t        ksem_stat;
  136 static fo_close_t       ksem_closef;
  137 static fo_chmod_t       ksem_chmod;
  138 static fo_chown_t       ksem_chown;
  139 
  140 /* File descriptor operations. */
  141 static struct fileops ksem_ops = {
  142         .fo_read = ksem_read,
  143         .fo_write = ksem_write,
  144         .fo_truncate = ksem_truncate,
  145         .fo_ioctl = ksem_ioctl,
  146         .fo_poll = ksem_poll,
  147         .fo_kqfilter = ksem_kqfilter,
  148         .fo_stat = ksem_stat,
  149         .fo_close = ksem_closef,
  150         .fo_chmod = ksem_chmod,
  151         .fo_chown = ksem_chown,
  152         .fo_sendfile = invfo_sendfile,
  153         .fo_flags = DFLAG_PASSABLE
  154 };
  155 
  156 FEATURE(posix_sem, "POSIX semaphores");
  157 
  158 static int
  159 ksem_read(struct file *fp, struct uio *uio, struct ucred *active_cred,
  160     int flags, struct thread *td)
  161 {
  162 
  163         return (EOPNOTSUPP);
  164 }
  165 
  166 static int
  167 ksem_write(struct file *fp, struct uio *uio, struct ucred *active_cred,
  168     int flags, struct thread *td)
  169 {
  170 
  171         return (EOPNOTSUPP);
  172 }
  173 
  174 static int
  175 ksem_truncate(struct file *fp, off_t length, struct ucred *active_cred,
  176     struct thread *td)
  177 {
  178 
  179         return (EINVAL);
  180 }
  181 
  182 static int
  183 ksem_ioctl(struct file *fp, u_long com, void *data,
  184     struct ucred *active_cred, struct thread *td)
  185 {
  186 
  187         return (EOPNOTSUPP);
  188 }
  189 
  190 static int
  191 ksem_poll(struct file *fp, int events, struct ucred *active_cred,
  192     struct thread *td)
  193 {
  194 
  195         return (EOPNOTSUPP);
  196 }
  197 
  198 static int
  199 ksem_kqfilter(struct file *fp, struct knote *kn)
  200 {
  201 
  202         return (EOPNOTSUPP);
  203 }
  204 
  205 static int
  206 ksem_stat(struct file *fp, struct stat *sb, struct ucred *active_cred,
  207     struct thread *td)
  208 {
  209         struct ksem *ks;
  210 #ifdef MAC
  211         int error;
  212 #endif
  213 
  214         ks = fp->f_data;
  215 
  216 #ifdef MAC
  217         error = mac_posixsem_check_stat(active_cred, fp->f_cred, ks);
  218         if (error)
  219                 return (error);
  220 #endif
  221         
  222         /*
  223          * Attempt to return sanish values for fstat() on a semaphore
  224          * file descriptor.
  225          */
  226         bzero(sb, sizeof(*sb));
  227 
  228         mtx_lock(&sem_lock);
  229         sb->st_atim = ks->ks_atime;
  230         sb->st_ctim = ks->ks_ctime;
  231         sb->st_mtim = ks->ks_mtime;
  232         sb->st_birthtim = ks->ks_birthtime;
  233         sb->st_uid = ks->ks_uid;
  234         sb->st_gid = ks->ks_gid;
  235         sb->st_mode = S_IFREG | ks->ks_mode;            /* XXX */
  236         mtx_unlock(&sem_lock);
  237 
  238         return (0);
  239 }
  240 
  241 static int
  242 ksem_chmod(struct file *fp, mode_t mode, struct ucred *active_cred,
  243     struct thread *td)
  244 {
  245         struct ksem *ks;
  246         int error;
  247 
  248         error = 0;
  249         ks = fp->f_data;
  250         mtx_lock(&sem_lock);
  251 #ifdef MAC
  252         error = mac_posixsem_check_setmode(active_cred, ks, mode);
  253         if (error != 0)
  254                 goto out;
  255 #endif
  256         error = vaccess(VREG, ks->ks_mode, ks->ks_uid, ks->ks_gid, VADMIN,
  257             active_cred, NULL);
  258         if (error != 0)
  259                 goto out;
  260         ks->ks_mode = mode & ACCESSPERMS;
  261 out:
  262         mtx_unlock(&sem_lock);
  263         return (error);
  264 }
  265 
  266 static int
  267 ksem_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred,
  268     struct thread *td)
  269 {
  270         struct ksem *ks;
  271         int error;
  272 
  273         error = 0;
  274         ks = fp->f_data;
  275         mtx_lock(&sem_lock);
  276 #ifdef MAC
  277         error = mac_posixsem_check_setowner(active_cred, ks, uid, gid);
  278         if (error != 0)
  279                 goto out;
  280 #endif
  281         if (uid == (uid_t)-1)
  282                 uid = ks->ks_uid;
  283         if (gid == (gid_t)-1)
  284                  gid = ks->ks_gid;
  285         if (((uid != ks->ks_uid && uid != active_cred->cr_uid) ||
  286             (gid != ks->ks_gid && !groupmember(gid, active_cred))) &&
  287             (error = priv_check_cred(active_cred, PRIV_VFS_CHOWN, 0)))
  288                 goto out;
  289         ks->ks_uid = uid;
  290         ks->ks_gid = gid;
  291 out:
  292         mtx_unlock(&sem_lock);
  293         return (error);
  294 }
  295 
  296 static int
  297 ksem_closef(struct file *fp, struct thread *td)
  298 {
  299         struct ksem *ks;
  300 
  301         ks = fp->f_data;
  302         fp->f_data = NULL;
  303         ksem_drop(ks);
  304 
  305         return (0);
  306 }
  307 
  308 /*
  309  * ksem object management including creation and reference counting
  310  * routines.
  311  */
  312 static struct ksem *
  313 ksem_alloc(struct ucred *ucred, mode_t mode, unsigned int value)
  314 {
  315         struct ksem *ks;
  316 
  317         mtx_lock(&ksem_count_lock);
  318         if (nsems == p31b_getcfg(CTL_P1003_1B_SEM_NSEMS_MAX) || ksem_dead) {
  319                 mtx_unlock(&ksem_count_lock);
  320                 return (NULL);
  321         }
  322         nsems++;
  323         mtx_unlock(&ksem_count_lock);
  324         ks = malloc(sizeof(*ks), M_KSEM, M_WAITOK | M_ZERO);
  325         ks->ks_uid = ucred->cr_uid;
  326         ks->ks_gid = ucred->cr_gid;
  327         ks->ks_mode = mode;
  328         ks->ks_value = value;
  329         cv_init(&ks->ks_cv, "ksem");
  330         vfs_timestamp(&ks->ks_birthtime);
  331         ks->ks_atime = ks->ks_mtime = ks->ks_ctime = ks->ks_birthtime;
  332         refcount_init(&ks->ks_ref, 1);
  333 #ifdef MAC
  334         mac_posixsem_init(ks);
  335         mac_posixsem_create(ucred, ks);
  336 #endif
  337 
  338         return (ks);
  339 }
  340 
  341 static struct ksem *
  342 ksem_hold(struct ksem *ks)
  343 {
  344 
  345         refcount_acquire(&ks->ks_ref);
  346         return (ks);
  347 }
  348 
  349 static void
  350 ksem_drop(struct ksem *ks)
  351 {
  352 
  353         if (refcount_release(&ks->ks_ref)) {
  354 #ifdef MAC
  355                 mac_posixsem_destroy(ks);
  356 #endif
  357                 cv_destroy(&ks->ks_cv);
  358                 free(ks, M_KSEM);
  359                 mtx_lock(&ksem_count_lock);
  360                 nsems--;
  361                 mtx_unlock(&ksem_count_lock);
  362         }
  363 }
  364 
  365 /*
  366  * Determine if the credentials have sufficient permissions for read
  367  * and write access.
  368  */
  369 static int
  370 ksem_access(struct ksem *ks, struct ucred *ucred)
  371 {
  372         int error;
  373 
  374         error = vaccess(VREG, ks->ks_mode, ks->ks_uid, ks->ks_gid,
  375             VREAD | VWRITE, ucred, NULL);
  376         if (error)
  377                 error = priv_check_cred(ucred, PRIV_SEM_WRITE, 0);
  378         return (error);
  379 }
  380 
  381 /*
  382  * Dictionary management.  We maintain an in-kernel dictionary to map
  383  * paths to semaphore objects.  We use the FNV hash on the path to
  384  * store the mappings in a hash table.
  385  */
  386 static struct ksem *
  387 ksem_lookup(char *path, Fnv32_t fnv)
  388 {
  389         struct ksem_mapping *map;
  390 
  391         LIST_FOREACH(map, KSEM_HASH(fnv), km_link) {
  392                 if (map->km_fnv != fnv)
  393                         continue;
  394                 if (strcmp(map->km_path, path) == 0)
  395                         return (map->km_ksem);
  396         }
  397 
  398         return (NULL);
  399 }
  400 
  401 static void
  402 ksem_insert(char *path, Fnv32_t fnv, struct ksem *ks)
  403 {
  404         struct ksem_mapping *map;
  405 
  406         map = malloc(sizeof(struct ksem_mapping), M_KSEM, M_WAITOK);
  407         map->km_path = path;
  408         map->km_fnv = fnv;
  409         map->km_ksem = ksem_hold(ks);
  410         ks->ks_path = path;
  411         LIST_INSERT_HEAD(KSEM_HASH(fnv), map, km_link);
  412 }
  413 
  414 static int
  415 ksem_remove(char *path, Fnv32_t fnv, struct ucred *ucred)
  416 {
  417         struct ksem_mapping *map;
  418         int error;
  419 
  420         LIST_FOREACH(map, KSEM_HASH(fnv), km_link) {
  421                 if (map->km_fnv != fnv)
  422                         continue;
  423                 if (strcmp(map->km_path, path) == 0) {
  424 #ifdef MAC
  425                         error = mac_posixsem_check_unlink(ucred, map->km_ksem);
  426                         if (error)
  427                                 return (error);
  428 #endif
  429                         error = ksem_access(map->km_ksem, ucred);
  430                         if (error)
  431                                 return (error);
  432                         map->km_ksem->ks_path = NULL;
  433                         LIST_REMOVE(map, km_link);
  434                         ksem_drop(map->km_ksem);
  435                         free(map->km_path, M_KSEM);
  436                         free(map, M_KSEM);
  437                         return (0);
  438                 }
  439         }
  440 
  441         return (ENOENT);
  442 }
  443 
  444 static void
  445 ksem_info_impl(struct ksem *ks, char *path, size_t size, uint32_t *value)
  446 {
  447 
  448         if (ks->ks_path == NULL)
  449                 return;
  450         sx_slock(&ksem_dict_lock);
  451         if (ks->ks_path != NULL)
  452                 strlcpy(path, ks->ks_path, size);
  453         if (value != NULL)
  454                 *value = ks->ks_value;
  455         sx_sunlock(&ksem_dict_lock);
  456 }
  457 
  458 static int
  459 ksem_create_copyout_semid(struct thread *td, semid_t *semidp, int fd,
  460     int compat32)
  461 {
  462         semid_t semid;
  463 #ifdef COMPAT_FREEBSD32
  464         int32_t semid32;
  465 #endif
  466         void *ptr;
  467         size_t ptrs;
  468 
  469 #ifdef COMPAT_FREEBSD32
  470         if (compat32) {
  471                 semid32 = fd;
  472                 ptr = &semid32;
  473                 ptrs = sizeof(semid32);
  474         } else {
  475 #endif
  476                 semid = fd;
  477                 ptr = &semid;
  478                 ptrs = sizeof(semid);
  479                 compat32 = 0; /* silence gcc */
  480 #ifdef COMPAT_FREEBSD32
  481         }
  482 #endif
  483 
  484         return (copyout(ptr, semidp, ptrs));
  485 }
  486 
  487 /* Other helper routines. */
  488 static int
  489 ksem_create(struct thread *td, const char *name, semid_t *semidp, mode_t mode,
  490     unsigned int value, int flags, int compat32)
  491 {
  492         struct filedesc *fdp;
  493         struct ksem *ks;
  494         struct file *fp;
  495         char *path;
  496         Fnv32_t fnv;
  497         int error, fd;
  498 
  499         if (value > SEM_VALUE_MAX)
  500                 return (EINVAL);
  501 
  502         fdp = td->td_proc->p_fd;
  503         mode = (mode & ~fdp->fd_cmask) & ACCESSPERMS;
  504         error = falloc(td, &fp, &fd, O_CLOEXEC);
  505         if (error) {
  506                 if (name == NULL)
  507                         error = ENOSPC;
  508                 return (error);
  509         }
  510 
  511         /*
  512          * Go ahead and copyout the file descriptor now.  This is a bit
  513          * premature, but it is a lot easier to handle errors as opposed
  514          * to later when we've possibly created a new semaphore, etc.
  515          */
  516         error = ksem_create_copyout_semid(td, semidp, fd, compat32);
  517         if (error) {
  518                 fdclose(fdp, fp, fd, td);
  519                 fdrop(fp, td);
  520                 return (error);
  521         }
  522 
  523         if (name == NULL) {
  524                 /* Create an anonymous semaphore. */
  525                 ks = ksem_alloc(td->td_ucred, mode, value);
  526                 if (ks == NULL)
  527                         error = ENOSPC;
  528                 else
  529                         ks->ks_flags |= KS_ANONYMOUS;
  530         } else {
  531                 path = malloc(MAXPATHLEN, M_KSEM, M_WAITOK);
  532                 error = copyinstr(name, path, MAXPATHLEN, NULL);
  533 
  534                 /* Require paths to start with a '/' character. */
  535                 if (error == 0 && path[0] != '/')
  536                         error = EINVAL;
  537                 if (error) {
  538                         fdclose(fdp, fp, fd, td);
  539                         fdrop(fp, td);
  540                         free(path, M_KSEM);
  541                         return (error);
  542                 }
  543 
  544                 fnv = fnv_32_str(path, FNV1_32_INIT);
  545                 sx_xlock(&ksem_dict_lock);
  546                 ks = ksem_lookup(path, fnv);
  547                 if (ks == NULL) {
  548                         /* Object does not exist, create it if requested. */
  549                         if (flags & O_CREAT) {
  550                                 ks = ksem_alloc(td->td_ucred, mode, value);
  551                                 if (ks == NULL)
  552                                         error = ENFILE;
  553                                 else {
  554                                         ksem_insert(path, fnv, ks);
  555                                         path = NULL;
  556                                 }
  557                         } else
  558                                 error = ENOENT;
  559                 } else {
  560                         /*
  561                          * Object already exists, obtain a new
  562                          * reference if requested and permitted.
  563                          */
  564                         if ((flags & (O_CREAT | O_EXCL)) ==
  565                             (O_CREAT | O_EXCL))
  566                                 error = EEXIST;
  567                         else {
  568 #ifdef MAC
  569                                 error = mac_posixsem_check_open(td->td_ucred,
  570                                     ks);
  571                                 if (error == 0)
  572 #endif
  573                                 error = ksem_access(ks, td->td_ucred);
  574                         }
  575                         if (error == 0)
  576                                 ksem_hold(ks);
  577 #ifdef INVARIANTS
  578                         else
  579                                 ks = NULL;
  580 #endif
  581                 }
  582                 sx_xunlock(&ksem_dict_lock);
  583                 if (path)
  584                         free(path, M_KSEM);
  585         }
  586 
  587         if (error) {
  588                 KASSERT(ks == NULL, ("ksem_create error with a ksem"));
  589                 fdclose(fdp, fp, fd, td);
  590                 fdrop(fp, td);
  591                 return (error);
  592         }
  593         KASSERT(ks != NULL, ("ksem_create w/o a ksem"));
  594 
  595         finit(fp, FREAD | FWRITE, DTYPE_SEM, ks, &ksem_ops);
  596 
  597         fdrop(fp, td);
  598 
  599         return (0);
  600 }
  601 
  602 static int
  603 ksem_get(struct thread *td, semid_t id, cap_rights_t *rightsp,
  604     struct file **fpp)
  605 {
  606         struct ksem *ks;
  607         struct file *fp;
  608         int error;
  609 
  610         error = fget(td, id, rightsp, &fp);
  611         if (error)
  612                 return (EINVAL);
  613         if (fp->f_type != DTYPE_SEM) {
  614                 fdrop(fp, td);
  615                 return (EINVAL);
  616         }
  617         ks = fp->f_data;
  618         if (ks->ks_flags & KS_DEAD) {
  619                 fdrop(fp, td);
  620                 return (EINVAL);
  621         }
  622         *fpp = fp;
  623         return (0);
  624 }
  625 
  626 /* System calls. */
  627 #ifndef _SYS_SYSPROTO_H_
  628 struct ksem_init_args {
  629         unsigned int    value;
  630         semid_t         *idp;
  631 };
  632 #endif
  633 int
  634 sys_ksem_init(struct thread *td, struct ksem_init_args *uap)
  635 {
  636 
  637         return (ksem_create(td, NULL, uap->idp, S_IRWXU | S_IRWXG, uap->value,
  638             0, 0));
  639 }
  640 
  641 #ifndef _SYS_SYSPROTO_H_
  642 struct ksem_open_args {
  643         char            *name;
  644         int             oflag;
  645         mode_t          mode;
  646         unsigned int    value;
  647         semid_t         *idp;   
  648 };
  649 #endif
  650 int
  651 sys_ksem_open(struct thread *td, struct ksem_open_args *uap)
  652 {
  653 
  654         DP((">>> ksem_open start, pid=%d\n", (int)td->td_proc->p_pid));
  655 
  656         if ((uap->oflag & ~(O_CREAT | O_EXCL)) != 0)
  657                 return (EINVAL);
  658         return (ksem_create(td, uap->name, uap->idp, uap->mode, uap->value,
  659             uap->oflag, 0));
  660 }
  661 
  662 #ifndef _SYS_SYSPROTO_H_
  663 struct ksem_unlink_args {
  664         char            *name;
  665 };
  666 #endif
  667 int
  668 sys_ksem_unlink(struct thread *td, struct ksem_unlink_args *uap)
  669 {
  670         char *path;
  671         Fnv32_t fnv;
  672         int error;
  673 
  674         path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
  675         error = copyinstr(uap->name, path, MAXPATHLEN, NULL);
  676         if (error) {
  677                 free(path, M_TEMP);
  678                 return (error);
  679         }
  680 
  681         fnv = fnv_32_str(path, FNV1_32_INIT);
  682         sx_xlock(&ksem_dict_lock);
  683         error = ksem_remove(path, fnv, td->td_ucred);
  684         sx_xunlock(&ksem_dict_lock);
  685         free(path, M_TEMP);
  686 
  687         return (error);
  688 }
  689 
  690 #ifndef _SYS_SYSPROTO_H_
  691 struct ksem_close_args {
  692         semid_t         id;
  693 };
  694 #endif
  695 int
  696 sys_ksem_close(struct thread *td, struct ksem_close_args *uap)
  697 {
  698         struct ksem *ks;
  699         struct file *fp;
  700         int error;
  701 
  702         /* No capability rights required to close a semaphore. */
  703         error = ksem_get(td, uap->id, 0, &fp);
  704         if (error)
  705                 return (error);
  706         ks = fp->f_data;
  707         if (ks->ks_flags & KS_ANONYMOUS) {
  708                 fdrop(fp, td);
  709                 return (EINVAL);
  710         }
  711         error = kern_close(td, uap->id);
  712         fdrop(fp, td);
  713         return (error);
  714 }
  715 
  716 #ifndef _SYS_SYSPROTO_H_
  717 struct ksem_post_args {
  718         semid_t id;
  719 };
  720 #endif
  721 int
  722 sys_ksem_post(struct thread *td, struct ksem_post_args *uap)
  723 {
  724         cap_rights_t rights;
  725         struct file *fp;
  726         struct ksem *ks;
  727         int error;
  728 
  729         error = ksem_get(td, uap->id,
  730             cap_rights_init(&rights, CAP_SEM_POST), &fp);
  731         if (error)
  732                 return (error);
  733         ks = fp->f_data;
  734 
  735         mtx_lock(&sem_lock);
  736 #ifdef MAC
  737         error = mac_posixsem_check_post(td->td_ucred, fp->f_cred, ks);
  738         if (error)
  739                 goto err;
  740 #endif
  741         if (ks->ks_value == SEM_VALUE_MAX) {
  742                 error = EOVERFLOW;
  743                 goto err;
  744         }
  745         ++ks->ks_value;
  746         if (ks->ks_waiters > 0)
  747                 cv_signal(&ks->ks_cv);
  748         error = 0;
  749         vfs_timestamp(&ks->ks_ctime);
  750 err:
  751         mtx_unlock(&sem_lock);
  752         fdrop(fp, td);
  753         return (error);
  754 }
  755 
  756 #ifndef _SYS_SYSPROTO_H_
  757 struct ksem_wait_args {
  758         semid_t         id;
  759 };
  760 #endif
  761 int
  762 sys_ksem_wait(struct thread *td, struct ksem_wait_args *uap)
  763 {
  764 
  765         return (kern_sem_wait(td, uap->id, 0, NULL));
  766 }
  767 
  768 #ifndef _SYS_SYSPROTO_H_
  769 struct ksem_timedwait_args {
  770         semid_t         id;
  771         const struct timespec *abstime;
  772 };
  773 #endif
  774 int
  775 sys_ksem_timedwait(struct thread *td, struct ksem_timedwait_args *uap)
  776 {
  777         struct timespec abstime;
  778         struct timespec *ts;
  779         int error;
  780 
  781         /*
  782          * We allow a null timespec (wait forever).
  783          */
  784         if (uap->abstime == NULL)
  785                 ts = NULL;
  786         else {
  787                 error = copyin(uap->abstime, &abstime, sizeof(abstime));
  788                 if (error != 0)
  789                         return (error);
  790                 if (abstime.tv_nsec >= 1000000000 || abstime.tv_nsec < 0)
  791                         return (EINVAL);
  792                 ts = &abstime;
  793         }
  794         return (kern_sem_wait(td, uap->id, 0, ts));
  795 }
  796 
  797 #ifndef _SYS_SYSPROTO_H_
  798 struct ksem_trywait_args {
  799         semid_t         id;
  800 };
  801 #endif
  802 int
  803 sys_ksem_trywait(struct thread *td, struct ksem_trywait_args *uap)
  804 {
  805 
  806         return (kern_sem_wait(td, uap->id, 1, NULL));
  807 }
  808 
  809 static int
  810 kern_sem_wait(struct thread *td, semid_t id, int tryflag,
  811     struct timespec *abstime)
  812 {
  813         struct timespec ts1, ts2;
  814         struct timeval tv;
  815         cap_rights_t rights;
  816         struct file *fp;
  817         struct ksem *ks;
  818         int error;
  819 
  820         DP((">>> kern_sem_wait entered! pid=%d\n", (int)td->td_proc->p_pid));
  821         error = ksem_get(td, id, cap_rights_init(&rights, CAP_SEM_WAIT), &fp);
  822         if (error)
  823                 return (error);
  824         ks = fp->f_data;
  825         mtx_lock(&sem_lock);
  826         DP((">>> kern_sem_wait critical section entered! pid=%d\n",
  827             (int)td->td_proc->p_pid));
  828 #ifdef MAC
  829         error = mac_posixsem_check_wait(td->td_ucred, fp->f_cred, ks);
  830         if (error) {
  831                 DP(("kern_sem_wait mac failed\n"));
  832                 goto err;
  833         }
  834 #endif
  835         DP(("kern_sem_wait value = %d, tryflag %d\n", ks->ks_value, tryflag));
  836         vfs_timestamp(&ks->ks_atime);
  837         while (ks->ks_value == 0) {
  838                 ks->ks_waiters++;
  839                 if (tryflag != 0)
  840                         error = EAGAIN;
  841                 else if (abstime == NULL)
  842                         error = cv_wait_sig(&ks->ks_cv, &sem_lock);
  843                 else {
  844                         for (;;) {
  845                                 ts1 = *abstime;
  846                                 getnanotime(&ts2);
  847                                 timespecsub(&ts1, &ts2);
  848                                 TIMESPEC_TO_TIMEVAL(&tv, &ts1);
  849                                 if (tv.tv_sec < 0) {
  850                                         error = ETIMEDOUT;
  851                                         break;
  852                                 }
  853                                 error = cv_timedwait_sig(&ks->ks_cv,
  854                                     &sem_lock, tvtohz(&tv));
  855                                 if (error != EWOULDBLOCK)
  856                                         break;
  857                         }
  858                 }
  859                 ks->ks_waiters--;
  860                 if (error)
  861                         goto err;
  862         }
  863         ks->ks_value--;
  864         DP(("kern_sem_wait value post-decrement = %d\n", ks->ks_value));
  865         error = 0;
  866 err:
  867         mtx_unlock(&sem_lock);
  868         fdrop(fp, td);
  869         DP(("<<< kern_sem_wait leaving, pid=%d, error = %d\n",
  870             (int)td->td_proc->p_pid, error));
  871         return (error);
  872 }
  873 
  874 #ifndef _SYS_SYSPROTO_H_
  875 struct ksem_getvalue_args {
  876         semid_t         id;
  877         int             *val;
  878 };
  879 #endif
  880 int
  881 sys_ksem_getvalue(struct thread *td, struct ksem_getvalue_args *uap)
  882 {
  883         cap_rights_t rights;
  884         struct file *fp;
  885         struct ksem *ks;
  886         int error, val;
  887 
  888         error = ksem_get(td, uap->id,
  889             cap_rights_init(&rights, CAP_SEM_GETVALUE), &fp);
  890         if (error)
  891                 return (error);
  892         ks = fp->f_data;
  893 
  894         mtx_lock(&sem_lock);
  895 #ifdef MAC
  896         error = mac_posixsem_check_getvalue(td->td_ucred, fp->f_cred, ks);
  897         if (error) {
  898                 mtx_unlock(&sem_lock);
  899                 fdrop(fp, td);
  900                 return (error);
  901         }
  902 #endif
  903         val = ks->ks_value;
  904         vfs_timestamp(&ks->ks_atime);
  905         mtx_unlock(&sem_lock);
  906         fdrop(fp, td);
  907         error = copyout(&val, uap->val, sizeof(val));
  908         return (error);
  909 }
  910 
  911 #ifndef _SYS_SYSPROTO_H_
  912 struct ksem_destroy_args {
  913         semid_t         id;
  914 };
  915 #endif
  916 int
  917 sys_ksem_destroy(struct thread *td, struct ksem_destroy_args *uap)
  918 {
  919         struct file *fp;
  920         struct ksem *ks;
  921         int error;
  922 
  923         /* No capability rights required to close a semaphore. */
  924         error = ksem_get(td, uap->id, 0, &fp);
  925         if (error)
  926                 return (error);
  927         ks = fp->f_data;
  928         if (!(ks->ks_flags & KS_ANONYMOUS)) {
  929                 fdrop(fp, td);
  930                 return (EINVAL);
  931         }
  932         mtx_lock(&sem_lock);
  933         if (ks->ks_waiters != 0) {
  934                 mtx_unlock(&sem_lock);
  935                 error = EBUSY;
  936                 goto err;
  937         }
  938         ks->ks_flags |= KS_DEAD;
  939         mtx_unlock(&sem_lock);
  940 
  941         error = kern_close(td, uap->id);
  942 err:
  943         fdrop(fp, td);
  944         return (error);
  945 }
  946 
  947 static struct syscall_helper_data ksem_syscalls[] = {
  948         SYSCALL_INIT_HELPER(ksem_init),
  949         SYSCALL_INIT_HELPER(ksem_open),
  950         SYSCALL_INIT_HELPER(ksem_unlink),
  951         SYSCALL_INIT_HELPER(ksem_close),
  952         SYSCALL_INIT_HELPER(ksem_post),
  953         SYSCALL_INIT_HELPER(ksem_wait),
  954         SYSCALL_INIT_HELPER(ksem_timedwait),
  955         SYSCALL_INIT_HELPER(ksem_trywait),
  956         SYSCALL_INIT_HELPER(ksem_getvalue),
  957         SYSCALL_INIT_HELPER(ksem_destroy),
  958         SYSCALL_INIT_LAST
  959 };
  960 
  961 #ifdef COMPAT_FREEBSD32
  962 #include <compat/freebsd32/freebsd32.h>
  963 #include <compat/freebsd32/freebsd32_proto.h>
  964 #include <compat/freebsd32/freebsd32_signal.h>
  965 #include <compat/freebsd32/freebsd32_syscall.h>
  966 #include <compat/freebsd32/freebsd32_util.h>
  967 
  968 int
  969 freebsd32_ksem_init(struct thread *td, struct freebsd32_ksem_init_args *uap)
  970 {
  971 
  972         return (ksem_create(td, NULL, uap->idp, S_IRWXU | S_IRWXG, uap->value,
  973             0, 1));
  974 }
  975 
  976 int
  977 freebsd32_ksem_open(struct thread *td, struct freebsd32_ksem_open_args *uap)
  978 {
  979 
  980         if ((uap->oflag & ~(O_CREAT | O_EXCL)) != 0)
  981                 return (EINVAL);
  982         return (ksem_create(td, uap->name, uap->idp, uap->mode, uap->value,
  983             uap->oflag, 1));
  984 }
  985 
  986 int
  987 freebsd32_ksem_timedwait(struct thread *td,
  988     struct freebsd32_ksem_timedwait_args *uap)
  989 {
  990         struct timespec32 abstime32;
  991         struct timespec *ts, abstime;
  992         int error;
  993 
  994         /*
  995          * We allow a null timespec (wait forever).
  996          */
  997         if (uap->abstime == NULL)
  998                 ts = NULL;
  999         else {
 1000                 error = copyin(uap->abstime, &abstime32, sizeof(abstime32));
 1001                 if (error != 0)
 1002                         return (error);
 1003                 CP(abstime32, abstime, tv_sec);
 1004                 CP(abstime32, abstime, tv_nsec);
 1005                 if (abstime.tv_nsec >= 1000000000 || abstime.tv_nsec < 0)
 1006                         return (EINVAL);
 1007                 ts = &abstime;
 1008         }
 1009         return (kern_sem_wait(td, uap->id, 0, ts));
 1010 }
 1011 
 1012 static struct syscall_helper_data ksem32_syscalls[] = {
 1013         SYSCALL32_INIT_HELPER(freebsd32_ksem_init),
 1014         SYSCALL32_INIT_HELPER(freebsd32_ksem_open),
 1015         SYSCALL32_INIT_HELPER_COMPAT(ksem_unlink),
 1016         SYSCALL32_INIT_HELPER_COMPAT(ksem_close),
 1017         SYSCALL32_INIT_HELPER_COMPAT(ksem_post),
 1018         SYSCALL32_INIT_HELPER_COMPAT(ksem_wait),
 1019         SYSCALL32_INIT_HELPER(freebsd32_ksem_timedwait),
 1020         SYSCALL32_INIT_HELPER_COMPAT(ksem_trywait),
 1021         SYSCALL32_INIT_HELPER_COMPAT(ksem_getvalue),
 1022         SYSCALL32_INIT_HELPER_COMPAT(ksem_destroy),
 1023         SYSCALL_INIT_LAST
 1024 };
 1025 #endif
 1026 
 1027 static int
 1028 ksem_module_init(void)
 1029 {
 1030         int error;
 1031 
 1032         mtx_init(&sem_lock, "sem", NULL, MTX_DEF);
 1033         mtx_init(&ksem_count_lock, "ksem count", NULL, MTX_DEF);
 1034         sx_init(&ksem_dict_lock, "ksem dictionary");
 1035         ksem_dictionary = hashinit(1024, M_KSEM, &ksem_hash);
 1036         p31b_setcfg(CTL_P1003_1B_SEMAPHORES, 200112L);
 1037         p31b_setcfg(CTL_P1003_1B_SEM_NSEMS_MAX, SEM_MAX);
 1038         p31b_setcfg(CTL_P1003_1B_SEM_VALUE_MAX, SEM_VALUE_MAX);
 1039         ksem_info = ksem_info_impl;
 1040 
 1041         error = syscall_helper_register(ksem_syscalls);
 1042         if (error)
 1043                 return (error);
 1044 #ifdef COMPAT_FREEBSD32
 1045         error = syscall32_helper_register(ksem32_syscalls);
 1046         if (error)
 1047                 return (error);
 1048 #endif
 1049         return (0);
 1050 }
 1051 
 1052 static void
 1053 ksem_module_destroy(void)
 1054 {
 1055 
 1056 #ifdef COMPAT_FREEBSD32
 1057         syscall32_helper_unregister(ksem32_syscalls);
 1058 #endif
 1059         syscall_helper_unregister(ksem_syscalls);
 1060 
 1061         ksem_info = NULL;
 1062         p31b_setcfg(CTL_P1003_1B_SEMAPHORES, 0);
 1063         hashdestroy(ksem_dictionary, M_KSEM, ksem_hash);
 1064         sx_destroy(&ksem_dict_lock);
 1065         mtx_destroy(&ksem_count_lock);
 1066         mtx_destroy(&sem_lock);
 1067         p31b_unsetcfg(CTL_P1003_1B_SEM_VALUE_MAX);
 1068         p31b_unsetcfg(CTL_P1003_1B_SEM_NSEMS_MAX);
 1069 }
 1070 
 1071 static int
 1072 sem_modload(struct module *module, int cmd, void *arg)
 1073 {
 1074         int error = 0;
 1075 
 1076         switch (cmd) {
 1077         case MOD_LOAD:
 1078                 error = ksem_module_init();
 1079                 if (error)
 1080                         ksem_module_destroy();
 1081                 break;
 1082 
 1083         case MOD_UNLOAD:
 1084                 mtx_lock(&ksem_count_lock);
 1085                 if (nsems != 0) {
 1086                         error = EOPNOTSUPP;
 1087                         mtx_unlock(&ksem_count_lock);
 1088                         break;
 1089                 }
 1090                 ksem_dead = 1;
 1091                 mtx_unlock(&ksem_count_lock);
 1092                 ksem_module_destroy();
 1093                 break;
 1094 
 1095         case MOD_SHUTDOWN:
 1096                 break;
 1097         default:
 1098                 error = EINVAL;
 1099                 break;
 1100         }
 1101         return (error);
 1102 }
 1103 
 1104 static moduledata_t sem_mod = {
 1105         "sem",
 1106         &sem_modload,
 1107         NULL
 1108 };
 1109 
 1110 DECLARE_MODULE(sem, sem_mod, SI_SUB_SYSV_SEM, SI_ORDER_FIRST);
 1111 MODULE_VERSION(sem, 1);

Cache object: 63a62decc94cff9efac8c91f93fe73db


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.