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_msg.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 /*      $NetBSD: sysv_msg.c,v 1.76 2019/10/04 23:20:22 kamil Exp $      */
    2 
    3 /*-
    4  * Copyright (c) 1999, 2006, 2007 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
    9  * NASA Ames Research Center, and by Andrew Doran.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   30  * POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 /*
   34  * Implementation of SVID messages
   35  *
   36  * Author: Daniel Boulet
   37  *
   38  * Copyright 1993 Daniel Boulet and RTMX Inc.
   39  *
   40  * This system call was implemented by Daniel Boulet under contract from RTMX.
   41  *
   42  * Redistribution and use in source forms, with and without modification,
   43  * are permitted provided that this entire comment appears intact.
   44  *
   45  * Redistribution in binary form may occur without any restrictions.
   46  * Obviously, it would be nice if you gave credit where credit is due
   47  * but requiring it would be too onerous.
   48  *
   49  * This software is provided ``AS IS'' without any warranties of any kind.
   50  */
   51 
   52 #include <sys/cdefs.h>
   53 __KERNEL_RCSID(0, "$NetBSD: sysv_msg.c,v 1.76 2019/10/04 23:20:22 kamil Exp $");
   54 
   55 #ifdef _KERNEL_OPT
   56 #include "opt_sysv.h"
   57 #endif
   58 
   59 #include <sys/param.h>
   60 #include <sys/kernel.h>
   61 #include <sys/msg.h>
   62 #include <sys/sysctl.h>
   63 #include <sys/mount.h>          /* XXX for <sys/syscallargs.h> */
   64 #include <sys/syscallargs.h>
   65 #include <sys/kauth.h>
   66 
   67 #define MSG_DEBUG
   68 #undef MSG_DEBUG_OK
   69 
   70 #ifdef MSG_DEBUG_OK
   71 #define MSG_PRINTF(a)   printf a
   72 #else
   73 #define MSG_PRINTF(a)
   74 #endif
   75 
   76 static int      nfree_msgmaps;          /* # of free map entries */
   77 static short    free_msgmaps;   /* head of linked list of free map entries */
   78 static struct   __msg *free_msghdrs;    /* list of free msg headers */
   79 static char     *msgpool;               /* MSGMAX byte long msg buffer pool */
   80 static struct   msgmap *msgmaps;        /* MSGSEG msgmap structures */
   81 static struct __msg *msghdrs;           /* MSGTQL msg headers */
   82 
   83 kmsq_t  *msqs;                          /* MSGMNI msqid_ds struct's */
   84 kmutex_t msgmutex;                      /* subsystem lock */
   85 
   86 static u_int    msg_waiters = 0;        /* total number of msgrcv waiters */
   87 static bool     msg_realloc_state;
   88 static kcondvar_t msg_realloc_cv;
   89 
   90 static void msg_freehdr(struct __msg *);
   91 
   92 extern int kern_has_sysvmsg;
   93 
   94 SYSCTL_SETUP_PROTO(sysctl_ipc_msg_setup);
   95 
   96 int
   97 msginit(void)
   98 {
   99         int i, sz;
  100         vaddr_t v;
  101 
  102         /*
  103          * msginfo.msgssz should be a power of two for efficiency reasons.
  104          * It is also pretty silly if msginfo.msgssz is less than 8
  105          * or greater than about 256 so ...
  106          */
  107 
  108         i = 8;
  109         while (i < 1024 && i != msginfo.msgssz)
  110                 i <<= 1;
  111         if (i != msginfo.msgssz) {
  112                 printf("msginfo.msgssz = %d, not a small power of 2",
  113                     msginfo.msgssz);
  114                 return EINVAL;
  115         }
  116 
  117         if (msginfo.msgseg > 32767) {
  118                 printf("msginfo.msgseg = %d > 32767", msginfo.msgseg);
  119                 return EINVAL;
  120         }
  121 
  122         /* Allocate the wired memory for our structures */
  123         sz = ALIGN(msginfo.msgmax) +
  124             ALIGN(msginfo.msgseg * sizeof(struct msgmap)) +
  125             ALIGN(msginfo.msgtql * sizeof(struct __msg)) +
  126             ALIGN(msginfo.msgmni * sizeof(kmsq_t));
  127         sz = round_page(sz);
  128         v = uvm_km_alloc(kernel_map, sz, 0, UVM_KMF_WIRED|UVM_KMF_ZERO);
  129         if (v == 0) {
  130                 printf("sysv_msg: cannot allocate memory");
  131                 return ENOMEM;
  132         }
  133         msgpool = (void *)v;
  134         msgmaps = (void *)((uintptr_t)msgpool + ALIGN(msginfo.msgmax));
  135         msghdrs = (void *)((uintptr_t)msgmaps +
  136             ALIGN(msginfo.msgseg * sizeof(struct msgmap)));
  137         msqs = (void *)((uintptr_t)msghdrs +
  138             ALIGN(msginfo.msgtql * sizeof(struct __msg)));
  139 
  140         for (i = 0; i < (msginfo.msgseg - 1); i++)
  141                 msgmaps[i].next = i + 1;
  142         msgmaps[msginfo.msgseg - 1].next = -1;
  143 
  144         free_msgmaps = 0;
  145         nfree_msgmaps = msginfo.msgseg;
  146 
  147         for (i = 0; i < (msginfo.msgtql - 1); i++) {
  148                 msghdrs[i].msg_type = 0;
  149                 msghdrs[i].msg_next = &msghdrs[i + 1];
  150         }
  151         i = msginfo.msgtql - 1;
  152         msghdrs[i].msg_type = 0;
  153         msghdrs[i].msg_next = NULL;
  154         free_msghdrs = &msghdrs[0];
  155 
  156         for (i = 0; i < msginfo.msgmni; i++) {
  157                 cv_init(&msqs[i].msq_cv, "msgwait");
  158                 /* Implies entry is available */
  159                 msqs[i].msq_u.msg_qbytes = 0;
  160                 /* Reset to a known value */
  161                 msqs[i].msq_u.msg_perm._seq = 0;
  162         }
  163 
  164         mutex_init(&msgmutex, MUTEX_DEFAULT, IPL_NONE);
  165         cv_init(&msg_realloc_cv, "msgrealc");
  166         msg_realloc_state = false;
  167 
  168         kern_has_sysvmsg = 1;
  169 
  170         return 0;
  171 }
  172 
  173 int
  174 msgfini(void)
  175 {
  176         int i, sz;
  177         vaddr_t v = (vaddr_t)msgpool;
  178 
  179         mutex_enter(&msgmutex);
  180         for (i = 0; i < msginfo.msgmni; i++) {
  181                 if (msqs[i].msq_u.msg_qbytes != 0) {
  182                         mutex_exit(&msgmutex);
  183                         return 1; /* queue not available, prevent unload! */
  184                 }
  185         }
  186 /*
  187  * Destroy all condvars and free the memory we're using
  188  */
  189         for (i = 0; i < msginfo.msgmni; i++) {
  190                 cv_destroy(&msqs[i].msq_cv);
  191         }
  192         sz = ALIGN(msginfo.msgmax) +
  193             ALIGN(msginfo.msgseg * sizeof(struct msgmap)) +
  194             ALIGN(msginfo.msgtql * sizeof(struct __msg)) +
  195             ALIGN(msginfo.msgmni * sizeof(kmsq_t));
  196         sz = round_page(sz);
  197         uvm_km_free(kernel_map, v, sz, UVM_KMF_WIRED);
  198 
  199         cv_destroy(&msg_realloc_cv);
  200         mutex_exit(&msgmutex);
  201         mutex_destroy(&msgmutex);
  202 
  203         kern_has_sysvmsg = 0;
  204 
  205         return 0;
  206 }
  207 
  208 static int
  209 msgrealloc(int newmsgmni, int newmsgseg)
  210 {
  211         struct msgmap *new_msgmaps;
  212         struct __msg *new_msghdrs, *new_free_msghdrs;
  213         char *old_msgpool, *new_msgpool;
  214         kmsq_t *new_msqs;
  215         vaddr_t v;
  216         int i, sz, msqid, newmsgmax, new_nfree_msgmaps;
  217         short new_free_msgmaps;
  218 
  219         if (newmsgmni < 1 || newmsgseg < 1)
  220                 return EINVAL;
  221 
  222         /* Allocate the wired memory for our structures */
  223         newmsgmax = msginfo.msgssz * newmsgseg;
  224         sz = ALIGN(newmsgmax) +
  225             ALIGN(newmsgseg * sizeof(struct msgmap)) +
  226             ALIGN(msginfo.msgtql * sizeof(struct __msg)) +
  227             ALIGN(newmsgmni * sizeof(kmsq_t));
  228         sz = round_page(sz);
  229         v = uvm_km_alloc(kernel_map, sz, 0, UVM_KMF_WIRED|UVM_KMF_ZERO);
  230         if (v == 0)
  231                 return ENOMEM;
  232 
  233         mutex_enter(&msgmutex);
  234         if (msg_realloc_state) {
  235                 mutex_exit(&msgmutex);
  236                 uvm_km_free(kernel_map, v, sz, UVM_KMF_WIRED);
  237                 return EBUSY;
  238         }
  239         msg_realloc_state = true;
  240         if (msg_waiters) {
  241                 /*
  242                  * Mark reallocation state, wake-up all waiters,
  243                  * and wait while they will all exit.
  244                  */
  245                 for (i = 0; i < msginfo.msgmni; i++)
  246                         cv_broadcast(&msqs[i].msq_cv);
  247                 while (msg_waiters)
  248                         cv_wait(&msg_realloc_cv, &msgmutex);
  249         }
  250         old_msgpool = msgpool;
  251 
  252         /* We cannot reallocate less memory than we use */
  253         i = 0;
  254         for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
  255                 struct msqid_ds *mptr;
  256                 kmsq_t *msq;
  257 
  258                 msq = &msqs[msqid];
  259                 mptr = &msq->msq_u;
  260                 if (mptr->msg_qbytes || (mptr->msg_perm.mode & MSG_LOCKED))
  261                         i = msqid;
  262         }
  263         if (i >= newmsgmni || (msginfo.msgseg - nfree_msgmaps) > newmsgseg) {
  264                 mutex_exit(&msgmutex);
  265                 uvm_km_free(kernel_map, v, sz, UVM_KMF_WIRED);
  266                 return EBUSY;
  267         }
  268 
  269         new_msgpool = (void *)v;
  270         new_msgmaps = (void *)((uintptr_t)new_msgpool + ALIGN(newmsgmax));
  271         new_msghdrs = (void *)((uintptr_t)new_msgmaps +
  272             ALIGN(newmsgseg * sizeof(struct msgmap)));
  273         new_msqs = (void *)((uintptr_t)new_msghdrs +
  274             ALIGN(msginfo.msgtql * sizeof(struct __msg)));
  275 
  276         /* Initialize the structures */
  277         for (i = 0; i < (newmsgseg - 1); i++)
  278                 new_msgmaps[i].next = i + 1;
  279         new_msgmaps[newmsgseg - 1].next = -1;
  280         new_free_msgmaps = 0;
  281         new_nfree_msgmaps = newmsgseg;
  282 
  283         for (i = 0; i < (msginfo.msgtql - 1); i++) {
  284                 new_msghdrs[i].msg_type = 0;
  285                 new_msghdrs[i].msg_next = &new_msghdrs[i + 1];
  286         }
  287         i = msginfo.msgtql - 1;
  288         new_msghdrs[i].msg_type = 0;
  289         new_msghdrs[i].msg_next = NULL;
  290         new_free_msghdrs = &new_msghdrs[0];
  291 
  292         for (i = 0; i < newmsgmni; i++) {
  293                 new_msqs[i].msq_u.msg_qbytes = 0;
  294                 new_msqs[i].msq_u.msg_perm._seq = 0;
  295                 cv_init(&new_msqs[i].msq_cv, "msgwait");
  296         }
  297 
  298         /*
  299          * Copy all message queue identifiers, message headers and buffer
  300          * pools to the new memory location.
  301          */
  302         for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
  303                 struct __msg *nmsghdr, *msghdr, *pmsghdr;
  304                 struct msqid_ds *nmptr, *mptr;
  305                 kmsq_t *nmsq, *msq;
  306 
  307                 msq = &msqs[msqid];
  308                 mptr = &msq->msq_u;
  309 
  310                 if (mptr->msg_qbytes == 0 &&
  311                     (mptr->msg_perm.mode & MSG_LOCKED) == 0)
  312                         continue;
  313 
  314                 nmsq = &new_msqs[msqid];
  315                 nmptr = &nmsq->msq_u;
  316                 memcpy(nmptr, mptr, sizeof(struct msqid_ds));
  317 
  318                 /*
  319                  * Go through the message headers, and copy each one
  320                  * by taking the new ones, and thus defragmenting.
  321                  */
  322                 nmsghdr = pmsghdr = NULL;
  323                 msghdr = mptr->_msg_first;
  324                 while (msghdr) {
  325                         short nnext = 0, next;
  326                         u_short msgsz, segcnt;
  327 
  328                         /* Take an entry from the new list of free msghdrs */
  329                         nmsghdr = new_free_msghdrs;
  330                         KASSERT(nmsghdr != NULL);
  331                         new_free_msghdrs = nmsghdr->msg_next;
  332 
  333                         nmsghdr->msg_next = NULL;
  334                         if (pmsghdr) {
  335                                 pmsghdr->msg_next = nmsghdr;
  336                         } else {
  337                                 nmptr->_msg_first = nmsghdr;
  338                                 pmsghdr = nmsghdr;
  339                         }
  340                         nmsghdr->msg_ts = msghdr->msg_ts;
  341                         nmsghdr->msg_spot = -1;
  342 
  343                         /* Compute the amount of segments and reserve them */
  344                         msgsz = msghdr->msg_ts;
  345                         segcnt = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz;
  346                         if (segcnt == 0)
  347                                 continue;
  348                         while (segcnt--) {
  349                                 nnext = new_free_msgmaps;
  350                                 new_free_msgmaps = new_msgmaps[nnext].next;
  351                                 new_nfree_msgmaps--;
  352                                 new_msgmaps[nnext].next = nmsghdr->msg_spot;
  353                                 nmsghdr->msg_spot = nnext;
  354                         }
  355 
  356                         /* Copy all segments */
  357                         KASSERT(nnext == nmsghdr->msg_spot);
  358                         next = msghdr->msg_spot;
  359                         while (msgsz > 0) {
  360                                 size_t tlen;
  361 
  362                                 if (msgsz >= msginfo.msgssz) {
  363                                         tlen = msginfo.msgssz;
  364                                         msgsz -= msginfo.msgssz;
  365                                 } else {
  366                                         tlen = msgsz;
  367                                         msgsz = 0;
  368                                 }
  369 
  370                                 /* Copy the message buffer */
  371                                 memcpy(&new_msgpool[nnext * msginfo.msgssz],
  372                                     &msgpool[next * msginfo.msgssz], tlen);
  373 
  374                                 /* Next entry of the map */
  375                                 nnext = msgmaps[nnext].next;
  376                                 next = msgmaps[next].next;
  377                         }
  378 
  379                         /* Next message header */
  380                         msghdr = msghdr->msg_next;
  381                 }
  382                 nmptr->_msg_last = nmsghdr;
  383         }
  384         KASSERT((msginfo.msgseg - nfree_msgmaps) ==
  385             (newmsgseg - new_nfree_msgmaps));
  386 
  387         sz = ALIGN(msginfo.msgmax) +
  388             ALIGN(msginfo.msgseg * sizeof(struct msgmap)) +
  389             ALIGN(msginfo.msgtql * sizeof(struct __msg)) +
  390             ALIGN(msginfo.msgmni * sizeof(kmsq_t));
  391         sz = round_page(sz);
  392 
  393         for (i = 0; i < msginfo.msgmni; i++)
  394                 cv_destroy(&msqs[i].msq_cv);
  395 
  396         /* Set the pointers and update the new values */
  397         msgpool = new_msgpool;
  398         msgmaps = new_msgmaps;
  399         msghdrs = new_msghdrs;
  400         msqs = new_msqs;
  401 
  402         free_msghdrs = new_free_msghdrs;
  403         free_msgmaps = new_free_msgmaps;
  404         nfree_msgmaps = new_nfree_msgmaps;
  405         msginfo.msgmni = newmsgmni;
  406         msginfo.msgseg = newmsgseg;
  407         msginfo.msgmax = newmsgmax;
  408 
  409         /* Reallocation completed - notify all waiters, if any */
  410         msg_realloc_state = false;
  411         cv_broadcast(&msg_realloc_cv);
  412         mutex_exit(&msgmutex);
  413 
  414         uvm_km_free(kernel_map, (vaddr_t)old_msgpool, sz, UVM_KMF_WIRED);
  415         return 0;
  416 }
  417 
  418 static void
  419 msg_freehdr(struct __msg *msghdr)
  420 {
  421 
  422         KASSERT(mutex_owned(&msgmutex));
  423 
  424         while (msghdr->msg_ts > 0) {
  425                 short next;
  426                 KASSERT(msghdr->msg_spot >= 0);
  427                 KASSERT(msghdr->msg_spot < msginfo.msgseg);
  428 
  429                 next = msgmaps[msghdr->msg_spot].next;
  430                 msgmaps[msghdr->msg_spot].next = free_msgmaps;
  431                 free_msgmaps = msghdr->msg_spot;
  432                 nfree_msgmaps++;
  433                 msghdr->msg_spot = next;
  434                 if (msghdr->msg_ts >= msginfo.msgssz)
  435                         msghdr->msg_ts -= msginfo.msgssz;
  436                 else
  437                         msghdr->msg_ts = 0;
  438         }
  439         KASSERT(msghdr->msg_spot == -1);
  440         msghdr->msg_next = free_msghdrs;
  441         free_msghdrs = msghdr;
  442 }
  443 
  444 int
  445 sys___msgctl50(struct lwp *l, const struct sys___msgctl50_args *uap,
  446     register_t *retval)
  447 {
  448         /* {
  449                 syscallarg(int) msqid;
  450                 syscallarg(int) cmd;
  451                 syscallarg(struct msqid_ds *) buf;
  452         } */
  453         struct msqid_ds msqbuf;
  454         int cmd, error;
  455 
  456         cmd = SCARG(uap, cmd);
  457 
  458         if (cmd == IPC_SET) {
  459                 error = copyin(SCARG(uap, buf), &msqbuf, sizeof(msqbuf));
  460                 if (error)
  461                         return (error);
  462         }
  463 
  464         error = msgctl1(l, SCARG(uap, msqid), cmd,
  465             (cmd == IPC_SET || cmd == IPC_STAT) ? &msqbuf : NULL);
  466 
  467         if (error == 0 && cmd == IPC_STAT)
  468                 error = copyout(&msqbuf, SCARG(uap, buf), sizeof(msqbuf));
  469 
  470         return (error);
  471 }
  472 
  473 int
  474 msgctl1(struct lwp *l, int msqid, int cmd, struct msqid_ds *msqbuf)
  475 {
  476         kauth_cred_t cred = l->l_cred;
  477         struct msqid_ds *msqptr;
  478         kmsq_t *msq;
  479         int error = 0, ix;
  480 
  481         MSG_PRINTF(("call to msgctl1(%d, %d)\n", msqid, cmd));
  482 
  483         ix = IPCID_TO_IX(msqid);
  484 
  485         mutex_enter(&msgmutex);
  486 
  487         if (ix < 0 || ix >= msginfo.msgmni) {
  488                 MSG_PRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", ix,
  489                     msginfo.msgmni));
  490                 error = EINVAL;
  491                 goto unlock;
  492         }
  493 
  494         msq = &msqs[ix];
  495         msqptr = &msq->msq_u;
  496 
  497         if (msqptr->msg_qbytes == 0) {
  498                 MSG_PRINTF(("no such msqid\n"));
  499                 error = EINVAL;
  500                 goto unlock;
  501         }
  502         if (msqptr->msg_perm._seq != IPCID_TO_SEQ(msqid)) {
  503                 MSG_PRINTF(("wrong sequence number\n"));
  504                 error = EINVAL;
  505                 goto unlock;
  506         }
  507 
  508         switch (cmd) {
  509         case IPC_RMID:
  510         {
  511                 struct __msg *msghdr;
  512                 if ((error = ipcperm(cred, &msqptr->msg_perm, IPC_M)) != 0)
  513                         break;
  514                 /* Free the message headers */
  515                 msghdr = msqptr->_msg_first;
  516                 while (msghdr != NULL) {
  517                         struct __msg *msghdr_tmp;
  518 
  519                         /* Free the segments of each message */
  520                         msqptr->_msg_cbytes -= msghdr->msg_ts;
  521                         msqptr->msg_qnum--;
  522                         msghdr_tmp = msghdr;
  523                         msghdr = msghdr->msg_next;
  524                         msg_freehdr(msghdr_tmp);
  525                 }
  526                 KASSERT(msqptr->_msg_cbytes == 0);
  527                 KASSERT(msqptr->msg_qnum == 0);
  528 
  529                 /* Mark it as free */
  530                 msqptr->msg_qbytes = 0;
  531                 cv_broadcast(&msq->msq_cv);
  532         }
  533                 break;
  534 
  535         case IPC_SET:
  536                 if ((error = ipcperm(cred, &msqptr->msg_perm, IPC_M)))
  537                         break;
  538                 if (msqbuf->msg_qbytes > msqptr->msg_qbytes &&
  539                     kauth_authorize_system(cred, KAUTH_SYSTEM_SYSVIPC,
  540                     KAUTH_REQ_SYSTEM_SYSVIPC_MSGQ_OVERSIZE,
  541                     KAUTH_ARG(msqbuf->msg_qbytes),
  542                     KAUTH_ARG(msqptr->msg_qbytes), NULL) != 0) {
  543                         error = EPERM;
  544                         break;
  545                 }
  546                 if (msqbuf->msg_qbytes > msginfo.msgmnb) {
  547                         MSG_PRINTF(("can't increase msg_qbytes beyond %d "
  548                             "(truncating)\n", msginfo.msgmnb));
  549                         /* silently restrict qbytes to system limit */
  550                         msqbuf->msg_qbytes = msginfo.msgmnb;
  551                 }
  552                 if (msqbuf->msg_qbytes == 0) {
  553                         MSG_PRINTF(("can't reduce msg_qbytes to 0\n"));
  554                         error = EINVAL;         /* XXX non-standard errno! */
  555                         break;
  556                 }
  557                 msqptr->msg_perm.uid = msqbuf->msg_perm.uid;
  558                 msqptr->msg_perm.gid = msqbuf->msg_perm.gid;
  559                 msqptr->msg_perm.mode = (msqptr->msg_perm.mode & ~0777) |
  560                     (msqbuf->msg_perm.mode & 0777);
  561                 msqptr->msg_qbytes = msqbuf->msg_qbytes;
  562                 msqptr->msg_ctime = time_second;
  563                 break;
  564 
  565         case IPC_STAT:
  566                 if ((error = ipcperm(cred, &msqptr->msg_perm, IPC_R))) {
  567                         MSG_PRINTF(("requester doesn't have read access\n"));
  568                         break;
  569                 }
  570                 memset(msqbuf, 0, sizeof *msqbuf);
  571                 msqbuf->msg_perm = msqptr->msg_perm;
  572                 msqbuf->msg_perm.mode &= 0777;
  573                 msqbuf->msg_qnum = msqptr->msg_qnum;
  574                 msqbuf->msg_qbytes = msqptr->msg_qbytes;
  575                 msqbuf->msg_lspid = msqptr->msg_lspid;
  576                 msqbuf->msg_lrpid = msqptr->msg_lrpid;
  577                 msqbuf->msg_stime = msqptr->msg_stime;
  578                 msqbuf->msg_rtime = msqptr->msg_rtime;
  579                 msqbuf->msg_ctime = msqptr->msg_ctime;
  580                 break;
  581 
  582         default:
  583                 MSG_PRINTF(("invalid command %d\n", cmd));
  584                 error = EINVAL;
  585                 break;
  586         }
  587 
  588 unlock:
  589         mutex_exit(&msgmutex);
  590         return (error);
  591 }
  592 
  593 int
  594 sys_msgget(struct lwp *l, const struct sys_msgget_args *uap, register_t *retval)
  595 {
  596         /* {
  597                 syscallarg(key_t) key;
  598                 syscallarg(int) msgflg;
  599         } */
  600         int msqid, error = 0;
  601         int key = SCARG(uap, key);
  602         int msgflg = SCARG(uap, msgflg);
  603         kauth_cred_t cred = l->l_cred;
  604         struct msqid_ds *msqptr = NULL;
  605         kmsq_t *msq;
  606 
  607         mutex_enter(&msgmutex);
  608 
  609         MSG_PRINTF(("msgget(0x%x, 0%o)\n", key, msgflg));
  610 
  611         if (key != IPC_PRIVATE) {
  612                 for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
  613                         msq = &msqs[msqid];
  614                         msqptr = &msq->msq_u;
  615                         if (msqptr->msg_qbytes != 0 &&
  616                             msqptr->msg_perm._key == key)
  617                                 break;
  618                 }
  619                 if (msqid < msginfo.msgmni) {
  620                         MSG_PRINTF(("found public key\n"));
  621                         if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) {
  622                                 MSG_PRINTF(("not exclusive\n"));
  623                                 error = EEXIST;
  624                                 goto unlock;
  625                         }
  626                         if ((error = ipcperm(cred, &msqptr->msg_perm,
  627                             msgflg & 0700 ))) {
  628                                 MSG_PRINTF(("requester doesn't have 0%o access\n",
  629                                     msgflg & 0700));
  630                                 goto unlock;
  631                         }
  632                         goto found;
  633                 }
  634         }
  635 
  636         MSG_PRINTF(("need to allocate the msqid_ds\n"));
  637         if (key == IPC_PRIVATE || (msgflg & IPC_CREAT)) {
  638                 for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
  639                         /*
  640                          * Look for an unallocated and unlocked msqid_ds.
  641                          * msqid_ds's can be locked by msgsnd or msgrcv while
  642                          * they are copying the message in/out.  We can't
  643                          * re-use the entry until they release it.
  644                          */
  645                         msq = &msqs[msqid];
  646                         msqptr = &msq->msq_u;
  647                         if (msqptr->msg_qbytes == 0 &&
  648                             (msqptr->msg_perm.mode & MSG_LOCKED) == 0)
  649                                 break;
  650                 }
  651                 if (msqid == msginfo.msgmni) {
  652                         MSG_PRINTF(("no more msqid_ds's available\n"));
  653                         error = ENOSPC;
  654                         goto unlock;
  655                 }
  656                 MSG_PRINTF(("msqid %d is available\n", msqid));
  657                 msqptr->msg_perm._key = key;
  658                 msqptr->msg_perm.cuid = kauth_cred_geteuid(cred);
  659                 msqptr->msg_perm.uid = kauth_cred_geteuid(cred);
  660                 msqptr->msg_perm.cgid = kauth_cred_getegid(cred);
  661                 msqptr->msg_perm.gid = kauth_cred_getegid(cred);
  662                 msqptr->msg_perm.mode = (msgflg & 0777);
  663                 /* Make sure that the returned msqid is unique */
  664                 msqptr->msg_perm._seq++;
  665                 msqptr->_msg_first = NULL;
  666                 msqptr->_msg_last = NULL;
  667                 msqptr->_msg_cbytes = 0;
  668                 msqptr->msg_qnum = 0;
  669                 msqptr->msg_qbytes = msginfo.msgmnb;
  670                 msqptr->msg_lspid = 0;
  671                 msqptr->msg_lrpid = 0;
  672                 msqptr->msg_stime = 0;
  673                 msqptr->msg_rtime = 0;
  674                 msqptr->msg_ctime = time_second;
  675         } else {
  676                 MSG_PRINTF(("didn't find it and wasn't asked to create it\n"));
  677                 error = ENOENT;
  678                 goto unlock;
  679         }
  680 
  681 found:
  682         /* Construct the unique msqid */
  683         *retval = IXSEQ_TO_IPCID(msqid, msqptr->msg_perm);
  684 
  685 unlock:
  686         mutex_exit(&msgmutex);
  687         return (error);
  688 }
  689 
  690 int
  691 sys_msgsnd(struct lwp *l, const struct sys_msgsnd_args *uap, register_t *retval)
  692 {
  693         /* {
  694                 syscallarg(int) msqid;
  695                 syscallarg(const void *) msgp;
  696                 syscallarg(size_t) msgsz;
  697                 syscallarg(int) msgflg;
  698         } */
  699 
  700         return msgsnd1(l, SCARG(uap, msqid), SCARG(uap, msgp),
  701             SCARG(uap, msgsz), SCARG(uap, msgflg), sizeof(long), copyin);
  702 }
  703 
  704 int
  705 msgsnd1(struct lwp *l, int msqidr, const char *user_msgp, size_t msgsz,
  706     int msgflg, size_t typesz, copyin_t fetch_type)
  707 {
  708         int segs_needed, error = 0, msqid;
  709         kauth_cred_t cred = l->l_cred;
  710         struct msqid_ds *msqptr;
  711         struct __msg *msghdr;
  712         kmsq_t *msq;
  713         short next;
  714 
  715         MSG_PRINTF(("call to msgsnd(%d, %p, %lld, %d)\n", msqidr,
  716              user_msgp, (long long)msgsz, msgflg));
  717 
  718         if ((ssize_t)msgsz < 0)
  719                 return EINVAL;
  720 
  721 restart:
  722         msqid = IPCID_TO_IX(msqidr);
  723 
  724         mutex_enter(&msgmutex);
  725         /* In case of reallocation, we will wait for completion */
  726         while (__predict_false(msg_realloc_state))
  727                 cv_wait(&msg_realloc_cv, &msgmutex);
  728 
  729         if (msqid < 0 || msqid >= msginfo.msgmni) {
  730                 MSG_PRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
  731                     msginfo.msgmni));
  732                 error = EINVAL;
  733                 goto unlock;
  734         }
  735 
  736         msq = &msqs[msqid];
  737         msqptr = &msq->msq_u;
  738 
  739         if (msqptr->msg_qbytes == 0) {
  740                 MSG_PRINTF(("no such message queue id\n"));
  741                 error = EINVAL;
  742                 goto unlock;
  743         }
  744         if (msqptr->msg_perm._seq != IPCID_TO_SEQ(msqidr)) {
  745                 MSG_PRINTF(("wrong sequence number\n"));
  746                 error = EINVAL;
  747                 goto unlock;
  748         }
  749 
  750         if ((error = ipcperm(cred, &msqptr->msg_perm, IPC_W))) {
  751                 MSG_PRINTF(("requester doesn't have write access\n"));
  752                 goto unlock;
  753         }
  754 
  755         segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz;
  756         MSG_PRINTF(("msgsz=%lld, msgssz=%d, segs_needed=%d\n",
  757             (long long)msgsz, msginfo.msgssz, segs_needed));
  758         for (;;) {
  759                 int need_more_resources = 0;
  760 
  761                 /*
  762                  * check msgsz [cannot be negative since it is unsigned]
  763                  * (inside this loop in case msg_qbytes changes while we sleep)
  764                  */
  765 
  766                 if (msgsz > msqptr->msg_qbytes) {
  767                         MSG_PRINTF(("msgsz > msqptr->msg_qbytes\n"));
  768                         error = EINVAL;
  769                         goto unlock;
  770                 }
  771 
  772                 if (msqptr->msg_perm.mode & MSG_LOCKED) {
  773                         MSG_PRINTF(("msqid is locked\n"));
  774                         need_more_resources = 1;
  775                 }
  776                 if (msgsz + msqptr->_msg_cbytes > msqptr->msg_qbytes) {
  777                         MSG_PRINTF(("msgsz + msg_cbytes > msg_qbytes\n"));
  778                         need_more_resources = 1;
  779                 }
  780                 if (segs_needed > nfree_msgmaps) {
  781                         MSG_PRINTF(("segs_needed > nfree_msgmaps\n"));
  782                         need_more_resources = 1;
  783                 }
  784                 if (free_msghdrs == NULL) {
  785                         MSG_PRINTF(("no more msghdrs\n"));
  786                         need_more_resources = 1;
  787                 }
  788 
  789                 if (need_more_resources) {
  790                         int we_own_it;
  791 
  792                         if ((msgflg & IPC_NOWAIT) != 0) {
  793                                 MSG_PRINTF(("need more resources but caller "
  794                                     "doesn't want to wait\n"));
  795                                 error = EAGAIN;
  796                                 goto unlock;
  797                         }
  798 
  799                         if ((msqptr->msg_perm.mode & MSG_LOCKED) != 0) {
  800                                 MSG_PRINTF(("we don't own the msqid_ds\n"));
  801                                 we_own_it = 0;
  802                         } else {
  803                                 /* Force later arrivals to wait for our
  804                                    request */
  805                                 MSG_PRINTF(("we own the msqid_ds\n"));
  806                                 msqptr->msg_perm.mode |= MSG_LOCKED;
  807                                 we_own_it = 1;
  808                         }
  809 
  810                         msg_waiters++;
  811                         MSG_PRINTF(("goodnight\n"));
  812                         error = cv_wait_sig(&msq->msq_cv, &msgmutex);
  813                         MSG_PRINTF(("good morning, error=%d\n", error));
  814                         msg_waiters--;
  815 
  816                         if (we_own_it)
  817                                 msqptr->msg_perm.mode &= ~MSG_LOCKED;
  818 
  819                         /*
  820                          * In case of such state, notify reallocator and
  821                          * restart the call.
  822                          */
  823                         if (msg_realloc_state) {
  824                                 cv_broadcast(&msg_realloc_cv);
  825                                 mutex_exit(&msgmutex);
  826                                 goto restart;
  827                         }
  828 
  829                         if (error != 0) {
  830                                 MSG_PRINTF(("msgsnd: interrupted system "
  831                                     "call\n"));
  832                                 error = EINTR;
  833                                 goto unlock;
  834                         }
  835 
  836                         /*
  837                          * Make sure that the msq queue still exists
  838                          */
  839 
  840                         if (msqptr->msg_qbytes == 0) {
  841                                 MSG_PRINTF(("msqid deleted\n"));
  842                                 error = EIDRM;
  843                                 goto unlock;
  844                         }
  845                 } else {
  846                         MSG_PRINTF(("got all the resources that we need\n"));
  847                         break;
  848                 }
  849         }
  850 
  851         /*
  852          * We have the resources that we need.
  853          * Make sure!
  854          */
  855 
  856         KASSERT((msqptr->msg_perm.mode & MSG_LOCKED) == 0);
  857         KASSERT(segs_needed <= nfree_msgmaps);
  858         KASSERT(msgsz + msqptr->_msg_cbytes <= msqptr->msg_qbytes);
  859         KASSERT(free_msghdrs != NULL);
  860 
  861         /*
  862          * Re-lock the msqid_ds in case we page-fault when copying in the
  863          * message
  864          */
  865 
  866         KASSERT((msqptr->msg_perm.mode & MSG_LOCKED) == 0);
  867         msqptr->msg_perm.mode |= MSG_LOCKED;
  868 
  869         /*
  870          * Allocate a message header
  871          */
  872 
  873         msghdr = free_msghdrs;
  874         free_msghdrs = msghdr->msg_next;
  875         msghdr->msg_spot = -1;
  876         msghdr->msg_ts = msgsz;
  877 
  878         /*
  879          * Allocate space for the message
  880          */
  881 
  882         while (segs_needed > 0) {
  883                 KASSERT(nfree_msgmaps > 0);
  884                 KASSERT(free_msgmaps != -1);
  885                 KASSERT(free_msgmaps < msginfo.msgseg);
  886 
  887                 next = free_msgmaps;
  888                 MSG_PRINTF(("allocating segment %d to message\n", next));
  889                 free_msgmaps = msgmaps[next].next;
  890                 nfree_msgmaps--;
  891                 msgmaps[next].next = msghdr->msg_spot;
  892                 msghdr->msg_spot = next;
  893                 segs_needed--;
  894         }
  895 
  896         /*
  897          * Copy in the message type
  898          */
  899         mutex_exit(&msgmutex);
  900         error = (*fetch_type)(user_msgp, &msghdr->msg_type, typesz);
  901         mutex_enter(&msgmutex);
  902         if (error != 0) {
  903                 MSG_PRINTF(("error %d copying the message type\n", error));
  904                 msg_freehdr(msghdr);
  905                 msqptr->msg_perm.mode &= ~MSG_LOCKED;
  906                 cv_broadcast(&msq->msq_cv);
  907                 goto unlock;
  908         }
  909         user_msgp += typesz;
  910 
  911         /*
  912          * Validate the message type
  913          */
  914 
  915         if (msghdr->msg_type < 1) {
  916                 msg_freehdr(msghdr);
  917                 msqptr->msg_perm.mode &= ~MSG_LOCKED;
  918                 cv_broadcast(&msq->msq_cv);
  919                 MSG_PRINTF(("mtype (%ld) < 1\n", msghdr->msg_type));
  920                 error = EINVAL;
  921                 goto unlock;
  922         }
  923 
  924         /*
  925          * Copy in the message body
  926          */
  927 
  928         next = msghdr->msg_spot;
  929         while (msgsz > 0) {
  930                 size_t tlen;
  931                 KASSERT(next > -1);
  932                 KASSERT(next < msginfo.msgseg);
  933 
  934                 if (msgsz > msginfo.msgssz)
  935                         tlen = msginfo.msgssz;
  936                 else
  937                         tlen = msgsz;
  938                 mutex_exit(&msgmutex);
  939                 error = copyin(user_msgp, &msgpool[next * msginfo.msgssz], tlen);
  940                 mutex_enter(&msgmutex);
  941                 if (error != 0) {
  942                         MSG_PRINTF(("error %d copying in message segment\n",
  943                             error));
  944                         msg_freehdr(msghdr);
  945                         msqptr->msg_perm.mode &= ~MSG_LOCKED;
  946                         cv_broadcast(&msq->msq_cv);
  947                         goto unlock;
  948                 }
  949                 msgsz -= tlen;
  950                 user_msgp += tlen;
  951                 next = msgmaps[next].next;
  952         }
  953         KASSERT(next == -1);
  954 
  955         /*
  956          * We've got the message.  Unlock the msqid_ds.
  957          */
  958 
  959         msqptr->msg_perm.mode &= ~MSG_LOCKED;
  960 
  961         /*
  962          * Make sure that the msqid_ds is still allocated.
  963          */
  964 
  965         if (msqptr->msg_qbytes == 0) {
  966                 msg_freehdr(msghdr);
  967                 cv_broadcast(&msq->msq_cv);
  968                 error = EIDRM;
  969                 goto unlock;
  970         }
  971 
  972         /*
  973          * Put the message into the queue
  974          */
  975 
  976         if (msqptr->_msg_first == NULL) {
  977                 msqptr->_msg_first = msghdr;
  978                 msqptr->_msg_last = msghdr;
  979         } else {
  980                 msqptr->_msg_last->msg_next = msghdr;
  981                 msqptr->_msg_last = msghdr;
  982         }
  983         msqptr->_msg_last->msg_next = NULL;
  984 
  985         msqptr->_msg_cbytes += msghdr->msg_ts;
  986         msqptr->msg_qnum++;
  987         msqptr->msg_lspid = l->l_proc->p_pid;
  988         msqptr->msg_stime = time_second;
  989 
  990         cv_broadcast(&msq->msq_cv);
  991 
  992 unlock:
  993         mutex_exit(&msgmutex);
  994         return error;
  995 }
  996 
  997 int
  998 sys_msgrcv(struct lwp *l, const struct sys_msgrcv_args *uap, register_t *retval)
  999 {
 1000         /* {
 1001                 syscallarg(int) msqid;
 1002                 syscallarg(void *) msgp;
 1003                 syscallarg(size_t) msgsz;
 1004                 syscallarg(long) msgtyp;
 1005                 syscallarg(int) msgflg;
 1006         } */
 1007 
 1008         return msgrcv1(l, SCARG(uap, msqid), SCARG(uap, msgp),
 1009             SCARG(uap, msgsz), SCARG(uap, msgtyp), SCARG(uap, msgflg),
 1010             sizeof(long), copyout, retval);
 1011 }
 1012 
 1013 int
 1014 msgrcv1(struct lwp *l, int msqidr, char *user_msgp, size_t msgsz, long msgtyp,
 1015     int msgflg, size_t typesz, copyout_t put_type, register_t *retval)
 1016 {
 1017         size_t len;
 1018         kauth_cred_t cred = l->l_cred;
 1019         struct msqid_ds *msqptr;
 1020         struct __msg *msghdr;
 1021         int error = 0, msqid;
 1022         kmsq_t *msq;
 1023         short next;
 1024 
 1025         MSG_PRINTF(("call to msgrcv(%d, %p, %lld, %ld, %d)\n", msqidr,
 1026             user_msgp, (long long)msgsz, msgtyp, msgflg));
 1027 
 1028         if ((ssize_t)msgsz < 0)
 1029                 return EINVAL;
 1030 
 1031 restart:
 1032         msqid = IPCID_TO_IX(msqidr);
 1033 
 1034         mutex_enter(&msgmutex);
 1035         /* In case of reallocation, we will wait for completion */
 1036         while (__predict_false(msg_realloc_state))
 1037                 cv_wait(&msg_realloc_cv, &msgmutex);
 1038 
 1039         if (msqid < 0 || msqid >= msginfo.msgmni) {
 1040                 MSG_PRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
 1041                     msginfo.msgmni));
 1042                 error = EINVAL;
 1043                 goto unlock;
 1044         }
 1045 
 1046         msq = &msqs[msqid];
 1047         msqptr = &msq->msq_u;
 1048 
 1049         if (msqptr->msg_qbytes == 0) {
 1050                 MSG_PRINTF(("no such message queue id\n"));
 1051                 error = EINVAL;
 1052                 goto unlock;
 1053         }
 1054         if (msqptr->msg_perm._seq != IPCID_TO_SEQ(msqidr)) {
 1055                 MSG_PRINTF(("wrong sequence number\n"));
 1056                 error = EINVAL;
 1057                 goto unlock;
 1058         }
 1059 
 1060         if ((error = ipcperm(cred, &msqptr->msg_perm, IPC_R))) {
 1061                 MSG_PRINTF(("requester doesn't have read access\n"));
 1062                 goto unlock;
 1063         }
 1064 
 1065         msghdr = NULL;
 1066         while (msghdr == NULL) {
 1067                 if (msgtyp == 0) {
 1068                         msghdr = msqptr->_msg_first;
 1069                         if (msghdr != NULL) {
 1070                                 if (msgsz < msghdr->msg_ts &&
 1071                                     (msgflg & MSG_NOERROR) == 0) {
 1072                                         MSG_PRINTF(("first msg on the queue "
 1073                                             "is too big (want %lld, got %d)\n",
 1074                                             (long long)msgsz, msghdr->msg_ts));
 1075                                         error = E2BIG;
 1076                                         goto unlock;
 1077                                 }
 1078                                 if (msqptr->_msg_first == msqptr->_msg_last) {
 1079                                         msqptr->_msg_first = NULL;
 1080                                         msqptr->_msg_last = NULL;
 1081                                 } else {
 1082                                         msqptr->_msg_first = msghdr->msg_next;
 1083                                         KASSERT(msqptr->_msg_first != NULL);
 1084                                 }
 1085                         }
 1086                 } else {
 1087                         struct __msg *previous;
 1088                         struct __msg **prev;
 1089 
 1090                         for (previous = NULL, prev = &msqptr->_msg_first;
 1091                              (msghdr = *prev) != NULL;
 1092                              previous = msghdr, prev = &msghdr->msg_next) {
 1093                                 /*
 1094                                  * Is this message's type an exact match or is
 1095                                  * this message's type less than or equal to
 1096                                  * the absolute value of a negative msgtyp?
 1097                                  * Note that the second half of this test can
 1098                                  * NEVER be true if msgtyp is positive since
 1099                                  * msg_type is always positive!
 1100                                  */
 1101 
 1102                                 if (msgtyp != msghdr->msg_type &&
 1103                                     msgtyp != LONG_MIN &&
 1104                                     msghdr->msg_type > -msgtyp)
 1105                                         continue;
 1106 
 1107                                 MSG_PRINTF(("found message type %ld, requested %ld\n",
 1108                                     msghdr->msg_type, msgtyp));
 1109                                 if (msgsz < msghdr->msg_ts &&
 1110                                      (msgflg & MSG_NOERROR) == 0) {
 1111                                         MSG_PRINTF(("requested message on the queue "
 1112                                             "is too big (want %lld, got %d)\n",
 1113                                             (long long)msgsz, msghdr->msg_ts));
 1114                                         error = E2BIG;
 1115                                         goto unlock;
 1116                                 }
 1117                                 *prev = msghdr->msg_next;
 1118                                 if (msghdr != msqptr->_msg_last)
 1119                                         break;
 1120                                 if (previous == NULL) {
 1121                                         KASSERT(prev == &msqptr->_msg_first);
 1122                                         msqptr->_msg_first = NULL;
 1123                                         msqptr->_msg_last = NULL;
 1124                                 } else {
 1125                                         KASSERT(prev != &msqptr->_msg_first);
 1126                                         msqptr->_msg_last = previous;
 1127                                 }
 1128                                 break;
 1129                         }
 1130                 }
 1131 
 1132                 /*
 1133                  * We've either extracted the msghdr for the appropriate
 1134                  * message or there isn't one.
 1135                  * If there is one then bail out of this loop.
 1136                  */
 1137                 if (msghdr != NULL)
 1138                         break;
 1139 
 1140                 /*
 1141                  * Hmph!  No message found.  Does the user want to wait?
 1142                  */
 1143 
 1144                 if ((msgflg & IPC_NOWAIT) != 0) {
 1145                         MSG_PRINTF(("no appropriate message found (msgtyp=%ld)\n",
 1146                             msgtyp));
 1147                         error = ENOMSG;
 1148                         goto unlock;
 1149                 }
 1150 
 1151                 /*
 1152                  * Wait for something to happen
 1153                  */
 1154 
 1155                 msg_waiters++;
 1156                 MSG_PRINTF(("msgrcv:  goodnight\n"));
 1157                 error = cv_wait_sig(&msq->msq_cv, &msgmutex);
 1158                 MSG_PRINTF(("msgrcv: good morning (error=%d)\n", error));
 1159                 msg_waiters--;
 1160 
 1161                 /*
 1162                  * In case of such state, notify reallocator and
 1163                  * restart the call.
 1164                  */
 1165                 if (msg_realloc_state) {
 1166                         cv_broadcast(&msg_realloc_cv);
 1167                         mutex_exit(&msgmutex);
 1168                         goto restart;
 1169                 }
 1170 
 1171                 if (error != 0) {
 1172                         MSG_PRINTF(("msgsnd: interrupted system call\n"));
 1173                         error = EINTR;
 1174                         goto unlock;
 1175                 }
 1176 
 1177                 /*
 1178                  * Make sure that the msq queue still exists
 1179                  */
 1180 
 1181                 if (msqptr->msg_qbytes == 0 ||
 1182                     msqptr->msg_perm._seq != IPCID_TO_SEQ(msqidr)) {
 1183                         MSG_PRINTF(("msqid deleted\n"));
 1184                         error = EIDRM;
 1185                         goto unlock;
 1186                 }
 1187         }
 1188 
 1189         /*
 1190          * Return the message to the user.
 1191          *
 1192          * First, do the bookkeeping (before we risk being interrupted).
 1193          */
 1194 
 1195         msqptr->_msg_cbytes -= msghdr->msg_ts;
 1196         msqptr->msg_qnum--;
 1197         msqptr->msg_lrpid = l->l_proc->p_pid;
 1198         msqptr->msg_rtime = time_second;
 1199 
 1200         /*
 1201          * Make msgsz the actual amount that we'll be returning.
 1202          * Note that this effectively truncates the message if it is too long
 1203          * (since msgsz is never increased).
 1204          */
 1205 
 1206         MSG_PRINTF(("found a message, msgsz=%lld, msg_ts=%d\n",
 1207             (long long)msgsz, msghdr->msg_ts));
 1208         if (msgsz > msghdr->msg_ts)
 1209                 msgsz = msghdr->msg_ts;
 1210 
 1211         /*
 1212          * Return the type to the user.
 1213          */
 1214         mutex_exit(&msgmutex);
 1215         error = (*put_type)(&msghdr->msg_type, user_msgp, typesz);
 1216         mutex_enter(&msgmutex);
 1217         if (error != 0) {
 1218                 MSG_PRINTF(("error (%d) copying out message type\n", error));
 1219                 msg_freehdr(msghdr);
 1220                 cv_broadcast(&msq->msq_cv);
 1221                 goto unlock;
 1222         }
 1223         user_msgp += typesz;
 1224 
 1225         /*
 1226          * Return the segments to the user
 1227          */
 1228 
 1229         next = msghdr->msg_spot;
 1230         for (len = 0; len < msgsz; len += msginfo.msgssz) {
 1231                 size_t tlen;
 1232                 KASSERT(next > -1);
 1233                 KASSERT(next < msginfo.msgseg);
 1234 
 1235                 if (msgsz - len > msginfo.msgssz)
 1236                         tlen = msginfo.msgssz;
 1237                 else
 1238                         tlen = msgsz - len;
 1239                 mutex_exit(&msgmutex);
 1240                 error = copyout(&msgpool[next * msginfo.msgssz],
 1241                     user_msgp, tlen);
 1242                 mutex_enter(&msgmutex);
 1243                 if (error != 0) {
 1244                         MSG_PRINTF(("error (%d) copying out message segment\n",
 1245                             error));
 1246                         msg_freehdr(msghdr);
 1247                         cv_broadcast(&msq->msq_cv);
 1248                         goto unlock;
 1249                 }
 1250                 user_msgp += tlen;
 1251                 next = msgmaps[next].next;
 1252         }
 1253 
 1254         /*
 1255          * Done, return the actual number of bytes copied out.
 1256          */
 1257 
 1258         msg_freehdr(msghdr);
 1259         cv_broadcast(&msq->msq_cv);
 1260         *retval = msgsz;
 1261 
 1262 unlock:
 1263         mutex_exit(&msgmutex);
 1264         return error;
 1265 }
 1266 
 1267 /*
 1268  * Sysctl initialization and nodes.
 1269  */
 1270 
 1271 static int
 1272 sysctl_ipc_msgmni(SYSCTLFN_ARGS)
 1273 {
 1274         int newsize, error;
 1275         struct sysctlnode node;
 1276         node = *rnode;
 1277         node.sysctl_data = &newsize;
 1278 
 1279         newsize = msginfo.msgmni;
 1280         error = sysctl_lookup(SYSCTLFN_CALL(&node));
 1281         if (error || newp == NULL)
 1282                 return error;
 1283 
 1284         sysctl_unlock();
 1285         error = msgrealloc(newsize, msginfo.msgseg);
 1286         sysctl_relock();
 1287         return error;
 1288 }
 1289 
 1290 static int
 1291 sysctl_ipc_msgseg(SYSCTLFN_ARGS)
 1292 {
 1293         int newsize, error;
 1294         struct sysctlnode node;
 1295         node = *rnode;
 1296         node.sysctl_data = &newsize;
 1297 
 1298         newsize = msginfo.msgseg;
 1299         error = sysctl_lookup(SYSCTLFN_CALL(&node));
 1300         if (error || newp == NULL)
 1301                 return error;
 1302 
 1303         sysctl_unlock();
 1304         error = msgrealloc(msginfo.msgmni, newsize);
 1305         sysctl_relock();
 1306         return error;
 1307 }
 1308 
 1309 SYSCTL_SETUP(sysctl_ipc_msg_setup, "sysctl kern.ipc subtree setup")
 1310 {
 1311         const struct sysctlnode *node = NULL;
 1312 
 1313         sysctl_createv(clog, 0, NULL, &node,
 1314                 CTLFLAG_PERMANENT,
 1315                 CTLTYPE_NODE, "ipc",
 1316                 SYSCTL_DESCR("SysV IPC options"),
 1317                 NULL, 0, NULL, 0,
 1318                 CTL_KERN, KERN_SYSVIPC, CTL_EOL);
 1319 
 1320         if (node == NULL)
 1321                 return;
 1322 
 1323         sysctl_createv(clog, 0, &node, NULL,
 1324                 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
 1325                 CTLTYPE_INT, "msgmni",
 1326                 SYSCTL_DESCR("Max number of message queue identifiers"),
 1327                 sysctl_ipc_msgmni, 0, &msginfo.msgmni, 0,
 1328                 CTL_CREATE, CTL_EOL);
 1329         sysctl_createv(clog, 0, &node, NULL,
 1330                 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
 1331                 CTLTYPE_INT, "msgseg",
 1332                 SYSCTL_DESCR("Max number of number of message segments"),
 1333                 sysctl_ipc_msgseg, 0, &msginfo.msgseg, 0,
 1334                 CTL_CREATE, CTL_EOL);
 1335 }

Cache object: 7f61298e8a35c627c5b9954b139455ae


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