1f2df0f7cSStathis Kamperis /* $NetBSD: sys_mqueue.c,v 1.16 2009/04/11 23:05:26 christos Exp $ */
2f2df0f7cSStathis Kamperis
3f2df0f7cSStathis Kamperis /*
4f2df0f7cSStathis Kamperis * Copyright (c) 2007, 2008 Mindaugas Rasiukevicius <rmind at NetBSD org>
5f2df0f7cSStathis Kamperis * All rights reserved.
6f2df0f7cSStathis Kamperis *
7f2df0f7cSStathis Kamperis * Redistribution and use in source and binary forms, with or without
8f2df0f7cSStathis Kamperis * modification, are permitted provided that the following conditions
9f2df0f7cSStathis Kamperis * are met:
10f2df0f7cSStathis Kamperis * 1. Redistributions of source code must retain the above copyright
11f2df0f7cSStathis Kamperis * notice, this list of conditions and the following disclaimer.
12f2df0f7cSStathis Kamperis * 2. Redistributions in binary form must reproduce the above copyright
13f2df0f7cSStathis Kamperis * notice, this list of conditions and the following disclaimer in the
14f2df0f7cSStathis Kamperis * documentation and/or other materials provided with the distribution.
15f2df0f7cSStathis Kamperis *
16f2df0f7cSStathis Kamperis * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17f2df0f7cSStathis Kamperis * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18f2df0f7cSStathis Kamperis * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19f2df0f7cSStathis Kamperis * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20f2df0f7cSStathis Kamperis * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21f2df0f7cSStathis Kamperis * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22f2df0f7cSStathis Kamperis * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23f2df0f7cSStathis Kamperis * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24f2df0f7cSStathis Kamperis * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25f2df0f7cSStathis Kamperis * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26f2df0f7cSStathis Kamperis * SUCH DAMAGE.
27f2df0f7cSStathis Kamperis */
28f2df0f7cSStathis Kamperis
29f2df0f7cSStathis Kamperis /*
30f2df0f7cSStathis Kamperis * Implementation of POSIX message queues.
31f2df0f7cSStathis Kamperis * Defined in the Base Definitions volume of IEEE Std 1003.1-2001.
32f2df0f7cSStathis Kamperis *
33f2df0f7cSStathis Kamperis * Locking
34f2df0f7cSStathis Kamperis *
35f2df0f7cSStathis Kamperis * Global list of message queues (mqueue_head) and proc_t::p_mqueue_cnt
36f2df0f7cSStathis Kamperis * counter are protected by mqlist_mtx lock. The very message queue and
37f2df0f7cSStathis Kamperis * its members are protected by mqueue::mq_mtx.
38f2df0f7cSStathis Kamperis *
39f2df0f7cSStathis Kamperis * Lock order:
40f2df0f7cSStathis Kamperis * mqlist_mtx
41f2df0f7cSStathis Kamperis * -> mqueue::mq_mtx
42f2df0f7cSStathis Kamperis */
43f2df0f7cSStathis Kamperis
44f2df0f7cSStathis Kamperis #include <sys/param.h>
45f2df0f7cSStathis Kamperis #include <sys/types.h>
46f2df0f7cSStathis Kamperis #include <sys/errno.h>
47f2df0f7cSStathis Kamperis #include <sys/fcntl.h>
48f2df0f7cSStathis Kamperis #include <sys/file.h>
49f2df0f7cSStathis Kamperis #include <sys/filedesc.h>
50f2df0f7cSStathis Kamperis #include <sys/ucred.h>
512b3f93eaSMatthew Dillon #include <sys/caps.h>
52f2df0f7cSStathis Kamperis #include <sys/kernel.h>
53f2df0f7cSStathis Kamperis #include <sys/malloc.h>
54f2df0f7cSStathis Kamperis #include <sys/mqueue.h>
55f2df0f7cSStathis Kamperis #include <sys/proc.h>
56f2df0f7cSStathis Kamperis #include <sys/queue.h>
57b06aab00SSamuel J. Greear #include <sys/event.h>
58f2df0f7cSStathis Kamperis #include <sys/serialize.h>
59f2df0f7cSStathis Kamperis #include <sys/signal.h>
60f2df0f7cSStathis Kamperis #include <sys/signalvar.h>
61f2df0f7cSStathis Kamperis #include <sys/spinlock.h>
62f2df0f7cSStathis Kamperis #include <sys/spinlock2.h>
63f2df0f7cSStathis Kamperis #include <sys/stat.h>
64f2df0f7cSStathis Kamperis #include <sys/sysctl.h>
6580d831e1SMatthew Dillon #include <sys/sysmsg.h>
66f2df0f7cSStathis Kamperis #include <sys/systm.h>
67f2df0f7cSStathis Kamperis #include <sys/lock.h>
68f2df0f7cSStathis Kamperis #include <sys/unistd.h>
69f2df0f7cSStathis Kamperis #include <sys/vnode.h>
70f2df0f7cSStathis Kamperis
71f2df0f7cSStathis Kamperis /* System-wide limits. */
72f2df0f7cSStathis Kamperis static u_int mq_open_max = MQ_OPEN_MAX;
73f2df0f7cSStathis Kamperis static u_int mq_prio_max = MQ_PRIO_MAX;
74f2df0f7cSStathis Kamperis static u_int mq_max_msgsize = 16 * MQ_DEF_MSGSIZE;
75f2df0f7cSStathis Kamperis static u_int mq_def_maxmsg = 32;
768658b626SStathis Kamperis static u_int mq_max_maxmsg = 16 * 32;
77f2df0f7cSStathis Kamperis
78f4e72adaSSascha Wildner static struct lock mqlist_mtx;
79f2df0f7cSStathis Kamperis static LIST_HEAD(, mqueue) mqueue_head =
80f2df0f7cSStathis Kamperis LIST_HEAD_INITIALIZER(mqueue_head);
81f2df0f7cSStathis Kamperis
82f2df0f7cSStathis Kamperis typedef struct file file_t; /* XXX: Should we put this in sys/types.h ? */
83f2df0f7cSStathis Kamperis
84f2df0f7cSStathis Kamperis /* Function prototypes */
85f2df0f7cSStathis Kamperis static int mq_stat_fop(file_t *, struct stat *, struct ucred *cred);
86f2df0f7cSStathis Kamperis static int mq_close_fop(file_t *);
87b06aab00SSamuel J. Greear static int mq_kqfilter_fop(struct file *fp, struct knote *kn);
88b06aab00SSamuel J. Greear static void mqfilter_read_detach(struct knote *kn);
89b06aab00SSamuel J. Greear static void mqfilter_write_detach(struct knote *kn);
90b06aab00SSamuel J. Greear static int mqfilter_read(struct knote *kn, long hint);
91b06aab00SSamuel J. Greear static int mqfilter_write(struct knote *kn, long hint);
92f2df0f7cSStathis Kamperis
93f2df0f7cSStathis Kamperis /* Some time-related utility functions */
94f2df0f7cSStathis Kamperis static int tstohz(const struct timespec *ts);
95f2df0f7cSStathis Kamperis
96f2df0f7cSStathis Kamperis /* File operations vector */
97f2df0f7cSStathis Kamperis static struct fileops mqops = {
98f2df0f7cSStathis Kamperis .fo_read = badfo_readwrite,
99f2df0f7cSStathis Kamperis .fo_write = badfo_readwrite,
100f2df0f7cSStathis Kamperis .fo_ioctl = badfo_ioctl,
101f2df0f7cSStathis Kamperis .fo_stat = mq_stat_fop,
102f2df0f7cSStathis Kamperis .fo_close = mq_close_fop,
103b06aab00SSamuel J. Greear .fo_kqfilter = mq_kqfilter_fop,
104*cc8e70bdSSergey Zigachev .fo_shutdown = badfo_shutdown,
105*cc8e70bdSSergey Zigachev .fo_seek = badfo_seek
106f2df0f7cSStathis Kamperis };
107f2df0f7cSStathis Kamperis
108f2df0f7cSStathis Kamperis /* Define a new malloc type for message queues */
109f2df0f7cSStathis Kamperis MALLOC_DECLARE(M_MQBUF);
110f2df0f7cSStathis Kamperis MALLOC_DEFINE(M_MQBUF, "mqueues", "Buffers to message queues");
111f2df0f7cSStathis Kamperis
112f2df0f7cSStathis Kamperis /*
113f2df0f7cSStathis Kamperis * Initialize POSIX message queue subsystem.
114f2df0f7cSStathis Kamperis */
115f2df0f7cSStathis Kamperis void
mqueue_sysinit(void)116f2df0f7cSStathis Kamperis mqueue_sysinit(void)
117f2df0f7cSStathis Kamperis {
118f2df0f7cSStathis Kamperis lockinit(&mqlist_mtx, "mqlist_mtx", 0, LK_CANRECURSE);
119f2df0f7cSStathis Kamperis }
120f2df0f7cSStathis Kamperis
121f2df0f7cSStathis Kamperis /*
122f2df0f7cSStathis Kamperis * Free the message.
123f2df0f7cSStathis Kamperis */
124f2df0f7cSStathis Kamperis static void
mqueue_freemsg(struct mq_msg * msg,const size_t size)125f2df0f7cSStathis Kamperis mqueue_freemsg(struct mq_msg *msg, const size_t size)
126f2df0f7cSStathis Kamperis {
127f2df0f7cSStathis Kamperis kfree(msg, M_MQBUF);
128d1d64679SStathis Kamperis }
129f2df0f7cSStathis Kamperis
130f2df0f7cSStathis Kamperis /*
131f2df0f7cSStathis Kamperis * Destroy the message queue.
132f2df0f7cSStathis Kamperis */
133f2df0f7cSStathis Kamperis static void
mqueue_destroy(struct mqueue * mq)134f2df0f7cSStathis Kamperis mqueue_destroy(struct mqueue *mq)
135f2df0f7cSStathis Kamperis {
136f2df0f7cSStathis Kamperis struct mq_msg *msg;
137f2df0f7cSStathis Kamperis size_t msz;
138f2df0f7cSStathis Kamperis u_int i;
139f2df0f7cSStathis Kamperis
140f2df0f7cSStathis Kamperis /* Note MQ_PQSIZE + 1. */
141f2df0f7cSStathis Kamperis for (i = 0; i < MQ_PQSIZE + 1; i++) {
142f2df0f7cSStathis Kamperis while ((msg = TAILQ_FIRST(&mq->mq_head[i])) != NULL) {
143f2df0f7cSStathis Kamperis TAILQ_REMOVE(&mq->mq_head[i], msg, msg_queue);
144f2df0f7cSStathis Kamperis msz = sizeof(struct mq_msg) + msg->msg_len;
145f2df0f7cSStathis Kamperis mqueue_freemsg(msg, msz);
146f2df0f7cSStathis Kamperis }
147f2df0f7cSStathis Kamperis }
148f2df0f7cSStathis Kamperis lockuninit(&mq->mq_mtx);
149f2df0f7cSStathis Kamperis kfree(mq, M_MQBUF);
150f2df0f7cSStathis Kamperis }
151f2df0f7cSStathis Kamperis
152f2df0f7cSStathis Kamperis /*
153f2df0f7cSStathis Kamperis * Lookup for file name in general list of message queues.
154f2df0f7cSStathis Kamperis * => locks the message queue
155f2df0f7cSStathis Kamperis */
156f2df0f7cSStathis Kamperis static void *
mqueue_lookup(char * name)157f2df0f7cSStathis Kamperis mqueue_lookup(char *name)
158f2df0f7cSStathis Kamperis {
159f2df0f7cSStathis Kamperis struct mqueue *mq;
160f2df0f7cSStathis Kamperis
161f2df0f7cSStathis Kamperis KKASSERT(lockstatus(&mqlist_mtx, curthread));
162f2df0f7cSStathis Kamperis
163f2df0f7cSStathis Kamperis LIST_FOREACH(mq, &mqueue_head, mq_list) {
164f2df0f7cSStathis Kamperis if (strncmp(mq->mq_name, name, MQ_NAMELEN) == 0) {
165f2df0f7cSStathis Kamperis lockmgr(&mq->mq_mtx, LK_EXCLUSIVE);
166f2df0f7cSStathis Kamperis return mq;
167f2df0f7cSStathis Kamperis }
168f2df0f7cSStathis Kamperis }
169f2df0f7cSStathis Kamperis
170f2df0f7cSStathis Kamperis return NULL;
171f2df0f7cSStathis Kamperis }
172f2df0f7cSStathis Kamperis
173f2df0f7cSStathis Kamperis /*
174f2df0f7cSStathis Kamperis * mqueue_get: get the mqueue from the descriptor.
175f2df0f7cSStathis Kamperis * => locks the message queue, if found.
176d1d64679SStathis Kamperis * => holds a reference on the file descriptor.
177f2df0f7cSStathis Kamperis */
178f2df0f7cSStathis Kamperis static int
mqueue_get(struct lwp * l,mqd_t mqd,file_t ** fpr)179f2df0f7cSStathis Kamperis mqueue_get(struct lwp *l, mqd_t mqd, file_t **fpr)
180f2df0f7cSStathis Kamperis {
181f2df0f7cSStathis Kamperis struct mqueue *mq;
182f2df0f7cSStathis Kamperis file_t *fp;
183f2df0f7cSStathis Kamperis
18435949930SMatthew Dillon fp = holdfp(curthread, (int)mqd, -1); /* XXX: Why -1 ? */
185f2df0f7cSStathis Kamperis if (__predict_false(fp == NULL))
186f2df0f7cSStathis Kamperis return EBADF;
187f2df0f7cSStathis Kamperis
188f2df0f7cSStathis Kamperis if (__predict_false(fp->f_type != DTYPE_MQUEUE)) {
189f2df0f7cSStathis Kamperis fdrop(fp);
190f2df0f7cSStathis Kamperis return EBADF;
191f2df0f7cSStathis Kamperis }
192f2df0f7cSStathis Kamperis mq = fp->f_data;
193f2df0f7cSStathis Kamperis lockmgr(&mq->mq_mtx, LK_EXCLUSIVE);
194f2df0f7cSStathis Kamperis
195f2df0f7cSStathis Kamperis *fpr = fp;
196f2df0f7cSStathis Kamperis return 0;
197f2df0f7cSStathis Kamperis }
198f2df0f7cSStathis Kamperis
199f2df0f7cSStathis Kamperis /*
200f2df0f7cSStathis Kamperis * mqueue_linear_insert: perform linear insert according to the message
201f2df0f7cSStathis Kamperis * priority into the reserved queue (MQ_PQRESQ). Reserved queue is a
202f2df0f7cSStathis Kamperis * sorted list used only when mq_prio_max is increased via sysctl.
203f2df0f7cSStathis Kamperis */
204f2df0f7cSStathis Kamperis static inline void
mqueue_linear_insert(struct mqueue * mq,struct mq_msg * msg)205f2df0f7cSStathis Kamperis mqueue_linear_insert(struct mqueue *mq, struct mq_msg *msg)
206f2df0f7cSStathis Kamperis {
207f2df0f7cSStathis Kamperis struct mq_msg *mit;
208f2df0f7cSStathis Kamperis
209f2df0f7cSStathis Kamperis TAILQ_FOREACH(mit, &mq->mq_head[MQ_PQRESQ], msg_queue) {
210f2df0f7cSStathis Kamperis if (msg->msg_prio > mit->msg_prio)
211f2df0f7cSStathis Kamperis break;
212f2df0f7cSStathis Kamperis }
213f2df0f7cSStathis Kamperis if (mit == NULL) {
214f2df0f7cSStathis Kamperis TAILQ_INSERT_TAIL(&mq->mq_head[MQ_PQRESQ], msg, msg_queue);
215f2df0f7cSStathis Kamperis } else {
216f2df0f7cSStathis Kamperis TAILQ_INSERT_BEFORE(mit, msg, msg_queue);
217f2df0f7cSStathis Kamperis }
218f2df0f7cSStathis Kamperis }
219f2df0f7cSStathis Kamperis
220f2df0f7cSStathis Kamperis /*
221f2df0f7cSStathis Kamperis * Compute number of ticks in the specified amount of time.
222f2df0f7cSStathis Kamperis */
22359b728a7SSascha Wildner static int
tstohz(const struct timespec * ts)224f2df0f7cSStathis Kamperis tstohz(const struct timespec *ts)
225f2df0f7cSStathis Kamperis {
226f2df0f7cSStathis Kamperis struct timeval tv;
227f2df0f7cSStathis Kamperis
228f2df0f7cSStathis Kamperis /*
229f2df0f7cSStathis Kamperis * usec has great enough resolution for hz, so convert to a
230f2df0f7cSStathis Kamperis * timeval and use tvtohz() above.
231f2df0f7cSStathis Kamperis */
232f2df0f7cSStathis Kamperis TIMESPEC_TO_TIMEVAL(&tv, ts);
233f2df0f7cSStathis Kamperis return tvtohz_high(&tv); /* XXX Why _high() and not _low() ? */
234f2df0f7cSStathis Kamperis }
235f2df0f7cSStathis Kamperis
236f2df0f7cSStathis Kamperis /*
237f2df0f7cSStathis Kamperis * Converter from struct timespec to the ticks.
238f2df0f7cSStathis Kamperis * Used by mq_timedreceive(), mq_timedsend().
239f2df0f7cSStathis Kamperis */
240f2df0f7cSStathis Kamperis int
abstimeout2timo(struct timespec * ts,int * timo)241f2df0f7cSStathis Kamperis abstimeout2timo(struct timespec *ts, int *timo)
242f2df0f7cSStathis Kamperis {
243f2df0f7cSStathis Kamperis struct timespec tsd;
244f2df0f7cSStathis Kamperis int error;
245f2df0f7cSStathis Kamperis
246959f863fSStathis Kamperis error = itimespecfix(ts);
247959f863fSStathis Kamperis if (error) {
248959f863fSStathis Kamperis return error;
249a27ab186SStathis Kamperis }
250f2df0f7cSStathis Kamperis getnanotime(&tsd);
251944cd60cSSascha Wildner timespecsub(ts, &tsd, ts);
252f2df0f7cSStathis Kamperis if (ts->tv_sec < 0 || (ts->tv_sec == 0 && ts->tv_nsec <= 0)) {
253f2df0f7cSStathis Kamperis return ETIMEDOUT;
254f2df0f7cSStathis Kamperis }
255f2df0f7cSStathis Kamperis *timo = tstohz(ts);
256f2df0f7cSStathis Kamperis KKASSERT(*timo != 0);
257f2df0f7cSStathis Kamperis
258f2df0f7cSStathis Kamperis return 0;
259f2df0f7cSStathis Kamperis }
260f2df0f7cSStathis Kamperis
261f2df0f7cSStathis Kamperis static int
mq_stat_fop(file_t * fp,struct stat * st,struct ucred * cred)262f2df0f7cSStathis Kamperis mq_stat_fop(file_t *fp, struct stat *st, struct ucred *cred)
263f2df0f7cSStathis Kamperis {
264f2df0f7cSStathis Kamperis struct mqueue *mq = fp->f_data;
265f2df0f7cSStathis Kamperis
266f2df0f7cSStathis Kamperis (void)memset(st, 0, sizeof(*st));
267f2df0f7cSStathis Kamperis
268f2df0f7cSStathis Kamperis lockmgr(&mq->mq_mtx, LK_EXCLUSIVE);
269f2df0f7cSStathis Kamperis st->st_mode = mq->mq_mode;
270f2df0f7cSStathis Kamperis st->st_uid = mq->mq_euid;
271f2df0f7cSStathis Kamperis st->st_gid = mq->mq_egid;
272f2df0f7cSStathis Kamperis st->st_atimespec = mq->mq_atime;
273f2df0f7cSStathis Kamperis st->st_mtimespec = mq->mq_mtime;
274f2df0f7cSStathis Kamperis /*st->st_ctimespec = st->st_birthtimespec = mq->mq_btime;*/
275f2df0f7cSStathis Kamperis st->st_uid = fp->f_cred->cr_uid;
276f2df0f7cSStathis Kamperis st->st_gid = fp->f_cred->cr_svgid;
277f2df0f7cSStathis Kamperis lockmgr(&mq->mq_mtx, LK_RELEASE);
278f2df0f7cSStathis Kamperis
279f2df0f7cSStathis Kamperis return 0;
280f2df0f7cSStathis Kamperis }
281f2df0f7cSStathis Kamperis
282b06aab00SSamuel J. Greear static struct filterops mqfiltops_read =
28345a3dbb7SVenkatesh Srinivas { FILTEROP_ISFD|FILTEROP_MPSAFE, NULL, mqfilter_read_detach, mqfilter_read };
284b06aab00SSamuel J. Greear static struct filterops mqfiltops_write =
28545a3dbb7SVenkatesh Srinivas { FILTEROP_ISFD|FILTEROP_MPSAFE, NULL, mqfilter_write_detach, mqfilter_write };
286b06aab00SSamuel J. Greear
287b06aab00SSamuel J. Greear static int
mq_kqfilter_fop(struct file * fp,struct knote * kn)288b06aab00SSamuel J. Greear mq_kqfilter_fop(struct file *fp, struct knote *kn)
289b06aab00SSamuel J. Greear {
290b06aab00SSamuel J. Greear struct mqueue *mq = fp->f_data;
291b06aab00SSamuel J. Greear struct klist *klist;
292b06aab00SSamuel J. Greear
293b06aab00SSamuel J. Greear lockmgr(&mq->mq_mtx, LK_EXCLUSIVE);
294b06aab00SSamuel J. Greear
295b06aab00SSamuel J. Greear switch (kn->kn_filter) {
296b06aab00SSamuel J. Greear case EVFILT_READ:
297b06aab00SSamuel J. Greear kn->kn_fop = &mqfiltops_read;
298b06aab00SSamuel J. Greear kn->kn_hook = (caddr_t)mq;
2995b22f1a7SSamuel J. Greear klist = &mq->mq_rkq.ki_note;
300b06aab00SSamuel J. Greear break;
301b06aab00SSamuel J. Greear case EVFILT_WRITE:
302b06aab00SSamuel J. Greear kn->kn_fop = &mqfiltops_write;
303b06aab00SSamuel J. Greear kn->kn_hook = (caddr_t)mq;
3045b22f1a7SSamuel J. Greear klist = &mq->mq_wkq.ki_note;
305b06aab00SSamuel J. Greear break;
306b06aab00SSamuel J. Greear default:
307b06aab00SSamuel J. Greear lockmgr(&mq->mq_mtx, LK_RELEASE);
308b06aab00SSamuel J. Greear return (EOPNOTSUPP);
309b06aab00SSamuel J. Greear }
310b06aab00SSamuel J. Greear
3115b22f1a7SSamuel J. Greear knote_insert(klist, kn);
312b06aab00SSamuel J. Greear lockmgr(&mq->mq_mtx, LK_RELEASE);
313b06aab00SSamuel J. Greear
314b06aab00SSamuel J. Greear return (0);
315b06aab00SSamuel J. Greear }
316b06aab00SSamuel J. Greear
317b06aab00SSamuel J. Greear static void
mqfilter_read_detach(struct knote * kn)318b06aab00SSamuel J. Greear mqfilter_read_detach(struct knote *kn)
319b06aab00SSamuel J. Greear {
320b06aab00SSamuel J. Greear struct mqueue *mq = (struct mqueue *)kn->kn_hook;
321b06aab00SSamuel J. Greear
322b06aab00SSamuel J. Greear lockmgr(&mq->mq_mtx, LK_EXCLUSIVE);
3235b22f1a7SSamuel J. Greear struct klist *klist = &mq->mq_rkq.ki_note;
3245b22f1a7SSamuel J. Greear knote_remove(klist, kn);
325b06aab00SSamuel J. Greear lockmgr(&mq->mq_mtx, LK_RELEASE);
326b06aab00SSamuel J. Greear }
327b06aab00SSamuel J. Greear
328b06aab00SSamuel J. Greear static void
mqfilter_write_detach(struct knote * kn)329b06aab00SSamuel J. Greear mqfilter_write_detach(struct knote *kn)
330b06aab00SSamuel J. Greear {
331b06aab00SSamuel J. Greear struct mqueue *mq = (struct mqueue *)kn->kn_hook;
332b06aab00SSamuel J. Greear
333b06aab00SSamuel J. Greear lockmgr(&mq->mq_mtx, LK_EXCLUSIVE);
3345b22f1a7SSamuel J. Greear struct klist *klist = &mq->mq_wkq.ki_note;
3355b22f1a7SSamuel J. Greear knote_remove(klist, kn);
336b06aab00SSamuel J. Greear lockmgr(&mq->mq_mtx, LK_RELEASE);
337b06aab00SSamuel J. Greear }
338b06aab00SSamuel J. Greear
339b06aab00SSamuel J. Greear static int
mqfilter_read(struct knote * kn,long hint)340b06aab00SSamuel J. Greear mqfilter_read(struct knote *kn, long hint)
341b06aab00SSamuel J. Greear {
342b06aab00SSamuel J. Greear struct mqueue *mq = (struct mqueue *)kn->kn_hook;
343b06aab00SSamuel J. Greear struct mq_attr *mqattr;
344b06aab00SSamuel J. Greear int ready = 0;
345b06aab00SSamuel J. Greear
346b06aab00SSamuel J. Greear lockmgr(&mq->mq_mtx, LK_EXCLUSIVE);
347b06aab00SSamuel J. Greear mqattr = &mq->mq_attrib;
348b06aab00SSamuel J. Greear /* Ready for receiving, if there are messages in the queue */
349b06aab00SSamuel J. Greear if (mqattr->mq_curmsgs)
350b06aab00SSamuel J. Greear ready = 1;
351b06aab00SSamuel J. Greear lockmgr(&mq->mq_mtx, LK_RELEASE);
352b06aab00SSamuel J. Greear
353b06aab00SSamuel J. Greear return (ready);
354b06aab00SSamuel J. Greear }
355b06aab00SSamuel J. Greear
356b06aab00SSamuel J. Greear static int
mqfilter_write(struct knote * kn,long hint)357b06aab00SSamuel J. Greear mqfilter_write(struct knote *kn, long hint)
358b06aab00SSamuel J. Greear {
359b06aab00SSamuel J. Greear struct mqueue *mq = (struct mqueue *)kn->kn_hook;
360b06aab00SSamuel J. Greear struct mq_attr *mqattr;
361b06aab00SSamuel J. Greear int ready = 0;
362b06aab00SSamuel J. Greear
363b06aab00SSamuel J. Greear lockmgr(&mq->mq_mtx, LK_EXCLUSIVE);
364b06aab00SSamuel J. Greear mqattr = &mq->mq_attrib;
365b06aab00SSamuel J. Greear /* Ready for sending, if the message queue is not full */
366b06aab00SSamuel J. Greear if (mqattr->mq_curmsgs < mqattr->mq_maxmsg)
367b06aab00SSamuel J. Greear ready = 1;
368b06aab00SSamuel J. Greear lockmgr(&mq->mq_mtx, LK_RELEASE);
369b06aab00SSamuel J. Greear
370b06aab00SSamuel J. Greear return (ready);
371b06aab00SSamuel J. Greear }
372b06aab00SSamuel J. Greear
373f2df0f7cSStathis Kamperis static int
mq_close_fop(file_t * fp)374f2df0f7cSStathis Kamperis mq_close_fop(file_t *fp)
375f2df0f7cSStathis Kamperis {
376f2df0f7cSStathis Kamperis struct proc *p = curproc;
377f2df0f7cSStathis Kamperis struct mqueue *mq = fp->f_data;
378f2df0f7cSStathis Kamperis bool destroy;
379f2df0f7cSStathis Kamperis
380f2df0f7cSStathis Kamperis lockmgr(&mqlist_mtx, LK_EXCLUSIVE);
381f2df0f7cSStathis Kamperis lockmgr(&mq->mq_mtx, LK_EXCLUSIVE);
382f2df0f7cSStathis Kamperis
383f2df0f7cSStathis Kamperis /* Decrease the counters */
384f2df0f7cSStathis Kamperis p->p_mqueue_cnt--;
385f2df0f7cSStathis Kamperis mq->mq_refcnt--;
386f2df0f7cSStathis Kamperis
387f2df0f7cSStathis Kamperis /* Remove notification if registered for this process */
388f2df0f7cSStathis Kamperis if (mq->mq_notify_proc == p)
389f2df0f7cSStathis Kamperis mq->mq_notify_proc = NULL;
390f2df0f7cSStathis Kamperis
391f2df0f7cSStathis Kamperis /*
392f2df0f7cSStathis Kamperis * If this is the last reference and mqueue is marked for unlink,
393f2df0f7cSStathis Kamperis * remove and later destroy the message queue.
394f2df0f7cSStathis Kamperis */
395f2df0f7cSStathis Kamperis if (mq->mq_refcnt == 0 && (mq->mq_attrib.mq_flags & MQ_UNLINK)) {
396f2df0f7cSStathis Kamperis LIST_REMOVE(mq, mq_list);
397f2df0f7cSStathis Kamperis destroy = true;
398f2df0f7cSStathis Kamperis } else
399f2df0f7cSStathis Kamperis destroy = false;
400f2df0f7cSStathis Kamperis
401f2df0f7cSStathis Kamperis lockmgr(&mq->mq_mtx, LK_RELEASE);
402f2df0f7cSStathis Kamperis lockmgr(&mqlist_mtx, LK_RELEASE);
403f2df0f7cSStathis Kamperis
404f2df0f7cSStathis Kamperis if (destroy)
405f2df0f7cSStathis Kamperis mqueue_destroy(mq);
406f2df0f7cSStathis Kamperis
407f2df0f7cSStathis Kamperis return 0;
408f2df0f7cSStathis Kamperis }
409f2df0f7cSStathis Kamperis
410f2df0f7cSStathis Kamperis /*
411f2df0f7cSStathis Kamperis * General mqueue system calls.
412f2df0f7cSStathis Kamperis */
413f2df0f7cSStathis Kamperis
414f2df0f7cSStathis Kamperis int
sys_mq_open(struct sysmsg * sysmsg,const struct mq_open_args * uap)41580d831e1SMatthew Dillon sys_mq_open(struct sysmsg *sysmsg, const struct mq_open_args *uap)
416f2df0f7cSStathis Kamperis {
417f2df0f7cSStathis Kamperis /* {
418f2df0f7cSStathis Kamperis syscallarg(const char *) name;
419f2df0f7cSStathis Kamperis syscallarg(int) oflag;
420f2df0f7cSStathis Kamperis syscallarg(mode_t) mode;
421f2df0f7cSStathis Kamperis syscallarg(struct mq_attr) attr;
422f2df0f7cSStathis Kamperis } */
4239910d07bSMatthew Dillon struct thread *td = curthread;
4249910d07bSMatthew Dillon struct proc *p = td->td_proc;
425f3a2d8c4SMatthew Dillon struct filedesc *fdp = p->p_fd;
426f2df0f7cSStathis Kamperis struct mqueue *mq, *mq_new = NULL;
427f2df0f7cSStathis Kamperis file_t *fp;
428f2df0f7cSStathis Kamperis char *name;
429f2df0f7cSStathis Kamperis int mqd, error, oflag;
430f2df0f7cSStathis Kamperis
431f2df0f7cSStathis Kamperis /* Check access mode flags */
43203608863SSascha Wildner oflag = uap->oflag;
433f2df0f7cSStathis Kamperis if ((oflag & O_ACCMODE) == (O_WRONLY | O_RDWR)) {
434f2df0f7cSStathis Kamperis return EINVAL;
435f2df0f7cSStathis Kamperis }
436f2df0f7cSStathis Kamperis
437f2df0f7cSStathis Kamperis /* Get the name from the user-space */
438d3a2b23dSVenkatesh Srinivas name = kmalloc(MQ_NAMELEN, M_MQBUF, M_WAITOK | M_ZERO | M_NULLOK);
439d3a2b23dSVenkatesh Srinivas if (name == NULL)
440d3a2b23dSVenkatesh Srinivas return (ENOMEM);
44103608863SSascha Wildner error = copyinstr(uap->name, name, MQ_NAMELEN - 1, NULL);
442f2df0f7cSStathis Kamperis if (error) {
443f2df0f7cSStathis Kamperis kfree(name, M_MQBUF);
444f2df0f7cSStathis Kamperis return error;
445f2df0f7cSStathis Kamperis }
446f2df0f7cSStathis Kamperis
447f2df0f7cSStathis Kamperis if (oflag & O_CREAT) {
448f2df0f7cSStathis Kamperis struct mq_attr attr;
449f2df0f7cSStathis Kamperis u_int i;
450f2df0f7cSStathis Kamperis
451f2df0f7cSStathis Kamperis /* Check the limit */
452f2df0f7cSStathis Kamperis if (p->p_mqueue_cnt == mq_open_max) {
453f2df0f7cSStathis Kamperis kfree(name, M_MQBUF);
454f2df0f7cSStathis Kamperis return EMFILE;
455f2df0f7cSStathis Kamperis }
456f2df0f7cSStathis Kamperis
457f2df0f7cSStathis Kamperis /* Empty name is invalid */
458f2df0f7cSStathis Kamperis if (name[0] == '\0') {
459f2df0f7cSStathis Kamperis kfree(name, M_MQBUF);
460f2df0f7cSStathis Kamperis return EINVAL;
461f2df0f7cSStathis Kamperis }
462f2df0f7cSStathis Kamperis
463f2df0f7cSStathis Kamperis /* Check for mqueue attributes */
46403608863SSascha Wildner if (uap->attr) {
46503608863SSascha Wildner error = copyin(uap->attr, &attr,
466f2df0f7cSStathis Kamperis sizeof(struct mq_attr));
467f2df0f7cSStathis Kamperis if (error) {
468f2df0f7cSStathis Kamperis kfree(name, M_MQBUF);
469f2df0f7cSStathis Kamperis return error;
470f2df0f7cSStathis Kamperis }
4718658b626SStathis Kamperis if (attr.mq_maxmsg <= 0 ||
4728658b626SStathis Kamperis attr.mq_maxmsg > mq_max_maxmsg ||
4738658b626SStathis Kamperis attr.mq_msgsize <= 0 ||
474f2df0f7cSStathis Kamperis attr.mq_msgsize > mq_max_msgsize) {
475f2df0f7cSStathis Kamperis kfree(name, M_MQBUF);
476f2df0f7cSStathis Kamperis return EINVAL;
477f2df0f7cSStathis Kamperis }
478f2df0f7cSStathis Kamperis attr.mq_curmsgs = 0;
479f2df0f7cSStathis Kamperis } else {
480f2df0f7cSStathis Kamperis memset(&attr, 0, sizeof(struct mq_attr));
481f2df0f7cSStathis Kamperis attr.mq_maxmsg = mq_def_maxmsg;
482f2df0f7cSStathis Kamperis attr.mq_msgsize =
483f2df0f7cSStathis Kamperis MQ_DEF_MSGSIZE - sizeof(struct mq_msg);
484f2df0f7cSStathis Kamperis }
485f2df0f7cSStathis Kamperis
486f2df0f7cSStathis Kamperis /*
487f2df0f7cSStathis Kamperis * Allocate new mqueue, initialize data structures,
488f2df0f7cSStathis Kamperis * copy the name, attributes and set the flag.
489f2df0f7cSStathis Kamperis */
490d3a2b23dSVenkatesh Srinivas mq_new = kmalloc(sizeof(struct mqueue), M_MQBUF,
491d3a2b23dSVenkatesh Srinivas M_WAITOK | M_ZERO | M_NULLOK);
492d3a2b23dSVenkatesh Srinivas if (mq_new == NULL) {
493d3a2b23dSVenkatesh Srinivas kfree(name, M_MQBUF);
494d3a2b23dSVenkatesh Srinivas return (ENOMEM);
495d3a2b23dSVenkatesh Srinivas }
496f2df0f7cSStathis Kamperis
497f2df0f7cSStathis Kamperis lockinit(&mq_new->mq_mtx, "mq_new->mq_mtx", 0, LK_CANRECURSE);
498f2df0f7cSStathis Kamperis for (i = 0; i < (MQ_PQSIZE + 1); i++) {
499f2df0f7cSStathis Kamperis TAILQ_INIT(&mq_new->mq_head[i]);
500f2df0f7cSStathis Kamperis }
501f2df0f7cSStathis Kamperis
502f2df0f7cSStathis Kamperis strlcpy(mq_new->mq_name, name, MQ_NAMELEN);
503f2df0f7cSStathis Kamperis memcpy(&mq_new->mq_attrib, &attr, sizeof(struct mq_attr));
504f2df0f7cSStathis Kamperis
505f2df0f7cSStathis Kamperis /*CTASSERT((O_MASK & (MQ_UNLINK | MQ_RECEIVE)) == 0);*/
506f2df0f7cSStathis Kamperis /* mq_new->mq_attrib.mq_flags = (O_MASK & oflag); */
507f2df0f7cSStathis Kamperis mq_new->mq_attrib.mq_flags = oflag;
508f2df0f7cSStathis Kamperis
509f2df0f7cSStathis Kamperis /* Store mode and effective UID with GID */
51003608863SSascha Wildner mq_new->mq_mode = ((uap->mode &
511f2df0f7cSStathis Kamperis ~p->p_fd->fd_cmask) & ALLPERMS) & ~S_ISTXT;
5129910d07bSMatthew Dillon mq_new->mq_euid = td->td_ucred->cr_uid;
5139910d07bSMatthew Dillon mq_new->mq_egid = td->td_ucred->cr_svgid;
514f2df0f7cSStathis Kamperis }
515f2df0f7cSStathis Kamperis
516f2df0f7cSStathis Kamperis /* Allocate file structure and descriptor */
517f3a2d8c4SMatthew Dillon error = falloc(td->td_lwp, &fp, &mqd);
518f2df0f7cSStathis Kamperis if (error) {
519f2df0f7cSStathis Kamperis if (mq_new)
520f2df0f7cSStathis Kamperis mqueue_destroy(mq_new);
521f2df0f7cSStathis Kamperis kfree(name, M_MQBUF);
522f2df0f7cSStathis Kamperis return error;
523f2df0f7cSStathis Kamperis }
524f2df0f7cSStathis Kamperis fp->f_type = DTYPE_MQUEUE;
525f2df0f7cSStathis Kamperis fp->f_flag = FFLAGS(oflag) & (FREAD | FWRITE);
526f2df0f7cSStathis Kamperis fp->f_ops = &mqops;
527f2df0f7cSStathis Kamperis
528f2df0f7cSStathis Kamperis /* Look up for mqueue with such name */
529f2df0f7cSStathis Kamperis lockmgr(&mqlist_mtx, LK_EXCLUSIVE);
530f2df0f7cSStathis Kamperis mq = mqueue_lookup(name);
531f2df0f7cSStathis Kamperis if (mq) {
532f2df0f7cSStathis Kamperis int acc_mode;
533f2df0f7cSStathis Kamperis
534f2df0f7cSStathis Kamperis KKASSERT(lockstatus(&mq->mq_mtx, curthread));
535f2df0f7cSStathis Kamperis
536f2df0f7cSStathis Kamperis /* Check if mqueue is not marked as unlinking */
537f2df0f7cSStathis Kamperis if (mq->mq_attrib.mq_flags & MQ_UNLINK) {
538f2df0f7cSStathis Kamperis error = EACCES;
539f2df0f7cSStathis Kamperis goto exit;
540f2df0f7cSStathis Kamperis }
541f2df0f7cSStathis Kamperis /* Fail if O_EXCL is set, and mqueue already exists */
542f2df0f7cSStathis Kamperis if ((oflag & O_CREAT) && (oflag & O_EXCL)) {
543f2df0f7cSStathis Kamperis error = EEXIST;
544f2df0f7cSStathis Kamperis goto exit;
545f2df0f7cSStathis Kamperis }
546f2df0f7cSStathis Kamperis
547f2df0f7cSStathis Kamperis /*
548f2df0f7cSStathis Kamperis * Check the permissions. Note the difference between
549f2df0f7cSStathis Kamperis * VREAD/VWRITE and FREAD/FWRITE.
550f2df0f7cSStathis Kamperis */
551f2df0f7cSStathis Kamperis acc_mode = 0;
552f2df0f7cSStathis Kamperis if (fp->f_flag & FREAD) {
553f2df0f7cSStathis Kamperis acc_mode |= VREAD;
554f2df0f7cSStathis Kamperis }
555f2df0f7cSStathis Kamperis if (fp->f_flag & FWRITE) {
556f2df0f7cSStathis Kamperis acc_mode |= VWRITE;
557f2df0f7cSStathis Kamperis }
558f2df0f7cSStathis Kamperis if (vaccess(VNON, mq->mq_mode, mq->mq_euid, mq->mq_egid,
5599910d07bSMatthew Dillon acc_mode, td->td_ucred)) {
560f2df0f7cSStathis Kamperis
561f2df0f7cSStathis Kamperis error = EACCES;
562f2df0f7cSStathis Kamperis goto exit;
563f2df0f7cSStathis Kamperis }
564f2df0f7cSStathis Kamperis } else {
565f2df0f7cSStathis Kamperis /* Fail if mqueue neither exists, nor we create it */
566f2df0f7cSStathis Kamperis if ((oflag & O_CREAT) == 0) {
567f2df0f7cSStathis Kamperis lockmgr(&mqlist_mtx, LK_RELEASE);
568f2df0f7cSStathis Kamperis KKASSERT(mq_new == NULL);
569f3a2d8c4SMatthew Dillon fsetfd(fdp, NULL, mqd);
570f2df0f7cSStathis Kamperis fp->f_ops = &badfileops;
571f2df0f7cSStathis Kamperis fdrop(fp);
572f2df0f7cSStathis Kamperis kfree(name, M_MQBUF);
573f2df0f7cSStathis Kamperis return ENOENT;
574f2df0f7cSStathis Kamperis }
575f2df0f7cSStathis Kamperis
576f2df0f7cSStathis Kamperis /* Check the limit */
577f2df0f7cSStathis Kamperis if (p->p_mqueue_cnt == mq_open_max) {
578f2df0f7cSStathis Kamperis error = EMFILE;
579f2df0f7cSStathis Kamperis goto exit;
580f2df0f7cSStathis Kamperis }
581f2df0f7cSStathis Kamperis
582f2df0f7cSStathis Kamperis /* Insert the queue to the list */
583f2df0f7cSStathis Kamperis mq = mq_new;
584f2df0f7cSStathis Kamperis lockmgr(&mq->mq_mtx, LK_EXCLUSIVE);
585f2df0f7cSStathis Kamperis LIST_INSERT_HEAD(&mqueue_head, mq, mq_list);
586f2df0f7cSStathis Kamperis mq_new = NULL;
587f2df0f7cSStathis Kamperis getnanotime(&mq->mq_btime);
588f2df0f7cSStathis Kamperis mq->mq_atime = mq->mq_mtime = mq->mq_btime;
589f2df0f7cSStathis Kamperis }
590f2df0f7cSStathis Kamperis
591f2df0f7cSStathis Kamperis /* Increase the counters, and make descriptor ready */
592f2df0f7cSStathis Kamperis p->p_mqueue_cnt++;
593f2df0f7cSStathis Kamperis mq->mq_refcnt++;
594f2df0f7cSStathis Kamperis fp->f_data = mq;
595f2df0f7cSStathis Kamperis exit:
596f2df0f7cSStathis Kamperis lockmgr(&mq->mq_mtx, LK_RELEASE);
597f2df0f7cSStathis Kamperis lockmgr(&mqlist_mtx, LK_RELEASE);
598f2df0f7cSStathis Kamperis
599f2df0f7cSStathis Kamperis if (mq_new)
600f2df0f7cSStathis Kamperis mqueue_destroy(mq_new);
601f2df0f7cSStathis Kamperis if (error) {
602f3a2d8c4SMatthew Dillon fsetfd(fdp, NULL, mqd);
603f2df0f7cSStathis Kamperis fp->f_ops = &badfileops;
604f2df0f7cSStathis Kamperis } else {
605f3a2d8c4SMatthew Dillon fsetfd(fdp, fp, mqd);
60680d831e1SMatthew Dillon sysmsg->sysmsg_result = mqd;
607f2df0f7cSStathis Kamperis }
608f2df0f7cSStathis Kamperis fdrop(fp);
609f2df0f7cSStathis Kamperis kfree(name, M_MQBUF);
610f2df0f7cSStathis Kamperis
611f2df0f7cSStathis Kamperis return error;
612f2df0f7cSStathis Kamperis }
613f2df0f7cSStathis Kamperis
614f2df0f7cSStathis Kamperis int
sys_mq_close(struct sysmsg * sysmsg,const struct mq_close_args * uap)61580d831e1SMatthew Dillon sys_mq_close(struct sysmsg *sysmsg, const struct mq_close_args *uap)
616f2df0f7cSStathis Kamperis {
61780d831e1SMatthew Dillon return sys_close(sysmsg, (const void *)uap);
618f2df0f7cSStathis Kamperis }
619f2df0f7cSStathis Kamperis
620f2df0f7cSStathis Kamperis /*
621f2df0f7cSStathis Kamperis * Primary mq_receive1() function.
622f2df0f7cSStathis Kamperis */
623f2df0f7cSStathis Kamperis int
mq_receive1(struct lwp * l,mqd_t mqdes,void * msg_ptr,size_t msg_len,unsigned * msg_prio,struct timespec * ts,ssize_t * mlen)624f2df0f7cSStathis Kamperis mq_receive1(struct lwp *l, mqd_t mqdes, void *msg_ptr, size_t msg_len,
625f2df0f7cSStathis Kamperis unsigned *msg_prio, struct timespec *ts, ssize_t *mlen)
626f2df0f7cSStathis Kamperis {
627f2df0f7cSStathis Kamperis file_t *fp = NULL;
628f2df0f7cSStathis Kamperis struct mqueue *mq;
629f2df0f7cSStathis Kamperis struct mq_msg *msg = NULL;
630f2df0f7cSStathis Kamperis struct mq_attr *mqattr;
631f2df0f7cSStathis Kamperis u_int idx;
632f2df0f7cSStathis Kamperis int error;
633f2df0f7cSStathis Kamperis
634f2df0f7cSStathis Kamperis /* Get the message queue */
635f2df0f7cSStathis Kamperis error = mqueue_get(l, mqdes, &fp);
636f2df0f7cSStathis Kamperis if (error) {
637f2df0f7cSStathis Kamperis return error;
638f2df0f7cSStathis Kamperis }
639f2df0f7cSStathis Kamperis mq = fp->f_data;
640f2df0f7cSStathis Kamperis if ((fp->f_flag & FREAD) == 0) {
641f2df0f7cSStathis Kamperis error = EBADF;
642f2df0f7cSStathis Kamperis goto error;
643f2df0f7cSStathis Kamperis }
644f2df0f7cSStathis Kamperis getnanotime(&mq->mq_atime);
645f2df0f7cSStathis Kamperis mqattr = &mq->mq_attrib;
646f2df0f7cSStathis Kamperis
647f2df0f7cSStathis Kamperis /* Check the message size limits */
648f2df0f7cSStathis Kamperis if (msg_len < mqattr->mq_msgsize) {
649f2df0f7cSStathis Kamperis error = EMSGSIZE;
650f2df0f7cSStathis Kamperis goto error;
651f2df0f7cSStathis Kamperis }
652f2df0f7cSStathis Kamperis
653f2df0f7cSStathis Kamperis /* Check if queue is empty */
654f2df0f7cSStathis Kamperis while (mqattr->mq_curmsgs == 0) {
655f2df0f7cSStathis Kamperis int t;
656f2df0f7cSStathis Kamperis
657f2df0f7cSStathis Kamperis if (mqattr->mq_flags & O_NONBLOCK) {
658f2df0f7cSStathis Kamperis error = EAGAIN;
659f2df0f7cSStathis Kamperis goto error;
660f2df0f7cSStathis Kamperis }
661c8b16402SStathis Kamperis if (ts) {
662f2df0f7cSStathis Kamperis error = abstimeout2timo(ts, &t);
663c8b16402SStathis Kamperis if (error)
664f2df0f7cSStathis Kamperis goto error;
665c8b16402SStathis Kamperis } else
666c8b16402SStathis Kamperis t = 0;
667f2df0f7cSStathis Kamperis /*
668f2df0f7cSStathis Kamperis * Block until someone sends the message.
669f2df0f7cSStathis Kamperis * While doing this, notification should not be sent.
670f2df0f7cSStathis Kamperis */
671f2df0f7cSStathis Kamperis mqattr->mq_flags |= MQ_RECEIVE;
672acb0b16fSStathis Kamperis error = lksleep(&mq->mq_send_cv, &mq->mq_mtx, PCATCH, "mqsend", t);
673f2df0f7cSStathis Kamperis mqattr->mq_flags &= ~MQ_RECEIVE;
674f2df0f7cSStathis Kamperis if (error || (mqattr->mq_flags & MQ_UNLINK)) {
675f2df0f7cSStathis Kamperis error = (error == EWOULDBLOCK) ? ETIMEDOUT : EINTR;
676f2df0f7cSStathis Kamperis goto error;
677f2df0f7cSStathis Kamperis }
678f2df0f7cSStathis Kamperis }
679f2df0f7cSStathis Kamperis
680f2df0f7cSStathis Kamperis
681f2df0f7cSStathis Kamperis /*
682f2df0f7cSStathis Kamperis * Find the highest priority message, and remove it from the queue.
683f2df0f7cSStathis Kamperis * At first, reserved queue is checked, bitmap is next.
684f2df0f7cSStathis Kamperis */
685f2df0f7cSStathis Kamperis msg = TAILQ_FIRST(&mq->mq_head[MQ_PQRESQ]);
686f2df0f7cSStathis Kamperis if (__predict_true(msg == NULL)) {
687f2df0f7cSStathis Kamperis idx = ffs(mq->mq_bitmap);
688f2df0f7cSStathis Kamperis msg = TAILQ_FIRST(&mq->mq_head[idx]);
689f2df0f7cSStathis Kamperis KKASSERT(msg != NULL);
690f2df0f7cSStathis Kamperis } else {
691f2df0f7cSStathis Kamperis idx = MQ_PQRESQ;
692f2df0f7cSStathis Kamperis }
693f2df0f7cSStathis Kamperis TAILQ_REMOVE(&mq->mq_head[idx], msg, msg_queue);
694f2df0f7cSStathis Kamperis
695f2df0f7cSStathis Kamperis /* Unmark the bit, if last message. */
696f2df0f7cSStathis Kamperis if (__predict_true(idx) && TAILQ_EMPTY(&mq->mq_head[idx])) {
697f2df0f7cSStathis Kamperis KKASSERT((MQ_PQSIZE - idx) == msg->msg_prio);
698f2df0f7cSStathis Kamperis mq->mq_bitmap &= ~(1 << --idx);
699f2df0f7cSStathis Kamperis }
700f2df0f7cSStathis Kamperis
701f2df0f7cSStathis Kamperis /* Decrement the counter and signal waiter, if any */
702f2df0f7cSStathis Kamperis mqattr->mq_curmsgs--;
703f2df0f7cSStathis Kamperis wakeup_one(&mq->mq_recv_cv);
704f2df0f7cSStathis Kamperis
705f2df0f7cSStathis Kamperis /* Ready for sending now */
7065b22f1a7SSamuel J. Greear KNOTE(&mq->mq_wkq.ki_note, 0);
707f2df0f7cSStathis Kamperis error:
708f2df0f7cSStathis Kamperis lockmgr(&mq->mq_mtx, LK_RELEASE);
709f2df0f7cSStathis Kamperis fdrop(fp);
710f2df0f7cSStathis Kamperis if (error)
711f2df0f7cSStathis Kamperis return error;
712f2df0f7cSStathis Kamperis
713f2df0f7cSStathis Kamperis /*
714f2df0f7cSStathis Kamperis * Copy the data to the user-space.
715f2df0f7cSStathis Kamperis * Note: According to POSIX, no message should be removed from the
716f2df0f7cSStathis Kamperis * queue in case of fail - this would be violated.
717f2df0f7cSStathis Kamperis */
718f2df0f7cSStathis Kamperis *mlen = msg->msg_len;
719f2df0f7cSStathis Kamperis error = copyout(msg->msg_ptr, msg_ptr, msg->msg_len);
720f2df0f7cSStathis Kamperis if (error == 0 && msg_prio)
721f2df0f7cSStathis Kamperis error = copyout(&msg->msg_prio, msg_prio, sizeof(unsigned));
722f2df0f7cSStathis Kamperis mqueue_freemsg(msg, sizeof(struct mq_msg) + msg->msg_len);
723f2df0f7cSStathis Kamperis
724f2df0f7cSStathis Kamperis return error;
725f2df0f7cSStathis Kamperis }
726f2df0f7cSStathis Kamperis
727f2df0f7cSStathis Kamperis int
sys_mq_receive(struct sysmsg * sysmsg,const struct mq_receive_args * uap)72880d831e1SMatthew Dillon sys_mq_receive(struct sysmsg *sysmsg, const struct mq_receive_args *uap)
729f2df0f7cSStathis Kamperis {
730f2df0f7cSStathis Kamperis /* {
731f2df0f7cSStathis Kamperis syscallarg(mqd_t) mqdes;
732f2df0f7cSStathis Kamperis syscallarg(char *) msg_ptr;
733f2df0f7cSStathis Kamperis syscallarg(size_t) msg_len;
734f2df0f7cSStathis Kamperis syscallarg(unsigned *) msg_prio;
735f2df0f7cSStathis Kamperis } */
736f2df0f7cSStathis Kamperis ssize_t mlen;
737f2df0f7cSStathis Kamperis int error;
738f2df0f7cSStathis Kamperis
73903608863SSascha Wildner error = mq_receive1(curthread->td_lwp, uap->mqdes, uap->msg_ptr,
74003608863SSascha Wildner uap->msg_len, uap->msg_prio, 0, &mlen);
741f2df0f7cSStathis Kamperis if (error == 0)
74280d831e1SMatthew Dillon sysmsg->sysmsg_result = mlen;
743f2df0f7cSStathis Kamperis
744f2df0f7cSStathis Kamperis return error;
745f2df0f7cSStathis Kamperis }
746f2df0f7cSStathis Kamperis
747f2df0f7cSStathis Kamperis int
sys_mq_timedreceive(struct sysmsg * sysmsg,const struct mq_timedreceive_args * uap)74880d831e1SMatthew Dillon sys_mq_timedreceive(struct sysmsg *sysmsg, const struct mq_timedreceive_args *uap)
749f2df0f7cSStathis Kamperis {
750f2df0f7cSStathis Kamperis /* {
751f2df0f7cSStathis Kamperis syscallarg(mqd_t) mqdes;
752f2df0f7cSStathis Kamperis syscallarg(char *) msg_ptr;
753f2df0f7cSStathis Kamperis syscallarg(size_t) msg_len;
754f2df0f7cSStathis Kamperis syscallarg(unsigned *) msg_prio;
755f2df0f7cSStathis Kamperis syscallarg(const struct timespec *) abs_timeout;
756f2df0f7cSStathis Kamperis } */
757f2df0f7cSStathis Kamperis int error;
758f2df0f7cSStathis Kamperis ssize_t mlen;
759f2df0f7cSStathis Kamperis struct timespec ts, *tsp;
760f2df0f7cSStathis Kamperis
761f2df0f7cSStathis Kamperis /* Get and convert time value */
76203608863SSascha Wildner if (uap->abs_timeout) {
76303608863SSascha Wildner error = copyin(uap->abs_timeout, &ts, sizeof(ts));
764f2df0f7cSStathis Kamperis if (error)
765f2df0f7cSStathis Kamperis return error;
766f2df0f7cSStathis Kamperis tsp = &ts;
767f2df0f7cSStathis Kamperis } else {
768f2df0f7cSStathis Kamperis tsp = NULL;
769f2df0f7cSStathis Kamperis }
770f2df0f7cSStathis Kamperis
77103608863SSascha Wildner error = mq_receive1(curthread->td_lwp, uap->mqdes, uap->msg_ptr,
77203608863SSascha Wildner uap->msg_len, uap->msg_prio, tsp, &mlen);
773f2df0f7cSStathis Kamperis if (error == 0)
77480d831e1SMatthew Dillon sysmsg->sysmsg_result = mlen;
775f2df0f7cSStathis Kamperis
776f2df0f7cSStathis Kamperis return error;
777f2df0f7cSStathis Kamperis }
778f2df0f7cSStathis Kamperis
779f2df0f7cSStathis Kamperis /*
780f2df0f7cSStathis Kamperis * Primary mq_send1() function.
781f2df0f7cSStathis Kamperis */
782f2df0f7cSStathis Kamperis int
mq_send1(struct lwp * l,mqd_t mqdes,const char * msg_ptr,size_t msg_len,unsigned msg_prio,struct timespec * ts)783f2df0f7cSStathis Kamperis mq_send1(struct lwp *l, mqd_t mqdes, const char *msg_ptr, size_t msg_len,
784f2df0f7cSStathis Kamperis unsigned msg_prio, struct timespec *ts)
785f2df0f7cSStathis Kamperis {
786f2df0f7cSStathis Kamperis file_t *fp = NULL;
787f2df0f7cSStathis Kamperis struct mqueue *mq;
788f2df0f7cSStathis Kamperis struct mq_msg *msg;
789f2df0f7cSStathis Kamperis struct mq_attr *mqattr;
790f2df0f7cSStathis Kamperis struct proc *notify = NULL;
791f2df0f7cSStathis Kamperis /*ksiginfo_t ksi;*/
792f2df0f7cSStathis Kamperis size_t size;
793f2df0f7cSStathis Kamperis int error;
794f2df0f7cSStathis Kamperis
795f2df0f7cSStathis Kamperis /* Check the priority range */
796f2df0f7cSStathis Kamperis if (msg_prio >= mq_prio_max)
797f2df0f7cSStathis Kamperis return EINVAL;
798f2df0f7cSStathis Kamperis
799f2df0f7cSStathis Kamperis /* Allocate a new message */
800f2df0f7cSStathis Kamperis size = sizeof(struct mq_msg) + msg_len;
801f2df0f7cSStathis Kamperis if (size > mq_max_msgsize)
802f2df0f7cSStathis Kamperis return EMSGSIZE;
803f2df0f7cSStathis Kamperis
804d3a2b23dSVenkatesh Srinivas msg = kmalloc(size, M_MQBUF, M_WAITOK | M_NULLOK);
805d3a2b23dSVenkatesh Srinivas if (msg == NULL)
806d3a2b23dSVenkatesh Srinivas return (ENOMEM);
807d3a2b23dSVenkatesh Srinivas
808f2df0f7cSStathis Kamperis
809f2df0f7cSStathis Kamperis /* Get the data from user-space */
810f2df0f7cSStathis Kamperis error = copyin(msg_ptr, msg->msg_ptr, msg_len);
811f2df0f7cSStathis Kamperis if (error) {
812f2df0f7cSStathis Kamperis mqueue_freemsg(msg, size);
813f2df0f7cSStathis Kamperis return error;
814f2df0f7cSStathis Kamperis }
815f2df0f7cSStathis Kamperis msg->msg_len = msg_len;
816f2df0f7cSStathis Kamperis msg->msg_prio = msg_prio;
817f2df0f7cSStathis Kamperis
818f2df0f7cSStathis Kamperis /* Get the mqueue */
819f2df0f7cSStathis Kamperis error = mqueue_get(l, mqdes, &fp);
820f2df0f7cSStathis Kamperis if (error) {
821f2df0f7cSStathis Kamperis mqueue_freemsg(msg, size);
822f2df0f7cSStathis Kamperis return error;
823f2df0f7cSStathis Kamperis }
824f2df0f7cSStathis Kamperis mq = fp->f_data;
825f2df0f7cSStathis Kamperis if ((fp->f_flag & FWRITE) == 0) {
826f2df0f7cSStathis Kamperis error = EBADF;
827f2df0f7cSStathis Kamperis goto error;
828f2df0f7cSStathis Kamperis }
829f2df0f7cSStathis Kamperis getnanotime(&mq->mq_mtime);
830f2df0f7cSStathis Kamperis mqattr = &mq->mq_attrib;
831f2df0f7cSStathis Kamperis
832f2df0f7cSStathis Kamperis /* Check the message size limit */
833f2df0f7cSStathis Kamperis if (msg_len <= 0 || msg_len > mqattr->mq_msgsize) {
834f2df0f7cSStathis Kamperis error = EMSGSIZE;
835f2df0f7cSStathis Kamperis goto error;
836f2df0f7cSStathis Kamperis }
837f2df0f7cSStathis Kamperis
838f2df0f7cSStathis Kamperis /* Check if queue is full */
839f2df0f7cSStathis Kamperis while (mqattr->mq_curmsgs >= mqattr->mq_maxmsg) {
840f2df0f7cSStathis Kamperis int t;
841f2df0f7cSStathis Kamperis
842f2df0f7cSStathis Kamperis if (mqattr->mq_flags & O_NONBLOCK) {
843f2df0f7cSStathis Kamperis error = EAGAIN;
844f2df0f7cSStathis Kamperis goto error;
845f2df0f7cSStathis Kamperis }
846c8b16402SStathis Kamperis if (ts) {
847f2df0f7cSStathis Kamperis error = abstimeout2timo(ts, &t);
848c8b16402SStathis Kamperis if (error)
849f2df0f7cSStathis Kamperis goto error;
850c8b16402SStathis Kamperis } else
851c8b16402SStathis Kamperis t = 0;
852f2df0f7cSStathis Kamperis /* Block until queue becomes available */
853acb0b16fSStathis Kamperis error = lksleep(&mq->mq_recv_cv, &mq->mq_mtx, PCATCH, "mqrecv", t);
854f2df0f7cSStathis Kamperis if (error || (mqattr->mq_flags & MQ_UNLINK)) {
855f2df0f7cSStathis Kamperis error = (error == EWOULDBLOCK) ? ETIMEDOUT : error;
856f2df0f7cSStathis Kamperis goto error;
857f2df0f7cSStathis Kamperis }
858f2df0f7cSStathis Kamperis }
859f2df0f7cSStathis Kamperis KKASSERT(mq->mq_attrib.mq_curmsgs < mq->mq_attrib.mq_maxmsg);
860f2df0f7cSStathis Kamperis
861f2df0f7cSStathis Kamperis /*
862f2df0f7cSStathis Kamperis * Insert message into the queue, according to the priority.
863f2df0f7cSStathis Kamperis * Note the difference between index and priority.
864f2df0f7cSStathis Kamperis */
865f2df0f7cSStathis Kamperis if (__predict_true(msg_prio < MQ_PQSIZE)) {
866f2df0f7cSStathis Kamperis u_int idx = MQ_PQSIZE - msg_prio;
867f2df0f7cSStathis Kamperis
868f2df0f7cSStathis Kamperis KKASSERT(idx != MQ_PQRESQ);
869f2df0f7cSStathis Kamperis TAILQ_INSERT_TAIL(&mq->mq_head[idx], msg, msg_queue);
870f2df0f7cSStathis Kamperis mq->mq_bitmap |= (1 << --idx);
871f2df0f7cSStathis Kamperis } else {
872f2df0f7cSStathis Kamperis mqueue_linear_insert(mq, msg);
873f2df0f7cSStathis Kamperis }
874f2df0f7cSStathis Kamperis
875f2df0f7cSStathis Kamperis /* Check for the notify */
876f2df0f7cSStathis Kamperis if (mqattr->mq_curmsgs == 0 && mq->mq_notify_proc &&
877c8b16402SStathis Kamperis (mqattr->mq_flags & MQ_RECEIVE) == 0 &&
878c8b16402SStathis Kamperis mq->mq_sig_notify.sigev_notify == SIGEV_SIGNAL) {
879f2df0f7cSStathis Kamperis /* Initialize the signal */
880f2df0f7cSStathis Kamperis /*KSI_INIT(&ksi);*/
881f2df0f7cSStathis Kamperis /*ksi.ksi_signo = mq->mq_sig_notify.sigev_signo;*/
882f2df0f7cSStathis Kamperis /*ksi.ksi_code = SI_MESGQ;*/
883f2df0f7cSStathis Kamperis /*ksi.ksi_value = mq->mq_sig_notify.sigev_value;*/
884f2df0f7cSStathis Kamperis /* Unregister the process */
885f2df0f7cSStathis Kamperis notify = mq->mq_notify_proc;
886f2df0f7cSStathis Kamperis mq->mq_notify_proc = NULL;
887f2df0f7cSStathis Kamperis }
888f2df0f7cSStathis Kamperis
889f2df0f7cSStathis Kamperis /* Increment the counter and signal waiter, if any */
890f2df0f7cSStathis Kamperis mqattr->mq_curmsgs++;
891f2df0f7cSStathis Kamperis wakeup_one(&mq->mq_send_cv);
892f2df0f7cSStathis Kamperis
893f2df0f7cSStathis Kamperis /* Ready for receiving now */
8945b22f1a7SSamuel J. Greear KNOTE(&mq->mq_rkq.ki_note, 0);
895f2df0f7cSStathis Kamperis error:
896a8d3ab53SMatthew Dillon if (error) {
897f2df0f7cSStathis Kamperis lockmgr(&mq->mq_mtx, LK_RELEASE);
898f2df0f7cSStathis Kamperis fdrop(fp);
899f2df0f7cSStathis Kamperis mqueue_freemsg(msg, size);
900f2df0f7cSStathis Kamperis } else if (notify) {
901a8d3ab53SMatthew Dillon PHOLD(notify);
902a8d3ab53SMatthew Dillon lockmgr(&mq->mq_mtx, LK_RELEASE);
903a8d3ab53SMatthew Dillon fdrop(fp);
904f2df0f7cSStathis Kamperis /* Send the notify, if needed */
905f2df0f7cSStathis Kamperis /*kpsignal(notify, &ksi, NULL);*/
906f2df0f7cSStathis Kamperis ksignal(notify, mq->mq_sig_notify.sigev_signo);
907a8d3ab53SMatthew Dillon PRELE(notify);
908a8d3ab53SMatthew Dillon } else {
909a8d3ab53SMatthew Dillon lockmgr(&mq->mq_mtx, LK_RELEASE);
910a8d3ab53SMatthew Dillon fdrop(fp);
911f2df0f7cSStathis Kamperis }
912f2df0f7cSStathis Kamperis return error;
913f2df0f7cSStathis Kamperis }
914f2df0f7cSStathis Kamperis
915f2df0f7cSStathis Kamperis int
sys_mq_send(struct sysmsg * sysmsg,const struct mq_send_args * uap)91680d831e1SMatthew Dillon sys_mq_send(struct sysmsg *sysmsg, const struct mq_send_args *uap)
917f2df0f7cSStathis Kamperis {
918f2df0f7cSStathis Kamperis /* {
919f2df0f7cSStathis Kamperis syscallarg(mqd_t) mqdes;
920f2df0f7cSStathis Kamperis syscallarg(const char *) msg_ptr;
921f2df0f7cSStathis Kamperis syscallarg(size_t) msg_len;
922f2df0f7cSStathis Kamperis syscallarg(unsigned) msg_prio;
923f2df0f7cSStathis Kamperis } */
924f2df0f7cSStathis Kamperis
92503608863SSascha Wildner return mq_send1(curthread->td_lwp, uap->mqdes, uap->msg_ptr,
92603608863SSascha Wildner uap->msg_len, uap->msg_prio, 0);
927f2df0f7cSStathis Kamperis }
928f2df0f7cSStathis Kamperis
929f2df0f7cSStathis Kamperis int
sys_mq_timedsend(struct sysmsg * sysmsg,const struct mq_timedsend_args * uap)93080d831e1SMatthew Dillon sys_mq_timedsend(struct sysmsg *sysmsg, const struct mq_timedsend_args *uap)
931f2df0f7cSStathis Kamperis {
932f2df0f7cSStathis Kamperis /* {
933f2df0f7cSStathis Kamperis syscallarg(mqd_t) mqdes;
934f2df0f7cSStathis Kamperis syscallarg(const char *) msg_ptr;
935f2df0f7cSStathis Kamperis syscallarg(size_t) msg_len;
936f2df0f7cSStathis Kamperis syscallarg(unsigned) msg_prio;
937f2df0f7cSStathis Kamperis syscallarg(const struct timespec *) abs_timeout;
938f2df0f7cSStathis Kamperis } */
939f2df0f7cSStathis Kamperis struct timespec ts, *tsp;
940f2df0f7cSStathis Kamperis int error;
941f2df0f7cSStathis Kamperis
942f2df0f7cSStathis Kamperis /* Get and convert time value */
94303608863SSascha Wildner if (uap->abs_timeout) {
94403608863SSascha Wildner error = copyin(uap->abs_timeout, &ts, sizeof(ts));
945f2df0f7cSStathis Kamperis if (error)
946f2df0f7cSStathis Kamperis return error;
947f2df0f7cSStathis Kamperis tsp = &ts;
948f2df0f7cSStathis Kamperis } else {
949f2df0f7cSStathis Kamperis tsp = NULL;
950f2df0f7cSStathis Kamperis }
951f2df0f7cSStathis Kamperis
95203608863SSascha Wildner return mq_send1(curthread->td_lwp, uap->mqdes, uap->msg_ptr,
95303608863SSascha Wildner uap->msg_len, uap->msg_prio, tsp);
954f2df0f7cSStathis Kamperis }
955f2df0f7cSStathis Kamperis
956f2df0f7cSStathis Kamperis int
sys_mq_notify(struct sysmsg * sysmsg,const struct mq_notify_args * uap)95780d831e1SMatthew Dillon sys_mq_notify(struct sysmsg *sysmsg, const struct mq_notify_args *uap)
958f2df0f7cSStathis Kamperis {
959f2df0f7cSStathis Kamperis /* {
960f2df0f7cSStathis Kamperis syscallarg(mqd_t) mqdes;
961f2df0f7cSStathis Kamperis syscallarg(const struct sigevent *) notification;
962f2df0f7cSStathis Kamperis } */
963f2df0f7cSStathis Kamperis file_t *fp = NULL;
964f2df0f7cSStathis Kamperis struct mqueue *mq;
965f2df0f7cSStathis Kamperis struct sigevent sig;
966f2df0f7cSStathis Kamperis int error;
967f2df0f7cSStathis Kamperis
96803608863SSascha Wildner if (uap->notification) {
969f2df0f7cSStathis Kamperis /* Get the signal from user-space */
97003608863SSascha Wildner error = copyin(uap->notification, &sig,
971f2df0f7cSStathis Kamperis sizeof(struct sigevent));
972f2df0f7cSStathis Kamperis if (error)
973f2df0f7cSStathis Kamperis return error;
974c8b16402SStathis Kamperis if (sig.sigev_notify == SIGEV_SIGNAL &&
975c8b16402SStathis Kamperis (sig.sigev_signo <= 0 || sig.sigev_signo >= NSIG))
976c8b16402SStathis Kamperis return EINVAL;
977f2df0f7cSStathis Kamperis }
978f2df0f7cSStathis Kamperis
97903608863SSascha Wildner error = mqueue_get(curthread->td_lwp, uap->mqdes, &fp);
980f2df0f7cSStathis Kamperis if (error)
981f2df0f7cSStathis Kamperis return error;
982f2df0f7cSStathis Kamperis mq = fp->f_data;
983f2df0f7cSStathis Kamperis
98403608863SSascha Wildner if (uap->notification) {
985f2df0f7cSStathis Kamperis /* Register notification: set the signal and target process */
986f2df0f7cSStathis Kamperis if (mq->mq_notify_proc == NULL) {
987f2df0f7cSStathis Kamperis memcpy(&mq->mq_sig_notify, &sig,
988f2df0f7cSStathis Kamperis sizeof(struct sigevent));
989f2df0f7cSStathis Kamperis mq->mq_notify_proc = curproc;
990f2df0f7cSStathis Kamperis } else {
991f2df0f7cSStathis Kamperis /* Fail if someone else already registered */
992f2df0f7cSStathis Kamperis error = EBUSY;
993f2df0f7cSStathis Kamperis }
994f2df0f7cSStathis Kamperis } else {
995f2df0f7cSStathis Kamperis /* Unregister the notification */
996f2df0f7cSStathis Kamperis mq->mq_notify_proc = NULL;
997f2df0f7cSStathis Kamperis }
998f2df0f7cSStathis Kamperis lockmgr(&mq->mq_mtx, LK_RELEASE);
999f2df0f7cSStathis Kamperis fdrop(fp);
1000f2df0f7cSStathis Kamperis
1001f2df0f7cSStathis Kamperis return error;
1002f2df0f7cSStathis Kamperis }
1003f2df0f7cSStathis Kamperis
1004f2df0f7cSStathis Kamperis int
sys_mq_getattr(struct sysmsg * sysmsg,const struct mq_getattr_args * uap)100580d831e1SMatthew Dillon sys_mq_getattr(struct sysmsg *sysmsg, const struct mq_getattr_args *uap)
1006f2df0f7cSStathis Kamperis {
1007f2df0f7cSStathis Kamperis /* {
1008f2df0f7cSStathis Kamperis syscallarg(mqd_t) mqdes;
1009f2df0f7cSStathis Kamperis syscallarg(struct mq_attr *) mqstat;
1010f2df0f7cSStathis Kamperis } */
1011f2df0f7cSStathis Kamperis file_t *fp = NULL;
1012f2df0f7cSStathis Kamperis struct mqueue *mq;
1013f2df0f7cSStathis Kamperis struct mq_attr attr;
1014f2df0f7cSStathis Kamperis int error;
1015f2df0f7cSStathis Kamperis
1016f2df0f7cSStathis Kamperis /* Get the message queue */
101703608863SSascha Wildner error = mqueue_get(curthread->td_lwp, uap->mqdes, &fp);
1018f2df0f7cSStathis Kamperis if (error)
1019f2df0f7cSStathis Kamperis return error;
1020f2df0f7cSStathis Kamperis mq = fp->f_data;
1021f2df0f7cSStathis Kamperis memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr));
1022f2df0f7cSStathis Kamperis lockmgr(&mq->mq_mtx, LK_RELEASE);
1023f2df0f7cSStathis Kamperis fdrop(fp);
1024f2df0f7cSStathis Kamperis
102503608863SSascha Wildner return copyout(&attr, uap->mqstat, sizeof(struct mq_attr));
1026f2df0f7cSStathis Kamperis }
1027f2df0f7cSStathis Kamperis
1028f2df0f7cSStathis Kamperis int
sys_mq_setattr(struct sysmsg * sysmsg,const struct mq_setattr_args * uap)102980d831e1SMatthew Dillon sys_mq_setattr(struct sysmsg *sysmsg, const struct mq_setattr_args *uap)
1030f2df0f7cSStathis Kamperis {
1031f2df0f7cSStathis Kamperis /* {
1032f2df0f7cSStathis Kamperis syscallarg(mqd_t) mqdes;
1033f2df0f7cSStathis Kamperis syscallarg(const struct mq_attr *) mqstat;
1034f2df0f7cSStathis Kamperis syscallarg(struct mq_attr *) omqstat;
1035f2df0f7cSStathis Kamperis } */
1036f2df0f7cSStathis Kamperis file_t *fp = NULL;
1037f2df0f7cSStathis Kamperis struct mqueue *mq;
1038f2df0f7cSStathis Kamperis struct mq_attr attr;
1039f2df0f7cSStathis Kamperis int error, nonblock;
1040f2df0f7cSStathis Kamperis
104103608863SSascha Wildner error = copyin(uap->mqstat, &attr, sizeof(struct mq_attr));
1042f2df0f7cSStathis Kamperis if (error)
1043f2df0f7cSStathis Kamperis return error;
1044f2df0f7cSStathis Kamperis nonblock = (attr.mq_flags & O_NONBLOCK);
1045f2df0f7cSStathis Kamperis
1046f2df0f7cSStathis Kamperis /* Get the message queue */
104703608863SSascha Wildner error = mqueue_get(curthread->td_lwp, uap->mqdes, &fp);
1048f2df0f7cSStathis Kamperis if (error)
1049f2df0f7cSStathis Kamperis return error;
1050f2df0f7cSStathis Kamperis mq = fp->f_data;
1051f2df0f7cSStathis Kamperis
1052f2df0f7cSStathis Kamperis /* Copy the old attributes, if needed */
105303608863SSascha Wildner if (uap->omqstat) {
1054f2df0f7cSStathis Kamperis memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr));
1055d1d64679SStathis Kamperis }
1056f2df0f7cSStathis Kamperis
1057f2df0f7cSStathis Kamperis /* Ignore everything, except O_NONBLOCK */
1058f2df0f7cSStathis Kamperis if (nonblock)
1059f2df0f7cSStathis Kamperis mq->mq_attrib.mq_flags |= O_NONBLOCK;
1060f2df0f7cSStathis Kamperis else
1061f2df0f7cSStathis Kamperis mq->mq_attrib.mq_flags &= ~O_NONBLOCK;
1062f2df0f7cSStathis Kamperis
1063f2df0f7cSStathis Kamperis lockmgr(&mq->mq_mtx, LK_RELEASE);
1064f2df0f7cSStathis Kamperis fdrop(fp);
1065f2df0f7cSStathis Kamperis
1066f2df0f7cSStathis Kamperis /*
1067f2df0f7cSStathis Kamperis * Copy the data to the user-space.
1068f2df0f7cSStathis Kamperis * Note: According to POSIX, the new attributes should not be set in
1069f2df0f7cSStathis Kamperis * case of fail - this would be violated.
1070f2df0f7cSStathis Kamperis */
107103608863SSascha Wildner if (uap->omqstat)
107203608863SSascha Wildner error = copyout(&attr, uap->omqstat, sizeof(struct mq_attr));
1073f2df0f7cSStathis Kamperis
1074f2df0f7cSStathis Kamperis return error;
1075f2df0f7cSStathis Kamperis }
1076f2df0f7cSStathis Kamperis
1077f2df0f7cSStathis Kamperis int
sys_mq_unlink(struct sysmsg * sysmsg,const struct mq_unlink_args * uap)107880d831e1SMatthew Dillon sys_mq_unlink(struct sysmsg *sysmsg, const struct mq_unlink_args *uap)
1079f2df0f7cSStathis Kamperis {
1080f2df0f7cSStathis Kamperis /* {
1081f2df0f7cSStathis Kamperis syscallarg(const char *) name;
1082f2df0f7cSStathis Kamperis } */
10839910d07bSMatthew Dillon struct thread *td = curthread;
1084f2df0f7cSStathis Kamperis struct mqueue *mq;
1085f2df0f7cSStathis Kamperis char *name;
1086f2df0f7cSStathis Kamperis int error, refcnt = 0;
1087f2df0f7cSStathis Kamperis
1088f2df0f7cSStathis Kamperis /* Get the name from the user-space */
1089d3a2b23dSVenkatesh Srinivas name = kmalloc(MQ_NAMELEN, M_MQBUF, M_WAITOK | M_ZERO | M_NULLOK);
1090d3a2b23dSVenkatesh Srinivas if (name == NULL)
1091d3a2b23dSVenkatesh Srinivas return (ENOMEM);
109203608863SSascha Wildner error = copyinstr(uap->name, name, MQ_NAMELEN - 1, NULL);
1093f2df0f7cSStathis Kamperis if (error) {
1094f2df0f7cSStathis Kamperis kfree(name, M_MQBUF);
1095f2df0f7cSStathis Kamperis return error;
1096f2df0f7cSStathis Kamperis }
1097f2df0f7cSStathis Kamperis
1098f2df0f7cSStathis Kamperis /* Lookup for this file */
1099f2df0f7cSStathis Kamperis lockmgr(&mqlist_mtx, LK_EXCLUSIVE);
1100f2df0f7cSStathis Kamperis mq = mqueue_lookup(name);
1101f2df0f7cSStathis Kamperis if (mq == NULL) {
1102f2df0f7cSStathis Kamperis error = ENOENT;
1103f2df0f7cSStathis Kamperis goto error;
1104f2df0f7cSStathis Kamperis }
1105f2df0f7cSStathis Kamperis
1106f2df0f7cSStathis Kamperis /* Check the permissions */
11079910d07bSMatthew Dillon if (td->td_ucred->cr_uid != mq->mq_euid &&
11082b3f93eaSMatthew Dillon caps_priv_check_td(td, SYSCAP_RESTRICTEDROOT) != 0)
11092b3f93eaSMatthew Dillon {
1110f2df0f7cSStathis Kamperis lockmgr(&mq->mq_mtx, LK_RELEASE);
1111f2df0f7cSStathis Kamperis error = EACCES;
1112f2df0f7cSStathis Kamperis goto error;
1113f2df0f7cSStathis Kamperis }
1114f2df0f7cSStathis Kamperis
1115f2df0f7cSStathis Kamperis /* Mark message queue as unlinking, before leaving the window */
1116f2df0f7cSStathis Kamperis mq->mq_attrib.mq_flags |= MQ_UNLINK;
1117f2df0f7cSStathis Kamperis
1118f2df0f7cSStathis Kamperis /* Wake up all waiters, if there are such */
1119f2df0f7cSStathis Kamperis wakeup(&mq->mq_send_cv);
1120f2df0f7cSStathis Kamperis wakeup(&mq->mq_recv_cv);
1121f2df0f7cSStathis Kamperis
11225b22f1a7SSamuel J. Greear KNOTE(&mq->mq_rkq.ki_note, 0);
11235b22f1a7SSamuel J. Greear KNOTE(&mq->mq_wkq.ki_note, 0);
1124f2df0f7cSStathis Kamperis
1125f2df0f7cSStathis Kamperis refcnt = mq->mq_refcnt;
1126f2df0f7cSStathis Kamperis if (refcnt == 0)
1127f2df0f7cSStathis Kamperis LIST_REMOVE(mq, mq_list);
1128f2df0f7cSStathis Kamperis
1129f2df0f7cSStathis Kamperis lockmgr(&mq->mq_mtx, LK_RELEASE);
1130f2df0f7cSStathis Kamperis error:
1131f2df0f7cSStathis Kamperis lockmgr(&mqlist_mtx, LK_RELEASE);
1132f2df0f7cSStathis Kamperis
1133f2df0f7cSStathis Kamperis /*
1134f2df0f7cSStathis Kamperis * If there are no references - destroy the message
1135f2df0f7cSStathis Kamperis * queue, otherwise, the last mq_close() will do that.
1136f2df0f7cSStathis Kamperis */
1137f2df0f7cSStathis Kamperis if (error == 0 && refcnt == 0)
1138f2df0f7cSStathis Kamperis mqueue_destroy(mq);
1139f2df0f7cSStathis Kamperis
1140f2df0f7cSStathis Kamperis kfree(name, M_MQBUF);
1141f2df0f7cSStathis Kamperis return error;
1142f2df0f7cSStathis Kamperis }
1143f2df0f7cSStathis Kamperis
1144f2df0f7cSStathis Kamperis /*
1145f2df0f7cSStathis Kamperis * SysCtl.
1146f2df0f7cSStathis Kamperis */
1147f2df0f7cSStathis Kamperis SYSCTL_NODE(_kern, OID_AUTO, mqueue,
1148f2df0f7cSStathis Kamperis CTLFLAG_RW, 0, "Message queue options");
1149f2df0f7cSStathis Kamperis
1150f2df0f7cSStathis Kamperis SYSCTL_INT(_kern_mqueue, OID_AUTO, mq_open_max,
1151f2df0f7cSStathis Kamperis CTLFLAG_RW, &mq_open_max, 0,
1152f2df0f7cSStathis Kamperis "Maximal number of message queue descriptors per process");
1153f2df0f7cSStathis Kamperis
1154f2df0f7cSStathis Kamperis SYSCTL_INT(_kern_mqueue, OID_AUTO, mq_prio_max,
1155f2df0f7cSStathis Kamperis CTLFLAG_RW, &mq_prio_max, 0,
1156f2df0f7cSStathis Kamperis "Maximal priority of the message");
1157f2df0f7cSStathis Kamperis
1158f2df0f7cSStathis Kamperis SYSCTL_INT(_kern_mqueue, OID_AUTO, mq_max_msgsize,
1159f2df0f7cSStathis Kamperis CTLFLAG_RW, &mq_max_msgsize, 0,
1160f2df0f7cSStathis Kamperis "Maximal allowed size of the message");
1161f2df0f7cSStathis Kamperis
1162f2df0f7cSStathis Kamperis SYSCTL_INT(_kern_mqueue, OID_AUTO, mq_def_maxmsg,
1163f2df0f7cSStathis Kamperis CTLFLAG_RW, &mq_def_maxmsg, 0,
1164f2df0f7cSStathis Kamperis "Default maximal message count");
1165f2df0f7cSStathis Kamperis
11668658b626SStathis Kamperis SYSCTL_INT(_kern_mqueue, OID_AUTO, mq_max_maxmsg,
11678658b626SStathis Kamperis CTLFLAG_RW, &mq_max_maxmsg, 0,
11688658b626SStathis Kamperis "Maximal allowed message count");
11698658b626SStathis Kamperis
1170f2df0f7cSStathis Kamperis SYSINIT(sys_mqueue_init, SI_SUB_PRE_DRIVERS, SI_ORDER_ANY, mqueue_sysinit, NULL);
1171