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/sysv_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  * Implementation of SVID semaphores
    3  *
    4  * Author:  Daniel Boulet
    5  *
    6  * This software is provided ``AS IS'' without any warranties of any kind.
    7  */
    8 /*-
    9  * Copyright (c) 2003-2005 McAfee, Inc.
   10  * All rights reserved.
   11  *
   12  * This software was developed for the FreeBSD Project in part by McAfee
   13  * Research, the Security Research Division of McAfee, Inc under DARPA/SPAWAR
   14  * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS research
   15  * program.
   16  *
   17  * Redistribution and use in source and binary forms, with or without
   18  * modification, are permitted provided that the following conditions
   19  * are met:
   20  * 1. Redistributions of source code must retain the above copyright
   21  *    notice, this list of conditions and the following disclaimer.
   22  * 2. Redistributions in binary form must reproduce the above copyright
   23  *    notice, this list of conditions and the following disclaimer in the
   24  *    documentation and/or other materials provided with the distribution.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   36  * SUCH DAMAGE.
   37  */
   38 
   39 #include <sys/cdefs.h>
   40 __FBSDID("$FreeBSD$");
   41 
   42 #include "opt_sysvipc.h"
   43 #include "opt_mac.h"
   44 
   45 #include <sys/param.h>
   46 #include <sys/systm.h>
   47 #include <sys/sysproto.h>
   48 #include <sys/eventhandler.h>
   49 #include <sys/kernel.h>
   50 #include <sys/proc.h>
   51 #include <sys/lock.h>
   52 #include <sys/module.h>
   53 #include <sys/mutex.h>
   54 #include <sys/sem.h>
   55 #include <sys/syscall.h>
   56 #include <sys/syscallsubr.h>
   57 #include <sys/sysent.h>
   58 #include <sys/sysctl.h>
   59 #include <sys/uio.h>
   60 #include <sys/malloc.h>
   61 #include <sys/jail.h>
   62 
   63 #include <security/mac/mac_framework.h>
   64 
   65 static MALLOC_DEFINE(M_SEM, "sem", "SVID compatible semaphores");
   66 
   67 #ifdef SEM_DEBUG
   68 #define DPRINTF(a)      printf a
   69 #else
   70 #define DPRINTF(a)
   71 #endif
   72 
   73 static void seminit(void);
   74 static int sysvsem_modload(struct module *, int, void *);
   75 static int semunload(void);
   76 static void semexit_myhook(void *arg, struct proc *p);
   77 static int sysctl_sema(SYSCTL_HANDLER_ARGS);
   78 static int semvalid(int semid, struct semid_kernel *semakptr);
   79 
   80 #ifndef _SYS_SYSPROTO_H_
   81 struct __semctl_args;
   82 int __semctl(struct thread *td, struct __semctl_args *uap);
   83 struct semget_args;
   84 int semget(struct thread *td, struct semget_args *uap);
   85 struct semop_args;
   86 int semop(struct thread *td, struct semop_args *uap);
   87 #endif
   88 
   89 static struct sem_undo *semu_alloc(struct thread *td);
   90 static int semundo_adjust(struct thread *td, struct sem_undo **supptr,
   91     int semid, int semseq, int semnum, int adjval);
   92 static void semundo_clear(int semid, int semnum);
   93 
   94 /* XXX casting to (sy_call_t *) is bogus, as usual. */
   95 static sy_call_t *semcalls[] = {
   96         (sy_call_t *)__semctl, (sy_call_t *)semget,
   97         (sy_call_t *)semop
   98 };
   99 
  100 static struct mtx       sem_mtx;        /* semaphore global lock */
  101 static struct mtx sem_undo_mtx;
  102 static int      semtot = 0;
  103 static struct semid_kernel *sema;       /* semaphore id pool */
  104 static struct mtx *sema_mtx;    /* semaphore id pool mutexes*/
  105 static struct sem *sem;         /* semaphore pool */
  106 LIST_HEAD(, sem_undo) semu_list;        /* list of active undo structures */
  107 LIST_HEAD(, sem_undo) semu_free_list;   /* list of free undo structures */
  108 static int      *semu;          /* undo structure pool */
  109 static eventhandler_tag semexit_tag;
  110 
  111 #define SEMUNDO_MTX             sem_undo_mtx
  112 #define SEMUNDO_LOCK()          mtx_lock(&SEMUNDO_MTX);
  113 #define SEMUNDO_UNLOCK()        mtx_unlock(&SEMUNDO_MTX);
  114 #define SEMUNDO_LOCKASSERT(how) mtx_assert(&SEMUNDO_MTX, (how));
  115 
  116 struct sem {
  117         u_short semval;         /* semaphore value */
  118         pid_t   sempid;         /* pid of last operation */
  119         u_short semncnt;        /* # awaiting semval > cval */
  120         u_short semzcnt;        /* # awaiting semval = 0 */
  121 };
  122 
  123 /*
  124  * Undo structure (one per process)
  125  */
  126 struct sem_undo {
  127         LIST_ENTRY(sem_undo) un_next;   /* ptr to next active undo structure */
  128         struct  proc *un_proc;          /* owner of this structure */
  129         short   un_cnt;                 /* # of active entries */
  130         struct undo {
  131                 short   un_adjval;      /* adjust on exit values */
  132                 short   un_num;         /* semaphore # */
  133                 int     un_id;          /* semid */
  134                 unsigned short un_seq;
  135         } un_ent[1];                    /* undo entries */
  136 };
  137 
  138 /*
  139  * Configuration parameters
  140  */
  141 #ifndef SEMMNI
  142 #define SEMMNI  10              /* # of semaphore identifiers */
  143 #endif
  144 #ifndef SEMMNS
  145 #define SEMMNS  60              /* # of semaphores in system */
  146 #endif
  147 #ifndef SEMUME
  148 #define SEMUME  10              /* max # of undo entries per process */
  149 #endif
  150 #ifndef SEMMNU
  151 #define SEMMNU  30              /* # of undo structures in system */
  152 #endif
  153 
  154 /* shouldn't need tuning */
  155 #ifndef SEMMAP
  156 #define SEMMAP  30              /* # of entries in semaphore map */
  157 #endif
  158 #ifndef SEMMSL
  159 #define SEMMSL  SEMMNS          /* max # of semaphores per id */
  160 #endif
  161 #ifndef SEMOPM
  162 #define SEMOPM  100             /* max # of operations per semop call */
  163 #endif
  164 
  165 #define SEMVMX  32767           /* semaphore maximum value */
  166 #define SEMAEM  16384           /* adjust on exit max value */
  167 
  168 /*
  169  * Due to the way semaphore memory is allocated, we have to ensure that
  170  * SEMUSZ is properly aligned.
  171  */
  172 
  173 #define SEM_ALIGN(bytes) (((bytes) + (sizeof(long) - 1)) & ~(sizeof(long) - 1))
  174 
  175 /* actual size of an undo structure */
  176 #define SEMUSZ  SEM_ALIGN(offsetof(struct sem_undo, un_ent[SEMUME]))
  177 
  178 /*
  179  * Macro to find a particular sem_undo vector
  180  */
  181 #define SEMU(ix) \
  182         ((struct sem_undo *)(((intptr_t)semu)+ix * seminfo.semusz))
  183 
  184 /*
  185  * semaphore info struct
  186  */
  187 struct seminfo seminfo = {
  188                 SEMMAP,         /* # of entries in semaphore map */
  189                 SEMMNI,         /* # of semaphore identifiers */
  190                 SEMMNS,         /* # of semaphores in system */
  191                 SEMMNU,         /* # of undo structures in system */
  192                 SEMMSL,         /* max # of semaphores per id */
  193                 SEMOPM,         /* max # of operations per semop call */
  194                 SEMUME,         /* max # of undo entries per process */
  195                 SEMUSZ,         /* size in bytes of undo structure */
  196                 SEMVMX,         /* semaphore maximum value */
  197                 SEMAEM          /* adjust on exit max value */
  198 };
  199 
  200 SYSCTL_INT(_kern_ipc, OID_AUTO, semmap, CTLFLAG_RW, &seminfo.semmap, 0,
  201     "Number of entries in the semaphore map");
  202 SYSCTL_INT(_kern_ipc, OID_AUTO, semmni, CTLFLAG_RDTUN, &seminfo.semmni, 0,
  203     "Number of semaphore identifiers");
  204 SYSCTL_INT(_kern_ipc, OID_AUTO, semmns, CTLFLAG_RDTUN, &seminfo.semmns, 0,
  205     "Maximum number of semaphores in the system");
  206 SYSCTL_INT(_kern_ipc, OID_AUTO, semmnu, CTLFLAG_RDTUN, &seminfo.semmnu, 0,
  207     "Maximum number of undo structures in the system");
  208 SYSCTL_INT(_kern_ipc, OID_AUTO, semmsl, CTLFLAG_RW, &seminfo.semmsl, 0,
  209     "Max semaphores per id");
  210 SYSCTL_INT(_kern_ipc, OID_AUTO, semopm, CTLFLAG_RDTUN, &seminfo.semopm, 0,
  211     "Max operations per semop call");
  212 SYSCTL_INT(_kern_ipc, OID_AUTO, semume, CTLFLAG_RDTUN, &seminfo.semume, 0,
  213     "Max undo entries per process");
  214 SYSCTL_INT(_kern_ipc, OID_AUTO, semusz, CTLFLAG_RDTUN, &seminfo.semusz, 0,
  215     "Size in bytes of undo structure");
  216 SYSCTL_INT(_kern_ipc, OID_AUTO, semvmx, CTLFLAG_RW, &seminfo.semvmx, 0,
  217     "Semaphore maximum value");
  218 SYSCTL_INT(_kern_ipc, OID_AUTO, semaem, CTLFLAG_RW, &seminfo.semaem, 0,
  219     "Adjust on exit max value");
  220 SYSCTL_PROC(_kern_ipc, OID_AUTO, sema, CTLFLAG_RD,
  221     NULL, 0, sysctl_sema, "", "");
  222 
  223 static void
  224 seminit(void)
  225 {
  226         int i;
  227 
  228         TUNABLE_INT_FETCH("kern.ipc.semmap", &seminfo.semmap);
  229         TUNABLE_INT_FETCH("kern.ipc.semmni", &seminfo.semmni);
  230         TUNABLE_INT_FETCH("kern.ipc.semmns", &seminfo.semmns);
  231         TUNABLE_INT_FETCH("kern.ipc.semmnu", &seminfo.semmnu);
  232         TUNABLE_INT_FETCH("kern.ipc.semmsl", &seminfo.semmsl);
  233         TUNABLE_INT_FETCH("kern.ipc.semopm", &seminfo.semopm);
  234         TUNABLE_INT_FETCH("kern.ipc.semume", &seminfo.semume);
  235         TUNABLE_INT_FETCH("kern.ipc.semusz", &seminfo.semusz);
  236         TUNABLE_INT_FETCH("kern.ipc.semvmx", &seminfo.semvmx);
  237         TUNABLE_INT_FETCH("kern.ipc.semaem", &seminfo.semaem);
  238 
  239         sem = malloc(sizeof(struct sem) * seminfo.semmns, M_SEM, M_WAITOK);
  240         sema = malloc(sizeof(struct semid_kernel) * seminfo.semmni, M_SEM,
  241             M_WAITOK);
  242         sema_mtx = malloc(sizeof(struct mtx) * seminfo.semmni, M_SEM,
  243             M_WAITOK | M_ZERO);
  244         semu = malloc(seminfo.semmnu * seminfo.semusz, M_SEM, M_WAITOK);
  245 
  246         for (i = 0; i < seminfo.semmni; i++) {
  247                 sema[i].u.sem_base = 0;
  248                 sema[i].u.sem_perm.mode = 0;
  249                 sema[i].u.sem_perm.seq = 0;
  250 #ifdef MAC
  251                 mac_init_sysv_sem(&sema[i]);
  252 #endif
  253         }
  254         for (i = 0; i < seminfo.semmni; i++)
  255                 mtx_init(&sema_mtx[i], "semid", NULL, MTX_DEF);
  256         LIST_INIT(&semu_free_list);
  257         for (i = 0; i < seminfo.semmnu; i++) {
  258                 struct sem_undo *suptr = SEMU(i);
  259                 suptr->un_proc = NULL;
  260                 LIST_INSERT_HEAD(&semu_free_list, suptr, un_next);
  261         }
  262         LIST_INIT(&semu_list);
  263         mtx_init(&sem_mtx, "sem", NULL, MTX_DEF);
  264         mtx_init(&sem_undo_mtx, "semu", NULL, MTX_DEF);
  265         semexit_tag = EVENTHANDLER_REGISTER(process_exit, semexit_myhook, NULL,
  266             EVENTHANDLER_PRI_ANY);
  267 }
  268 
  269 static int
  270 semunload(void)
  271 {
  272         int i;
  273 
  274         /* XXXKIB */
  275         if (semtot != 0)
  276                 return (EBUSY);
  277 
  278         EVENTHANDLER_DEREGISTER(process_exit, semexit_tag);
  279 #ifdef MAC
  280         for (i = 0; i < seminfo.semmni; i++)
  281                 mac_destroy_sysv_sem(&sema[i]);
  282 #endif
  283         free(sem, M_SEM);
  284         free(sema, M_SEM);
  285         free(semu, M_SEM);
  286         for (i = 0; i < seminfo.semmni; i++)
  287                 mtx_destroy(&sema_mtx[i]);
  288         free(sema_mtx, M_SEM);
  289         mtx_destroy(&sem_mtx);
  290         mtx_destroy(&sem_undo_mtx);
  291         return (0);
  292 }
  293 
  294 static int
  295 sysvsem_modload(struct module *module, int cmd, void *arg)
  296 {
  297         int error = 0;
  298 
  299         switch (cmd) {
  300         case MOD_LOAD:
  301                 seminit();
  302                 break;
  303         case MOD_UNLOAD:
  304                 error = semunload();
  305                 break;
  306         case MOD_SHUTDOWN:
  307                 break;
  308         default:
  309                 error = EINVAL;
  310                 break;
  311         }
  312         return (error);
  313 }
  314 
  315 static moduledata_t sysvsem_mod = {
  316         "sysvsem",
  317         &sysvsem_modload,
  318         NULL
  319 };
  320 
  321 SYSCALL_MODULE_HELPER(semsys);
  322 SYSCALL_MODULE_HELPER(__semctl);
  323 SYSCALL_MODULE_HELPER(semget);
  324 SYSCALL_MODULE_HELPER(semop);
  325 
  326 DECLARE_MODULE(sysvsem, sysvsem_mod,
  327         SI_SUB_SYSV_SEM, SI_ORDER_FIRST);
  328 MODULE_VERSION(sysvsem, 1);
  329 
  330 /*
  331  * Entry point for all SEM calls.
  332  */
  333 int
  334 semsys(td, uap)
  335         struct thread *td;
  336         /* XXX actually varargs. */
  337         struct semsys_args /* {
  338                 int     which;
  339                 int     a2;
  340                 int     a3;
  341                 int     a4;
  342                 int     a5;
  343         } */ *uap;
  344 {
  345         int error;
  346 
  347         if (!jail_sysvipc_allowed && jailed(td->td_ucred))
  348                 return (ENOSYS);
  349         if (uap->which < 0 ||
  350             uap->which >= sizeof(semcalls)/sizeof(semcalls[0]))
  351                 return (EINVAL);
  352         error = (*semcalls[uap->which])(td, &uap->a2);
  353         return (error);
  354 }
  355 
  356 /*
  357  * Allocate a new sem_undo structure for a process
  358  * (returns ptr to structure or NULL if no more room)
  359  */
  360 
  361 static struct sem_undo *
  362 semu_alloc(struct thread *td)
  363 {
  364         struct sem_undo *suptr;
  365 
  366         SEMUNDO_LOCKASSERT(MA_OWNED);
  367         if ((suptr = LIST_FIRST(&semu_free_list)) == NULL)
  368                 return (NULL);
  369         LIST_REMOVE(suptr, un_next);
  370         LIST_INSERT_HEAD(&semu_list, suptr, un_next);
  371         suptr->un_cnt = 0;
  372         suptr->un_proc = td->td_proc;
  373         return (suptr);
  374 }
  375 
  376 static int
  377 semu_try_free(struct sem_undo *suptr)
  378 {
  379 
  380         SEMUNDO_LOCKASSERT(MA_OWNED);
  381 
  382         if (suptr->un_cnt != 0)
  383                 return (0);
  384         LIST_REMOVE(suptr, un_next);
  385         LIST_INSERT_HEAD(&semu_free_list, suptr, un_next);
  386         return (1);
  387 }
  388 
  389 /*
  390  * Adjust a particular entry for a particular proc
  391  */
  392 
  393 static int
  394 semundo_adjust(struct thread *td, struct sem_undo **supptr, int semid,
  395     int semseq, int semnum, int adjval)
  396 {
  397         struct proc *p = td->td_proc;
  398         struct sem_undo *suptr;
  399         struct undo *sunptr;
  400         int i;
  401 
  402         SEMUNDO_LOCKASSERT(MA_OWNED);
  403         /* Look for and remember the sem_undo if the caller doesn't provide
  404            it */
  405 
  406         suptr = *supptr;
  407         if (suptr == NULL) {
  408                 LIST_FOREACH(suptr, &semu_list, un_next) {
  409                         if (suptr->un_proc == p) {
  410                                 *supptr = suptr;
  411                                 break;
  412                         }
  413                 }
  414                 if (suptr == NULL) {
  415                         if (adjval == 0)
  416                                 return(0);
  417                         suptr = semu_alloc(td);
  418                         if (suptr == NULL)
  419                                 return (ENOSPC);
  420                         *supptr = suptr;
  421                 }
  422         }
  423 
  424         /*
  425          * Look for the requested entry and adjust it (delete if adjval becomes
  426          * 0).
  427          */
  428         sunptr = &suptr->un_ent[0];
  429         for (i = 0; i < suptr->un_cnt; i++, sunptr++) {
  430                 if (sunptr->un_id != semid || sunptr->un_num != semnum)
  431                         continue;
  432                 if (adjval != 0) {
  433                         adjval += sunptr->un_adjval;
  434                         if (adjval > seminfo.semaem || adjval < -seminfo.semaem)
  435                                 return (ERANGE);
  436                 }
  437                 sunptr->un_adjval = adjval;
  438                 if (sunptr->un_adjval == 0) {
  439                         suptr->un_cnt--;
  440                         if (i < suptr->un_cnt)
  441                                 suptr->un_ent[i] =
  442                                     suptr->un_ent[suptr->un_cnt];
  443                         if (suptr->un_cnt == 0)
  444                                 semu_try_free(suptr);
  445                 }
  446                 return (0);
  447         }
  448 
  449         /* Didn't find the right entry - create it */
  450         if (adjval == 0)
  451                 return (0);
  452         if (adjval > seminfo.semaem || adjval < -seminfo.semaem)
  453                 return (ERANGE);
  454         if (suptr->un_cnt != seminfo.semume) {
  455                 sunptr = &suptr->un_ent[suptr->un_cnt];
  456                 suptr->un_cnt++;
  457                 sunptr->un_adjval = adjval;
  458                 sunptr->un_id = semid;
  459                 sunptr->un_num = semnum;
  460                 sunptr->un_seq = semseq;
  461         } else
  462                 return (EINVAL);
  463         return (0);
  464 }
  465 
  466 static void
  467 semundo_clear(int semid, int semnum)
  468 {
  469         struct sem_undo *suptr, *suptr1;
  470         struct undo *sunptr;
  471         int i;
  472 
  473         SEMUNDO_LOCKASSERT(MA_OWNED);
  474         LIST_FOREACH_SAFE(suptr, &semu_list, un_next, suptr1) {
  475                 sunptr = &suptr->un_ent[0];
  476                 for (i = 0; i < suptr->un_cnt; i++, sunptr++) {
  477                         if (sunptr->un_id != semid)
  478                                 continue;
  479                         if (semnum == -1 || sunptr->un_num == semnum) {
  480                                 suptr->un_cnt--;
  481                                 if (i < suptr->un_cnt) {
  482                                         suptr->un_ent[i] =
  483                                             suptr->un_ent[suptr->un_cnt];
  484                                         continue;
  485                                 }
  486                                 semu_try_free(suptr);
  487                         }
  488                         if (semnum != -1)
  489                                 break;
  490                 }
  491         }
  492 }
  493 
  494 static int
  495 semvalid(int semid, struct semid_kernel *semakptr)
  496 {
  497 
  498         return ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 ||
  499             semakptr->u.sem_perm.seq != IPCID_TO_SEQ(semid) ? EINVAL : 0);
  500 }
  501 
  502 /*
  503  * Note that the user-mode half of this passes a union, not a pointer.
  504  */
  505 #ifndef _SYS_SYSPROTO_H_
  506 struct __semctl_args {
  507         int     semid;
  508         int     semnum;
  509         int     cmd;
  510         union   semun *arg;
  511 };
  512 #endif
  513 int
  514 __semctl(struct thread *td, struct __semctl_args *uap)
  515 {
  516         struct semid_ds dsbuf;
  517         union semun arg, semun;
  518         register_t rval;
  519         int error;
  520 
  521         switch (uap->cmd) {
  522         case SEM_STAT:
  523         case IPC_SET:
  524         case IPC_STAT:
  525         case GETALL:
  526         case SETVAL:
  527         case SETALL:
  528                 error = copyin(uap->arg, &arg, sizeof(arg));
  529                 if (error)
  530                         return (error);
  531                 break;
  532         }
  533 
  534         switch (uap->cmd) {
  535         case SEM_STAT:
  536         case IPC_STAT:
  537                 semun.buf = &dsbuf;
  538                 break;
  539         case IPC_SET:
  540                 error = copyin(arg.buf, &dsbuf, sizeof(dsbuf));
  541                 if (error)
  542                         return (error);
  543                 semun.buf = &dsbuf;
  544                 break;
  545         case GETALL:
  546         case SETALL:
  547                 semun.array = arg.array;
  548                 break;
  549         case SETVAL:
  550                 semun.val = arg.val;
  551                 break;          
  552         }
  553 
  554         error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun,
  555             &rval);
  556         if (error)
  557                 return (error);
  558 
  559         switch (uap->cmd) {
  560         case SEM_STAT:
  561         case IPC_STAT:
  562                 error = copyout(&dsbuf, arg.buf, sizeof(dsbuf));
  563                 break;
  564         }
  565 
  566         if (error == 0)
  567                 td->td_retval[0] = rval;
  568         return (error);
  569 }
  570 
  571 int
  572 kern_semctl(struct thread *td, int semid, int semnum, int cmd,
  573     union semun *arg, register_t *rval)
  574 {
  575         u_short *array;
  576         struct ucred *cred = td->td_ucred;
  577         int i, error;
  578         struct semid_ds *sbuf;
  579         struct semid_kernel *semakptr;
  580         struct mtx *sema_mtxp;
  581         u_short usval, count;
  582         int semidx;
  583 
  584         DPRINTF(("call to semctl(%d, %d, %d, 0x%p)\n",
  585             semid, semnum, cmd, arg));
  586         if (!jail_sysvipc_allowed && jailed(td->td_ucred))
  587                 return (ENOSYS);
  588 
  589         array = NULL;
  590 
  591         switch(cmd) {
  592         case SEM_STAT:
  593                 /*
  594                  * For this command we assume semid is an array index
  595                  * rather than an IPC id.
  596                  */
  597                 if (semid < 0 || semid >= seminfo.semmni)
  598                         return (EINVAL);
  599                 semakptr = &sema[semid];
  600                 sema_mtxp = &sema_mtx[semid];
  601                 mtx_lock(sema_mtxp);
  602                 if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) {
  603                         error = EINVAL;
  604                         goto done2;
  605                 }
  606                 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
  607                         goto done2;
  608 #ifdef MAC
  609                 error = mac_check_sysv_semctl(cred, semakptr, cmd);
  610                 if (error != 0)
  611                         goto done2;
  612 #endif
  613                 bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds));
  614                 *rval = IXSEQ_TO_IPCID(semid, semakptr->u.sem_perm);
  615                 mtx_unlock(sema_mtxp);
  616                 return (0);
  617         }
  618 
  619         semidx = IPCID_TO_IX(semid);
  620         if (semidx < 0 || semidx >= seminfo.semmni)
  621                 return (EINVAL);
  622 
  623         semakptr = &sema[semidx];
  624         sema_mtxp = &sema_mtx[semidx];
  625         if (cmd == IPC_RMID)
  626                 mtx_lock(&sem_mtx);
  627         mtx_lock(sema_mtxp);
  628 #ifdef MAC
  629         error = mac_check_sysv_semctl(cred, semakptr, cmd);
  630         if (error != 0)
  631                 goto done2;
  632 #endif
  633 
  634         error = 0;
  635         *rval = 0;
  636 
  637         switch (cmd) {
  638         case IPC_RMID:
  639                 if ((error = semvalid(semid, semakptr)) != 0)
  640                         goto done2;
  641                 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M)))
  642                         goto done2;
  643                 semakptr->u.sem_perm.cuid = cred->cr_uid;
  644                 semakptr->u.sem_perm.uid = cred->cr_uid;
  645                 semakptr->u.sem_perm.mode = 0;
  646                 SEMUNDO_LOCK();
  647                 semundo_clear(semidx, -1);
  648                 SEMUNDO_UNLOCK();
  649 #ifdef MAC
  650                 mac_cleanup_sysv_sem(semakptr);
  651 #endif
  652                 wakeup(semakptr);
  653                 for (i = 0; i < seminfo.semmni; i++) {
  654                         if ((sema[i].u.sem_perm.mode & SEM_ALLOC) &&
  655                             sema[i].u.sem_base > semakptr->u.sem_base)
  656                                 mtx_lock_flags(&sema_mtx[i], LOP_DUPOK);
  657                 }
  658                 for (i = semakptr->u.sem_base - sem; i < semtot; i++)
  659                         sem[i] = sem[i + semakptr->u.sem_nsems];
  660                 for (i = 0; i < seminfo.semmni; i++) {
  661                         if ((sema[i].u.sem_perm.mode & SEM_ALLOC) &&
  662                             sema[i].u.sem_base > semakptr->u.sem_base) {
  663                                 sema[i].u.sem_base -= semakptr->u.sem_nsems;
  664                                 mtx_unlock(&sema_mtx[i]);
  665                         }
  666                 }
  667                 semtot -= semakptr->u.sem_nsems;
  668                 break;
  669 
  670         case IPC_SET:
  671                 if ((error = semvalid(semid, semakptr)) != 0)
  672                         goto done2;
  673                 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M)))
  674                         goto done2;
  675                 sbuf = arg->buf;
  676                 semakptr->u.sem_perm.uid = sbuf->sem_perm.uid;
  677                 semakptr->u.sem_perm.gid = sbuf->sem_perm.gid;
  678                 semakptr->u.sem_perm.mode = (semakptr->u.sem_perm.mode &
  679                     ~0777) | (sbuf->sem_perm.mode & 0777);
  680                 semakptr->u.sem_ctime = time_second;
  681                 break;
  682 
  683         case IPC_STAT:
  684                 if ((error = semvalid(semid, semakptr)) != 0)
  685                         goto done2;
  686                 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
  687                         goto done2;
  688                 bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds));
  689                 break;
  690 
  691         case GETNCNT:
  692                 if ((error = semvalid(semid, semakptr)) != 0)
  693                         goto done2;
  694                 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
  695                         goto done2;
  696                 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
  697                         error = EINVAL;
  698                         goto done2;
  699                 }
  700                 *rval = semakptr->u.sem_base[semnum].semncnt;
  701                 break;
  702 
  703         case GETPID:
  704                 if ((error = semvalid(semid, semakptr)) != 0)
  705                         goto done2;
  706                 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
  707                         goto done2;
  708                 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
  709                         error = EINVAL;
  710                         goto done2;
  711                 }
  712                 *rval = semakptr->u.sem_base[semnum].sempid;
  713                 break;
  714 
  715         case GETVAL:
  716                 if ((error = semvalid(semid, semakptr)) != 0)
  717                         goto done2;
  718                 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
  719                         goto done2;
  720                 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
  721                         error = EINVAL;
  722                         goto done2;
  723                 }
  724                 *rval = semakptr->u.sem_base[semnum].semval;
  725                 break;
  726 
  727         case GETALL:
  728                 /*
  729                  * Unfortunately, callers of this function don't know
  730                  * in advance how many semaphores are in this set.
  731                  * While we could just allocate the maximum size array
  732                  * and pass the actual size back to the caller, that
  733                  * won't work for SETALL since we can't copyin() more
  734                  * data than the user specified as we may return a
  735                  * spurious EFAULT.
  736                  * 
  737                  * Note that the number of semaphores in a set is
  738                  * fixed for the life of that set.  The only way that
  739                  * the 'count' could change while are blocked in
  740                  * malloc() is if this semaphore set were destroyed
  741                  * and a new one created with the same index.
  742                  * However, semvalid() will catch that due to the
  743                  * sequence number unless exactly 0x8000 (or a
  744                  * multiple thereof) semaphore sets for the same index
  745                  * are created and destroyed while we are in malloc!
  746                  *
  747                  */
  748                 count = semakptr->u.sem_nsems;
  749                 mtx_unlock(sema_mtxp);              
  750                 array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK);
  751                 mtx_lock(sema_mtxp);
  752                 if ((error = semvalid(semid, semakptr)) != 0)
  753                         goto done2;
  754                 KASSERT(count == semakptr->u.sem_nsems, ("nsems changed"));
  755                 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
  756                         goto done2;
  757                 for (i = 0; i < semakptr->u.sem_nsems; i++)
  758                         array[i] = semakptr->u.sem_base[i].semval;
  759                 mtx_unlock(sema_mtxp);
  760                 error = copyout(array, arg->array, count * sizeof(*array));
  761                 mtx_lock(sema_mtxp);
  762                 break;
  763 
  764         case GETZCNT:
  765                 if ((error = semvalid(semid, semakptr)) != 0)
  766                         goto done2;
  767                 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
  768                         goto done2;
  769                 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
  770                         error = EINVAL;
  771                         goto done2;
  772                 }
  773                 *rval = semakptr->u.sem_base[semnum].semzcnt;
  774                 break;
  775 
  776         case SETVAL:
  777                 if ((error = semvalid(semid, semakptr)) != 0)
  778                         goto done2;
  779                 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W)))
  780                         goto done2;
  781                 if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
  782                         error = EINVAL;
  783                         goto done2;
  784                 }
  785                 if (arg->val < 0 || arg->val > seminfo.semvmx) {
  786                         error = ERANGE;
  787                         goto done2;
  788                 }
  789                 semakptr->u.sem_base[semnum].semval = arg->val;
  790                 SEMUNDO_LOCK();
  791                 semundo_clear(semidx, semnum);
  792                 SEMUNDO_UNLOCK();
  793                 wakeup(semakptr);
  794                 break;
  795 
  796         case SETALL:
  797                 /*
  798                  * See comment on GETALL for why 'count' shouldn't change
  799                  * and why we require a userland buffer.
  800                  */
  801                 count = semakptr->u.sem_nsems;
  802                 mtx_unlock(sema_mtxp);              
  803                 array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK);
  804                 error = copyin(arg->array, array, count * sizeof(*array));
  805                 mtx_lock(sema_mtxp);
  806                 if (error)
  807                         break;
  808                 if ((error = semvalid(semid, semakptr)) != 0)
  809                         goto done2;
  810                 KASSERT(count == semakptr->u.sem_nsems, ("nsems changed"));
  811                 if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W)))
  812                         goto done2;
  813                 for (i = 0; i < semakptr->u.sem_nsems; i++) {
  814                         usval = array[i];
  815                         if (usval > seminfo.semvmx) {
  816                                 error = ERANGE;
  817                                 break;
  818                         }
  819                         semakptr->u.sem_base[i].semval = usval;
  820                 }
  821                 SEMUNDO_LOCK();
  822                 semundo_clear(semidx, -1);
  823                 SEMUNDO_UNLOCK();
  824                 wakeup(semakptr);
  825                 break;
  826 
  827         default:
  828                 error = EINVAL;
  829                 break;
  830         }
  831 
  832 done2:
  833         mtx_unlock(sema_mtxp);
  834         if (cmd == IPC_RMID)
  835                 mtx_unlock(&sem_mtx);
  836         if (array != NULL)
  837                 free(array, M_TEMP);
  838         return(error);
  839 }
  840 
  841 #ifndef _SYS_SYSPROTO_H_
  842 struct semget_args {
  843         key_t   key;
  844         int     nsems;
  845         int     semflg;
  846 };
  847 #endif
  848 int
  849 semget(struct thread *td, struct semget_args *uap)
  850 {
  851         int semid, error = 0;
  852         int key = uap->key;
  853         int nsems = uap->nsems;
  854         int semflg = uap->semflg;
  855         struct ucred *cred = td->td_ucred;
  856 
  857         DPRINTF(("semget(0x%x, %d, 0%o)\n", key, nsems, semflg));
  858         if (!jail_sysvipc_allowed && jailed(td->td_ucred))
  859                 return (ENOSYS);
  860 
  861         mtx_lock(&sem_mtx);
  862         if (key != IPC_PRIVATE) {
  863                 for (semid = 0; semid < seminfo.semmni; semid++) {
  864                         if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) &&
  865                             sema[semid].u.sem_perm.key == key)
  866                                 break;
  867                 }
  868                 if (semid < seminfo.semmni) {
  869                         DPRINTF(("found public key\n"));
  870                         if ((error = ipcperm(td, &sema[semid].u.sem_perm,
  871                             semflg & 0700))) {
  872                                 goto done2;
  873                         }
  874                         if (nsems > 0 && sema[semid].u.sem_nsems < nsems) {
  875                                 DPRINTF(("too small\n"));
  876                                 error = EINVAL;
  877                                 goto done2;
  878                         }
  879                         if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) {
  880                                 DPRINTF(("not exclusive\n"));
  881                                 error = EEXIST;
  882                                 goto done2;
  883                         }
  884 #ifdef MAC
  885                         error = mac_check_sysv_semget(cred, &sema[semid]);
  886                         if (error != 0)
  887                                 goto done2;
  888 #endif
  889                         goto found;
  890                 }
  891         }
  892 
  893         DPRINTF(("need to allocate the semid_kernel\n"));
  894         if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) {
  895                 if (nsems <= 0 || nsems > seminfo.semmsl) {
  896                         DPRINTF(("nsems out of range (0<%d<=%d)\n", nsems,
  897                             seminfo.semmsl));
  898                         error = EINVAL;
  899                         goto done2;
  900                 }
  901                 if (nsems > seminfo.semmns - semtot) {
  902                         DPRINTF((
  903                             "not enough semaphores left (need %d, got %d)\n",
  904                             nsems, seminfo.semmns - semtot));
  905                         error = ENOSPC;
  906                         goto done2;
  907                 }
  908                 for (semid = 0; semid < seminfo.semmni; semid++) {
  909                         if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0)
  910                                 break;
  911                 }
  912                 if (semid == seminfo.semmni) {
  913                         DPRINTF(("no more semid_kernel's available\n"));
  914                         error = ENOSPC;
  915                         goto done2;
  916                 }
  917                 DPRINTF(("semid %d is available\n", semid));
  918                 mtx_lock(&sema_mtx[semid]);
  919                 KASSERT((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0,
  920                     ("Lost semaphore %d", semid));
  921                 sema[semid].u.sem_perm.key = key;
  922                 sema[semid].u.sem_perm.cuid = cred->cr_uid;
  923                 sema[semid].u.sem_perm.uid = cred->cr_uid;
  924                 sema[semid].u.sem_perm.cgid = cred->cr_gid;
  925                 sema[semid].u.sem_perm.gid = cred->cr_gid;
  926                 sema[semid].u.sem_perm.mode = (semflg & 0777) | SEM_ALLOC;
  927                 sema[semid].u.sem_perm.seq =
  928                     (sema[semid].u.sem_perm.seq + 1) & 0x7fff;
  929                 sema[semid].u.sem_nsems = nsems;
  930                 sema[semid].u.sem_otime = 0;
  931                 sema[semid].u.sem_ctime = time_second;
  932                 sema[semid].u.sem_base = &sem[semtot];
  933                 semtot += nsems;
  934                 bzero(sema[semid].u.sem_base,
  935                     sizeof(sema[semid].u.sem_base[0])*nsems);
  936 #ifdef MAC
  937                 mac_create_sysv_sem(cred, &sema[semid]);
  938 #endif
  939                 mtx_unlock(&sema_mtx[semid]);
  940                 DPRINTF(("sembase = %p, next = %p\n",
  941                     sema[semid].u.sem_base, &sem[semtot]));
  942         } else {
  943                 DPRINTF(("didn't find it and wasn't asked to create it\n"));
  944                 error = ENOENT;
  945                 goto done2;
  946         }
  947 
  948 found:
  949         td->td_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].u.sem_perm);
  950 done2:
  951         mtx_unlock(&sem_mtx);
  952         return (error);
  953 }
  954 
  955 #ifndef _SYS_SYSPROTO_H_
  956 struct semop_args {
  957         int     semid;
  958         struct  sembuf *sops;
  959         size_t  nsops;
  960 };
  961 #endif
  962 int
  963 semop(struct thread *td, struct semop_args *uap)
  964 {
  965 #define SMALL_SOPS      8
  966         struct sembuf small_sops[SMALL_SOPS];
  967         int semid = uap->semid;
  968         size_t nsops = uap->nsops;
  969         struct sembuf *sops;
  970         struct semid_kernel *semakptr;
  971         struct sembuf *sopptr = 0;
  972         struct sem *semptr = 0;
  973         struct sem_undo *suptr;
  974         struct mtx *sema_mtxp;
  975         size_t i, j, k;
  976         int error;
  977         int do_wakeup, do_undos;
  978         unsigned short seq;
  979 
  980 #ifdef SEM_DEBUG
  981         sops = NULL;
  982 #endif
  983         DPRINTF(("call to semop(%d, %p, %u)\n", semid, sops, nsops));
  984 
  985         if (!jail_sysvipc_allowed && jailed(td->td_ucred))
  986                 return (ENOSYS);
  987 
  988         semid = IPCID_TO_IX(semid);     /* Convert back to zero origin */
  989 
  990         if (semid < 0 || semid >= seminfo.semmni)
  991                 return (EINVAL);
  992 
  993         /* Allocate memory for sem_ops */
  994         if (nsops <= SMALL_SOPS)
  995                 sops = small_sops;
  996         else if (nsops <= seminfo.semopm)
  997                 sops = malloc(nsops * sizeof(*sops), M_TEMP, M_WAITOK);
  998         else {
  999                 DPRINTF(("too many sops (max=%d, nsops=%d)\n", seminfo.semopm,
 1000                     nsops));
 1001                 return (E2BIG);
 1002         }
 1003         if ((error = copyin(uap->sops, sops, nsops * sizeof(sops[0]))) != 0) {
 1004                 DPRINTF(("error = %d from copyin(%p, %p, %d)\n", error,
 1005                     uap->sops, sops, nsops * sizeof(sops[0])));
 1006                 if (sops != small_sops)
 1007                         free(sops, M_SEM);
 1008                 return (error);
 1009         }
 1010 
 1011         semakptr = &sema[semid];
 1012         sema_mtxp = &sema_mtx[semid];
 1013         mtx_lock(sema_mtxp);
 1014         if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) {
 1015                 error = EINVAL;
 1016                 goto done2;
 1017         }
 1018         seq = semakptr->u.sem_perm.seq;
 1019         if (seq != IPCID_TO_SEQ(uap->semid)) {
 1020                 error = EINVAL;
 1021                 goto done2;
 1022         }
 1023         /*
 1024          * Initial pass thru sops to see what permissions are needed.
 1025          * Also perform any checks that don't need repeating on each
 1026          * attempt to satisfy the request vector.
 1027          */
 1028         j = 0;          /* permission needed */
 1029         do_undos = 0;
 1030         for (i = 0; i < nsops; i++) {
 1031                 sopptr = &sops[i];
 1032                 if (sopptr->sem_num >= semakptr->u.sem_nsems) {
 1033                         error = EFBIG;
 1034                         goto done2;
 1035                 }
 1036                 if (sopptr->sem_flg & SEM_UNDO && sopptr->sem_op != 0)
 1037                         do_undos = 1;
 1038                 j |= (sopptr->sem_op == 0) ? SEM_R : SEM_A;
 1039         }
 1040 
 1041         if ((error = ipcperm(td, &semakptr->u.sem_perm, j))) {
 1042                 DPRINTF(("error = %d from ipaccess\n", error));
 1043                 goto done2;
 1044         }
 1045 #ifdef MAC
 1046         error = mac_check_sysv_semop(td->td_ucred, semakptr, j);
 1047         if (error != 0)
 1048                 goto done2;
 1049 #endif
 1050 
 1051         /*
 1052          * Loop trying to satisfy the vector of requests.
 1053          * If we reach a point where we must wait, any requests already
 1054          * performed are rolled back and we go to sleep until some other
 1055          * process wakes us up.  At this point, we start all over again.
 1056          *
 1057          * This ensures that from the perspective of other tasks, a set
 1058          * of requests is atomic (never partially satisfied).
 1059          */
 1060         for (;;) {
 1061                 do_wakeup = 0;
 1062                 error = 0;      /* error return if necessary */
 1063 
 1064                 for (i = 0; i < nsops; i++) {
 1065                         sopptr = &sops[i];
 1066                         semptr = &semakptr->u.sem_base[sopptr->sem_num];
 1067 
 1068                         DPRINTF((
 1069                             "semop:  semakptr=%p, sem_base=%p, "
 1070                             "semptr=%p, sem[%d]=%d : op=%d, flag=%s\n",
 1071                             semakptr, semakptr->u.sem_base, semptr,
 1072                             sopptr->sem_num, semptr->semval, sopptr->sem_op,
 1073                             (sopptr->sem_flg & IPC_NOWAIT) ?
 1074                             "nowait" : "wait"));
 1075 
 1076                         if (sopptr->sem_op < 0) {
 1077                                 if (semptr->semval + sopptr->sem_op < 0) {
 1078                                         DPRINTF(("semop:  can't do it now\n"));
 1079                                         break;
 1080                                 } else {
 1081                                         semptr->semval += sopptr->sem_op;
 1082                                         if (semptr->semval == 0 &&
 1083                                             semptr->semzcnt > 0)
 1084                                                 do_wakeup = 1;
 1085                                 }
 1086                         } else if (sopptr->sem_op == 0) {
 1087                                 if (semptr->semval != 0) {
 1088                                         DPRINTF(("semop:  not zero now\n"));
 1089                                         break;
 1090                                 }
 1091                         } else if (semptr->semval + sopptr->sem_op >
 1092                             seminfo.semvmx) {
 1093                                 error = ERANGE;
 1094                                 break;
 1095                         } else {
 1096                                 if (semptr->semncnt > 0)
 1097                                         do_wakeup = 1;
 1098                                 semptr->semval += sopptr->sem_op;
 1099                         }
 1100                 }
 1101 
 1102                 /*
 1103                  * Did we get through the entire vector?
 1104                  */
 1105                 if (i >= nsops)
 1106                         goto done;
 1107 
 1108                 /*
 1109                  * No ... rollback anything that we've already done
 1110                  */
 1111                 DPRINTF(("semop:  rollback 0 through %d\n", i-1));
 1112                 for (j = 0; j < i; j++)
 1113                         semakptr->u.sem_base[sops[j].sem_num].semval -=
 1114                             sops[j].sem_op;
 1115 
 1116                 /* If we detected an error, return it */
 1117                 if (error != 0)
 1118                         goto done2;
 1119 
 1120                 /*
 1121                  * If the request that we couldn't satisfy has the
 1122                  * NOWAIT flag set then return with EAGAIN.
 1123                  */
 1124                 if (sopptr->sem_flg & IPC_NOWAIT) {
 1125                         error = EAGAIN;
 1126                         goto done2;
 1127                 }
 1128 
 1129                 if (sopptr->sem_op == 0)
 1130                         semptr->semzcnt++;
 1131                 else
 1132                         semptr->semncnt++;
 1133 
 1134                 DPRINTF(("semop:  good night!\n"));
 1135                 error = msleep(semakptr, sema_mtxp, (PZERO - 4) | PCATCH,
 1136                     "semwait", 0);
 1137                 DPRINTF(("semop:  good morning (error=%d)!\n", error));
 1138                 /* return code is checked below, after sem[nz]cnt-- */
 1139 
 1140                 /*
 1141                  * Make sure that the semaphore still exists
 1142                  */
 1143                 seq = semakptr->u.sem_perm.seq;
 1144                 if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 ||
 1145                     seq != IPCID_TO_SEQ(uap->semid)) {
 1146                         error = EIDRM;
 1147                         goto done2;
 1148                 }
 1149 
 1150                 /*
 1151                  * Renew the semaphore's pointer after wakeup since
 1152                  * during msleep sem_base may have been modified and semptr
 1153                  * is not valid any more
 1154                  */
 1155                 semptr = &semakptr->u.sem_base[sopptr->sem_num];
 1156 
 1157                 /*
 1158                  * The semaphore is still alive.  Readjust the count of
 1159                  * waiting processes.
 1160                  */
 1161                 if (sopptr->sem_op == 0)
 1162                         semptr->semzcnt--;
 1163                 else
 1164                         semptr->semncnt--;
 1165 
 1166                 /*
 1167                  * Is it really morning, or was our sleep interrupted?
 1168                  * (Delayed check of msleep() return code because we
 1169                  * need to decrement sem[nz]cnt either way.)
 1170                  */
 1171                 if (error != 0) {
 1172                         error = EINTR;
 1173                         goto done2;
 1174                 }
 1175                 DPRINTF(("semop:  good morning!\n"));
 1176         }
 1177 
 1178 done:
 1179         /*
 1180          * Process any SEM_UNDO requests.
 1181          */
 1182         if (do_undos) {
 1183                 SEMUNDO_LOCK();
 1184                 suptr = NULL;
 1185                 for (i = 0; i < nsops; i++) {
 1186                         /*
 1187                          * We only need to deal with SEM_UNDO's for non-zero
 1188                          * op's.
 1189                          */
 1190                         int adjval;
 1191 
 1192                         if ((sops[i].sem_flg & SEM_UNDO) == 0)
 1193                                 continue;
 1194                         adjval = sops[i].sem_op;
 1195                         if (adjval == 0)
 1196                                 continue;
 1197                         error = semundo_adjust(td, &suptr, semid, seq,
 1198                             sops[i].sem_num, -adjval);
 1199                         if (error == 0)
 1200                                 continue;
 1201 
 1202                         /*
 1203                          * Oh-Oh!  We ran out of either sem_undo's or undo's.
 1204                          * Rollback the adjustments to this point and then
 1205                          * rollback the semaphore ups and down so we can return
 1206                          * with an error with all structures restored.  We
 1207                          * rollback the undo's in the exact reverse order that
 1208                          * we applied them.  This guarantees that we won't run
 1209                          * out of space as we roll things back out.
 1210                          */
 1211                         for (j = 0; j < i; j++) {
 1212                                 k = i - j - 1;
 1213                                 if ((sops[k].sem_flg & SEM_UNDO) == 0)
 1214                                         continue;
 1215                                 adjval = sops[k].sem_op;
 1216                                 if (adjval == 0)
 1217                                         continue;
 1218                                 if (semundo_adjust(td, &suptr, semid, seq,
 1219                                     sops[k].sem_num, adjval) != 0)
 1220                                         panic("semop - can't undo undos");
 1221                         }
 1222 
 1223                         for (j = 0; j < nsops; j++)
 1224                                 semakptr->u.sem_base[sops[j].sem_num].semval -=
 1225                                     sops[j].sem_op;
 1226 
 1227                         DPRINTF(("error = %d from semundo_adjust\n", error));
 1228                         SEMUNDO_UNLOCK();
 1229                         goto done2;
 1230                 } /* loop through the sops */
 1231                 SEMUNDO_UNLOCK();
 1232         } /* if (do_undos) */
 1233 
 1234         /* We're definitely done - set the sempid's and time */
 1235         for (i = 0; i < nsops; i++) {
 1236                 sopptr = &sops[i];
 1237                 semptr = &semakptr->u.sem_base[sopptr->sem_num];
 1238                 semptr->sempid = td->td_proc->p_pid;
 1239         }
 1240         semakptr->u.sem_otime = time_second;
 1241 
 1242         /*
 1243          * Do a wakeup if any semaphore was up'd whilst something was
 1244          * sleeping on it.
 1245          */
 1246         if (do_wakeup) {
 1247                 DPRINTF(("semop:  doing wakeup\n"));
 1248                 wakeup(semakptr);
 1249                 DPRINTF(("semop:  back from wakeup\n"));
 1250         }
 1251         DPRINTF(("semop:  done\n"));
 1252         td->td_retval[0] = 0;
 1253 done2:
 1254         mtx_unlock(sema_mtxp);
 1255         if (sops != small_sops)
 1256                 free(sops, M_SEM);
 1257         return (error);
 1258 }
 1259 
 1260 /*
 1261  * Go through the undo structures for this process and apply the adjustments to
 1262  * semaphores.
 1263  */
 1264 static void
 1265 semexit_myhook(void *arg, struct proc *p)
 1266 {
 1267         struct sem_undo *suptr;
 1268         struct semid_kernel *semakptr;
 1269         struct mtx *sema_mtxp;
 1270         int semid, semnum, adjval, ix;
 1271         unsigned short seq;
 1272 
 1273         /*
 1274          * Go through the chain of undo vectors looking for one
 1275          * associated with this process.
 1276          */
 1277         SEMUNDO_LOCK();
 1278         LIST_FOREACH(suptr, &semu_list, un_next) {
 1279                 if (suptr->un_proc == p)
 1280                         break;
 1281         }
 1282         if (suptr == NULL) {
 1283                 SEMUNDO_UNLOCK();
 1284                 return;
 1285         }
 1286         LIST_REMOVE(suptr, un_next);
 1287 
 1288         DPRINTF(("proc @%p has undo structure with %d entries\n", p,
 1289             suptr->un_cnt));
 1290 
 1291         /*
 1292          * If there are any active undo elements then process them.
 1293          */
 1294         if (suptr->un_cnt > 0) {
 1295                 SEMUNDO_UNLOCK();
 1296                 for (ix = 0; ix < suptr->un_cnt; ix++) {
 1297                         semid = suptr->un_ent[ix].un_id;
 1298                         semnum = suptr->un_ent[ix].un_num;
 1299                         adjval = suptr->un_ent[ix].un_adjval;
 1300                         seq = suptr->un_ent[ix].un_seq;
 1301                         semakptr = &sema[semid];
 1302                         sema_mtxp = &sema_mtx[semid];
 1303 
 1304                         mtx_lock(sema_mtxp);
 1305                         if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 ||
 1306                             (semakptr->u.sem_perm.seq != seq)) {
 1307                                 mtx_unlock(sema_mtxp);
 1308                                 continue;
 1309                         }
 1310                         if (semnum >= semakptr->u.sem_nsems)
 1311                                 panic("semexit - semnum out of range");
 1312 
 1313                         DPRINTF((
 1314                             "semexit:  %p id=%d num=%d(adj=%d) ; sem=%d\n",
 1315                             suptr->un_proc, suptr->un_ent[ix].un_id,
 1316                             suptr->un_ent[ix].un_num,
 1317                             suptr->un_ent[ix].un_adjval,
 1318                             semakptr->u.sem_base[semnum].semval));
 1319 
 1320                         if (adjval < 0 && semakptr->u.sem_base[semnum].semval <
 1321                             -adjval)
 1322                                 semakptr->u.sem_base[semnum].semval = 0;
 1323                         else
 1324                                 semakptr->u.sem_base[semnum].semval += adjval;
 1325 
 1326                         wakeup(semakptr);
 1327                         DPRINTF(("semexit:  back from wakeup\n"));
 1328                         mtx_unlock(sema_mtxp);
 1329                 }
 1330                 SEMUNDO_LOCK();
 1331         }
 1332 
 1333         /*
 1334          * Deallocate the undo vector.
 1335          */
 1336         DPRINTF(("removing vector\n"));
 1337         suptr->un_proc = NULL;
 1338         suptr->un_cnt = 0;
 1339         LIST_INSERT_HEAD(&semu_free_list, suptr, un_next);
 1340         SEMUNDO_UNLOCK();
 1341 }
 1342 
 1343 static int
 1344 sysctl_sema(SYSCTL_HANDLER_ARGS)
 1345 {
 1346 
 1347         return (SYSCTL_OUT(req, sema,
 1348             sizeof(struct semid_kernel) * seminfo.semmni));
 1349 }

Cache object: 960e8b09163c2161344d8afb79f4b48f


[ 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.