Home | History | Annotate | Line # | Download | only in kern
sys_mqueue.c revision 1.12.4.1.2.3.2.1
      1  1.12.4.1.2.3.2.1   matt /*	$NetBSD: sys_mqueue.c,v 1.12.4.1.2.3.2.1 2010/04/21 00:28:18 matt Exp $	*/
      2               1.1  rmind 
      3               1.1  rmind /*
      4  1.12.4.1.2.3.2.1   matt  * Copyright (c) 2007-2009 Mindaugas Rasiukevicius <rmind at NetBSD org>
      5               1.5  rmind  * All rights reserved.
      6               1.1  rmind  *
      7               1.1  rmind  * Redistribution and use in source and binary forms, with or without
      8               1.1  rmind  * modification, are permitted provided that the following conditions
      9               1.1  rmind  * are met:
     10               1.1  rmind  * 1. Redistributions of source code must retain the above copyright
     11               1.1  rmind  *    notice, this list of conditions and the following disclaimer.
     12               1.1  rmind  * 2. Redistributions in binary form must reproduce the above copyright
     13               1.1  rmind  *    notice, this list of conditions and the following disclaimer in the
     14               1.1  rmind  *    documentation and/or other materials provided with the distribution.
     15               1.1  rmind  *
     16               1.8  rmind  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     17               1.8  rmind  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18               1.8  rmind  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19               1.8  rmind  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     20               1.8  rmind  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21               1.8  rmind  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22               1.8  rmind  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23               1.8  rmind  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24               1.8  rmind  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25               1.8  rmind  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26               1.8  rmind  * SUCH DAMAGE.
     27               1.1  rmind  */
     28               1.1  rmind 
     29               1.1  rmind /*
     30               1.1  rmind  * Implementation of POSIX message queues.
     31               1.1  rmind  * Defined in the Base Definitions volume of IEEE Std 1003.1-2001.
     32              1.12  rmind  *
     33              1.12  rmind  * Locking
     34               1.1  rmind  *
     35              1.12  rmind  * Global list of message queues (mqueue_head) and proc_t::p_mqueue_cnt
     36              1.12  rmind  * counter are protected by mqlist_mtx lock.  The very message queue and
     37              1.12  rmind  * its members are protected by mqueue::mq_mtx.
     38               1.1  rmind  *
     39               1.1  rmind  * Lock order:
     40               1.1  rmind  * 	mqlist_mtx
     41               1.1  rmind  * 	  -> mqueue::mq_mtx
     42               1.1  rmind  */
     43               1.1  rmind 
     44               1.1  rmind #include <sys/cdefs.h>
     45  1.12.4.1.2.3.2.1   matt __KERNEL_RCSID(0, "$NetBSD: sys_mqueue.c,v 1.12.4.1.2.3.2.1 2010/04/21 00:28:18 matt Exp $");
     46               1.1  rmind 
     47               1.1  rmind #include <sys/param.h>
     48               1.1  rmind #include <sys/types.h>
     49               1.1  rmind #include <sys/condvar.h>
     50               1.1  rmind #include <sys/errno.h>
     51               1.1  rmind #include <sys/fcntl.h>
     52               1.1  rmind #include <sys/file.h>
     53               1.1  rmind #include <sys/filedesc.h>
     54               1.1  rmind #include <sys/kauth.h>
     55               1.1  rmind #include <sys/kernel.h>
     56               1.1  rmind #include <sys/kmem.h>
     57               1.1  rmind #include <sys/lwp.h>
     58               1.1  rmind #include <sys/mqueue.h>
     59               1.1  rmind #include <sys/mutex.h>
     60               1.1  rmind #include <sys/pool.h>
     61               1.8  rmind #include <sys/poll.h>
     62               1.1  rmind #include <sys/proc.h>
     63               1.1  rmind #include <sys/queue.h>
     64               1.8  rmind #include <sys/select.h>
     65               1.1  rmind #include <sys/signal.h>
     66               1.1  rmind #include <sys/signalvar.h>
     67              1.12  rmind #include <sys/stat.h>
     68               1.1  rmind #include <sys/sysctl.h>
     69               1.1  rmind #include <sys/syscallargs.h>
     70               1.1  rmind #include <sys/systm.h>
     71               1.1  rmind #include <sys/unistd.h>
     72               1.1  rmind #include <sys/vnode.h>
     73               1.1  rmind 
     74               1.1  rmind /* System-wide limits. */
     75               1.1  rmind static u_int			mq_open_max = MQ_OPEN_MAX;
     76               1.1  rmind static u_int			mq_prio_max = MQ_PRIO_MAX;
     77               1.1  rmind 
     78               1.1  rmind static u_int			mq_max_msgsize = 16 * MQ_DEF_MSGSIZE;
     79               1.1  rmind static u_int			mq_def_maxmsg = 32;
     80  1.12.4.1.2.3.2.1   matt static u_int			mq_max_maxmsg = 16 * 32;
     81               1.1  rmind 
     82               1.1  rmind static kmutex_t			mqlist_mtx;
     83               1.8  rmind static pool_cache_t		mqmsg_cache;
     84               1.4   matt static LIST_HEAD(, mqueue)	mqueue_head =
     85               1.4   matt 	LIST_HEAD_INITIALIZER(mqueue_head);
     86               1.1  rmind 
     87               1.8  rmind static int	mq_poll_fop(file_t *, int);
     88               1.7     ad static int	mq_close_fop(file_t *);
     89               1.1  rmind 
     90               1.1  rmind static const struct fileops mqops = {
     91          1.12.4.1    snj 	.fo_read = fbadop_read,
     92          1.12.4.1    snj 	.fo_write = fbadop_write,
     93          1.12.4.1    snj 	.fo_ioctl = fbadop_ioctl,
     94          1.12.4.1    snj 	.fo_fcntl = fnullop_fcntl,
     95          1.12.4.1    snj 	.fo_poll = mq_poll_fop,
     96          1.12.4.1    snj 	.fo_stat = fbadop_stat,
     97          1.12.4.1    snj 	.fo_close = mq_close_fop,
     98          1.12.4.1    snj 	.fo_kqfilter = fnullop_kqfilter,
     99          1.12.4.1    snj 	.fo_drain = fnullop_drain,
    100               1.1  rmind };
    101               1.1  rmind 
    102               1.1  rmind /*
    103               1.1  rmind  * Initialize POSIX message queue subsystem.
    104               1.1  rmind  */
    105               1.1  rmind void
    106               1.1  rmind mqueue_sysinit(void)
    107               1.1  rmind {
    108               1.1  rmind 
    109               1.9     ad 	mqmsg_cache = pool_cache_init(MQ_DEF_MSGSIZE, coherency_unit,
    110              1.12  rmind 	    0, 0, "mqmsgpl", NULL, IPL_NONE, NULL, NULL, NULL);
    111               1.1  rmind 	mutex_init(&mqlist_mtx, MUTEX_DEFAULT, IPL_NONE);
    112               1.1  rmind }
    113               1.1  rmind 
    114               1.1  rmind /*
    115               1.1  rmind  * Free the message.
    116               1.1  rmind  */
    117               1.1  rmind static void
    118               1.1  rmind mqueue_freemsg(struct mq_msg *msg, const size_t size)
    119               1.1  rmind {
    120               1.1  rmind 
    121               1.1  rmind 	if (size > MQ_DEF_MSGSIZE)
    122               1.1  rmind 		kmem_free(msg, size);
    123               1.1  rmind 	else
    124               1.8  rmind 		pool_cache_put(mqmsg_cache, msg);
    125               1.1  rmind }
    126               1.1  rmind 
    127               1.1  rmind /*
    128               1.1  rmind  * Destroy the message queue.
    129               1.1  rmind  */
    130               1.1  rmind static void
    131               1.1  rmind mqueue_destroy(struct mqueue *mq)
    132               1.1  rmind {
    133               1.1  rmind 	struct mq_msg *msg;
    134               1.1  rmind 
    135               1.1  rmind 	while ((msg = TAILQ_FIRST(&mq->mq_head)) != NULL) {
    136               1.1  rmind 		TAILQ_REMOVE(&mq->mq_head, msg, msg_queue);
    137               1.1  rmind 		mqueue_freemsg(msg, sizeof(struct mq_msg) + msg->msg_len);
    138               1.1  rmind 	}
    139               1.8  rmind 	seldestroy(&mq->mq_rsel);
    140               1.8  rmind 	seldestroy(&mq->mq_wsel);
    141               1.1  rmind 	cv_destroy(&mq->mq_send_cv);
    142               1.1  rmind 	cv_destroy(&mq->mq_recv_cv);
    143               1.1  rmind 	mutex_destroy(&mq->mq_mtx);
    144               1.1  rmind 	kmem_free(mq, sizeof(struct mqueue));
    145               1.1  rmind }
    146               1.1  rmind 
    147               1.1  rmind /*
    148               1.1  rmind  * Lookup for file name in general list of message queues.
    149               1.1  rmind  *  => locks the message queue
    150               1.1  rmind  */
    151               1.1  rmind static void *
    152               1.1  rmind mqueue_lookup(char *name)
    153               1.1  rmind {
    154               1.1  rmind 	struct mqueue *mq;
    155               1.1  rmind 	KASSERT(mutex_owned(&mqlist_mtx));
    156               1.1  rmind 
    157               1.1  rmind 	LIST_FOREACH(mq, &mqueue_head, mq_list) {
    158               1.1  rmind 		if (strncmp(mq->mq_name, name, MQ_NAMELEN) == 0) {
    159               1.1  rmind 			mutex_enter(&mq->mq_mtx);
    160               1.1  rmind 			return mq;
    161               1.1  rmind 		}
    162               1.1  rmind 	}
    163               1.1  rmind 
    164               1.1  rmind 	return NULL;
    165               1.1  rmind }
    166               1.1  rmind 
    167               1.1  rmind /*
    168      1.12.4.1.2.2    snj  * mqueue_get: get the mqueue from the descriptor.
    169      1.12.4.1.2.2    snj  *  => locks the message queue, if found.
    170      1.12.4.1.2.2    snj  *  => holds a reference on the file descriptor.
    171               1.1  rmind  */
    172               1.1  rmind static int
    173      1.12.4.1.2.2    snj mqueue_get(mqd_t mqd, file_t **fpr)
    174               1.1  rmind {
    175               1.1  rmind 	struct mqueue *mq;
    176      1.12.4.1.2.2    snj 	file_t *fp;
    177               1.1  rmind 
    178               1.7     ad 	fp = fd_getfile((int)mqd);
    179      1.12.4.1.2.2    snj 	if (__predict_false(fp == NULL)) {
    180               1.1  rmind 		return EBADF;
    181              1.12  rmind 	}
    182      1.12.4.1.2.2    snj 	if (__predict_false(fp->f_type != DTYPE_MQUEUE)) {
    183               1.7     ad 		fd_putfile((int)mqd);
    184      1.12.4.1.2.2    snj 		return EBADF;
    185               1.1  rmind 	}
    186      1.12.4.1.2.2    snj 	mq = fp->f_data;
    187      1.12.4.1.2.2    snj 	mutex_enter(&mq->mq_mtx);
    188      1.12.4.1.2.2    snj 
    189      1.12.4.1.2.2    snj 	*fpr = fp;
    190               1.1  rmind 	return 0;
    191               1.1  rmind }
    192               1.1  rmind 
    193               1.1  rmind /*
    194  1.12.4.1.2.3.2.1   matt  * Calculate delta and convert from struct timespec to the ticks.
    195               1.1  rmind  * Used by mq_timedreceive(), mq_timedsend().
    196               1.1  rmind  */
    197               1.1  rmind static int
    198  1.12.4.1.2.3.2.1   matt abstimeout2timo(struct timespec *ts, int *timo)
    199               1.1  rmind {
    200  1.12.4.1.2.3.2.1   matt 	struct timespec tsd;
    201               1.1  rmind 	int error;
    202               1.1  rmind 
    203  1.12.4.1.2.3.2.1   matt 	getnanotime(&tsd);
    204  1.12.4.1.2.3.2.1   matt 	timespecsub(ts, &tsd, &tsd);
    205  1.12.4.1.2.3.2.1   matt 	if (tsd.tv_sec < 0 || (tsd.tv_sec == 0 && tsd.tv_nsec <= 0)) {
    206  1.12.4.1.2.3.2.1   matt 		return ETIMEDOUT;
    207  1.12.4.1.2.3.2.1   matt 	}
    208  1.12.4.1.2.3.2.1   matt 	error = itimespecfix(&tsd);
    209  1.12.4.1.2.3.2.1   matt 	if (error) {
    210               1.1  rmind 		return error;
    211  1.12.4.1.2.3.2.1   matt 	}
    212  1.12.4.1.2.3.2.1   matt 	*timo = tstohz(&tsd);
    213  1.12.4.1.2.3.2.1   matt 	KASSERT(*timo != 0);
    214               1.1  rmind 
    215               1.1  rmind 	return 0;
    216               1.1  rmind }
    217               1.1  rmind 
    218               1.1  rmind static int
    219               1.8  rmind mq_poll_fop(file_t *fp, int events)
    220               1.8  rmind {
    221               1.8  rmind 	struct mqueue *mq = fp->f_data;
    222               1.8  rmind 	int revents = 0;
    223               1.8  rmind 
    224               1.8  rmind 	mutex_enter(&mq->mq_mtx);
    225               1.8  rmind 	if (events & (POLLIN | POLLRDNORM)) {
    226               1.8  rmind 		/* Ready for receiving, if there are messages in the queue */
    227               1.8  rmind 		if (mq->mq_attrib.mq_curmsgs)
    228               1.8  rmind 			revents |= (POLLIN | POLLRDNORM);
    229               1.8  rmind 		else
    230               1.8  rmind 			selrecord(curlwp, &mq->mq_rsel);
    231               1.8  rmind 	}
    232               1.8  rmind 	if (events & (POLLOUT | POLLWRNORM)) {
    233               1.8  rmind 		/* Ready for sending, if the message queue is not full */
    234               1.8  rmind 		if (mq->mq_attrib.mq_curmsgs < mq->mq_attrib.mq_maxmsg)
    235               1.8  rmind 			revents |= (POLLOUT | POLLWRNORM);
    236               1.8  rmind 		else
    237               1.8  rmind 			selrecord(curlwp, &mq->mq_wsel);
    238               1.8  rmind 	}
    239               1.8  rmind 	mutex_exit(&mq->mq_mtx);
    240               1.8  rmind 
    241               1.8  rmind 	return revents;
    242               1.8  rmind }
    243               1.8  rmind 
    244               1.8  rmind static int
    245               1.7     ad mq_close_fop(file_t *fp)
    246               1.1  rmind {
    247               1.7     ad 	struct proc *p = curproc;
    248               1.1  rmind 	struct mqueue *mq = fp->f_data;
    249               1.1  rmind 	bool destroy;
    250               1.1  rmind 
    251               1.1  rmind 	mutex_enter(&mqlist_mtx);
    252               1.1  rmind 	mutex_enter(&mq->mq_mtx);
    253               1.1  rmind 
    254               1.1  rmind 	/* Decrease the counters */
    255               1.1  rmind 	p->p_mqueue_cnt--;
    256               1.1  rmind 	mq->mq_refcnt--;
    257               1.1  rmind 
    258               1.1  rmind 	/* Remove notification if registered for this process */
    259               1.1  rmind 	if (mq->mq_notify_proc == p)
    260               1.1  rmind 		mq->mq_notify_proc = NULL;
    261               1.1  rmind 
    262               1.1  rmind 	/*
    263               1.1  rmind 	 * If this is the last reference and mqueue is marked for unlink,
    264               1.1  rmind 	 * remove and later destroy the message queue.
    265               1.1  rmind 	 */
    266               1.1  rmind 	if (mq->mq_refcnt == 0 && (mq->mq_attrib.mq_flags & MQ_UNLINK)) {
    267               1.1  rmind 		LIST_REMOVE(mq, mq_list);
    268               1.1  rmind 		destroy = true;
    269               1.1  rmind 	} else
    270               1.1  rmind 		destroy = false;
    271               1.1  rmind 
    272               1.1  rmind 	mutex_exit(&mq->mq_mtx);
    273               1.1  rmind 	mutex_exit(&mqlist_mtx);
    274               1.1  rmind 
    275               1.1  rmind 	if (destroy)
    276               1.1  rmind 		mqueue_destroy(mq);
    277               1.1  rmind 
    278               1.1  rmind 	return 0;
    279               1.1  rmind }
    280               1.1  rmind 
    281               1.1  rmind /*
    282               1.1  rmind  * General mqueue system calls.
    283               1.1  rmind  */
    284               1.1  rmind 
    285               1.1  rmind int
    286               1.8  rmind sys_mq_open(struct lwp *l, const struct sys_mq_open_args *uap,
    287               1.8  rmind     register_t *retval)
    288               1.1  rmind {
    289               1.6    dsl 	/* {
    290               1.1  rmind 		syscallarg(const char *) name;
    291               1.1  rmind 		syscallarg(int) oflag;
    292               1.1  rmind 		syscallarg(mode_t) mode;
    293               1.1  rmind 		syscallarg(struct mq_attr) attr;
    294               1.6    dsl 	} */
    295               1.1  rmind 	struct proc *p = l->l_proc;
    296               1.1  rmind 	struct mqueue *mq, *mq_new = NULL;
    297               1.7     ad 	file_t *fp;
    298               1.1  rmind 	char *name;
    299               1.1  rmind 	int mqd, error, oflag;
    300               1.1  rmind 
    301               1.1  rmind 	oflag = SCARG(uap, oflag);
    302               1.1  rmind 
    303               1.1  rmind 	/* Get the name from the user-space */
    304               1.1  rmind 	name = kmem_zalloc(MQ_NAMELEN, KM_SLEEP);
    305               1.1  rmind 	error = copyinstr(SCARG(uap, name), name, MQ_NAMELEN - 1, NULL);
    306               1.1  rmind 	if (error) {
    307               1.1  rmind 		kmem_free(name, MQ_NAMELEN);
    308               1.1  rmind 		return error;
    309               1.1  rmind 	}
    310               1.1  rmind 
    311               1.1  rmind 	if (oflag & O_CREAT) {
    312              1.12  rmind 		struct cwdinfo *cwdi = p->p_cwdi;
    313               1.1  rmind 		struct mq_attr attr;
    314               1.1  rmind 
    315               1.1  rmind 		/* Check the limit */
    316               1.1  rmind 		if (p->p_mqueue_cnt == mq_open_max) {
    317               1.1  rmind 			kmem_free(name, MQ_NAMELEN);
    318               1.1  rmind 			return EMFILE;
    319               1.1  rmind 		}
    320               1.1  rmind 
    321      1.12.4.1.2.2    snj 		/* Empty name is invalid */
    322      1.12.4.1.2.2    snj 		if (name[0] == '\0') {
    323      1.12.4.1.2.2    snj 			kmem_free(name, MQ_NAMELEN);
    324      1.12.4.1.2.2    snj 			return EINVAL;
    325      1.12.4.1.2.2    snj 		}
    326      1.12.4.1.2.2    snj 
    327               1.1  rmind 		/* Check for mqueue attributes */
    328               1.1  rmind 		if (SCARG(uap, attr)) {
    329               1.1  rmind 			error = copyin(SCARG(uap, attr), &attr,
    330               1.1  rmind 				sizeof(struct mq_attr));
    331               1.1  rmind 			if (error) {
    332               1.1  rmind 				kmem_free(name, MQ_NAMELEN);
    333               1.1  rmind 				return error;
    334               1.1  rmind 			}
    335  1.12.4.1.2.3.2.1   matt 			if (attr.mq_maxmsg <= 0 ||
    336  1.12.4.1.2.3.2.1   matt 			    attr.mq_maxmsg > mq_max_maxmsg ||
    337  1.12.4.1.2.3.2.1   matt 			    attr.mq_msgsize <= 0 ||
    338               1.1  rmind 			    attr.mq_msgsize > mq_max_msgsize) {
    339               1.1  rmind 				kmem_free(name, MQ_NAMELEN);
    340               1.1  rmind 				return EINVAL;
    341               1.1  rmind 			}
    342               1.1  rmind 			attr.mq_curmsgs = 0;
    343               1.1  rmind 		} else {
    344               1.1  rmind 			memset(&attr, 0, sizeof(struct mq_attr));
    345               1.1  rmind 			attr.mq_maxmsg = mq_def_maxmsg;
    346               1.1  rmind 			attr.mq_msgsize =
    347               1.1  rmind 			    MQ_DEF_MSGSIZE - sizeof(struct mq_msg);
    348               1.1  rmind 		}
    349               1.1  rmind 
    350               1.1  rmind 		/*
    351               1.1  rmind 		 * Allocate new mqueue, initialize data structures,
    352               1.1  rmind 		 * copy the name, attributes and set the flag.
    353               1.1  rmind 		 */
    354               1.1  rmind 		mq_new = kmem_zalloc(sizeof(struct mqueue), KM_SLEEP);
    355               1.1  rmind 
    356               1.1  rmind 		mutex_init(&mq_new->mq_mtx, MUTEX_DEFAULT, IPL_NONE);
    357               1.1  rmind 		cv_init(&mq_new->mq_send_cv, "mqsendcv");
    358               1.1  rmind 		cv_init(&mq_new->mq_recv_cv, "mqrecvcv");
    359               1.1  rmind 		TAILQ_INIT(&mq_new->mq_head);
    360               1.8  rmind 		selinit(&mq_new->mq_rsel);
    361               1.8  rmind 		selinit(&mq_new->mq_wsel);
    362               1.1  rmind 
    363               1.1  rmind 		strlcpy(mq_new->mq_name, name, MQ_NAMELEN);
    364               1.1  rmind 		memcpy(&mq_new->mq_attrib, &attr, sizeof(struct mq_attr));
    365      1.12.4.1.2.2    snj 
    366      1.12.4.1.2.2    snj 		CTASSERT((O_MASK & (MQ_UNLINK | MQ_RECEIVE)) == 0);
    367      1.12.4.1.2.2    snj 		mq_new->mq_attrib.mq_flags = (O_MASK & oflag);
    368               1.1  rmind 
    369               1.1  rmind 		/* Store mode and effective UID with GID */
    370              1.12  rmind 		mq_new->mq_mode = ((SCARG(uap, mode) &
    371              1.12  rmind 		    ~cwdi->cwdi_cmask) & ALLPERMS) & ~S_ISTXT;
    372               1.1  rmind 		mq_new->mq_euid = kauth_cred_geteuid(l->l_cred);
    373               1.1  rmind 		mq_new->mq_egid = kauth_cred_getegid(l->l_cred);
    374               1.1  rmind 	}
    375               1.1  rmind 
    376               1.1  rmind 	/* Allocate file structure and descriptor */
    377               1.7     ad 	error = fd_allocfile(&fp, &mqd);
    378               1.1  rmind 	if (error) {
    379               1.1  rmind 		if (mq_new)
    380               1.1  rmind 			mqueue_destroy(mq_new);
    381               1.1  rmind 		kmem_free(name, MQ_NAMELEN);
    382               1.1  rmind 		return error;
    383               1.1  rmind 	}
    384               1.1  rmind 	fp->f_type = DTYPE_MQUEUE;
    385              1.11  rmind 	fp->f_flag = FFLAGS(oflag) & (FREAD | FWRITE);
    386               1.1  rmind 	fp->f_ops = &mqops;
    387               1.1  rmind 
    388               1.1  rmind 	/* Look up for mqueue with such name */
    389               1.1  rmind 	mutex_enter(&mqlist_mtx);
    390               1.1  rmind 	mq = mqueue_lookup(name);
    391               1.1  rmind 	if (mq) {
    392      1.12.4.1.2.2    snj 		mode_t acc_mode;
    393      1.12.4.1.2.2    snj 
    394              1.12  rmind 		KASSERT(mutex_owned(&mq->mq_mtx));
    395              1.11  rmind 
    396               1.1  rmind 		/* Check if mqueue is not marked as unlinking */
    397               1.1  rmind 		if (mq->mq_attrib.mq_flags & MQ_UNLINK) {
    398               1.1  rmind 			error = EACCES;
    399               1.1  rmind 			goto exit;
    400               1.1  rmind 		}
    401               1.1  rmind 		/* Fail if O_EXCL is set, and mqueue already exists */
    402               1.1  rmind 		if ((oflag & O_CREAT) && (oflag & O_EXCL)) {
    403               1.1  rmind 			error = EEXIST;
    404               1.1  rmind 			goto exit;
    405               1.1  rmind 		}
    406      1.12.4.1.2.2    snj 
    407      1.12.4.1.2.2    snj 		/*
    408      1.12.4.1.2.2    snj 		 * Check the permissions.  Note the difference between
    409      1.12.4.1.2.2    snj 		 * VREAD/VWRITE and FREAD/FWRITE.
    410      1.12.4.1.2.2    snj 		 */
    411      1.12.4.1.2.2    snj 		acc_mode = 0;
    412      1.12.4.1.2.2    snj 		if (fp->f_flag & FREAD) {
    413      1.12.4.1.2.2    snj 			acc_mode |= VREAD;
    414      1.12.4.1.2.2    snj 		}
    415      1.12.4.1.2.2    snj 		if (fp->f_flag & FWRITE) {
    416      1.12.4.1.2.2    snj 			acc_mode |= VWRITE;
    417      1.12.4.1.2.2    snj 		}
    418      1.12.4.1.2.2    snj 		if (vaccess(VNON, mq->mq_mode, mq->mq_euid, mq->mq_egid,
    419      1.12.4.1.2.2    snj 		    acc_mode, l->l_cred)) {
    420               1.1  rmind 			error = EACCES;
    421               1.1  rmind 			goto exit;
    422               1.1  rmind 		}
    423               1.1  rmind 	} else {
    424               1.1  rmind 		/* Fail if mqueue neither exists, nor we create it */
    425               1.1  rmind 		if ((oflag & O_CREAT) == 0) {
    426               1.1  rmind 			mutex_exit(&mqlist_mtx);
    427               1.1  rmind 			KASSERT(mq_new == NULL);
    428               1.7     ad 			fd_abort(p, fp, mqd);
    429               1.1  rmind 			kmem_free(name, MQ_NAMELEN);
    430               1.1  rmind 			return ENOENT;
    431               1.1  rmind 		}
    432               1.1  rmind 
    433               1.1  rmind 		/* Check the limit */
    434               1.1  rmind 		if (p->p_mqueue_cnt == mq_open_max) {
    435               1.1  rmind 			error = EMFILE;
    436               1.1  rmind 			goto exit;
    437               1.1  rmind 		}
    438               1.1  rmind 
    439               1.1  rmind 		/* Insert the queue to the list */
    440               1.1  rmind 		mq = mq_new;
    441               1.1  rmind 		mutex_enter(&mq->mq_mtx);
    442               1.1  rmind 		LIST_INSERT_HEAD(&mqueue_head, mq, mq_list);
    443               1.1  rmind 		mq_new = NULL;
    444               1.1  rmind 	}
    445               1.1  rmind 
    446               1.1  rmind 	/* Increase the counters, and make descriptor ready */
    447               1.1  rmind 	p->p_mqueue_cnt++;
    448               1.1  rmind 	mq->mq_refcnt++;
    449               1.1  rmind 	fp->f_data = mq;
    450               1.1  rmind exit:
    451               1.1  rmind 	mutex_exit(&mq->mq_mtx);
    452               1.1  rmind 	mutex_exit(&mqlist_mtx);
    453               1.1  rmind 
    454               1.1  rmind 	if (mq_new)
    455               1.1  rmind 		mqueue_destroy(mq_new);
    456               1.1  rmind 	if (error) {
    457               1.7     ad 		fd_abort(p, fp, mqd);
    458               1.7     ad 	} else {
    459               1.7     ad 		fd_affix(p, fp, mqd);
    460               1.1  rmind 		*retval = mqd;
    461               1.7     ad 	}
    462               1.1  rmind 	kmem_free(name, MQ_NAMELEN);
    463               1.1  rmind 
    464               1.1  rmind 	return error;
    465               1.1  rmind }
    466               1.1  rmind 
    467               1.1  rmind int
    468               1.8  rmind sys_mq_close(struct lwp *l, const struct sys_mq_close_args *uap,
    469               1.8  rmind     register_t *retval)
    470               1.1  rmind {
    471               1.1  rmind 
    472               1.6    dsl 	return sys_close(l, (const void *)uap, retval);
    473               1.1  rmind }
    474               1.1  rmind 
    475               1.1  rmind /*
    476  1.12.4.1.2.3.2.1   matt  * Primary mq_recv1() function.
    477               1.1  rmind  */
    478               1.1  rmind static int
    479  1.12.4.1.2.3.2.1   matt mq_recv1(mqd_t mqdes, void *msg_ptr, size_t msg_len, u_int *msg_prio,
    480  1.12.4.1.2.3.2.1   matt     struct timespec *ts, ssize_t *mlen)
    481               1.1  rmind {
    482               1.7     ad 	file_t *fp = NULL;
    483               1.1  rmind 	struct mqueue *mq;
    484               1.1  rmind 	struct mq_msg *msg = NULL;
    485               1.1  rmind 	int error;
    486               1.1  rmind 
    487               1.1  rmind 	/* Get the message queue */
    488      1.12.4.1.2.2    snj 	error = mqueue_get(mqdes, &fp);
    489      1.12.4.1.2.3    snj 	if (error) {
    490               1.1  rmind 		return error;
    491      1.12.4.1.2.3    snj 	}
    492               1.1  rmind 	mq = fp->f_data;
    493      1.12.4.1.2.3    snj 	if ((fp->f_flag & FREAD) == 0) {
    494      1.12.4.1.2.3    snj 		error = EBADF;
    495      1.12.4.1.2.3    snj 		goto error;
    496      1.12.4.1.2.3    snj 	}
    497               1.1  rmind 
    498               1.1  rmind 	/* Check the message size limits */
    499               1.1  rmind 	if (msg_len < mq->mq_attrib.mq_msgsize) {
    500               1.1  rmind 		error = EMSGSIZE;
    501               1.1  rmind 		goto error;
    502               1.1  rmind 	}
    503               1.1  rmind 
    504               1.1  rmind 	/* Check if queue is empty */
    505               1.2     ad 	while (TAILQ_EMPTY(&mq->mq_head)) {
    506  1.12.4.1.2.3.2.1   matt 		int t;
    507  1.12.4.1.2.3.2.1   matt 
    508               1.1  rmind 		if (mq->mq_attrib.mq_flags & O_NONBLOCK) {
    509               1.1  rmind 			error = EAGAIN;
    510               1.1  rmind 			goto error;
    511               1.1  rmind 		}
    512  1.12.4.1.2.3.2.1   matt 		if (ts) {
    513  1.12.4.1.2.3.2.1   matt 			error = abstimeout2timo(ts, &t);
    514  1.12.4.1.2.3.2.1   matt 			if (error)
    515  1.12.4.1.2.3.2.1   matt 				goto error;
    516  1.12.4.1.2.3.2.1   matt 		} else
    517  1.12.4.1.2.3.2.1   matt 			t = 0;
    518               1.1  rmind 		/*
    519               1.1  rmind 		 * Block until someone sends the message.
    520               1.1  rmind 		 * While doing this, notification should not be sent.
    521               1.1  rmind 		 */
    522               1.1  rmind 		mq->mq_attrib.mq_flags |= MQ_RECEIVE;
    523               1.1  rmind 		error = cv_timedwait_sig(&mq->mq_send_cv, &mq->mq_mtx, t);
    524               1.1  rmind 		mq->mq_attrib.mq_flags &= ~MQ_RECEIVE;
    525               1.1  rmind 		if (error || (mq->mq_attrib.mq_flags & MQ_UNLINK)) {
    526               1.3  rmind 			error = (error == EWOULDBLOCK) ? ETIMEDOUT : EINTR;
    527               1.1  rmind 			goto error;
    528               1.1  rmind 		}
    529               1.1  rmind 	}
    530               1.1  rmind 
    531               1.1  rmind 	/* Remove the message from the queue */
    532               1.1  rmind 	msg = TAILQ_FIRST(&mq->mq_head);
    533               1.1  rmind 	KASSERT(msg != NULL);
    534               1.1  rmind 	TAILQ_REMOVE(&mq->mq_head, msg, msg_queue);
    535               1.1  rmind 
    536               1.1  rmind 	/* Decrement the counter and signal waiter, if any */
    537               1.1  rmind 	mq->mq_attrib.mq_curmsgs--;
    538               1.1  rmind 	cv_signal(&mq->mq_recv_cv);
    539               1.8  rmind 
    540               1.8  rmind 	/* Ready for sending now */
    541               1.8  rmind 	selnotify(&mq->mq_wsel, POLLOUT | POLLWRNORM, 0);
    542               1.1  rmind error:
    543               1.1  rmind 	mutex_exit(&mq->mq_mtx);
    544               1.7     ad 	fd_putfile((int)mqdes);
    545               1.1  rmind 	if (error)
    546               1.1  rmind 		return error;
    547               1.1  rmind 
    548               1.1  rmind 	/*
    549               1.1  rmind 	 * Copy the data to the user-space.
    550               1.1  rmind 	 * Note: According to POSIX, no message should be removed from the
    551               1.1  rmind 	 * queue in case of fail - this would be violated.
    552               1.1  rmind 	 */
    553               1.1  rmind 	*mlen = msg->msg_len;
    554               1.1  rmind 	error = copyout(msg->msg_ptr, msg_ptr, msg->msg_len);
    555               1.1  rmind 	if (error == 0 && msg_prio)
    556               1.1  rmind 		error = copyout(&msg->msg_prio, msg_prio, sizeof(unsigned));
    557               1.1  rmind 	mqueue_freemsg(msg, sizeof(struct mq_msg) + msg->msg_len);
    558               1.1  rmind 
    559               1.1  rmind 	return error;
    560               1.1  rmind }
    561               1.1  rmind 
    562               1.1  rmind int
    563               1.8  rmind sys_mq_receive(struct lwp *l, const struct sys_mq_receive_args *uap,
    564               1.8  rmind     register_t *retval)
    565               1.1  rmind {
    566               1.6    dsl 	/* {
    567               1.1  rmind 		syscallarg(mqd_t) mqdes;
    568               1.1  rmind 		syscallarg(char *) msg_ptr;
    569               1.1  rmind 		syscallarg(size_t) msg_len;
    570               1.1  rmind 		syscallarg(unsigned *) msg_prio;
    571               1.6    dsl 	} */
    572               1.1  rmind 	ssize_t mlen;
    573  1.12.4.1.2.3.2.1   matt 	int error;
    574               1.1  rmind 
    575  1.12.4.1.2.3.2.1   matt 	error = mq_recv1(SCARG(uap, mqdes), SCARG(uap, msg_ptr),
    576  1.12.4.1.2.3.2.1   matt 	    SCARG(uap, msg_len), SCARG(uap, msg_prio), NULL, &mlen);
    577               1.1  rmind 	if (error == 0)
    578               1.1  rmind 		*retval = mlen;
    579               1.1  rmind 
    580               1.1  rmind 	return error;
    581               1.1  rmind }
    582               1.1  rmind 
    583               1.1  rmind int
    584               1.8  rmind sys_mq_timedreceive(struct lwp *l, const struct sys_mq_timedreceive_args *uap,
    585               1.8  rmind     register_t *retval)
    586               1.1  rmind {
    587               1.6    dsl 	/* {
    588               1.1  rmind 		syscallarg(mqd_t) mqdes;
    589               1.1  rmind 		syscallarg(char *) msg_ptr;
    590               1.1  rmind 		syscallarg(size_t) msg_len;
    591               1.1  rmind 		syscallarg(unsigned *) msg_prio;
    592               1.1  rmind 		syscallarg(const struct timespec *) abs_timeout;
    593               1.6    dsl 	} */
    594  1.12.4.1.2.3.2.1   matt 	struct timespec ts, *tsp;
    595               1.1  rmind 	ssize_t mlen;
    596  1.12.4.1.2.3.2.1   matt 	int error;
    597               1.1  rmind 
    598               1.1  rmind 	/* Get and convert time value */
    599               1.1  rmind 	if (SCARG(uap, abs_timeout)) {
    600  1.12.4.1.2.3.2.1   matt 		error = copyin(SCARG(uap, abs_timeout), &ts, sizeof(ts));
    601               1.1  rmind 		if (error)
    602               1.1  rmind 			return error;
    603  1.12.4.1.2.3.2.1   matt 		tsp = &ts;
    604  1.12.4.1.2.3.2.1   matt 	} else {
    605  1.12.4.1.2.3.2.1   matt 		tsp = NULL;
    606  1.12.4.1.2.3.2.1   matt 	}
    607               1.1  rmind 
    608  1.12.4.1.2.3.2.1   matt 	error = mq_recv1(SCARG(uap, mqdes), SCARG(uap, msg_ptr),
    609  1.12.4.1.2.3.2.1   matt 	    SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp, &mlen);
    610               1.1  rmind 	if (error == 0)
    611               1.1  rmind 		*retval = mlen;
    612               1.1  rmind 
    613               1.1  rmind 	return error;
    614               1.1  rmind }
    615               1.1  rmind 
    616               1.1  rmind /*
    617               1.1  rmind  * Primary mq_send1() function.
    618               1.1  rmind  */
    619               1.1  rmind static int
    620  1.12.4.1.2.3.2.1   matt mq_send1(mqd_t mqdes, const char *msg_ptr, size_t msg_len, u_int msg_prio,
    621  1.12.4.1.2.3.2.1   matt     struct timespec *ts)
    622               1.1  rmind {
    623               1.7     ad 	file_t *fp = NULL;
    624               1.1  rmind 	struct mqueue *mq;
    625               1.1  rmind 	struct mq_msg *msg, *pos_msg;
    626               1.1  rmind 	struct proc *notify = NULL;
    627               1.1  rmind 	ksiginfo_t ksi;
    628               1.1  rmind 	size_t size;
    629               1.1  rmind 	int error;
    630               1.1  rmind 
    631               1.1  rmind 	/* Check the priority range */
    632               1.1  rmind 	if (msg_prio >= mq_prio_max)
    633               1.1  rmind 		return EINVAL;
    634               1.1  rmind 
    635               1.1  rmind 	/* Allocate a new message */
    636               1.1  rmind 	size = sizeof(struct mq_msg) + msg_len;
    637               1.1  rmind 	if (size > mq_max_msgsize)
    638               1.1  rmind 		return EMSGSIZE;
    639               1.1  rmind 
    640               1.1  rmind 	if (size > MQ_DEF_MSGSIZE)
    641               1.1  rmind 		msg = kmem_alloc(size, KM_SLEEP);
    642               1.1  rmind 	else
    643               1.8  rmind 		msg = pool_cache_get(mqmsg_cache, PR_WAITOK);
    644               1.1  rmind 
    645               1.1  rmind 	/* Get the data from user-space */
    646               1.1  rmind 	error = copyin(msg_ptr, msg->msg_ptr, msg_len);
    647               1.1  rmind 	if (error) {
    648               1.1  rmind 		mqueue_freemsg(msg, size);
    649               1.1  rmind 		return error;
    650               1.1  rmind 	}
    651               1.1  rmind 	msg->msg_len = msg_len;
    652               1.1  rmind 	msg->msg_prio = msg_prio;
    653               1.1  rmind 
    654               1.1  rmind 	/* Get the mqueue */
    655      1.12.4.1.2.2    snj 	error = mqueue_get(mqdes, &fp);
    656               1.1  rmind 	if (error) {
    657               1.1  rmind 		mqueue_freemsg(msg, size);
    658               1.1  rmind 		return error;
    659               1.1  rmind 	}
    660               1.1  rmind 	mq = fp->f_data;
    661      1.12.4.1.2.3    snj 	if ((fp->f_flag & FWRITE) == 0) {
    662      1.12.4.1.2.3    snj 		error = EBADF;
    663      1.12.4.1.2.3    snj 		goto error;
    664      1.12.4.1.2.3    snj 	}
    665               1.1  rmind 
    666               1.1  rmind 	/* Check the message size limit */
    667               1.1  rmind 	if (msg_len <= 0 || msg_len > mq->mq_attrib.mq_msgsize) {
    668               1.1  rmind 		error = EMSGSIZE;
    669               1.1  rmind 		goto error;
    670               1.1  rmind 	}
    671               1.1  rmind 
    672               1.1  rmind 	/* Check if queue is full */
    673               1.2     ad 	while (mq->mq_attrib.mq_curmsgs >= mq->mq_attrib.mq_maxmsg) {
    674  1.12.4.1.2.3.2.1   matt 		int t;
    675  1.12.4.1.2.3.2.1   matt 
    676               1.1  rmind 		if (mq->mq_attrib.mq_flags & O_NONBLOCK) {
    677               1.1  rmind 			error = EAGAIN;
    678               1.1  rmind 			goto error;
    679               1.1  rmind 		}
    680  1.12.4.1.2.3.2.1   matt 		if (ts) {
    681  1.12.4.1.2.3.2.1   matt 			error = abstimeout2timo(ts, &t);
    682  1.12.4.1.2.3.2.1   matt 			if (error)
    683  1.12.4.1.2.3.2.1   matt 				goto error;
    684  1.12.4.1.2.3.2.1   matt 		} else
    685  1.12.4.1.2.3.2.1   matt 			t = 0;
    686               1.1  rmind 		/* Block until queue becomes available */
    687               1.1  rmind 		error = cv_timedwait_sig(&mq->mq_recv_cv, &mq->mq_mtx, t);
    688               1.1  rmind 		if (error || (mq->mq_attrib.mq_flags & MQ_UNLINK)) {
    689               1.1  rmind 			error = (error == EWOULDBLOCK) ? ETIMEDOUT : error;
    690               1.1  rmind 			goto error;
    691               1.1  rmind 		}
    692               1.1  rmind 	}
    693               1.1  rmind 	KASSERT(mq->mq_attrib.mq_curmsgs < mq->mq_attrib.mq_maxmsg);
    694               1.1  rmind 
    695               1.1  rmind 	/* Insert message into the queue, according to the priority */
    696               1.1  rmind 	TAILQ_FOREACH(pos_msg, &mq->mq_head, msg_queue)
    697               1.1  rmind 		if (msg->msg_prio > pos_msg->msg_prio)
    698               1.1  rmind 			break;
    699               1.1  rmind 	if (pos_msg == NULL)
    700               1.1  rmind 		TAILQ_INSERT_TAIL(&mq->mq_head, msg, msg_queue);
    701               1.1  rmind 	else
    702               1.1  rmind 		TAILQ_INSERT_BEFORE(pos_msg, msg, msg_queue);
    703               1.1  rmind 
    704               1.1  rmind 	/* Check for the notify */
    705               1.1  rmind 	if (mq->mq_attrib.mq_curmsgs == 0 && mq->mq_notify_proc &&
    706  1.12.4.1.2.3.2.1   matt 	    (mq->mq_attrib.mq_flags & MQ_RECEIVE) == 0 &&
    707  1.12.4.1.2.3.2.1   matt 	    mq->mq_sig_notify.sigev_notify == SIGEV_SIGNAL) {
    708               1.1  rmind 		/* Initialize the signal */
    709               1.1  rmind 		KSI_INIT(&ksi);
    710               1.1  rmind 		ksi.ksi_signo = mq->mq_sig_notify.sigev_signo;
    711               1.1  rmind 		ksi.ksi_code = SI_MESGQ;
    712               1.1  rmind 		ksi.ksi_value = mq->mq_sig_notify.sigev_value;
    713               1.1  rmind 		/* Unregister the process */
    714               1.1  rmind 		notify = mq->mq_notify_proc;
    715               1.1  rmind 		mq->mq_notify_proc = NULL;
    716               1.1  rmind 	}
    717               1.1  rmind 
    718               1.1  rmind 	/* Increment the counter and signal waiter, if any */
    719               1.1  rmind 	mq->mq_attrib.mq_curmsgs++;
    720               1.1  rmind 	cv_signal(&mq->mq_send_cv);
    721               1.8  rmind 
    722               1.8  rmind 	/* Ready for receiving now */
    723               1.8  rmind 	selnotify(&mq->mq_rsel, POLLIN | POLLRDNORM, 0);
    724               1.1  rmind error:
    725               1.1  rmind 	mutex_exit(&mq->mq_mtx);
    726               1.7     ad 	fd_putfile((int)mqdes);
    727               1.1  rmind 
    728               1.1  rmind 	if (error) {
    729               1.1  rmind 		mqueue_freemsg(msg, size);
    730               1.1  rmind 	} else if (notify) {
    731               1.1  rmind 		/* Send the notify, if needed */
    732              1.10     ad 		mutex_enter(proc_lock);
    733               1.1  rmind 		kpsignal(notify, &ksi, NULL);
    734              1.10     ad 		mutex_exit(proc_lock);
    735               1.1  rmind 	}
    736               1.1  rmind 
    737               1.1  rmind 	return error;
    738               1.1  rmind }
    739               1.1  rmind 
    740               1.1  rmind int
    741               1.8  rmind sys_mq_send(struct lwp *l, const struct sys_mq_send_args *uap,
    742               1.8  rmind     register_t *retval)
    743               1.1  rmind {
    744               1.6    dsl 	/* {
    745               1.1  rmind 		syscallarg(mqd_t) mqdes;
    746               1.1  rmind 		syscallarg(const char *) msg_ptr;
    747               1.1  rmind 		syscallarg(size_t) msg_len;
    748               1.1  rmind 		syscallarg(unsigned) msg_prio;
    749               1.6    dsl 	} */
    750               1.1  rmind 
    751  1.12.4.1.2.3.2.1   matt 	return mq_send1(SCARG(uap, mqdes), SCARG(uap, msg_ptr),
    752  1.12.4.1.2.3.2.1   matt 	    SCARG(uap, msg_len), SCARG(uap, msg_prio), NULL);
    753               1.1  rmind }
    754               1.1  rmind 
    755               1.1  rmind int
    756               1.8  rmind sys_mq_timedsend(struct lwp *l, const struct sys_mq_timedsend_args *uap,
    757               1.8  rmind     register_t *retval)
    758               1.1  rmind {
    759               1.6    dsl 	/* {
    760               1.1  rmind 		syscallarg(mqd_t) mqdes;
    761               1.1  rmind 		syscallarg(const char *) msg_ptr;
    762               1.1  rmind 		syscallarg(size_t) msg_len;
    763               1.1  rmind 		syscallarg(unsigned) msg_prio;
    764               1.1  rmind 		syscallarg(const struct timespec *) abs_timeout;
    765               1.6    dsl 	} */
    766  1.12.4.1.2.3.2.1   matt 	struct timespec ts, *tsp;
    767  1.12.4.1.2.3.2.1   matt 	int error;
    768               1.1  rmind 
    769               1.1  rmind 	/* Get and convert time value */
    770               1.1  rmind 	if (SCARG(uap, abs_timeout)) {
    771  1.12.4.1.2.3.2.1   matt 		error = copyin(SCARG(uap, abs_timeout), &ts, sizeof(ts));
    772               1.1  rmind 		if (error)
    773               1.1  rmind 			return error;
    774  1.12.4.1.2.3.2.1   matt 		tsp = &ts;
    775  1.12.4.1.2.3.2.1   matt 	} else {
    776  1.12.4.1.2.3.2.1   matt 		tsp = NULL;
    777  1.12.4.1.2.3.2.1   matt 	}
    778               1.1  rmind 
    779  1.12.4.1.2.3.2.1   matt 	return mq_send1(SCARG(uap, mqdes), SCARG(uap, msg_ptr),
    780  1.12.4.1.2.3.2.1   matt 	    SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp);
    781               1.1  rmind }
    782               1.1  rmind 
    783               1.1  rmind int
    784               1.8  rmind sys_mq_notify(struct lwp *l, const struct sys_mq_notify_args *uap,
    785               1.8  rmind     register_t *retval)
    786               1.1  rmind {
    787               1.6    dsl 	/* {
    788               1.1  rmind 		syscallarg(mqd_t) mqdes;
    789               1.1  rmind 		syscallarg(const struct sigevent *) notification;
    790               1.6    dsl 	} */
    791               1.7     ad 	file_t *fp = NULL;
    792               1.1  rmind 	struct mqueue *mq;
    793               1.1  rmind 	struct sigevent sig;
    794               1.1  rmind 	int error;
    795               1.1  rmind 
    796               1.1  rmind 	if (SCARG(uap, notification)) {
    797               1.1  rmind 		/* Get the signal from user-space */
    798               1.1  rmind 		error = copyin(SCARG(uap, notification), &sig,
    799               1.1  rmind 		    sizeof(struct sigevent));
    800               1.1  rmind 		if (error)
    801               1.1  rmind 			return error;
    802  1.12.4.1.2.3.2.1   matt 		if (sig.sigev_notify == SIGEV_SIGNAL &&
    803  1.12.4.1.2.3.2.1   matt 		    (sig.sigev_signo <=0 || sig.sigev_signo >= NSIG))
    804  1.12.4.1.2.3.2.1   matt 			return EINVAL;
    805               1.1  rmind 	}
    806               1.1  rmind 
    807      1.12.4.1.2.2    snj 	error = mqueue_get(SCARG(uap, mqdes), &fp);
    808               1.1  rmind 	if (error)
    809               1.1  rmind 		return error;
    810               1.1  rmind 	mq = fp->f_data;
    811               1.1  rmind 
    812               1.1  rmind 	if (SCARG(uap, notification)) {
    813               1.1  rmind 		/* Register notification: set the signal and target process */
    814               1.1  rmind 		if (mq->mq_notify_proc == NULL) {
    815               1.1  rmind 			memcpy(&mq->mq_sig_notify, &sig,
    816               1.1  rmind 			    sizeof(struct sigevent));
    817               1.1  rmind 			mq->mq_notify_proc = l->l_proc;
    818               1.1  rmind 		} else {
    819               1.1  rmind 			/* Fail if someone else already registered */
    820               1.1  rmind 			error = EBUSY;
    821               1.1  rmind 		}
    822               1.1  rmind 	} else {
    823               1.1  rmind 		/* Unregister the notification */
    824               1.1  rmind 		mq->mq_notify_proc = NULL;
    825               1.1  rmind 	}
    826               1.1  rmind 	mutex_exit(&mq->mq_mtx);
    827               1.7     ad 	fd_putfile((int)SCARG(uap, mqdes));
    828               1.1  rmind 
    829               1.1  rmind 	return error;
    830               1.1  rmind }
    831               1.1  rmind 
    832               1.1  rmind int
    833               1.8  rmind sys_mq_getattr(struct lwp *l, const struct sys_mq_getattr_args *uap,
    834               1.8  rmind     register_t *retval)
    835               1.1  rmind {
    836               1.6    dsl 	/* {
    837               1.1  rmind 		syscallarg(mqd_t) mqdes;
    838               1.1  rmind 		syscallarg(struct mq_attr *) mqstat;
    839               1.6    dsl 	} */
    840               1.7     ad 	file_t *fp = NULL;
    841               1.1  rmind 	struct mqueue *mq;
    842               1.1  rmind 	struct mq_attr attr;
    843               1.1  rmind 	int error;
    844               1.1  rmind 
    845               1.1  rmind 	/* Get the message queue */
    846      1.12.4.1.2.2    snj 	error = mqueue_get(SCARG(uap, mqdes), &fp);
    847               1.1  rmind 	if (error)
    848               1.1  rmind 		return error;
    849               1.1  rmind 	mq = fp->f_data;
    850               1.1  rmind 	memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr));
    851               1.1  rmind 	mutex_exit(&mq->mq_mtx);
    852               1.7     ad 	fd_putfile((int)SCARG(uap, mqdes));
    853               1.1  rmind 
    854               1.1  rmind 	return copyout(&attr, SCARG(uap, mqstat), sizeof(struct mq_attr));
    855               1.1  rmind }
    856               1.1  rmind 
    857               1.1  rmind int
    858               1.8  rmind sys_mq_setattr(struct lwp *l, const struct sys_mq_setattr_args *uap,
    859               1.8  rmind     register_t *retval)
    860               1.1  rmind {
    861               1.6    dsl 	/* {
    862               1.1  rmind 		syscallarg(mqd_t) mqdes;
    863               1.1  rmind 		syscallarg(const struct mq_attr *) mqstat;
    864               1.1  rmind 		syscallarg(struct mq_attr *) omqstat;
    865               1.6    dsl 	} */
    866               1.7     ad 	file_t *fp = NULL;
    867               1.1  rmind 	struct mqueue *mq;
    868               1.1  rmind 	struct mq_attr attr;
    869               1.1  rmind 	int error, nonblock;
    870               1.1  rmind 
    871               1.1  rmind 	error = copyin(SCARG(uap, mqstat), &attr, sizeof(struct mq_attr));
    872               1.1  rmind 	if (error)
    873               1.1  rmind 		return error;
    874               1.1  rmind 	nonblock = (attr.mq_flags & O_NONBLOCK);
    875               1.1  rmind 
    876               1.1  rmind 	/* Get the message queue */
    877      1.12.4.1.2.2    snj 	error = mqueue_get(SCARG(uap, mqdes), &fp);
    878               1.1  rmind 	if (error)
    879               1.1  rmind 		return error;
    880               1.1  rmind 	mq = fp->f_data;
    881               1.1  rmind 
    882               1.1  rmind 	/* Copy the old attributes, if needed */
    883               1.1  rmind 	if (SCARG(uap, omqstat))
    884               1.1  rmind 		memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr));
    885               1.1  rmind 
    886               1.1  rmind 	/* Ignore everything, except O_NONBLOCK */
    887               1.1  rmind 	if (nonblock)
    888               1.1  rmind 		mq->mq_attrib.mq_flags |= O_NONBLOCK;
    889               1.1  rmind 	else
    890               1.1  rmind 		mq->mq_attrib.mq_flags &= ~O_NONBLOCK;
    891               1.1  rmind 
    892               1.1  rmind 	mutex_exit(&mq->mq_mtx);
    893               1.7     ad 	fd_putfile((int)SCARG(uap, mqdes));
    894               1.1  rmind 
    895               1.1  rmind 	/*
    896               1.1  rmind 	 * Copy the data to the user-space.
    897               1.1  rmind 	 * Note: According to POSIX, the new attributes should not be set in
    898               1.1  rmind 	 * case of fail - this would be violated.
    899               1.1  rmind 	 */
    900               1.1  rmind 	if (SCARG(uap, omqstat))
    901               1.1  rmind 		error = copyout(&attr, SCARG(uap, omqstat),
    902               1.1  rmind 		    sizeof(struct mq_attr));
    903               1.1  rmind 
    904               1.1  rmind 	return error;
    905               1.1  rmind }
    906               1.1  rmind 
    907               1.1  rmind int
    908               1.8  rmind sys_mq_unlink(struct lwp *l, const struct sys_mq_unlink_args *uap,
    909               1.8  rmind     register_t *retval)
    910               1.1  rmind {
    911               1.6    dsl 	/* {
    912               1.1  rmind 		syscallarg(const char *) name;
    913               1.6    dsl 	} */
    914               1.1  rmind 	struct mqueue *mq;
    915               1.1  rmind 	char *name;
    916               1.1  rmind 	int error, refcnt = 0;
    917               1.1  rmind 
    918               1.1  rmind 	/* Get the name from the user-space */
    919               1.1  rmind 	name = kmem_zalloc(MQ_NAMELEN, KM_SLEEP);
    920               1.1  rmind 	error = copyinstr(SCARG(uap, name), name, MQ_NAMELEN - 1, NULL);
    921               1.1  rmind 	if (error) {
    922               1.1  rmind 		kmem_free(name, MQ_NAMELEN);
    923               1.1  rmind 		return error;
    924               1.1  rmind 	}
    925               1.1  rmind 
    926               1.1  rmind 	/* Lookup for this file */
    927               1.1  rmind 	mutex_enter(&mqlist_mtx);
    928               1.1  rmind 	mq = mqueue_lookup(name);
    929               1.1  rmind 	if (mq == NULL) {
    930               1.1  rmind 		error = ENOENT;
    931               1.1  rmind 		goto error;
    932               1.1  rmind 	}
    933               1.1  rmind 
    934               1.1  rmind 	/* Check the permissions */
    935      1.12.4.1.2.2    snj 	if (kauth_cred_geteuid(l->l_cred) != mq->mq_euid &&
    936      1.12.4.1.2.2    snj 	    kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, NULL)) {
    937               1.1  rmind 		mutex_exit(&mq->mq_mtx);
    938               1.1  rmind 		error = EACCES;
    939               1.1  rmind 		goto error;
    940               1.1  rmind 	}
    941               1.1  rmind 
    942               1.1  rmind 	/* Mark message queue as unlinking, before leaving the window */
    943               1.1  rmind 	mq->mq_attrib.mq_flags |= MQ_UNLINK;
    944               1.1  rmind 
    945               1.1  rmind 	/* Wake up all waiters, if there are such */
    946               1.1  rmind 	cv_broadcast(&mq->mq_send_cv);
    947               1.1  rmind 	cv_broadcast(&mq->mq_recv_cv);
    948               1.1  rmind 
    949               1.8  rmind 	selnotify(&mq->mq_rsel, POLLHUP, 0);
    950               1.8  rmind 	selnotify(&mq->mq_wsel, POLLHUP, 0);
    951               1.8  rmind 
    952               1.1  rmind 	refcnt = mq->mq_refcnt;
    953               1.1  rmind 	if (refcnt == 0)
    954               1.1  rmind 		LIST_REMOVE(mq, mq_list);
    955               1.1  rmind 
    956               1.1  rmind 	mutex_exit(&mq->mq_mtx);
    957               1.1  rmind error:
    958               1.1  rmind 	mutex_exit(&mqlist_mtx);
    959               1.1  rmind 
    960               1.1  rmind 	/*
    961               1.1  rmind 	 * If there are no references - destroy the message
    962               1.1  rmind 	 * queue, otherwise, the last mq_close() will do that.
    963               1.1  rmind 	 */
    964               1.1  rmind 	if (error == 0 && refcnt == 0)
    965               1.1  rmind 		mqueue_destroy(mq);
    966               1.1  rmind 
    967               1.1  rmind 	kmem_free(name, MQ_NAMELEN);
    968               1.1  rmind 	return error;
    969               1.1  rmind }
    970               1.1  rmind 
    971               1.1  rmind /*
    972               1.1  rmind  * SysCtl.
    973               1.1  rmind  */
    974               1.1  rmind 
    975               1.1  rmind SYSCTL_SETUP(sysctl_mqueue_setup, "sysctl mqueue setup")
    976               1.1  rmind {
    977               1.1  rmind 	const struct sysctlnode *node = NULL;
    978               1.1  rmind 
    979               1.1  rmind 	sysctl_createv(clog, 0, NULL, NULL,
    980               1.1  rmind 		CTLFLAG_PERMANENT,
    981               1.1  rmind 		CTLTYPE_NODE, "kern", NULL,
    982               1.1  rmind 		NULL, 0, NULL, 0,
    983               1.1  rmind 		CTL_KERN, CTL_EOL);
    984               1.1  rmind 	sysctl_createv(clog, 0, NULL, NULL,
    985               1.1  rmind 		CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
    986               1.1  rmind 		CTLTYPE_INT, "posix_msg",
    987               1.1  rmind 		SYSCTL_DESCR("Version of IEEE Std 1003.1 and its "
    988               1.1  rmind 			     "Message Passing option to which the "
    989               1.1  rmind 			     "system attempts to conform"),
    990               1.1  rmind 		NULL, _POSIX_MESSAGE_PASSING, NULL, 0,
    991               1.1  rmind 		CTL_KERN, CTL_CREATE, CTL_EOL);
    992               1.1  rmind 	sysctl_createv(clog, 0, NULL, &node,
    993               1.1  rmind 		CTLFLAG_PERMANENT,
    994               1.1  rmind 		CTLTYPE_NODE, "mqueue",
    995               1.1  rmind 		SYSCTL_DESCR("Message queue options"),
    996               1.1  rmind 		NULL, 0, NULL, 0,
    997               1.1  rmind 		CTL_KERN, CTL_CREATE, CTL_EOL);
    998               1.1  rmind 
    999               1.1  rmind 	if (node == NULL)
   1000               1.1  rmind 		return;
   1001               1.1  rmind 
   1002               1.1  rmind 	sysctl_createv(clog, 0, &node, NULL,
   1003               1.1  rmind 		CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
   1004               1.1  rmind 		CTLTYPE_INT, "mq_open_max",
   1005               1.1  rmind 		SYSCTL_DESCR("Maximal number of message queue descriptors "
   1006               1.1  rmind 			     "that process could open"),
   1007               1.1  rmind 		NULL, 0, &mq_open_max, 0,
   1008               1.1  rmind 		CTL_CREATE, CTL_EOL);
   1009               1.1  rmind 	sysctl_createv(clog, 0, &node, NULL,
   1010               1.1  rmind 		CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
   1011               1.1  rmind 		CTLTYPE_INT, "mq_prio_max",
   1012               1.1  rmind 		SYSCTL_DESCR("Maximal priority of the message"),
   1013               1.1  rmind 		NULL, 0, &mq_prio_max, 0,
   1014               1.1  rmind 		CTL_CREATE, CTL_EOL);
   1015               1.1  rmind 	sysctl_createv(clog, 0, &node, NULL,
   1016               1.1  rmind 		CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
   1017               1.1  rmind 		CTLTYPE_INT, "mq_max_msgsize",
   1018               1.1  rmind 		SYSCTL_DESCR("Maximal allowed size of the message"),
   1019               1.1  rmind 		NULL, 0, &mq_max_msgsize, 0,
   1020               1.1  rmind 		CTL_CREATE, CTL_EOL);
   1021               1.1  rmind 	sysctl_createv(clog, 0, &node, NULL,
   1022               1.1  rmind 		CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
   1023               1.1  rmind 		CTLTYPE_INT, "mq_def_maxmsg",
   1024               1.1  rmind 		SYSCTL_DESCR("Default maximal message count"),
   1025               1.1  rmind 		NULL, 0, &mq_def_maxmsg, 0,
   1026               1.1  rmind 		CTL_CREATE, CTL_EOL);
   1027  1.12.4.1.2.3.2.1   matt 	sysctl_createv(clog, 0, &node, NULL,
   1028  1.12.4.1.2.3.2.1   matt 		CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
   1029  1.12.4.1.2.3.2.1   matt 		CTLTYPE_INT, "mq_max_maxmsg",
   1030  1.12.4.1.2.3.2.1   matt 		SYSCTL_DESCR("Maximal allowed message count"),
   1031  1.12.4.1.2.3.2.1   matt 		NULL, 0, &mq_max_maxmsg, 0,
   1032  1.12.4.1.2.3.2.1   matt 		CTL_CREATE, CTL_EOL);
   1033               1.1  rmind }
   1034               1.1  rmind 
   1035               1.1  rmind /*
   1036               1.1  rmind  * Debugging.
   1037               1.1  rmind  */
   1038               1.1  rmind #if defined(DDB)
   1039               1.1  rmind 
   1040               1.1  rmind void
   1041               1.1  rmind mqueue_print_list(void (*pr)(const char *, ...))
   1042               1.1  rmind {
   1043               1.1  rmind 	struct mqueue *mq;
   1044               1.1  rmind 
   1045               1.1  rmind 	(*pr)("Global list of the message queues:\n");
   1046               1.1  rmind 	(*pr)("%20s %10s %8s %8s %3s %4s %4s %4s\n",
   1047               1.1  rmind 	    "Name", "Ptr", "Mode", "Flags",  "Ref",
   1048               1.1  rmind 	    "MaxMsg", "MsgSze", "CurMsg");
   1049               1.1  rmind 	LIST_FOREACH(mq, &mqueue_head, mq_list) {
   1050               1.1  rmind 		(*pr)("%20s %10p %8x %8x %3u %6lu %6lu %6lu\n",
   1051               1.1  rmind 		    mq->mq_name, mq, mq->mq_mode,
   1052               1.1  rmind 		    mq->mq_attrib.mq_flags, mq->mq_refcnt,
   1053               1.1  rmind 		    mq->mq_attrib.mq_maxmsg, mq->mq_attrib.mq_msgsize,
   1054               1.1  rmind 		    mq->mq_attrib.mq_curmsgs);
   1055               1.1  rmind 	}
   1056               1.1  rmind }
   1057               1.1  rmind 
   1058               1.1  rmind #endif /* defined(DDB) */
   1059