Wed May 27 21:33:50 2009 UTC ()
Pull up following revision(s) (requested by rmind in ticket #779):
	sys/kern/sys_mqueue.c: revision 1.18
- Slightly rework the way permissions are checked. Neither mq_receive() not
  mq_send() should fail due to permissions.  Noted by Stathis Kamperis!
- Check for empty message queue name (POSIX does not allow this for regular
  files, and it's weird), check for DTYPE_MQUEUE, fix permission check in
  mq_unlink(), clean up.


(snj)
diff -r1.12.4.1.2.1 -r1.12.4.1.2.2 src/sys/kern/sys_mqueue.c

cvs diff -r1.12.4.1.2.1 -r1.12.4.1.2.2 src/sys/kern/sys_mqueue.c (switch to unified diff)

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