1*a9ca7a37Sad /* $NetBSD: sys_mqueue.c,v 1.7 2008/03/21 21:55:00 ad Exp $ */ 22cecf9bbSrmind 32cecf9bbSrmind /* 42cecf9bbSrmind * Copyright (c) 2007, Mindaugas Rasiukevicius <rmind at NetBSD org> 5c75dc327Srmind * All rights reserved. 62cecf9bbSrmind * 72cecf9bbSrmind * Redistribution and use in source and binary forms, with or without 82cecf9bbSrmind * modification, are permitted provided that the following conditions 92cecf9bbSrmind * are met: 102cecf9bbSrmind * 1. Redistributions of source code must retain the above copyright 112cecf9bbSrmind * notice, this list of conditions and the following disclaimer. 122cecf9bbSrmind * 2. Redistributions in binary form must reproduce the above copyright 132cecf9bbSrmind * notice, this list of conditions and the following disclaimer in the 142cecf9bbSrmind * documentation and/or other materials provided with the distribution. 152cecf9bbSrmind * 162cecf9bbSrmind * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172cecf9bbSrmind * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 182cecf9bbSrmind * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 192cecf9bbSrmind * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 202cecf9bbSrmind * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 212cecf9bbSrmind * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 222cecf9bbSrmind * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 232cecf9bbSrmind * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 242cecf9bbSrmind * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 252cecf9bbSrmind * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 262cecf9bbSrmind * POSSIBILITY OF SUCH DAMAGE. 272cecf9bbSrmind */ 282cecf9bbSrmind 292cecf9bbSrmind /* 302cecf9bbSrmind * Implementation of POSIX message queues. 312cecf9bbSrmind * Defined in the Base Definitions volume of IEEE Std 1003.1-2001. 322cecf9bbSrmind * 332cecf9bbSrmind * Locking 342cecf9bbSrmind * Global list of message queues and proc::p_mqueue_cnt counter are protected 352cecf9bbSrmind * by mqlist_mtx lock. Concrete message queue and its members are protected 362cecf9bbSrmind * by mqueue::mq_mtx. 372cecf9bbSrmind * 382cecf9bbSrmind * Lock order: 392cecf9bbSrmind * mqlist_mtx 402cecf9bbSrmind * -> mqueue::mq_mtx 412cecf9bbSrmind * 422cecf9bbSrmind * TODO: 432cecf9bbSrmind * - Hashing or RB-tree for the global list. 442cecf9bbSrmind * - Support for select(), poll() and perhaps kqueue(). 452cecf9bbSrmind */ 462cecf9bbSrmind 472cecf9bbSrmind #include <sys/cdefs.h> 48*a9ca7a37Sad __KERNEL_RCSID(0, "$NetBSD: sys_mqueue.c,v 1.7 2008/03/21 21:55:00 ad Exp $"); 492cecf9bbSrmind 502cecf9bbSrmind #include <sys/param.h> 512cecf9bbSrmind #include <sys/types.h> 522cecf9bbSrmind #include <sys/condvar.h> 532cecf9bbSrmind #include <sys/errno.h> 542cecf9bbSrmind #include <sys/fcntl.h> 552cecf9bbSrmind #include <sys/file.h> 562cecf9bbSrmind #include <sys/filedesc.h> 572cecf9bbSrmind #include <sys/kauth.h> 582cecf9bbSrmind #include <sys/kernel.h> 592cecf9bbSrmind #include <sys/kmem.h> 602cecf9bbSrmind #include <sys/lwp.h> 612cecf9bbSrmind #include <sys/mqueue.h> 622cecf9bbSrmind #include <sys/mutex.h> 632cecf9bbSrmind #include <sys/pool.h> 642cecf9bbSrmind #include <sys/proc.h> 652cecf9bbSrmind #include <sys/queue.h> 662cecf9bbSrmind #include <sys/signal.h> 672cecf9bbSrmind #include <sys/signalvar.h> 682cecf9bbSrmind #include <sys/sysctl.h> 692cecf9bbSrmind #include <sys/syscallargs.h> 702cecf9bbSrmind #include <sys/systm.h> 712cecf9bbSrmind #include <sys/unistd.h> 722cecf9bbSrmind #include <sys/vnode.h> 732cecf9bbSrmind 742cecf9bbSrmind /* System-wide limits. */ 752cecf9bbSrmind static u_int mq_open_max = MQ_OPEN_MAX; 762cecf9bbSrmind static u_int mq_prio_max = MQ_PRIO_MAX; 772cecf9bbSrmind 782cecf9bbSrmind static u_int mq_max_msgsize = 16 * MQ_DEF_MSGSIZE; 792cecf9bbSrmind static u_int mq_def_maxmsg = 32; 802cecf9bbSrmind 812cecf9bbSrmind static kmutex_t mqlist_mtx; 822cecf9bbSrmind static struct pool mqmsg_poll; 8311910619Smatt static LIST_HEAD(, mqueue) mqueue_head = 8411910619Smatt LIST_HEAD_INITIALIZER(mqueue_head); 852cecf9bbSrmind 86*a9ca7a37Sad static int mq_close_fop(file_t *); 872cecf9bbSrmind 882cecf9bbSrmind static const struct fileops mqops = { 892cecf9bbSrmind fbadop_read, fbadop_write, fbadop_ioctl, fnullop_fcntl, fnullop_poll, 902cecf9bbSrmind fbadop_stat, mq_close_fop, fnullop_kqfilter 912cecf9bbSrmind }; 922cecf9bbSrmind 932cecf9bbSrmind /* 942cecf9bbSrmind * Initialize POSIX message queue subsystem. 952cecf9bbSrmind */ 962cecf9bbSrmind void 972cecf9bbSrmind mqueue_sysinit(void) 982cecf9bbSrmind { 992cecf9bbSrmind 1002cecf9bbSrmind pool_init(&mqmsg_poll, MQ_DEF_MSGSIZE, 0, 0, 0, 1012cecf9bbSrmind "mqmsg_poll", &pool_allocator_nointr, IPL_NONE); 1022cecf9bbSrmind mutex_init(&mqlist_mtx, MUTEX_DEFAULT, IPL_NONE); 1032cecf9bbSrmind } 1042cecf9bbSrmind 1052cecf9bbSrmind /* 1062cecf9bbSrmind * Free the message. 1072cecf9bbSrmind */ 1082cecf9bbSrmind static void 1092cecf9bbSrmind mqueue_freemsg(struct mq_msg *msg, const size_t size) 1102cecf9bbSrmind { 1112cecf9bbSrmind 1122cecf9bbSrmind if (size > MQ_DEF_MSGSIZE) 1132cecf9bbSrmind kmem_free(msg, size); 1142cecf9bbSrmind else 1152cecf9bbSrmind pool_put(&mqmsg_poll, msg); 1162cecf9bbSrmind } 1172cecf9bbSrmind 1182cecf9bbSrmind /* 1192cecf9bbSrmind * Destroy the message queue. 1202cecf9bbSrmind */ 1212cecf9bbSrmind static void 1222cecf9bbSrmind mqueue_destroy(struct mqueue *mq) 1232cecf9bbSrmind { 1242cecf9bbSrmind struct mq_msg *msg; 1252cecf9bbSrmind 1262cecf9bbSrmind while ((msg = TAILQ_FIRST(&mq->mq_head)) != NULL) { 1272cecf9bbSrmind TAILQ_REMOVE(&mq->mq_head, msg, msg_queue); 1282cecf9bbSrmind mqueue_freemsg(msg, sizeof(struct mq_msg) + msg->msg_len); 1292cecf9bbSrmind } 1302cecf9bbSrmind cv_destroy(&mq->mq_send_cv); 1312cecf9bbSrmind cv_destroy(&mq->mq_recv_cv); 1322cecf9bbSrmind mutex_destroy(&mq->mq_mtx); 1332cecf9bbSrmind kmem_free(mq, sizeof(struct mqueue)); 1342cecf9bbSrmind } 1352cecf9bbSrmind 1362cecf9bbSrmind /* 1372cecf9bbSrmind * Lookup for file name in general list of message queues. 1382cecf9bbSrmind * => locks the message queue 1392cecf9bbSrmind */ 1402cecf9bbSrmind static void * 1412cecf9bbSrmind mqueue_lookup(char *name) 1422cecf9bbSrmind { 1432cecf9bbSrmind struct mqueue *mq; 1442cecf9bbSrmind KASSERT(mutex_owned(&mqlist_mtx)); 1452cecf9bbSrmind 1462cecf9bbSrmind LIST_FOREACH(mq, &mqueue_head, mq_list) { 1472cecf9bbSrmind if (strncmp(mq->mq_name, name, MQ_NAMELEN) == 0) { 1482cecf9bbSrmind mutex_enter(&mq->mq_mtx); 1492cecf9bbSrmind return mq; 1502cecf9bbSrmind } 1512cecf9bbSrmind } 1522cecf9bbSrmind 1532cecf9bbSrmind return NULL; 1542cecf9bbSrmind } 1552cecf9bbSrmind 1562cecf9bbSrmind /* 1572cecf9bbSrmind * Check access against message queue. 1582cecf9bbSrmind */ 1592cecf9bbSrmind static inline int 1602cecf9bbSrmind mqueue_access(struct lwp *l, struct mqueue *mq, mode_t acc_mode) 1612cecf9bbSrmind { 1622cecf9bbSrmind 1632cecf9bbSrmind KASSERT(mutex_owned(&mq->mq_mtx)); 1642cecf9bbSrmind return vaccess(VNON, mq->mq_mode, mq->mq_euid, mq->mq_egid, 1652cecf9bbSrmind acc_mode, l->l_cred); 1662cecf9bbSrmind } 1672cecf9bbSrmind 1682cecf9bbSrmind /* 1692cecf9bbSrmind * Get the mqueue from the descriptor. 1702cecf9bbSrmind * => locks the message queue 1712cecf9bbSrmind * => increments the reference on file entry 1722cecf9bbSrmind */ 1732cecf9bbSrmind static int 174*a9ca7a37Sad mqueue_get(struct lwp *l, mqd_t mqd, mode_t acc_mode, file_t **fpr) 1752cecf9bbSrmind { 176*a9ca7a37Sad file_t *fp; 1772cecf9bbSrmind struct mqueue *mq; 1782cecf9bbSrmind 1792cecf9bbSrmind /* Get the file and descriptor */ 180*a9ca7a37Sad fp = fd_getfile((int)mqd); 1812cecf9bbSrmind if (fp == NULL) 1822cecf9bbSrmind return EBADF; 1832cecf9bbSrmind 1842cecf9bbSrmind /* Increment the reference of file entry, and lock the mqueue */ 1852cecf9bbSrmind mq = fp->f_data; 1862cecf9bbSrmind *fpr = fp; 1872cecf9bbSrmind mutex_enter(&mq->mq_mtx); 1882cecf9bbSrmind 1892cecf9bbSrmind /* Check the access mode and permission if needed */ 1902cecf9bbSrmind if (acc_mode == VNOVAL) 1912cecf9bbSrmind return 0; 1922cecf9bbSrmind if ((acc_mode & fp->f_flag) == 0 || mqueue_access(l, mq, acc_mode)) { 1932cecf9bbSrmind mutex_exit(&mq->mq_mtx); 194*a9ca7a37Sad fd_putfile((int)mqd); 1952cecf9bbSrmind return EPERM; 1962cecf9bbSrmind } 1972cecf9bbSrmind 1982cecf9bbSrmind return 0; 1992cecf9bbSrmind } 2002cecf9bbSrmind 2012cecf9bbSrmind /* 2022cecf9bbSrmind * Converter from struct timespec to the ticks. 2032cecf9bbSrmind * Used by mq_timedreceive(), mq_timedsend(). 2042cecf9bbSrmind */ 2052cecf9bbSrmind static int 2062cecf9bbSrmind abstimeout2timo(const void *uaddr, int *timo) 2072cecf9bbSrmind { 2082cecf9bbSrmind struct timespec ts; 2092cecf9bbSrmind int error; 2102cecf9bbSrmind 2112cecf9bbSrmind error = copyin(uaddr, &ts, sizeof(struct timespec)); 2122cecf9bbSrmind if (error) 2132cecf9bbSrmind return error; 2142cecf9bbSrmind 2152cecf9bbSrmind /* 2162cecf9bbSrmind * According to POSIX, validation check is needed only in case of 2172cecf9bbSrmind * blocking. Thus, set the invalid value right now, and fail latter. 2182cecf9bbSrmind */ 2192cecf9bbSrmind error = itimespecfix(&ts); 2202cecf9bbSrmind *timo = (error == 0) ? tstohz(&ts) : -1; 2212cecf9bbSrmind 2222cecf9bbSrmind return 0; 2232cecf9bbSrmind } 2242cecf9bbSrmind 2252cecf9bbSrmind static int 226*a9ca7a37Sad mq_close_fop(file_t *fp) 2272cecf9bbSrmind { 228*a9ca7a37Sad struct proc *p = curproc; 2292cecf9bbSrmind struct mqueue *mq = fp->f_data; 2302cecf9bbSrmind bool destroy; 2312cecf9bbSrmind 2322cecf9bbSrmind mutex_enter(&mqlist_mtx); 2332cecf9bbSrmind mutex_enter(&mq->mq_mtx); 2342cecf9bbSrmind 2352cecf9bbSrmind /* Decrease the counters */ 2362cecf9bbSrmind p->p_mqueue_cnt--; 2372cecf9bbSrmind mq->mq_refcnt--; 2382cecf9bbSrmind 2392cecf9bbSrmind /* Remove notification if registered for this process */ 2402cecf9bbSrmind if (mq->mq_notify_proc == p) 2412cecf9bbSrmind mq->mq_notify_proc = NULL; 2422cecf9bbSrmind 2432cecf9bbSrmind /* 2442cecf9bbSrmind * If this is the last reference and mqueue is marked for unlink, 2452cecf9bbSrmind * remove and later destroy the message queue. 2462cecf9bbSrmind */ 2472cecf9bbSrmind if (mq->mq_refcnt == 0 && (mq->mq_attrib.mq_flags & MQ_UNLINK)) { 2482cecf9bbSrmind LIST_REMOVE(mq, mq_list); 2492cecf9bbSrmind destroy = true; 2502cecf9bbSrmind } else 2512cecf9bbSrmind destroy = false; 2522cecf9bbSrmind 2532cecf9bbSrmind mutex_exit(&mq->mq_mtx); 2542cecf9bbSrmind mutex_exit(&mqlist_mtx); 2552cecf9bbSrmind 2562cecf9bbSrmind if (destroy) 2572cecf9bbSrmind mqueue_destroy(mq); 2582cecf9bbSrmind 2592cecf9bbSrmind return 0; 2602cecf9bbSrmind } 2612cecf9bbSrmind 2622cecf9bbSrmind /* 2632cecf9bbSrmind * General mqueue system calls. 2642cecf9bbSrmind */ 2652cecf9bbSrmind 2662cecf9bbSrmind int 2677e2790cfSdsl sys_mq_open(struct lwp *l, const struct sys_mq_open_args *uap, register_t *retval) 2682cecf9bbSrmind { 2697e2790cfSdsl /* { 2702cecf9bbSrmind syscallarg(const char *) name; 2712cecf9bbSrmind syscallarg(int) oflag; 2722cecf9bbSrmind syscallarg(mode_t) mode; 2732cecf9bbSrmind syscallarg(struct mq_attr) attr; 2747e2790cfSdsl } */ 2752cecf9bbSrmind struct proc *p = l->l_proc; 2762cecf9bbSrmind struct mqueue *mq, *mq_new = NULL; 277*a9ca7a37Sad file_t *fp; 2782cecf9bbSrmind char *name; 2792cecf9bbSrmind int mqd, error, oflag; 2802cecf9bbSrmind 2812cecf9bbSrmind /* Check access mode flags */ 2822cecf9bbSrmind oflag = SCARG(uap, oflag); 2832cecf9bbSrmind if ((oflag & (O_RDWR | O_RDONLY | O_WRONLY)) == 0) 2842cecf9bbSrmind return EINVAL; 2852cecf9bbSrmind 2862cecf9bbSrmind /* Get the name from the user-space */ 2872cecf9bbSrmind name = kmem_zalloc(MQ_NAMELEN, KM_SLEEP); 2882cecf9bbSrmind error = copyinstr(SCARG(uap, name), name, MQ_NAMELEN - 1, NULL); 2892cecf9bbSrmind if (error) { 2902cecf9bbSrmind kmem_free(name, MQ_NAMELEN); 2912cecf9bbSrmind return error; 2922cecf9bbSrmind } 2932cecf9bbSrmind 2942cecf9bbSrmind if (oflag & O_CREAT) { 2952cecf9bbSrmind struct mq_attr attr; 2962cecf9bbSrmind 2972cecf9bbSrmind /* Check the limit */ 2982cecf9bbSrmind if (p->p_mqueue_cnt == mq_open_max) { 2992cecf9bbSrmind kmem_free(name, MQ_NAMELEN); 3002cecf9bbSrmind return EMFILE; 3012cecf9bbSrmind } 3022cecf9bbSrmind 3032cecf9bbSrmind /* Check for mqueue attributes */ 3042cecf9bbSrmind if (SCARG(uap, attr)) { 3052cecf9bbSrmind error = copyin(SCARG(uap, attr), &attr, 3062cecf9bbSrmind sizeof(struct mq_attr)); 3072cecf9bbSrmind if (error) { 3082cecf9bbSrmind kmem_free(name, MQ_NAMELEN); 3092cecf9bbSrmind return error; 3102cecf9bbSrmind } 3112cecf9bbSrmind if (attr.mq_maxmsg <= 0 || attr.mq_msgsize <= 0 || 3122cecf9bbSrmind attr.mq_msgsize > mq_max_msgsize) { 3132cecf9bbSrmind kmem_free(name, MQ_NAMELEN); 3142cecf9bbSrmind return EINVAL; 3152cecf9bbSrmind } 3162cecf9bbSrmind attr.mq_curmsgs = 0; 3172cecf9bbSrmind } else { 3182cecf9bbSrmind memset(&attr, 0, sizeof(struct mq_attr)); 3192cecf9bbSrmind attr.mq_maxmsg = mq_def_maxmsg; 3202cecf9bbSrmind attr.mq_msgsize = 3212cecf9bbSrmind MQ_DEF_MSGSIZE - sizeof(struct mq_msg); 3222cecf9bbSrmind } 3232cecf9bbSrmind 3242cecf9bbSrmind /* 3252cecf9bbSrmind * Allocate new mqueue, initialize data structures, 3262cecf9bbSrmind * copy the name, attributes and set the flag. 3272cecf9bbSrmind */ 3282cecf9bbSrmind mq_new = kmem_zalloc(sizeof(struct mqueue), KM_SLEEP); 3292cecf9bbSrmind 3302cecf9bbSrmind mutex_init(&mq_new->mq_mtx, MUTEX_DEFAULT, IPL_NONE); 3312cecf9bbSrmind cv_init(&mq_new->mq_send_cv, "mqsendcv"); 3322cecf9bbSrmind cv_init(&mq_new->mq_recv_cv, "mqrecvcv"); 3332cecf9bbSrmind TAILQ_INIT(&mq_new->mq_head); 3342cecf9bbSrmind 3352cecf9bbSrmind strlcpy(mq_new->mq_name, name, MQ_NAMELEN); 3362cecf9bbSrmind memcpy(&mq_new->mq_attrib, &attr, sizeof(struct mq_attr)); 3372cecf9bbSrmind mq_new->mq_attrib.mq_flags = oflag; 3382cecf9bbSrmind 3392cecf9bbSrmind /* Store mode and effective UID with GID */ 3402cecf9bbSrmind mq_new->mq_mode = SCARG(uap, mode); 3412cecf9bbSrmind mq_new->mq_euid = kauth_cred_geteuid(l->l_cred); 3422cecf9bbSrmind mq_new->mq_egid = kauth_cred_getegid(l->l_cred); 3432cecf9bbSrmind } 3442cecf9bbSrmind 3452cecf9bbSrmind /* Allocate file structure and descriptor */ 346*a9ca7a37Sad error = fd_allocfile(&fp, &mqd); 3472cecf9bbSrmind if (error) { 3482cecf9bbSrmind if (mq_new) 3492cecf9bbSrmind mqueue_destroy(mq_new); 3502cecf9bbSrmind kmem_free(name, MQ_NAMELEN); 3512cecf9bbSrmind return error; 3522cecf9bbSrmind } 3532cecf9bbSrmind fp->f_type = DTYPE_MQUEUE; 3542cecf9bbSrmind fp->f_flag = (oflag & O_RDWR) ? (VREAD | VWRITE) : 3552cecf9bbSrmind ((oflag & O_RDONLY) ? VREAD : VWRITE); 3562cecf9bbSrmind fp->f_ops = &mqops; 3572cecf9bbSrmind 3582cecf9bbSrmind /* Look up for mqueue with such name */ 3592cecf9bbSrmind mutex_enter(&mqlist_mtx); 3602cecf9bbSrmind mq = mqueue_lookup(name); 3612cecf9bbSrmind if (mq) { 3622cecf9bbSrmind KASSERT(mutex_owned(&mq->mq_mtx)); 3632cecf9bbSrmind /* Check if mqueue is not marked as unlinking */ 3642cecf9bbSrmind if (mq->mq_attrib.mq_flags & MQ_UNLINK) { 3652cecf9bbSrmind error = EACCES; 3662cecf9bbSrmind goto exit; 3672cecf9bbSrmind } 3682cecf9bbSrmind /* Fail if O_EXCL is set, and mqueue already exists */ 3692cecf9bbSrmind if ((oflag & O_CREAT) && (oflag & O_EXCL)) { 3702cecf9bbSrmind error = EEXIST; 3712cecf9bbSrmind goto exit; 3722cecf9bbSrmind } 3732cecf9bbSrmind /* Check the permission */ 3742cecf9bbSrmind if (mqueue_access(l, mq, fp->f_flag)) { 3752cecf9bbSrmind error = EACCES; 3762cecf9bbSrmind goto exit; 3772cecf9bbSrmind } 3782cecf9bbSrmind } else { 3792cecf9bbSrmind /* Fail if mqueue neither exists, nor we create it */ 3802cecf9bbSrmind if ((oflag & O_CREAT) == 0) { 3812cecf9bbSrmind mutex_exit(&mqlist_mtx); 3822cecf9bbSrmind KASSERT(mq_new == NULL); 383*a9ca7a37Sad fd_abort(p, fp, mqd); 3842cecf9bbSrmind kmem_free(name, MQ_NAMELEN); 3852cecf9bbSrmind return ENOENT; 3862cecf9bbSrmind } 3872cecf9bbSrmind 3882cecf9bbSrmind /* Check the limit */ 3892cecf9bbSrmind if (p->p_mqueue_cnt == mq_open_max) { 3902cecf9bbSrmind error = EMFILE; 3912cecf9bbSrmind goto exit; 3922cecf9bbSrmind } 3932cecf9bbSrmind 3942cecf9bbSrmind /* Insert the queue to the list */ 3952cecf9bbSrmind mq = mq_new; 3962cecf9bbSrmind mutex_enter(&mq->mq_mtx); 3972cecf9bbSrmind LIST_INSERT_HEAD(&mqueue_head, mq, mq_list); 3982cecf9bbSrmind mq_new = NULL; 3992cecf9bbSrmind } 4002cecf9bbSrmind 4012cecf9bbSrmind /* Increase the counters, and make descriptor ready */ 4022cecf9bbSrmind p->p_mqueue_cnt++; 4032cecf9bbSrmind mq->mq_refcnt++; 4042cecf9bbSrmind fp->f_data = mq; 4052cecf9bbSrmind exit: 4062cecf9bbSrmind mutex_exit(&mq->mq_mtx); 4072cecf9bbSrmind mutex_exit(&mqlist_mtx); 4082cecf9bbSrmind 4092cecf9bbSrmind if (mq_new) 4102cecf9bbSrmind mqueue_destroy(mq_new); 4112cecf9bbSrmind if (error) { 412*a9ca7a37Sad fd_abort(p, fp, mqd); 413*a9ca7a37Sad } else { 414*a9ca7a37Sad fd_affix(p, fp, mqd); 4152cecf9bbSrmind *retval = mqd; 416*a9ca7a37Sad } 4172cecf9bbSrmind kmem_free(name, MQ_NAMELEN); 4182cecf9bbSrmind 4192cecf9bbSrmind return error; 4202cecf9bbSrmind } 4212cecf9bbSrmind 4222cecf9bbSrmind int 4237e2790cfSdsl sys_mq_close(struct lwp *l, const struct sys_mq_close_args *uap, register_t *retval) 4242cecf9bbSrmind { 4252cecf9bbSrmind 4267e2790cfSdsl return sys_close(l, (const void *)uap, retval); 4272cecf9bbSrmind } 4282cecf9bbSrmind 4292cecf9bbSrmind /* 4302cecf9bbSrmind * Primary mq_receive1() function. 4312cecf9bbSrmind */ 4322cecf9bbSrmind static int 4332cecf9bbSrmind mq_receive1(struct lwp *l, mqd_t mqdes, void *msg_ptr, size_t msg_len, 4342cecf9bbSrmind unsigned *msg_prio, int t, ssize_t *mlen) 4352cecf9bbSrmind { 436*a9ca7a37Sad file_t *fp = NULL; 4372cecf9bbSrmind struct mqueue *mq; 4382cecf9bbSrmind struct mq_msg *msg = NULL; 4392cecf9bbSrmind int error; 4402cecf9bbSrmind 4412cecf9bbSrmind /* Get the message queue */ 4422cecf9bbSrmind error = mqueue_get(l, mqdes, VREAD, &fp); 4432cecf9bbSrmind if (error) 4442cecf9bbSrmind return error; 4452cecf9bbSrmind mq = fp->f_data; 4462cecf9bbSrmind 4472cecf9bbSrmind /* Check the message size limits */ 4482cecf9bbSrmind if (msg_len < mq->mq_attrib.mq_msgsize) { 4492cecf9bbSrmind error = EMSGSIZE; 4502cecf9bbSrmind goto error; 4512cecf9bbSrmind } 4522cecf9bbSrmind 4532cecf9bbSrmind /* Check if queue is empty */ 454d62c40efSad while (TAILQ_EMPTY(&mq->mq_head)) { 4552cecf9bbSrmind if (mq->mq_attrib.mq_flags & O_NONBLOCK) { 4562cecf9bbSrmind error = EAGAIN; 4572cecf9bbSrmind goto error; 4582cecf9bbSrmind } 4592cecf9bbSrmind if (t < 0) { 4602cecf9bbSrmind error = EINVAL; 4612cecf9bbSrmind goto error; 4622cecf9bbSrmind } 4632cecf9bbSrmind /* 4642cecf9bbSrmind * Block until someone sends the message. 4652cecf9bbSrmind * While doing this, notification should not be sent. 4662cecf9bbSrmind */ 4672cecf9bbSrmind mq->mq_attrib.mq_flags |= MQ_RECEIVE; 4682cecf9bbSrmind error = cv_timedwait_sig(&mq->mq_send_cv, &mq->mq_mtx, t); 4692cecf9bbSrmind mq->mq_attrib.mq_flags &= ~MQ_RECEIVE; 4702cecf9bbSrmind if (error || (mq->mq_attrib.mq_flags & MQ_UNLINK)) { 471f0701231Srmind error = (error == EWOULDBLOCK) ? ETIMEDOUT : EINTR; 4722cecf9bbSrmind goto error; 4732cecf9bbSrmind } 4742cecf9bbSrmind } 4752cecf9bbSrmind 4762cecf9bbSrmind /* Remove the message from the queue */ 4772cecf9bbSrmind msg = TAILQ_FIRST(&mq->mq_head); 4782cecf9bbSrmind KASSERT(msg != NULL); 4792cecf9bbSrmind TAILQ_REMOVE(&mq->mq_head, msg, msg_queue); 4802cecf9bbSrmind 4812cecf9bbSrmind /* Decrement the counter and signal waiter, if any */ 4822cecf9bbSrmind mq->mq_attrib.mq_curmsgs--; 4832cecf9bbSrmind cv_signal(&mq->mq_recv_cv); 4842cecf9bbSrmind error: 4852cecf9bbSrmind mutex_exit(&mq->mq_mtx); 486*a9ca7a37Sad fd_putfile((int)mqdes); 4872cecf9bbSrmind if (error) 4882cecf9bbSrmind return error; 4892cecf9bbSrmind 4902cecf9bbSrmind /* 4912cecf9bbSrmind * Copy the data to the user-space. 4922cecf9bbSrmind * Note: According to POSIX, no message should be removed from the 4932cecf9bbSrmind * queue in case of fail - this would be violated. 4942cecf9bbSrmind */ 4952cecf9bbSrmind *mlen = msg->msg_len; 4962cecf9bbSrmind error = copyout(msg->msg_ptr, msg_ptr, msg->msg_len); 4972cecf9bbSrmind if (error == 0 && msg_prio) 4982cecf9bbSrmind error = copyout(&msg->msg_prio, msg_prio, sizeof(unsigned)); 4992cecf9bbSrmind mqueue_freemsg(msg, sizeof(struct mq_msg) + msg->msg_len); 5002cecf9bbSrmind 5012cecf9bbSrmind return error; 5022cecf9bbSrmind } 5032cecf9bbSrmind 5042cecf9bbSrmind int 5057e2790cfSdsl sys_mq_receive(struct lwp *l, const struct sys_mq_receive_args *uap, register_t *retval) 5062cecf9bbSrmind { 5077e2790cfSdsl /* { 5082cecf9bbSrmind syscallarg(mqd_t) mqdes; 5092cecf9bbSrmind syscallarg(char *) msg_ptr; 5102cecf9bbSrmind syscallarg(size_t) msg_len; 5112cecf9bbSrmind syscallarg(unsigned *) msg_prio; 5127e2790cfSdsl } */ 5132cecf9bbSrmind int error; 5142cecf9bbSrmind ssize_t mlen; 5152cecf9bbSrmind 5162cecf9bbSrmind error = mq_receive1(l, SCARG(uap, mqdes), SCARG(uap, msg_ptr), 5172cecf9bbSrmind SCARG(uap, msg_len), SCARG(uap, msg_prio), 0, &mlen); 5182cecf9bbSrmind if (error == 0) 5192cecf9bbSrmind *retval = mlen; 5202cecf9bbSrmind 5212cecf9bbSrmind return error; 5222cecf9bbSrmind } 5232cecf9bbSrmind 5242cecf9bbSrmind int 5257e2790cfSdsl sys_mq_timedreceive(struct lwp *l, const struct sys_mq_timedreceive_args *uap, register_t *retval) 5262cecf9bbSrmind { 5277e2790cfSdsl /* { 5282cecf9bbSrmind syscallarg(mqd_t) mqdes; 5292cecf9bbSrmind syscallarg(char *) msg_ptr; 5302cecf9bbSrmind syscallarg(size_t) msg_len; 5312cecf9bbSrmind syscallarg(unsigned *) msg_prio; 5322cecf9bbSrmind syscallarg(const struct timespec *) abs_timeout; 5337e2790cfSdsl } */ 5342cecf9bbSrmind int error, t; 5352cecf9bbSrmind ssize_t mlen; 5362cecf9bbSrmind 5372cecf9bbSrmind /* Get and convert time value */ 5382cecf9bbSrmind if (SCARG(uap, abs_timeout)) { 5392cecf9bbSrmind error = abstimeout2timo(SCARG(uap, abs_timeout), &t); 5402cecf9bbSrmind if (error) 5412cecf9bbSrmind return error; 5422cecf9bbSrmind } else 5432cecf9bbSrmind t = 0; 5442cecf9bbSrmind 5452cecf9bbSrmind error = mq_receive1(l, SCARG(uap, mqdes), SCARG(uap, msg_ptr), 5462cecf9bbSrmind SCARG(uap, msg_len), SCARG(uap, msg_prio), t, &mlen); 5472cecf9bbSrmind if (error == 0) 5482cecf9bbSrmind *retval = mlen; 5492cecf9bbSrmind 5502cecf9bbSrmind return error; 5512cecf9bbSrmind } 5522cecf9bbSrmind 5532cecf9bbSrmind /* 5542cecf9bbSrmind * Primary mq_send1() function. 5552cecf9bbSrmind */ 5562cecf9bbSrmind static int 5572cecf9bbSrmind mq_send1(struct lwp *l, mqd_t mqdes, const char *msg_ptr, size_t msg_len, 5582cecf9bbSrmind unsigned msg_prio, int t) 5592cecf9bbSrmind { 560*a9ca7a37Sad file_t *fp = NULL; 5612cecf9bbSrmind struct mqueue *mq; 5622cecf9bbSrmind struct mq_msg *msg, *pos_msg; 5632cecf9bbSrmind struct proc *notify = NULL; 5642cecf9bbSrmind ksiginfo_t ksi; 5652cecf9bbSrmind size_t size; 5662cecf9bbSrmind int error; 5672cecf9bbSrmind 5682cecf9bbSrmind /* Check the priority range */ 5692cecf9bbSrmind if (msg_prio >= mq_prio_max) 5702cecf9bbSrmind return EINVAL; 5712cecf9bbSrmind 5722cecf9bbSrmind /* Allocate a new message */ 5732cecf9bbSrmind size = sizeof(struct mq_msg) + msg_len; 5742cecf9bbSrmind if (size > mq_max_msgsize) 5752cecf9bbSrmind return EMSGSIZE; 5762cecf9bbSrmind 5772cecf9bbSrmind if (size > MQ_DEF_MSGSIZE) 5782cecf9bbSrmind msg = kmem_alloc(size, KM_SLEEP); 5792cecf9bbSrmind else 5802cecf9bbSrmind msg = pool_get(&mqmsg_poll, PR_WAITOK); 5812cecf9bbSrmind 5822cecf9bbSrmind /* Get the data from user-space */ 5832cecf9bbSrmind error = copyin(msg_ptr, msg->msg_ptr, msg_len); 5842cecf9bbSrmind if (error) { 5852cecf9bbSrmind mqueue_freemsg(msg, size); 5862cecf9bbSrmind return error; 5872cecf9bbSrmind } 5882cecf9bbSrmind msg->msg_len = msg_len; 5892cecf9bbSrmind msg->msg_prio = msg_prio; 5902cecf9bbSrmind 5912cecf9bbSrmind /* Get the mqueue */ 5922cecf9bbSrmind error = mqueue_get(l, mqdes, VWRITE, &fp); 5932cecf9bbSrmind if (error) { 5942cecf9bbSrmind mqueue_freemsg(msg, size); 5952cecf9bbSrmind return error; 5962cecf9bbSrmind } 5972cecf9bbSrmind mq = fp->f_data; 5982cecf9bbSrmind 5992cecf9bbSrmind /* Check the message size limit */ 6002cecf9bbSrmind if (msg_len <= 0 || msg_len > mq->mq_attrib.mq_msgsize) { 6012cecf9bbSrmind error = EMSGSIZE; 6022cecf9bbSrmind goto error; 6032cecf9bbSrmind } 6042cecf9bbSrmind 6052cecf9bbSrmind /* Check if queue is full */ 606d62c40efSad while (mq->mq_attrib.mq_curmsgs >= mq->mq_attrib.mq_maxmsg) { 6072cecf9bbSrmind if (mq->mq_attrib.mq_flags & O_NONBLOCK) { 6082cecf9bbSrmind error = EAGAIN; 6092cecf9bbSrmind goto error; 6102cecf9bbSrmind } 6112cecf9bbSrmind if (t < 0) { 6122cecf9bbSrmind error = EINVAL; 6132cecf9bbSrmind goto error; 6142cecf9bbSrmind } 6152cecf9bbSrmind /* Block until queue becomes available */ 6162cecf9bbSrmind error = cv_timedwait_sig(&mq->mq_recv_cv, &mq->mq_mtx, t); 6172cecf9bbSrmind if (error || (mq->mq_attrib.mq_flags & MQ_UNLINK)) { 6182cecf9bbSrmind error = (error == EWOULDBLOCK) ? ETIMEDOUT : error; 6192cecf9bbSrmind goto error; 6202cecf9bbSrmind } 6212cecf9bbSrmind } 6222cecf9bbSrmind KASSERT(mq->mq_attrib.mq_curmsgs < mq->mq_attrib.mq_maxmsg); 6232cecf9bbSrmind 6242cecf9bbSrmind /* Insert message into the queue, according to the priority */ 6252cecf9bbSrmind TAILQ_FOREACH(pos_msg, &mq->mq_head, msg_queue) 6262cecf9bbSrmind if (msg->msg_prio > pos_msg->msg_prio) 6272cecf9bbSrmind break; 6282cecf9bbSrmind if (pos_msg == NULL) 6292cecf9bbSrmind TAILQ_INSERT_TAIL(&mq->mq_head, msg, msg_queue); 6302cecf9bbSrmind else 6312cecf9bbSrmind TAILQ_INSERT_BEFORE(pos_msg, msg, msg_queue); 6322cecf9bbSrmind 6332cecf9bbSrmind /* Check for the notify */ 6342cecf9bbSrmind if (mq->mq_attrib.mq_curmsgs == 0 && mq->mq_notify_proc && 6352cecf9bbSrmind (mq->mq_attrib.mq_flags & MQ_RECEIVE) == 0) { 6362cecf9bbSrmind /* Initialize the signal */ 6372cecf9bbSrmind KSI_INIT(&ksi); 6382cecf9bbSrmind ksi.ksi_signo = mq->mq_sig_notify.sigev_signo; 6392cecf9bbSrmind ksi.ksi_code = SI_MESGQ; 6402cecf9bbSrmind ksi.ksi_value = mq->mq_sig_notify.sigev_value; 6412cecf9bbSrmind /* Unregister the process */ 6422cecf9bbSrmind notify = mq->mq_notify_proc; 6432cecf9bbSrmind mq->mq_notify_proc = NULL; 6442cecf9bbSrmind } 6452cecf9bbSrmind 6462cecf9bbSrmind /* Increment the counter and signal waiter, if any */ 6472cecf9bbSrmind mq->mq_attrib.mq_curmsgs++; 6482cecf9bbSrmind cv_signal(&mq->mq_send_cv); 6492cecf9bbSrmind error: 6502cecf9bbSrmind mutex_exit(&mq->mq_mtx); 651*a9ca7a37Sad fd_putfile((int)mqdes); 6522cecf9bbSrmind 6532cecf9bbSrmind if (error) { 6542cecf9bbSrmind mqueue_freemsg(msg, size); 6552cecf9bbSrmind } else if (notify) { 6562cecf9bbSrmind /* Send the notify, if needed */ 6572cecf9bbSrmind mutex_enter(&proclist_mutex); 6582cecf9bbSrmind kpsignal(notify, &ksi, NULL); 6592cecf9bbSrmind mutex_exit(&proclist_mutex); 6602cecf9bbSrmind } 6612cecf9bbSrmind 6622cecf9bbSrmind return error; 6632cecf9bbSrmind } 6642cecf9bbSrmind 6652cecf9bbSrmind int 6667e2790cfSdsl sys_mq_send(struct lwp *l, const struct sys_mq_send_args *uap, register_t *retval) 6672cecf9bbSrmind { 6687e2790cfSdsl /* { 6692cecf9bbSrmind syscallarg(mqd_t) mqdes; 6702cecf9bbSrmind syscallarg(const char *) msg_ptr; 6712cecf9bbSrmind syscallarg(size_t) msg_len; 6722cecf9bbSrmind syscallarg(unsigned) msg_prio; 6737e2790cfSdsl } */ 6742cecf9bbSrmind 6752cecf9bbSrmind return mq_send1(l, SCARG(uap, mqdes), SCARG(uap, msg_ptr), 6762cecf9bbSrmind SCARG(uap, msg_len), SCARG(uap, msg_prio), 0); 6772cecf9bbSrmind } 6782cecf9bbSrmind 6792cecf9bbSrmind int 6807e2790cfSdsl sys_mq_timedsend(struct lwp *l, const struct sys_mq_timedsend_args *uap, register_t *retval) 6812cecf9bbSrmind { 6827e2790cfSdsl /* { 6832cecf9bbSrmind syscallarg(mqd_t) mqdes; 6842cecf9bbSrmind syscallarg(const char *) msg_ptr; 6852cecf9bbSrmind syscallarg(size_t) msg_len; 6862cecf9bbSrmind syscallarg(unsigned) msg_prio; 6872cecf9bbSrmind syscallarg(const struct timespec *) abs_timeout; 6887e2790cfSdsl } */ 6892cecf9bbSrmind int t; 6902cecf9bbSrmind 6912cecf9bbSrmind /* Get and convert time value */ 6922cecf9bbSrmind if (SCARG(uap, abs_timeout)) { 6932cecf9bbSrmind int error = abstimeout2timo(SCARG(uap, abs_timeout), &t); 6942cecf9bbSrmind if (error) 6952cecf9bbSrmind return error; 6962cecf9bbSrmind } else 6972cecf9bbSrmind t = 0; 6982cecf9bbSrmind 6992cecf9bbSrmind return mq_send1(l, SCARG(uap, mqdes), SCARG(uap, msg_ptr), 7002cecf9bbSrmind SCARG(uap, msg_len), SCARG(uap, msg_prio), t); 7012cecf9bbSrmind } 7022cecf9bbSrmind 7032cecf9bbSrmind int 7047e2790cfSdsl sys_mq_notify(struct lwp *l, const struct sys_mq_notify_args *uap, register_t *retval) 7052cecf9bbSrmind { 7067e2790cfSdsl /* { 7072cecf9bbSrmind syscallarg(mqd_t) mqdes; 7082cecf9bbSrmind syscallarg(const struct sigevent *) notification; 7097e2790cfSdsl } */ 710*a9ca7a37Sad file_t *fp = NULL; 7112cecf9bbSrmind struct mqueue *mq; 7122cecf9bbSrmind struct sigevent sig; 7132cecf9bbSrmind int error; 7142cecf9bbSrmind 7152cecf9bbSrmind if (SCARG(uap, notification)) { 7162cecf9bbSrmind /* Get the signal from user-space */ 7172cecf9bbSrmind error = copyin(SCARG(uap, notification), &sig, 7182cecf9bbSrmind sizeof(struct sigevent)); 7192cecf9bbSrmind if (error) 7202cecf9bbSrmind return error; 7212cecf9bbSrmind } 7222cecf9bbSrmind 7232cecf9bbSrmind error = mqueue_get(l, SCARG(uap, mqdes), VNOVAL, &fp); 7242cecf9bbSrmind if (error) 7252cecf9bbSrmind return error; 7262cecf9bbSrmind mq = fp->f_data; 7272cecf9bbSrmind 7282cecf9bbSrmind if (SCARG(uap, notification)) { 7292cecf9bbSrmind /* Register notification: set the signal and target process */ 7302cecf9bbSrmind if (mq->mq_notify_proc == NULL) { 7312cecf9bbSrmind memcpy(&mq->mq_sig_notify, &sig, 7322cecf9bbSrmind sizeof(struct sigevent)); 7332cecf9bbSrmind mq->mq_notify_proc = l->l_proc; 7342cecf9bbSrmind } else { 7352cecf9bbSrmind /* Fail if someone else already registered */ 7362cecf9bbSrmind error = EBUSY; 7372cecf9bbSrmind } 7382cecf9bbSrmind } else { 7392cecf9bbSrmind /* Unregister the notification */ 7402cecf9bbSrmind mq->mq_notify_proc = NULL; 7412cecf9bbSrmind } 7422cecf9bbSrmind mutex_exit(&mq->mq_mtx); 743*a9ca7a37Sad fd_putfile((int)SCARG(uap, mqdes)); 7442cecf9bbSrmind 7452cecf9bbSrmind return error; 7462cecf9bbSrmind } 7472cecf9bbSrmind 7482cecf9bbSrmind int 7497e2790cfSdsl sys_mq_getattr(struct lwp *l, const struct sys_mq_getattr_args *uap, register_t *retval) 7502cecf9bbSrmind { 7517e2790cfSdsl /* { 7522cecf9bbSrmind syscallarg(mqd_t) mqdes; 7532cecf9bbSrmind syscallarg(struct mq_attr *) mqstat; 7547e2790cfSdsl } */ 755*a9ca7a37Sad file_t *fp = NULL; 7562cecf9bbSrmind struct mqueue *mq; 7572cecf9bbSrmind struct mq_attr attr; 7582cecf9bbSrmind int error; 7592cecf9bbSrmind 7602cecf9bbSrmind /* Get the message queue */ 7612cecf9bbSrmind error = mqueue_get(l, SCARG(uap, mqdes), VNOVAL, &fp); 7622cecf9bbSrmind if (error) 7632cecf9bbSrmind return error; 7642cecf9bbSrmind mq = fp->f_data; 7652cecf9bbSrmind memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr)); 7662cecf9bbSrmind mutex_exit(&mq->mq_mtx); 767*a9ca7a37Sad fd_putfile((int)SCARG(uap, mqdes)); 7682cecf9bbSrmind 7692cecf9bbSrmind return copyout(&attr, SCARG(uap, mqstat), sizeof(struct mq_attr)); 7702cecf9bbSrmind } 7712cecf9bbSrmind 7722cecf9bbSrmind int 7737e2790cfSdsl sys_mq_setattr(struct lwp *l, const struct sys_mq_setattr_args *uap, register_t *retval) 7742cecf9bbSrmind { 7757e2790cfSdsl /* { 7762cecf9bbSrmind syscallarg(mqd_t) mqdes; 7772cecf9bbSrmind syscallarg(const struct mq_attr *) mqstat; 7782cecf9bbSrmind syscallarg(struct mq_attr *) omqstat; 7797e2790cfSdsl } */ 780*a9ca7a37Sad file_t *fp = NULL; 7812cecf9bbSrmind struct mqueue *mq; 7822cecf9bbSrmind struct mq_attr attr; 7832cecf9bbSrmind int error, nonblock; 7842cecf9bbSrmind 7852cecf9bbSrmind error = copyin(SCARG(uap, mqstat), &attr, sizeof(struct mq_attr)); 7862cecf9bbSrmind if (error) 7872cecf9bbSrmind return error; 7882cecf9bbSrmind nonblock = (attr.mq_flags & O_NONBLOCK); 7892cecf9bbSrmind 7902cecf9bbSrmind /* Get the message queue */ 7912cecf9bbSrmind error = mqueue_get(l, SCARG(uap, mqdes), VNOVAL, &fp); 7922cecf9bbSrmind if (error) 7932cecf9bbSrmind return error; 7942cecf9bbSrmind mq = fp->f_data; 7952cecf9bbSrmind 7962cecf9bbSrmind /* Copy the old attributes, if needed */ 7972cecf9bbSrmind if (SCARG(uap, omqstat)) 7982cecf9bbSrmind memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr)); 7992cecf9bbSrmind 8002cecf9bbSrmind /* Ignore everything, except O_NONBLOCK */ 8012cecf9bbSrmind if (nonblock) 8022cecf9bbSrmind mq->mq_attrib.mq_flags |= O_NONBLOCK; 8032cecf9bbSrmind else 8042cecf9bbSrmind mq->mq_attrib.mq_flags &= ~O_NONBLOCK; 8052cecf9bbSrmind 8062cecf9bbSrmind mutex_exit(&mq->mq_mtx); 807*a9ca7a37Sad fd_putfile((int)SCARG(uap, mqdes)); 8082cecf9bbSrmind 8092cecf9bbSrmind /* 8102cecf9bbSrmind * Copy the data to the user-space. 8112cecf9bbSrmind * Note: According to POSIX, the new attributes should not be set in 8122cecf9bbSrmind * case of fail - this would be violated. 8132cecf9bbSrmind */ 8142cecf9bbSrmind if (SCARG(uap, omqstat)) 8152cecf9bbSrmind error = copyout(&attr, SCARG(uap, omqstat), 8162cecf9bbSrmind sizeof(struct mq_attr)); 8172cecf9bbSrmind 8182cecf9bbSrmind return error; 8192cecf9bbSrmind } 8202cecf9bbSrmind 8212cecf9bbSrmind int 8227e2790cfSdsl sys_mq_unlink(struct lwp *l, const struct sys_mq_unlink_args *uap, register_t *retval) 8232cecf9bbSrmind { 8247e2790cfSdsl /* { 8252cecf9bbSrmind syscallarg(const char *) name; 8267e2790cfSdsl } */ 8272cecf9bbSrmind struct mqueue *mq; 8282cecf9bbSrmind char *name; 8292cecf9bbSrmind int error, refcnt = 0; 8302cecf9bbSrmind 8312cecf9bbSrmind /* Get the name from the user-space */ 8322cecf9bbSrmind name = kmem_zalloc(MQ_NAMELEN, KM_SLEEP); 8332cecf9bbSrmind error = copyinstr(SCARG(uap, name), name, MQ_NAMELEN - 1, NULL); 8342cecf9bbSrmind if (error) { 8352cecf9bbSrmind kmem_free(name, MQ_NAMELEN); 8362cecf9bbSrmind return error; 8372cecf9bbSrmind } 8382cecf9bbSrmind 8392cecf9bbSrmind /* Lookup for this file */ 8402cecf9bbSrmind mutex_enter(&mqlist_mtx); 8412cecf9bbSrmind mq = mqueue_lookup(name); 8422cecf9bbSrmind if (mq == NULL) { 8432cecf9bbSrmind error = ENOENT; 8442cecf9bbSrmind goto error; 8452cecf9bbSrmind } 8462cecf9bbSrmind 8472cecf9bbSrmind /* Check the permissions */ 8482cecf9bbSrmind if (mqueue_access(l, mq, VWRITE)) { 8492cecf9bbSrmind mutex_exit(&mq->mq_mtx); 8502cecf9bbSrmind error = EACCES; 8512cecf9bbSrmind goto error; 8522cecf9bbSrmind } 8532cecf9bbSrmind 8542cecf9bbSrmind /* Mark message queue as unlinking, before leaving the window */ 8552cecf9bbSrmind mq->mq_attrib.mq_flags |= MQ_UNLINK; 8562cecf9bbSrmind 8572cecf9bbSrmind /* Wake up all waiters, if there are such */ 8582cecf9bbSrmind cv_broadcast(&mq->mq_send_cv); 8592cecf9bbSrmind cv_broadcast(&mq->mq_recv_cv); 8602cecf9bbSrmind 8612cecf9bbSrmind refcnt = mq->mq_refcnt; 8622cecf9bbSrmind if (refcnt == 0) 8632cecf9bbSrmind LIST_REMOVE(mq, mq_list); 8642cecf9bbSrmind 8652cecf9bbSrmind mutex_exit(&mq->mq_mtx); 8662cecf9bbSrmind error: 8672cecf9bbSrmind mutex_exit(&mqlist_mtx); 8682cecf9bbSrmind 8692cecf9bbSrmind /* 8702cecf9bbSrmind * If there are no references - destroy the message 8712cecf9bbSrmind * queue, otherwise, the last mq_close() will do that. 8722cecf9bbSrmind */ 8732cecf9bbSrmind if (error == 0 && refcnt == 0) 8742cecf9bbSrmind mqueue_destroy(mq); 8752cecf9bbSrmind 8762cecf9bbSrmind kmem_free(name, MQ_NAMELEN); 8772cecf9bbSrmind return error; 8782cecf9bbSrmind } 8792cecf9bbSrmind 8802cecf9bbSrmind /* 8812cecf9bbSrmind * SysCtl. 8822cecf9bbSrmind */ 8832cecf9bbSrmind 8842cecf9bbSrmind SYSCTL_SETUP(sysctl_mqueue_setup, "sysctl mqueue setup") 8852cecf9bbSrmind { 8862cecf9bbSrmind const struct sysctlnode *node = NULL; 8872cecf9bbSrmind 8882cecf9bbSrmind sysctl_createv(clog, 0, NULL, NULL, 8892cecf9bbSrmind CTLFLAG_PERMANENT, 8902cecf9bbSrmind CTLTYPE_NODE, "kern", NULL, 8912cecf9bbSrmind NULL, 0, NULL, 0, 8922cecf9bbSrmind CTL_KERN, CTL_EOL); 8932cecf9bbSrmind sysctl_createv(clog, 0, NULL, NULL, 8942cecf9bbSrmind CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE, 8952cecf9bbSrmind CTLTYPE_INT, "posix_msg", 8962cecf9bbSrmind SYSCTL_DESCR("Version of IEEE Std 1003.1 and its " 8972cecf9bbSrmind "Message Passing option to which the " 8982cecf9bbSrmind "system attempts to conform"), 8992cecf9bbSrmind NULL, _POSIX_MESSAGE_PASSING, NULL, 0, 9002cecf9bbSrmind CTL_KERN, CTL_CREATE, CTL_EOL); 9012cecf9bbSrmind sysctl_createv(clog, 0, NULL, &node, 9022cecf9bbSrmind CTLFLAG_PERMANENT, 9032cecf9bbSrmind CTLTYPE_NODE, "mqueue", 9042cecf9bbSrmind SYSCTL_DESCR("Message queue options"), 9052cecf9bbSrmind NULL, 0, NULL, 0, 9062cecf9bbSrmind CTL_KERN, CTL_CREATE, CTL_EOL); 9072cecf9bbSrmind 9082cecf9bbSrmind if (node == NULL) 9092cecf9bbSrmind return; 9102cecf9bbSrmind 9112cecf9bbSrmind sysctl_createv(clog, 0, &node, NULL, 9122cecf9bbSrmind CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 9132cecf9bbSrmind CTLTYPE_INT, "mq_open_max", 9142cecf9bbSrmind SYSCTL_DESCR("Maximal number of message queue descriptors " 9152cecf9bbSrmind "that process could open"), 9162cecf9bbSrmind NULL, 0, &mq_open_max, 0, 9172cecf9bbSrmind CTL_CREATE, CTL_EOL); 9182cecf9bbSrmind sysctl_createv(clog, 0, &node, NULL, 9192cecf9bbSrmind CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 9202cecf9bbSrmind CTLTYPE_INT, "mq_prio_max", 9212cecf9bbSrmind SYSCTL_DESCR("Maximal priority of the message"), 9222cecf9bbSrmind NULL, 0, &mq_prio_max, 0, 9232cecf9bbSrmind CTL_CREATE, CTL_EOL); 9242cecf9bbSrmind sysctl_createv(clog, 0, &node, NULL, 9252cecf9bbSrmind CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 9262cecf9bbSrmind CTLTYPE_INT, "mq_max_msgsize", 9272cecf9bbSrmind SYSCTL_DESCR("Maximal allowed size of the message"), 9282cecf9bbSrmind NULL, 0, &mq_max_msgsize, 0, 9292cecf9bbSrmind CTL_CREATE, CTL_EOL); 9302cecf9bbSrmind sysctl_createv(clog, 0, &node, NULL, 9312cecf9bbSrmind CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 9322cecf9bbSrmind CTLTYPE_INT, "mq_def_maxmsg", 9332cecf9bbSrmind SYSCTL_DESCR("Default maximal message count"), 9342cecf9bbSrmind NULL, 0, &mq_def_maxmsg, 0, 9352cecf9bbSrmind CTL_CREATE, CTL_EOL); 9362cecf9bbSrmind } 9372cecf9bbSrmind 9382cecf9bbSrmind /* 9392cecf9bbSrmind * Debugging. 9402cecf9bbSrmind */ 9412cecf9bbSrmind #if defined(DDB) 9422cecf9bbSrmind 9432cecf9bbSrmind void 9442cecf9bbSrmind mqueue_print_list(void (*pr)(const char *, ...)) 9452cecf9bbSrmind { 9462cecf9bbSrmind struct mqueue *mq; 9472cecf9bbSrmind 9482cecf9bbSrmind (*pr)("Global list of the message queues:\n"); 9492cecf9bbSrmind (*pr)("%20s %10s %8s %8s %3s %4s %4s %4s\n", 9502cecf9bbSrmind "Name", "Ptr", "Mode", "Flags", "Ref", 9512cecf9bbSrmind "MaxMsg", "MsgSze", "CurMsg"); 9522cecf9bbSrmind LIST_FOREACH(mq, &mqueue_head, mq_list) { 9532cecf9bbSrmind (*pr)("%20s %10p %8x %8x %3u %6lu %6lu %6lu\n", 9542cecf9bbSrmind mq->mq_name, mq, mq->mq_mode, 9552cecf9bbSrmind mq->mq_attrib.mq_flags, mq->mq_refcnt, 9562cecf9bbSrmind mq->mq_attrib.mq_maxmsg, mq->mq_attrib.mq_msgsize, 9572cecf9bbSrmind mq->mq_attrib.mq_curmsgs); 9582cecf9bbSrmind } 9592cecf9bbSrmind } 9602cecf9bbSrmind 9612cecf9bbSrmind #endif /* defined(DDB) */ 962