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.46 2006/11/01 10:17:59 yamt Exp $       */
    2 
    3 /*-
    4  * Copyright (c) 1999 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.
   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  * 3. All advertising materials mentioning features or use of this software
   20  *    must display the following acknowledgement:
   21  *      This product includes software developed by the NetBSD
   22  *      Foundation, Inc. and its contributors.
   23  * 4. Neither the name of The NetBSD Foundation nor the names of its
   24  *    contributors may be used to endorse or promote products derived
   25  *    from this software without specific prior written permission.
   26  *
   27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   37  * POSSIBILITY OF SUCH DAMAGE.
   38  */
   39 
   40 /*
   41  * Implementation of SVID messages
   42  *
   43  * Author: Daniel Boulet
   44  *
   45  * Copyright 1993 Daniel Boulet and RTMX Inc.
   46  *
   47  * This system call was implemented by Daniel Boulet under contract from RTMX.
   48  *
   49  * Redistribution and use in source forms, with and without modification,
   50  * are permitted provided that this entire comment appears intact.
   51  *
   52  * Redistribution in binary form may occur without any restrictions.
   53  * Obviously, it would be nice if you gave credit where credit is due
   54  * but requiring it would be too onerous.
   55  *
   56  * This software is provided ``AS IS'' without any warranties of any kind.
   57  */
   58 
   59 #include <sys/cdefs.h>
   60 __KERNEL_RCSID(0, "$NetBSD: sysv_msg.c,v 1.46 2006/11/01 10:17:59 yamt Exp $");
   61 
   62 #define SYSVMSG
   63 
   64 #include <sys/param.h>
   65 #include <sys/kernel.h>
   66 #include <sys/msg.h>
   67 #include <sys/sysctl.h>
   68 #include <sys/mount.h>          /* XXX for <sys/syscallargs.h> */
   69 #include <sys/sa.h>
   70 #include <sys/syscallargs.h>
   71 #include <sys/kauth.h>
   72 
   73 #define MSG_DEBUG
   74 #undef MSG_DEBUG_OK
   75 
   76 #ifdef MSG_DEBUG_OK
   77 #define MSG_PRINTF(a)   printf a
   78 #else
   79 #define MSG_PRINTF(a)
   80 #endif
   81 
   82 static int      nfree_msgmaps;          /* # of free map entries */
   83 static short    free_msgmaps;   /* head of linked list of free map entries */
   84 static struct   __msg *free_msghdrs;    /* list of free msg headers */
   85 static char     *msgpool;               /* MSGMAX byte long msg buffer pool */
   86 static struct   msgmap *msgmaps;        /* MSGSEG msgmap structures */
   87 static struct __msg *msghdrs;           /* MSGTQL msg headers */
   88 struct  msqid_ds *msqids;               /* MSGMNI msqid_ds struct's */
   89 
   90 static void msg_freehdr(struct __msg *);
   91 
   92 void
   93 msginit(void)
   94 {
   95         int i, sz;
   96         vaddr_t v;
   97 
   98         /*
   99          * msginfo.msgssz should be a power of two for efficiency reasons.
  100          * It is also pretty silly if msginfo.msgssz is less than 8
  101          * or greater than about 256 so ...
  102          */
  103 
  104         i = 8;
  105         while (i < 1024 && i != msginfo.msgssz)
  106                 i <<= 1;
  107         if (i != msginfo.msgssz) {
  108                 MSG_PRINTF(("msginfo.msgssz=%d (0x%x)\n", msginfo.msgssz,
  109                     msginfo.msgssz));
  110                 panic("msginfo.msgssz not a small power of 2");
  111         }
  112 
  113         if (msginfo.msgseg > 32767) {
  114                 MSG_PRINTF(("msginfo.msgseg=%d\n", msginfo.msgseg));
  115                 panic("msginfo.msgseg > 32767");
  116         }
  117 
  118         /* Allocate pageable memory for our structures */
  119         sz = msginfo.msgmax
  120                 + msginfo.msgseg * sizeof(struct msgmap)
  121                 + msginfo.msgtql * sizeof(struct __msg)
  122                 + msginfo.msgmni * sizeof(struct msqid_ds);
  123         v = uvm_km_alloc(kernel_map, round_page(sz), 0,
  124             UVM_KMF_WIRED|UVM_KMF_ZERO);
  125         if (v == 0)
  126                 panic("sysv_msg: cannot allocate memory");
  127         msgpool = (void *)v;
  128         msgmaps = (void *) (msgpool + msginfo.msgmax);
  129         msghdrs = (void *) (msgmaps + msginfo.msgseg);
  130         msqids = (void *) (msghdrs + msginfo.msgtql);
  131 
  132         for (i = 0; i < msginfo.msgseg; i++) {
  133                 if (i > 0)
  134                         msgmaps[i-1].next = i;
  135                 msgmaps[i].next = -1;   /* implies entry is available */
  136         }
  137         free_msgmaps = 0;
  138         nfree_msgmaps = msginfo.msgseg;
  139 
  140         if (msghdrs == NULL)
  141                 panic("msghdrs is NULL");
  142 
  143         for (i = 0; i < msginfo.msgtql; i++) {
  144                 msghdrs[i].msg_type = 0;
  145                 if (i > 0)
  146                         msghdrs[i-1].msg_next = &msghdrs[i];
  147                 msghdrs[i].msg_next = NULL;
  148         }
  149         free_msghdrs = &msghdrs[0];
  150 
  151         if (msqids == NULL)
  152                 panic("msqids is NULL");
  153 
  154         for (i = 0; i < msginfo.msgmni; i++) {
  155                 msqids[i].msg_qbytes = 0;       /* implies entry is available */
  156                 msqids[i].msg_perm._seq = 0;    /* reset to a known value */
  157         }
  158 }
  159 
  160 static void
  161 msg_freehdr(struct __msg *msghdr)
  162 {
  163         while (msghdr->msg_ts > 0) {
  164                 short next;
  165                 if (msghdr->msg_spot < 0 || msghdr->msg_spot >= msginfo.msgseg)
  166                         panic("msghdr->msg_spot out of range");
  167                 next = msgmaps[msghdr->msg_spot].next;
  168                 msgmaps[msghdr->msg_spot].next = free_msgmaps;
  169                 free_msgmaps = msghdr->msg_spot;
  170                 nfree_msgmaps++;
  171                 msghdr->msg_spot = next;
  172                 if (msghdr->msg_ts >= msginfo.msgssz)
  173                         msghdr->msg_ts -= msginfo.msgssz;
  174                 else
  175                         msghdr->msg_ts = 0;
  176         }
  177         if (msghdr->msg_spot != -1)
  178                 panic("msghdr->msg_spot != -1");
  179         msghdr->msg_next = free_msghdrs;
  180         free_msghdrs = msghdr;
  181 }
  182 
  183 int
  184 sys___msgctl13(struct lwp *l, void *v, register_t *retval)
  185 {
  186         struct sys___msgctl13_args /* {
  187                 syscallarg(int) msqid;
  188                 syscallarg(int) cmd;
  189                 syscallarg(struct msqid_ds *) buf;
  190         } */ *uap = v;
  191         struct msqid_ds msqbuf;
  192         int cmd, error;
  193 
  194         cmd = SCARG(uap, cmd);
  195 
  196         if (cmd == IPC_SET) {
  197                 error = copyin(SCARG(uap, buf), &msqbuf, sizeof(msqbuf));
  198                 if (error)
  199                         return (error);
  200         }
  201 
  202         error = msgctl1(l, SCARG(uap, msqid), cmd,
  203             (cmd == IPC_SET || cmd == IPC_STAT) ? &msqbuf : NULL);
  204 
  205         if (error == 0 && cmd == IPC_STAT)
  206                 error = copyout(&msqbuf, SCARG(uap, buf), sizeof(msqbuf));
  207 
  208         return (error);
  209 }
  210 
  211 int
  212 msgctl1(struct lwp *l, int msqid, int cmd, struct msqid_ds *msqbuf)
  213 {
  214         kauth_cred_t cred = l->l_cred;
  215         struct msqid_ds *msqptr;
  216         int error = 0, ix;
  217 
  218         MSG_PRINTF(("call to msgctl1(%d, %d)\n", msqid, cmd));
  219 
  220         ix = IPCID_TO_IX(msqid);
  221 
  222         if (ix < 0 || ix >= msginfo.msgmni) {
  223                 MSG_PRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", ix,
  224                     msginfo.msgmni));
  225                 return (EINVAL);
  226         }
  227 
  228         msqptr = &msqids[ix];
  229 
  230         if (msqptr->msg_qbytes == 0) {
  231                 MSG_PRINTF(("no such msqid\n"));
  232                 return (EINVAL);
  233         }
  234         if (msqptr->msg_perm._seq != IPCID_TO_SEQ(msqid)) {
  235                 MSG_PRINTF(("wrong sequence number\n"));
  236                 return (EINVAL);
  237         }
  238 
  239         switch (cmd) {
  240         case IPC_RMID:
  241         {
  242                 struct __msg *msghdr;
  243                 if ((error = ipcperm(cred, &msqptr->msg_perm, IPC_M)) != 0)
  244                         return (error);
  245                 /* Free the message headers */
  246                 msghdr = msqptr->_msg_first;
  247                 while (msghdr != NULL) {
  248                         struct __msg *msghdr_tmp;
  249 
  250                         /* Free the segments of each message */
  251                         msqptr->_msg_cbytes -= msghdr->msg_ts;
  252                         msqptr->msg_qnum--;
  253                         msghdr_tmp = msghdr;
  254                         msghdr = msghdr->msg_next;
  255                         msg_freehdr(msghdr_tmp);
  256                 }
  257 
  258                 if (msqptr->_msg_cbytes != 0)
  259                         panic("msg_cbytes is screwed up");
  260                 if (msqptr->msg_qnum != 0)
  261                         panic("msg_qnum is screwed up");
  262 
  263                 msqptr->msg_qbytes = 0; /* Mark it as free */
  264 
  265                 wakeup(msqptr);
  266         }
  267                 break;
  268 
  269         case IPC_SET:
  270                 if ((error = ipcperm(cred, &msqptr->msg_perm, IPC_M)))
  271                         return (error);
  272                 if (msqbuf->msg_qbytes > msqptr->msg_qbytes &&
  273                     kauth_cred_geteuid(cred) != 0)
  274                         return (EPERM);
  275                 if (msqbuf->msg_qbytes > msginfo.msgmnb) {
  276                         MSG_PRINTF(("can't increase msg_qbytes beyond %d "
  277                             "(truncating)\n", msginfo.msgmnb));
  278                         /* silently restrict qbytes to system limit */
  279                         msqbuf->msg_qbytes = msginfo.msgmnb;
  280                 }
  281                 if (msqbuf->msg_qbytes == 0) {
  282                         MSG_PRINTF(("can't reduce msg_qbytes to 0\n"));
  283                         return (EINVAL);        /* XXX non-standard errno! */
  284                 }
  285                 msqptr->msg_perm.uid = msqbuf->msg_perm.uid;
  286                 msqptr->msg_perm.gid = msqbuf->msg_perm.gid;
  287                 msqptr->msg_perm.mode = (msqptr->msg_perm.mode & ~0777) |
  288                     (msqbuf->msg_perm.mode & 0777);
  289                 msqptr->msg_qbytes = msqbuf->msg_qbytes;
  290                 msqptr->msg_ctime = time_second;
  291                 break;
  292 
  293         case IPC_STAT:
  294                 if ((error = ipcperm(cred, &msqptr->msg_perm, IPC_R))) {
  295                         MSG_PRINTF(("requester doesn't have read access\n"));
  296                         return (error);
  297                 }
  298                 memcpy(msqbuf, msqptr, sizeof(struct msqid_ds));
  299                 break;
  300 
  301         default:
  302                 MSG_PRINTF(("invalid command %d\n", cmd));
  303                 return (EINVAL);
  304         }
  305 
  306         return (error);
  307 }
  308 
  309 int
  310 sys_msgget(struct lwp *l, void *v, register_t *retval)
  311 {
  312         struct sys_msgget_args /* {
  313                 syscallarg(key_t) key;
  314                 syscallarg(int) msgflg;
  315         } */ *uap = v;
  316         int msqid, error;
  317         int key = SCARG(uap, key);
  318         int msgflg = SCARG(uap, msgflg);
  319         kauth_cred_t cred = l->l_cred;
  320         struct msqid_ds *msqptr = NULL;
  321 
  322         MSG_PRINTF(("msgget(0x%x, 0%o)\n", key, msgflg));
  323 
  324         if (key != IPC_PRIVATE) {
  325                 for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
  326                         msqptr = &msqids[msqid];
  327                         if (msqptr->msg_qbytes != 0 &&
  328                             msqptr->msg_perm._key == key)
  329                                 break;
  330                 }
  331                 if (msqid < msginfo.msgmni) {
  332                         MSG_PRINTF(("found public key\n"));
  333                         if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) {
  334                                 MSG_PRINTF(("not exclusive\n"));
  335                                 return(EEXIST);
  336                         }
  337                         if ((error = ipcperm(cred, &msqptr->msg_perm,
  338                             msgflg & 0700 ))) {
  339                                 MSG_PRINTF(("requester doesn't have 0%o access\n",
  340                                     msgflg & 0700));
  341                                 return (error);
  342                         }
  343                         goto found;
  344                 }
  345         }
  346 
  347         MSG_PRINTF(("need to allocate the msqid_ds\n"));
  348         if (key == IPC_PRIVATE || (msgflg & IPC_CREAT)) {
  349                 for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
  350                         /*
  351                          * Look for an unallocated and unlocked msqid_ds.
  352                          * msqid_ds's can be locked by msgsnd or msgrcv while
  353                          * they are copying the message in/out.  We can't
  354                          * re-use the entry until they release it.
  355                          */
  356                         msqptr = &msqids[msqid];
  357                         if (msqptr->msg_qbytes == 0 &&
  358                             (msqptr->msg_perm.mode & MSG_LOCKED) == 0)
  359                                 break;
  360                 }
  361                 if (msqid == msginfo.msgmni) {
  362                         MSG_PRINTF(("no more msqid_ds's available\n"));
  363                         return (ENOSPC);
  364                 }
  365                 MSG_PRINTF(("msqid %d is available\n", msqid));
  366                 msqptr->msg_perm._key = key;
  367                 msqptr->msg_perm.cuid = kauth_cred_geteuid(cred);
  368                 msqptr->msg_perm.uid = kauth_cred_geteuid(cred);
  369                 msqptr->msg_perm.cgid = kauth_cred_getegid(cred);
  370                 msqptr->msg_perm.gid = kauth_cred_getegid(cred);
  371                 msqptr->msg_perm.mode = (msgflg & 0777);
  372                 /* Make sure that the returned msqid is unique */
  373                 msqptr->msg_perm._seq++;
  374                 msqptr->_msg_first = NULL;
  375                 msqptr->_msg_last = NULL;
  376                 msqptr->_msg_cbytes = 0;
  377                 msqptr->msg_qnum = 0;
  378                 msqptr->msg_qbytes = msginfo.msgmnb;
  379                 msqptr->msg_lspid = 0;
  380                 msqptr->msg_lrpid = 0;
  381                 msqptr->msg_stime = 0;
  382                 msqptr->msg_rtime = 0;
  383                 msqptr->msg_ctime = time_second;
  384         } else {
  385                 MSG_PRINTF(("didn't find it and wasn't asked to create it\n"));
  386                 return (ENOENT);
  387         }
  388 
  389  found:
  390         /* Construct the unique msqid */
  391         *retval = IXSEQ_TO_IPCID(msqid, msqptr->msg_perm);
  392         return (0);
  393 }
  394 
  395 int
  396 sys_msgsnd(struct lwp *l, void *v, register_t *retval)
  397 {
  398         struct sys_msgsnd_args /* {
  399                 syscallarg(int) msqid;
  400                 syscallarg(const void *) msgp;
  401                 syscallarg(size_t) msgsz;
  402                 syscallarg(int) msgflg;
  403         } */ *uap = v;
  404 
  405         return msgsnd1(l, SCARG(uap, msqid), SCARG(uap, msgp),
  406             SCARG(uap, msgsz), SCARG(uap, msgflg), sizeof(long), copyin);
  407 }
  408 
  409 int
  410 msgsnd1(struct lwp *l, int msqidr, const char *user_msgp, size_t msgsz,
  411     int msgflg, size_t typesz, copyin_t fetch_type)
  412 {
  413         int segs_needed, error, msqid;
  414         kauth_cred_t cred = l->l_cred;
  415         struct msqid_ds *msqptr;
  416         struct __msg *msghdr;
  417         short next;
  418 
  419         MSG_PRINTF(("call to msgsnd(%d, %p, %lld, %d)\n", msqid, user_msgp,
  420             (long long)msgsz, msgflg));
  421 
  422         msqid = IPCID_TO_IX(msqidr);
  423 
  424         if (msqid < 0 || msqid >= msginfo.msgmni) {
  425                 MSG_PRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
  426                     msginfo.msgmni));
  427                 return (EINVAL);
  428         }
  429 
  430         msqptr = &msqids[msqid];
  431         if (msqptr->msg_qbytes == 0) {
  432                 MSG_PRINTF(("no such message queue id\n"));
  433                 return (EINVAL);
  434         }
  435         if (msqptr->msg_perm._seq != IPCID_TO_SEQ(msqidr)) {
  436                 MSG_PRINTF(("wrong sequence number\n"));
  437                 return (EINVAL);
  438         }
  439 
  440         if ((error = ipcperm(cred, &msqptr->msg_perm, IPC_W))) {
  441                 MSG_PRINTF(("requester doesn't have write access\n"));
  442                 return (error);
  443         }
  444 
  445         segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz;
  446         MSG_PRINTF(("msgsz=%lld, msgssz=%d, segs_needed=%d\n",
  447             (long long)msgsz, msginfo.msgssz, segs_needed));
  448         for (;;) {
  449                 int need_more_resources = 0;
  450 
  451                 /*
  452                  * check msgsz [cannot be negative since it is unsigned]
  453                  * (inside this loop in case msg_qbytes changes while we sleep)
  454                  */
  455 
  456                 if (msgsz > msqptr->msg_qbytes) {
  457                         MSG_PRINTF(("msgsz > msqptr->msg_qbytes\n"));
  458                         return (EINVAL);
  459                 }
  460 
  461                 if (msqptr->msg_perm.mode & MSG_LOCKED) {
  462                         MSG_PRINTF(("msqid is locked\n"));
  463                         need_more_resources = 1;
  464                 }
  465                 if (msgsz + msqptr->_msg_cbytes > msqptr->msg_qbytes) {
  466                         MSG_PRINTF(("msgsz + msg_cbytes > msg_qbytes\n"));
  467                         need_more_resources = 1;
  468                 }
  469                 if (segs_needed > nfree_msgmaps) {
  470                         MSG_PRINTF(("segs_needed > nfree_msgmaps\n"));
  471                         need_more_resources = 1;
  472                 }
  473                 if (free_msghdrs == NULL) {
  474                         MSG_PRINTF(("no more msghdrs\n"));
  475                         need_more_resources = 1;
  476                 }
  477 
  478                 if (need_more_resources) {
  479                         int we_own_it;
  480 
  481                         if ((msgflg & IPC_NOWAIT) != 0) {
  482                                 MSG_PRINTF(("need more resources but caller "
  483                                     "doesn't want to wait\n"));
  484                                 return (EAGAIN);
  485                         }
  486 
  487                         if ((msqptr->msg_perm.mode & MSG_LOCKED) != 0) {
  488                                 MSG_PRINTF(("we don't own the msqid_ds\n"));
  489                                 we_own_it = 0;
  490                         } else {
  491                                 /* Force later arrivals to wait for our
  492                                    request */
  493                                 MSG_PRINTF(("we own the msqid_ds\n"));
  494                                 msqptr->msg_perm.mode |= MSG_LOCKED;
  495                                 we_own_it = 1;
  496                         }
  497                         MSG_PRINTF(("goodnight\n"));
  498                         error = tsleep(msqptr, (PZERO - 4) | PCATCH,
  499                             "msgwait", 0);
  500                         MSG_PRINTF(("good morning, error=%d\n", error));
  501                         if (we_own_it)
  502                                 msqptr->msg_perm.mode &= ~MSG_LOCKED;
  503                         if (error != 0) {
  504                                 MSG_PRINTF(("msgsnd: interrupted system "
  505                                     "call\n"));
  506                                 return (EINTR);
  507                         }
  508 
  509                         /*
  510                          * Make sure that the msq queue still exists
  511                          */
  512 
  513                         if (msqptr->msg_qbytes == 0) {
  514                                 MSG_PRINTF(("msqid deleted\n"));
  515                                 return (EIDRM);
  516                         }
  517                 } else {
  518                         MSG_PRINTF(("got all the resources that we need\n"));
  519                         break;
  520                 }
  521         }
  522 
  523         /*
  524          * We have the resources that we need.
  525          * Make sure!
  526          */
  527 
  528         if (msqptr->msg_perm.mode & MSG_LOCKED)
  529                 panic("msg_perm.mode & MSG_LOCKED");
  530         if (segs_needed > nfree_msgmaps)
  531                 panic("segs_needed > nfree_msgmaps");
  532         if (msgsz + msqptr->_msg_cbytes > msqptr->msg_qbytes)
  533                 panic("msgsz + msg_cbytes > msg_qbytes");
  534         if (free_msghdrs == NULL)
  535                 panic("no more msghdrs");
  536 
  537         /*
  538          * Re-lock the msqid_ds in case we page-fault when copying in the
  539          * message
  540          */
  541 
  542         if ((msqptr->msg_perm.mode & MSG_LOCKED) != 0)
  543                 panic("msqid_ds is already locked");
  544         msqptr->msg_perm.mode |= MSG_LOCKED;
  545 
  546         /*
  547          * Allocate a message header
  548          */
  549 
  550         msghdr = free_msghdrs;
  551         free_msghdrs = msghdr->msg_next;
  552         msghdr->msg_spot = -1;
  553         msghdr->msg_ts = msgsz;
  554 
  555         /*
  556          * Allocate space for the message
  557          */
  558 
  559         while (segs_needed > 0) {
  560                 if (nfree_msgmaps <= 0)
  561                         panic("not enough msgmaps");
  562                 if (free_msgmaps == -1)
  563                         panic("nil free_msgmaps");
  564                 next = free_msgmaps;
  565                 if (next <= -1)
  566                         panic("next too low #1");
  567                 if (next >= msginfo.msgseg)
  568                         panic("next out of range #1");
  569                 MSG_PRINTF(("allocating segment %d to message\n", next));
  570                 free_msgmaps = msgmaps[next].next;
  571                 nfree_msgmaps--;
  572                 msgmaps[next].next = msghdr->msg_spot;
  573                 msghdr->msg_spot = next;
  574                 segs_needed--;
  575         }
  576 
  577         /*
  578          * Copy in the message type
  579          */
  580 
  581         if ((error = (*fetch_type)(user_msgp, &msghdr->msg_type,
  582             typesz)) != 0) {
  583                 MSG_PRINTF(("error %d copying the message type\n", error));
  584                 msg_freehdr(msghdr);
  585                 msqptr->msg_perm.mode &= ~MSG_LOCKED;
  586                 wakeup(msqptr);
  587                 return (error);
  588         }
  589         user_msgp += typesz;
  590 
  591         /*
  592          * Validate the message type
  593          */
  594 
  595         if (msghdr->msg_type < 1) {
  596                 msg_freehdr(msghdr);
  597                 msqptr->msg_perm.mode &= ~MSG_LOCKED;
  598                 wakeup(msqptr);
  599                 MSG_PRINTF(("mtype (%ld) < 1\n", msghdr->msg_type));
  600                 return (EINVAL);
  601         }
  602 
  603         /*
  604          * Copy in the message body
  605          */
  606 
  607         next = msghdr->msg_spot;
  608         while (msgsz > 0) {
  609                 size_t tlen;
  610                 if (msgsz > msginfo.msgssz)
  611                         tlen = msginfo.msgssz;
  612                 else
  613                         tlen = msgsz;
  614                 if (next <= -1)
  615                         panic("next too low #2");
  616                 if (next >= msginfo.msgseg)
  617                         panic("next out of range #2");
  618                 if ((error = copyin(user_msgp, &msgpool[next * msginfo.msgssz],
  619                     tlen)) != 0) {
  620                         MSG_PRINTF(("error %d copying in message segment\n",
  621                             error));
  622                         msg_freehdr(msghdr);
  623                         msqptr->msg_perm.mode &= ~MSG_LOCKED;
  624                         wakeup(msqptr);
  625                         return (error);
  626                 }
  627                 msgsz -= tlen;
  628                 user_msgp += tlen;
  629                 next = msgmaps[next].next;
  630         }
  631         if (next != -1)
  632                 panic("didn't use all the msg segments");
  633 
  634         /*
  635          * We've got the message.  Unlock the msqid_ds.
  636          */
  637 
  638         msqptr->msg_perm.mode &= ~MSG_LOCKED;
  639 
  640         /*
  641          * Make sure that the msqid_ds is still allocated.
  642          */
  643 
  644         if (msqptr->msg_qbytes == 0) {
  645                 msg_freehdr(msghdr);
  646                 wakeup(msqptr);
  647                 return (EIDRM);
  648         }
  649 
  650         /*
  651          * Put the message into the queue
  652          */
  653 
  654         if (msqptr->_msg_first == NULL) {
  655                 msqptr->_msg_first = msghdr;
  656                 msqptr->_msg_last = msghdr;
  657         } else {
  658                 msqptr->_msg_last->msg_next = msghdr;
  659                 msqptr->_msg_last = msghdr;
  660         }
  661         msqptr->_msg_last->msg_next = NULL;
  662 
  663         msqptr->_msg_cbytes += msghdr->msg_ts;
  664         msqptr->msg_qnum++;
  665         msqptr->msg_lspid = l->l_proc->p_pid;
  666         msqptr->msg_stime = time_second;
  667 
  668         wakeup(msqptr);
  669         return (0);
  670 }
  671 
  672 int
  673 sys_msgrcv(struct lwp *l, void *v, register_t *retval)
  674 {
  675         struct sys_msgrcv_args /* {
  676                 syscallarg(int) msqid;
  677                 syscallarg(void *) msgp;
  678                 syscallarg(size_t) msgsz;
  679                 syscallarg(long) msgtyp;
  680                 syscallarg(int) msgflg;
  681         } */ *uap = v;
  682 
  683         return msgrcv1(l, SCARG(uap, msqid), SCARG(uap, msgp),
  684             SCARG(uap, msgsz), SCARG(uap, msgtyp), SCARG(uap, msgflg),
  685             sizeof(long), copyout, retval);
  686 }
  687 
  688 int
  689 msgrcv1(struct lwp *l, int msqidr, char *user_msgp, size_t msgsz, long msgtyp,
  690     int msgflg, size_t typesz, copyout_t put_type, register_t *retval)
  691 {
  692         size_t len;
  693         kauth_cred_t cred = l->l_cred;
  694         struct msqid_ds *msqptr;
  695         struct __msg *msghdr;
  696         int error, msqid;
  697         short next;
  698 
  699         MSG_PRINTF(("call to msgrcv(%d, %p, %lld, %ld, %d)\n", msqid,
  700             user_msgp, (long long)msgsz, msgtyp, msgflg));
  701 
  702         msqid = IPCID_TO_IX(msqidr);
  703 
  704         if (msqid < 0 || msqid >= msginfo.msgmni) {
  705                 MSG_PRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
  706                     msginfo.msgmni));
  707                 return (EINVAL);
  708         }
  709 
  710         msqptr = &msqids[msqid];
  711         if (msqptr->msg_qbytes == 0) {
  712                 MSG_PRINTF(("no such message queue id\n"));
  713                 return (EINVAL);
  714         }
  715         if (msqptr->msg_perm._seq != IPCID_TO_SEQ(msqidr)) {
  716                 MSG_PRINTF(("wrong sequence number\n"));
  717                 return (EINVAL);
  718         }
  719 
  720         if ((error = ipcperm(cred, &msqptr->msg_perm, IPC_R))) {
  721                 MSG_PRINTF(("requester doesn't have read access\n"));
  722                 return (error);
  723         }
  724 
  725 #if 0
  726         /* cannot happen, msgsz is unsigned */
  727         if (msgsz < 0) {
  728                 MSG_PRINTF(("msgsz < 0\n"));
  729                 return (EINVAL);
  730         }
  731 #endif
  732 
  733         msghdr = NULL;
  734         while (msghdr == NULL) {
  735                 if (msgtyp == 0) {
  736                         msghdr = msqptr->_msg_first;
  737                         if (msghdr != NULL) {
  738                                 if (msgsz < msghdr->msg_ts &&
  739                                     (msgflg & MSG_NOERROR) == 0) {
  740                                         MSG_PRINTF(("first message on the "
  741                                             "queue is too big "
  742                                             "(want %lld, got %d)\n",
  743                                             (long long)msgsz, msghdr->msg_ts));
  744                                         return (E2BIG);
  745                                 }
  746                                 if (msqptr->_msg_first == msqptr->_msg_last) {
  747                                         msqptr->_msg_first = NULL;
  748                                         msqptr->_msg_last = NULL;
  749                                 } else {
  750                                         msqptr->_msg_first = msghdr->msg_next;
  751                                         if (msqptr->_msg_first == NULL)
  752                                                 panic("msg_first/last screwed "
  753                                                     "up #1");
  754                                 }
  755                         }
  756                 } else {
  757                         struct __msg *previous;
  758                         struct __msg **prev;
  759 
  760                         for (previous = NULL, prev = &msqptr->_msg_first;
  761                              (msghdr = *prev) != NULL;
  762                              previous = msghdr, prev = &msghdr->msg_next) {
  763                                 /*
  764                                  * Is this message's type an exact match or is
  765                                  * this message's type less than or equal to
  766                                  * the absolute value of a negative msgtyp?
  767                                  * Note that the second half of this test can
  768                                  * NEVER be true if msgtyp is positive since
  769                                  * msg_type is always positive!
  770                                  */
  771 
  772                                 if (msgtyp == msghdr->msg_type ||
  773                                     msghdr->msg_type <= -msgtyp) {
  774                                         MSG_PRINTF(("found message type %ld, "
  775                                             "requested %ld\n",
  776                                             msghdr->msg_type, msgtyp));
  777                                         if (msgsz < msghdr->msg_ts &&
  778                                             (msgflg & MSG_NOERROR) == 0) {
  779                                                 MSG_PRINTF(("requested message "
  780                                                     "on the queue is too big "
  781                                                     "(want %lld, got %d)\n",
  782                                                     (long long)msgsz,
  783                                                     msghdr->msg_ts));
  784                                                 return (E2BIG);
  785                                         }
  786                                         *prev = msghdr->msg_next;
  787                                         if (msghdr == msqptr->_msg_last) {
  788                                                 if (previous == NULL) {
  789                                                         if (prev !=
  790                                                             &msqptr->_msg_first)
  791                                                                 panic("msg_first/last screwed up #2");
  792                                                         msqptr->_msg_first =
  793                                                             NULL;
  794                                                         msqptr->_msg_last =
  795                                                             NULL;
  796                                                 } else {
  797                                                         if (prev ==
  798                                                             &msqptr->_msg_first)
  799                                                                 panic("msg_first/last screwed up #3");
  800                                                         msqptr->_msg_last =
  801                                                             previous;
  802                                                 }
  803                                         }
  804                                         break;
  805                                 }
  806                         }
  807                 }
  808 
  809                 /*
  810                  * We've either extracted the msghdr for the appropriate
  811                  * message or there isn't one.
  812                  * If there is one then bail out of this loop.
  813                  */
  814 
  815                 if (msghdr != NULL)
  816                         break;
  817 
  818                 /*
  819                  * Hmph!  No message found.  Does the user want to wait?
  820                  */
  821 
  822                 if ((msgflg & IPC_NOWAIT) != 0) {
  823                         MSG_PRINTF(("no appropriate message found (msgtyp=%ld)\n",
  824                             msgtyp));
  825                         /* The SVID says to return ENOMSG. */
  826 #ifdef ENOMSG
  827                         return (ENOMSG);
  828 #else
  829                         /* Unfortunately, BSD doesn't define that code yet! */
  830                         return (EAGAIN);
  831 #endif
  832                 }
  833 
  834                 /*
  835                  * Wait for something to happen
  836                  */
  837 
  838                 MSG_PRINTF(("msgrcv:  goodnight\n"));
  839                 error = tsleep(msqptr, (PZERO - 4) | PCATCH, "msgwait",
  840                     0);
  841                 MSG_PRINTF(("msgrcv: good morning (error=%d)\n", error));
  842 
  843                 if (error != 0) {
  844                         MSG_PRINTF(("msgsnd: interrupted system call\n"));
  845                         return (EINTR);
  846                 }
  847 
  848                 /*
  849                  * Make sure that the msq queue still exists
  850                  */
  851 
  852                 if (msqptr->msg_qbytes == 0 ||
  853                     msqptr->msg_perm._seq != IPCID_TO_SEQ(msqidr)) {
  854                         MSG_PRINTF(("msqid deleted\n"));
  855                         return (EIDRM);
  856                 }
  857         }
  858 
  859         /*
  860          * Return the message to the user.
  861          *
  862          * First, do the bookkeeping (before we risk being interrupted).
  863          */
  864 
  865         msqptr->_msg_cbytes -= msghdr->msg_ts;
  866         msqptr->msg_qnum--;
  867         msqptr->msg_lrpid = l->l_proc->p_pid;
  868         msqptr->msg_rtime = time_second;
  869 
  870         /*
  871          * Make msgsz the actual amount that we'll be returning.
  872          * Note that this effectively truncates the message if it is too long
  873          * (since msgsz is never increased).
  874          */
  875 
  876         MSG_PRINTF(("found a message, msgsz=%lld, msg_ts=%d\n",
  877             (long long)msgsz, msghdr->msg_ts));
  878         if (msgsz > msghdr->msg_ts)
  879                 msgsz = msghdr->msg_ts;
  880 
  881         /*
  882          * Return the type to the user.
  883          */
  884 
  885         error = (*put_type)(&msghdr->msg_type, user_msgp, typesz);
  886         if (error != 0) {
  887                 MSG_PRINTF(("error (%d) copying out message type\n", error));
  888                 msg_freehdr(msghdr);
  889                 wakeup(msqptr);
  890                 return (error);
  891         }
  892         user_msgp += typesz;
  893 
  894         /*
  895          * Return the segments to the user
  896          */
  897 
  898         next = msghdr->msg_spot;
  899         for (len = 0; len < msgsz; len += msginfo.msgssz) {
  900                 size_t tlen;
  901 
  902                 if (msgsz - len > msginfo.msgssz)
  903                         tlen = msginfo.msgssz;
  904                 else
  905                         tlen = msgsz - len;
  906                 if (next <= -1)
  907                         panic("next too low #3");
  908                 if (next >= msginfo.msgseg)
  909                         panic("next out of range #3");
  910                 error = copyout(&msgpool[next * msginfo.msgssz],
  911                     user_msgp, tlen);
  912                 if (error != 0) {
  913                         MSG_PRINTF(("error (%d) copying out message segment\n",
  914                             error));
  915                         msg_freehdr(msghdr);
  916                         wakeup(msqptr);
  917                         return (error);
  918                 }
  919                 user_msgp += tlen;
  920                 next = msgmaps[next].next;
  921         }
  922 
  923         /*
  924          * Done, return the actual number of bytes copied out.
  925          */
  926 
  927         msg_freehdr(msghdr);
  928         wakeup(msqptr);
  929         *retval = msgsz;
  930         return (0);
  931 }

Cache object: 6fd69979c59ea8424d184297ee2a8d1f


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