sys_mqueue.c revision 1.30.2.1 1 /* $NetBSD: sys_mqueue.c,v 1.30.2.1 2011/06/06 09:09:36 jruoho Exp $ */
2
3 /*
4 * Copyright (c) 2007-2011 Mindaugas Rasiukevicius <rmind at NetBSD org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
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
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
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
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
26 * SUCH DAMAGE.
27 */
28
29 /*
30 * Implementation of POSIX message queues.
31 * Defined in the Base Definitions volume of IEEE Std 1003.1-2001.
32 *
33 * Locking
34 *
35 * Global list of message queues (mqueue_head) is protected by mqlist_lock.
36 * Each message queue and its members are protected by mqueue::mq_mtx.
37 * Note that proc_t::p_mqueue_cnt is updated atomically.
38 *
39 * Lock order:
40 *
41 * mqlist_lock ->
42 * mqueue::mq_mtx
43 */
44
45 #include <sys/cdefs.h>
46 __KERNEL_RCSID(0, "$NetBSD: sys_mqueue.c,v 1.30.2.1 2011/06/06 09:09:36 jruoho Exp $");
47
48 #include <sys/param.h>
49 #include <sys/types.h>
50 #include <sys/atomic.h>
51
52 #include <sys/file.h>
53 #include <sys/filedesc.h>
54 #include <sys/kauth.h>
55 #include <sys/lwp.h>
56 #include <sys/mqueue.h>
57 #include <sys/module.h>
58 #include <sys/poll.h>
59 #include <sys/select.h>
60 #include <sys/signal.h>
61 #include <sys/signalvar.h>
62 #include <sys/stat.h>
63 #include <sys/sysctl.h>
64 #include <sys/syscall.h>
65 #include <sys/syscallvar.h>
66 #include <sys/syscallargs.h>
67
68 #include <miscfs/genfs/genfs.h>
69
70 MODULE(MODULE_CLASS_MISC, mqueue, NULL);
71
72 /* System-wide limits. */
73 static u_int mq_open_max = MQ_OPEN_MAX;
74 static u_int mq_prio_max = MQ_PRIO_MAX;
75 static u_int mq_max_msgsize = 16 * MQ_DEF_MSGSIZE;
76 static u_int mq_def_maxmsg = 32;
77 static u_int mq_max_maxmsg = 16 * 32;
78
79 static pool_cache_t mqmsg_cache __read_mostly;
80 static kmutex_t mqlist_lock __cacheline_aligned;
81 static LIST_HEAD(, mqueue) mqueue_head __cacheline_aligned;
82 static struct sysctllog * mqsysctl_log;
83
84 static int mqueue_sysinit(void);
85 static int mqueue_sysfini(bool);
86 static int mqueue_sysctl_init(void);
87 static int mq_poll_fop(file_t *, int);
88 static int mq_stat_fop(file_t *, struct stat *);
89 static int mq_close_fop(file_t *);
90
91 static const struct fileops mqops = {
92 .fo_read = fbadop_read,
93 .fo_write = fbadop_write,
94 .fo_ioctl = fbadop_ioctl,
95 .fo_fcntl = fnullop_fcntl,
96 .fo_poll = mq_poll_fop,
97 .fo_stat = mq_stat_fop,
98 .fo_close = mq_close_fop,
99 .fo_kqfilter = fnullop_kqfilter,
100 .fo_restart = fnullop_restart,
101 };
102
103 static const struct syscall_package mqueue_syscalls[] = {
104 { SYS_mq_open, 0, (sy_call_t *)sys_mq_open },
105 { SYS_mq_close, 0, (sy_call_t *)sys_mq_close },
106 { SYS_mq_unlink, 0, (sy_call_t *)sys_mq_unlink },
107 { SYS_mq_getattr, 0, (sy_call_t *)sys_mq_getattr },
108 { SYS_mq_setattr, 0, (sy_call_t *)sys_mq_setattr },
109 { SYS_mq_notify, 0, (sy_call_t *)sys_mq_notify },
110 { SYS_mq_send, 0, (sy_call_t *)sys_mq_send },
111 { SYS_mq_receive, 0, (sy_call_t *)sys_mq_receive },
112 { SYS___mq_timedsend50, 0, (sy_call_t *)sys___mq_timedsend50 },
113 { SYS___mq_timedreceive50, 0, (sy_call_t *)sys___mq_timedreceive50 },
114 { 0, 0, NULL }
115 };
116
117 /*
118 * Initialisation and unloading of POSIX message queue subsystem.
119 */
120
121 static int
122 mqueue_sysinit(void)
123 {
124 int error;
125
126 mqmsg_cache = pool_cache_init(MQ_DEF_MSGSIZE, coherency_unit,
127 0, 0, "mqmsgpl", NULL, IPL_NONE, NULL, NULL, NULL);
128 mutex_init(&mqlist_lock, MUTEX_DEFAULT, IPL_NONE);
129 LIST_INIT(&mqueue_head);
130
131 error = mqueue_sysctl_init();
132 if (error) {
133 (void)mqueue_sysfini(false);
134 return error;
135 }
136 error = syscall_establish(NULL, mqueue_syscalls);
137 if (error) {
138 (void)mqueue_sysfini(false);
139 }
140 return error;
141 }
142
143 static int
144 mqueue_sysfini(bool interface)
145 {
146
147 if (interface) {
148 int error;
149 bool inuse;
150
151 /* Stop syscall activity. */
152 error = syscall_disestablish(NULL, mqueue_syscalls);
153 if (error)
154 return error;
155 /* Check if there are any message queues in use. */
156 mutex_enter(&mqlist_lock);
157 inuse = !LIST_EMPTY(&mqueue_head);
158 mutex_exit(&mqlist_lock);
159 if (inuse) {
160 error = syscall_establish(NULL, mqueue_syscalls);
161 KASSERT(error == 0);
162 return EBUSY;
163 }
164 }
165
166 if (mqsysctl_log != NULL)
167 sysctl_teardown(&mqsysctl_log);
168
169 mutex_destroy(&mqlist_lock);
170 pool_cache_destroy(mqmsg_cache);
171 return 0;
172 }
173
174 /*
175 * Module interface.
176 */
177 static int
178 mqueue_modcmd(modcmd_t cmd, void *arg)
179 {
180
181 switch (cmd) {
182 case MODULE_CMD_INIT:
183 return mqueue_sysinit();
184 case MODULE_CMD_FINI:
185 return mqueue_sysfini(true);
186 default:
187 return ENOTTY;
188 }
189 }
190
191 /*
192 * Free the message.
193 */
194 static void
195 mqueue_freemsg(struct mq_msg *msg, const size_t size)
196 {
197
198 if (size > MQ_DEF_MSGSIZE) {
199 kmem_free(msg, size);
200 } else {
201 pool_cache_put(mqmsg_cache, msg);
202 }
203 }
204
205 /*
206 * Destroy the message queue.
207 */
208 static void
209 mqueue_destroy(struct mqueue *mq)
210 {
211 struct mq_msg *msg;
212 size_t msz;
213 u_int i;
214
215 /* Note MQ_PQSIZE + 1. */
216 for (i = 0; i <= MQ_PQSIZE; i++) {
217 while ((msg = TAILQ_FIRST(&mq->mq_head[i])) != NULL) {
218 TAILQ_REMOVE(&mq->mq_head[i], msg, msg_queue);
219 msz = sizeof(struct mq_msg) + msg->msg_len;
220 mqueue_freemsg(msg, msz);
221 }
222 }
223 if (mq->mq_name) {
224 kmem_free(mq->mq_name, MQ_NAMELEN);
225 }
226 seldestroy(&mq->mq_rsel);
227 seldestroy(&mq->mq_wsel);
228 cv_destroy(&mq->mq_send_cv);
229 cv_destroy(&mq->mq_recv_cv);
230 mutex_destroy(&mq->mq_mtx);
231 kmem_free(mq, sizeof(struct mqueue));
232 }
233
234 /*
235 * mqueue_lookup: lookup for file name in general list of message queues.
236 *
237 * => locks the message queue on success
238 */
239 static mqueue_t *
240 mqueue_lookup(const char *name)
241 {
242 mqueue_t *mq;
243
244 KASSERT(mutex_owned(&mqlist_lock));
245
246 LIST_FOREACH(mq, &mqueue_head, mq_list) {
247 if (strncmp(mq->mq_name, name, MQ_NAMELEN) == 0) {
248 mutex_enter(&mq->mq_mtx);
249 return mq;
250 }
251 }
252 return NULL;
253 }
254
255 /*
256 * mqueue_get: get the mqueue from the descriptor.
257 *
258 * => locks the message queue, if found.
259 * => holds a reference on the file descriptor.
260 */
261 static int
262 mqueue_get(mqd_t mqd, int fflag, mqueue_t **mqret)
263 {
264 const int fd = (int)mqd;
265 mqueue_t *mq;
266 file_t *fp;
267
268 fp = fd_getfile(fd);
269 if (__predict_false(fp == NULL)) {
270 return EBADF;
271 }
272 if (__predict_false(fp->f_type != DTYPE_MQUEUE)) {
273 fd_putfile(fd);
274 return EBADF;
275 }
276 if (fflag && (fp->f_flag & fflag) == 0) {
277 fd_putfile(fd);
278 return EBADF;
279 }
280 mq = fp->f_data;
281 mutex_enter(&mq->mq_mtx);
282
283 *mqret = mq;
284 return 0;
285 }
286
287 /*
288 * mqueue_linear_insert: perform linear insert according to the message
289 * priority into the reserved queue (MQ_PQRESQ). Reserved queue is a
290 * sorted list used only when mq_prio_max is increased via sysctl.
291 */
292 static inline void
293 mqueue_linear_insert(struct mqueue *mq, struct mq_msg *msg)
294 {
295 struct mq_msg *mit;
296
297 TAILQ_FOREACH(mit, &mq->mq_head[MQ_PQRESQ], msg_queue) {
298 if (msg->msg_prio > mit->msg_prio)
299 break;
300 }
301 if (mit == NULL) {
302 TAILQ_INSERT_TAIL(&mq->mq_head[MQ_PQRESQ], msg, msg_queue);
303 } else {
304 TAILQ_INSERT_BEFORE(mit, msg, msg_queue);
305 }
306 }
307
308 static int
309 mq_stat_fop(file_t *fp, struct stat *st)
310 {
311 struct mqueue *mq = fp->f_data;
312
313 memset(st, 0, sizeof(*st));
314
315 mutex_enter(&mq->mq_mtx);
316 st->st_mode = mq->mq_mode;
317 st->st_uid = mq->mq_euid;
318 st->st_gid = mq->mq_egid;
319 st->st_atimespec = mq->mq_atime;
320 st->st_mtimespec = mq->mq_mtime;
321 st->st_ctimespec = st->st_birthtimespec = mq->mq_btime;
322 st->st_uid = kauth_cred_geteuid(fp->f_cred);
323 st->st_gid = kauth_cred_getegid(fp->f_cred);
324 mutex_exit(&mq->mq_mtx);
325
326 return 0;
327 }
328
329 static int
330 mq_poll_fop(file_t *fp, int events)
331 {
332 struct mqueue *mq = fp->f_data;
333 struct mq_attr *mqattr;
334 int revents = 0;
335
336 mutex_enter(&mq->mq_mtx);
337 mqattr = &mq->mq_attrib;
338 if (events & (POLLIN | POLLRDNORM)) {
339 /* Ready for receiving, if there are messages in the queue. */
340 if (mqattr->mq_curmsgs)
341 revents |= events & (POLLIN | POLLRDNORM);
342 else
343 selrecord(curlwp, &mq->mq_rsel);
344 }
345 if (events & (POLLOUT | POLLWRNORM)) {
346 /* Ready for sending, if the message queue is not full. */
347 if (mqattr->mq_curmsgs < mqattr->mq_maxmsg)
348 revents |= events & (POLLOUT | POLLWRNORM);
349 else
350 selrecord(curlwp, &mq->mq_wsel);
351 }
352 mutex_exit(&mq->mq_mtx);
353
354 return revents;
355 }
356
357 static int
358 mq_close_fop(file_t *fp)
359 {
360 proc_t *p = curproc;
361 mqueue_t *mq = fp->f_data;
362 bool destroy = false;
363
364 mutex_enter(&mq->mq_mtx);
365 KASSERT(mq->mq_refcnt > 0);
366 if (--mq->mq_refcnt == 0) {
367 /* Destroy if the last reference and unlinked. */
368 destroy = (mq->mq_attrib.mq_flags & MQ_UNLINKED) != 0;
369 }
370 mutex_exit(&mq->mq_mtx);
371
372 if (destroy) {
373 mqueue_destroy(mq);
374 }
375 atomic_dec_uint(&p->p_mqueue_cnt);
376 return 0;
377 }
378
379 static int
380 mqueue_access(mqueue_t *mq, int access, kauth_cred_t cred)
381 {
382 mode_t acc_mode = 0;
383
384 /* Note the difference between VREAD/VWRITE and FREAD/FWRITE. */
385 if (access & FREAD) {
386 acc_mode |= VREAD;
387 }
388 if (access & FWRITE) {
389 acc_mode |= VWRITE;
390 }
391 if (genfs_can_access(VNON, mq->mq_mode, mq->mq_euid,
392 mq->mq_egid, acc_mode, cred)) {
393 return EACCES;
394 }
395 return 0;
396 }
397
398 static int
399 mqueue_create(lwp_t *l, char *name, struct mq_attr *uattr, mode_t mode,
400 int oflag, mqueue_t **mqret)
401 {
402 proc_t *p = l->l_proc;
403 struct cwdinfo *cwdi = p->p_cwdi;
404 mqueue_t *mq;
405 struct mq_attr attr;
406 u_int i;
407
408 /* Pre-check the limit. */
409 if (p->p_mqueue_cnt >= mq_open_max) {
410 return EMFILE;
411 }
412
413 /* Empty name is invalid. */
414 if (name[0] == '\0') {
415 return EINVAL;
416 }
417
418 /* Check for mqueue attributes. */
419 if (uattr) {
420 int error;
421
422 error = copyin(uattr, &attr, sizeof(struct mq_attr));
423 if (error) {
424 return error;
425 }
426 if (attr.mq_maxmsg <= 0 || attr.mq_maxmsg > mq_max_maxmsg ||
427 attr.mq_msgsize <= 0 || attr.mq_msgsize > mq_max_msgsize) {
428 return EINVAL;
429 }
430 attr.mq_curmsgs = 0;
431 } else {
432 memset(&attr, 0, sizeof(struct mq_attr));
433 attr.mq_maxmsg = mq_def_maxmsg;
434 attr.mq_msgsize = MQ_DEF_MSGSIZE - sizeof(struct mq_msg);
435 }
436
437 /*
438 * Allocate new message queue, initialize data structures, copy the
439 * name attributes. Note that the initial reference is set here.
440 */
441 mq = kmem_zalloc(sizeof(mqueue_t), KM_SLEEP);
442
443 mutex_init(&mq->mq_mtx, MUTEX_DEFAULT, IPL_NONE);
444 cv_init(&mq->mq_send_cv, "mqsendcv");
445 cv_init(&mq->mq_recv_cv, "mqrecvcv");
446 for (i = 0; i < (MQ_PQSIZE + 1); i++) {
447 TAILQ_INIT(&mq->mq_head[i]);
448 }
449 selinit(&mq->mq_rsel);
450 selinit(&mq->mq_wsel);
451 mq->mq_name = name;
452 mq->mq_refcnt = 1;
453
454 memcpy(&mq->mq_attrib, &attr, sizeof(struct mq_attr));
455
456 CTASSERT((O_MASK & (MQ_UNLINKED | MQ_RECEIVE)) == 0);
457 mq->mq_attrib.mq_flags = (O_MASK & oflag);
458
459 /* Store mode and effective UID with GID. */
460 mq->mq_mode = ((mode & ~cwdi->cwdi_cmask) & ALLPERMS) & ~S_ISTXT;
461 mq->mq_euid = kauth_cred_geteuid(l->l_cred);
462 mq->mq_egid = kauth_cred_getegid(l->l_cred);
463
464 *mqret = mq;
465 return 0;
466 }
467
468 /*
469 * General mqueue system calls.
470 */
471
472 int
473 sys_mq_open(struct lwp *l, const struct sys_mq_open_args *uap,
474 register_t *retval)
475 {
476 /* {
477 syscallarg(const char *) name;
478 syscallarg(int) oflag;
479 syscallarg(mode_t) mode;
480 syscallarg(struct mq_attr) attr;
481 } */
482 struct proc *p = l->l_proc;
483 struct mqueue *mq, *mq_new = NULL;
484 int mqd, error, oflag = SCARG(uap, oflag);
485 file_t *fp;
486 char *name;
487
488 /* Get the name from the user-space. */
489 name = kmem_alloc(MQ_NAMELEN, KM_SLEEP);
490 error = copyinstr(SCARG(uap, name), name, MQ_NAMELEN - 1, NULL);
491 if (error) {
492 kmem_free(name, MQ_NAMELEN);
493 return error;
494 }
495
496 /* Allocate file structure and descriptor. */
497 error = fd_allocfile(&fp, &mqd);
498 if (error) {
499 kmem_free(name, MQ_NAMELEN);
500 return error;
501 }
502 fp->f_type = DTYPE_MQUEUE;
503 fp->f_flag = FFLAGS(oflag) & (FREAD | FWRITE);
504 fp->f_ops = &mqops;
505
506 if (oflag & O_CREAT) {
507 /* Create a new message queue. */
508 error = mqueue_create(l, name, SCARG(uap, attr),
509 SCARG(uap, mode), oflag, &mq_new);
510 if (error) {
511 goto err;
512 }
513 KASSERT(mq_new != NULL);
514 }
515
516 /* Lookup for a message queue with such name. */
517 mutex_enter(&mqlist_lock);
518 mq = mqueue_lookup(name);
519 if (mq) {
520 KASSERT(mutex_owned(&mq->mq_mtx));
521 mutex_exit(&mqlist_lock);
522
523 /* Check for exclusive create. */
524 if (oflag & O_EXCL) {
525 mutex_exit(&mq->mq_mtx);
526 error = EEXIST;
527 goto err;
528 }
529
530 /* Verify permissions. */
531 if (mqueue_access(mq, fp->f_flag, l->l_cred) != 0) {
532 mutex_exit(&mq->mq_mtx);
533 error = EACCES;
534 goto err;
535 }
536
537 /* If we have the access, add a new reference. */
538 mq->mq_refcnt++;
539 mutex_exit(&mq->mq_mtx);
540 } else {
541 /* Fail if not found and not creating. */
542 if ((oflag & O_CREAT) == 0) {
543 mutex_exit(&mqlist_lock);
544 KASSERT(mq_new == NULL);
545 error = ENOENT;
546 goto err;
547 }
548
549 /* Account and check for the limit. */
550 if (atomic_inc_uint_nv(&p->p_mqueue_cnt) > mq_open_max) {
551 mutex_exit(&mqlist_lock);
552 atomic_dec_uint(&p->p_mqueue_cnt);
553 error = EMFILE;
554 goto err;
555 }
556
557 /* Initial timestamps. */
558 mq = mq_new;
559 getnanotime(&mq->mq_btime);
560 mq->mq_atime = mq->mq_mtime = mq->mq_btime;
561
562 /*
563 * Finally, insert message queue into the list.
564 * Note: it already has the initial reference.
565 */
566 LIST_INSERT_HEAD(&mqueue_head, mq, mq_list);
567 mutex_exit(&mqlist_lock);
568
569 mq_new = NULL;
570 name = NULL;
571 }
572 KASSERT(mq != NULL);
573 fp->f_data = mq;
574 fd_affix(p, fp, mqd);
575 *retval = mqd;
576 err:
577 if (error) {
578 fd_abort(p, fp, mqd);
579 }
580 if (mq_new) {
581 /* Note: will free the 'name'. */
582 mqueue_destroy(mq_new);
583 } else if (name) {
584 kmem_free(name, MQ_NAMELEN);
585 }
586 return error;
587 }
588
589 int
590 sys_mq_close(struct lwp *l, const struct sys_mq_close_args *uap,
591 register_t *retval)
592 {
593
594 return sys_close(l, (const void *)uap, retval);
595 }
596
597 /*
598 * Primary mq_recv1() function.
599 */
600 int
601 mq_recv1(mqd_t mqdes, void *msg_ptr, size_t msg_len, u_int *msg_prio,
602 struct timespec *ts, ssize_t *mlen)
603 {
604 struct mqueue *mq;
605 struct mq_msg *msg = NULL;
606 struct mq_attr *mqattr;
607 u_int idx;
608 int error;
609
610 error = mqueue_get(mqdes, FREAD, &mq);
611 if (error) {
612 return error;
613 }
614 getnanotime(&mq->mq_atime);
615 mqattr = &mq->mq_attrib;
616
617 /* Check the message size limits */
618 if (msg_len < mqattr->mq_msgsize) {
619 error = EMSGSIZE;
620 goto error;
621 }
622
623 /* Check if queue is empty */
624 while (mqattr->mq_curmsgs == 0) {
625 int t;
626
627 if (mqattr->mq_flags & O_NONBLOCK) {
628 error = EAGAIN;
629 goto error;
630 }
631 if (ts) {
632 error = abstimeout2timo(ts, &t);
633 if (error)
634 goto error;
635 } else
636 t = 0;
637 /*
638 * Block until someone sends the message.
639 * While doing this, notification should not be sent.
640 */
641 mqattr->mq_flags |= MQ_RECEIVE;
642 error = cv_timedwait_sig(&mq->mq_send_cv, &mq->mq_mtx, t);
643 mqattr->mq_flags &= ~MQ_RECEIVE;
644 if (error || (mqattr->mq_flags & MQ_UNLINKED)) {
645 error = (error == EWOULDBLOCK) ? ETIMEDOUT : EINTR;
646 goto error;
647 }
648 }
649
650 /*
651 * Find the highest priority message, and remove it from the queue.
652 * At first, reserved queue is checked, bitmap is next.
653 */
654 msg = TAILQ_FIRST(&mq->mq_head[MQ_PQRESQ]);
655 if (__predict_true(msg == NULL)) {
656 idx = ffs(mq->mq_bitmap);
657 msg = TAILQ_FIRST(&mq->mq_head[idx]);
658 KASSERT(msg != NULL);
659 } else {
660 idx = MQ_PQRESQ;
661 }
662 TAILQ_REMOVE(&mq->mq_head[idx], msg, msg_queue);
663
664 /* Unmark the bit, if last message. */
665 if (__predict_true(idx) && TAILQ_EMPTY(&mq->mq_head[idx])) {
666 KASSERT((MQ_PQSIZE - idx) == msg->msg_prio);
667 mq->mq_bitmap &= ~(1 << --idx);
668 }
669
670 /* Decrement the counter and signal waiter, if any */
671 mqattr->mq_curmsgs--;
672 cv_signal(&mq->mq_recv_cv);
673
674 /* Ready for sending now */
675 selnotify(&mq->mq_wsel, POLLOUT | POLLWRNORM, 0);
676 error:
677 mutex_exit(&mq->mq_mtx);
678 fd_putfile((int)mqdes);
679 if (error)
680 return error;
681
682 /*
683 * Copy the data to the user-space.
684 * Note: According to POSIX, no message should be removed from the
685 * queue in case of fail - this would be violated.
686 */
687 *mlen = msg->msg_len;
688 error = copyout(msg->msg_ptr, msg_ptr, msg->msg_len);
689 if (error == 0 && msg_prio)
690 error = copyout(&msg->msg_prio, msg_prio, sizeof(unsigned));
691 mqueue_freemsg(msg, sizeof(struct mq_msg) + msg->msg_len);
692
693 return error;
694 }
695
696 int
697 sys_mq_receive(struct lwp *l, const struct sys_mq_receive_args *uap,
698 register_t *retval)
699 {
700 /* {
701 syscallarg(mqd_t) mqdes;
702 syscallarg(char *) msg_ptr;
703 syscallarg(size_t) msg_len;
704 syscallarg(unsigned *) msg_prio;
705 } */
706 ssize_t mlen;
707 int error;
708
709 error = mq_recv1(SCARG(uap, mqdes), SCARG(uap, msg_ptr),
710 SCARG(uap, msg_len), SCARG(uap, msg_prio), NULL, &mlen);
711 if (error == 0)
712 *retval = mlen;
713
714 return error;
715 }
716
717 int
718 sys___mq_timedreceive50(struct lwp *l,
719 const struct sys___mq_timedreceive50_args *uap, register_t *retval)
720 {
721 /* {
722 syscallarg(mqd_t) mqdes;
723 syscallarg(char *) msg_ptr;
724 syscallarg(size_t) msg_len;
725 syscallarg(unsigned *) msg_prio;
726 syscallarg(const struct timespec *) abs_timeout;
727 } */
728 struct timespec ts, *tsp;
729 ssize_t mlen;
730 int error;
731
732 /* Get and convert time value */
733 if (SCARG(uap, abs_timeout)) {
734 error = copyin(SCARG(uap, abs_timeout), &ts, sizeof(ts));
735 if (error)
736 return error;
737 tsp = &ts;
738 } else {
739 tsp = NULL;
740 }
741
742 error = mq_recv1(SCARG(uap, mqdes), SCARG(uap, msg_ptr),
743 SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp, &mlen);
744 if (error == 0)
745 *retval = mlen;
746
747 return error;
748 }
749
750 /*
751 * Primary mq_send1() function.
752 */
753 int
754 mq_send1(mqd_t mqdes, const char *msg_ptr, size_t msg_len, u_int msg_prio,
755 struct timespec *ts)
756 {
757 struct mqueue *mq;
758 struct mq_msg *msg;
759 struct mq_attr *mqattr;
760 struct proc *notify = NULL;
761 ksiginfo_t ksi;
762 size_t size;
763 int error;
764
765 /* Check the priority range */
766 if (msg_prio >= mq_prio_max)
767 return EINVAL;
768
769 /* Allocate a new message */
770 size = sizeof(struct mq_msg) + msg_len;
771 if (size > mq_max_msgsize)
772 return EMSGSIZE;
773
774 if (size > MQ_DEF_MSGSIZE) {
775 msg = kmem_alloc(size, KM_SLEEP);
776 } else {
777 msg = pool_cache_get(mqmsg_cache, PR_WAITOK);
778 }
779
780 /* Get the data from user-space */
781 error = copyin(msg_ptr, msg->msg_ptr, msg_len);
782 if (error) {
783 mqueue_freemsg(msg, size);
784 return error;
785 }
786 msg->msg_len = msg_len;
787 msg->msg_prio = msg_prio;
788
789 error = mqueue_get(mqdes, FWRITE, &mq);
790 if (error) {
791 mqueue_freemsg(msg, size);
792 return error;
793 }
794 getnanotime(&mq->mq_mtime);
795 mqattr = &mq->mq_attrib;
796
797 /* Check the message size limit */
798 if (msg_len <= 0 || msg_len > mqattr->mq_msgsize) {
799 error = EMSGSIZE;
800 goto error;
801 }
802
803 /* Check if queue is full */
804 while (mqattr->mq_curmsgs >= mqattr->mq_maxmsg) {
805 int t;
806
807 if (mqattr->mq_flags & O_NONBLOCK) {
808 error = EAGAIN;
809 goto error;
810 }
811 if (ts) {
812 error = abstimeout2timo(ts, &t);
813 if (error)
814 goto error;
815 } else
816 t = 0;
817 /* Block until queue becomes available */
818 error = cv_timedwait_sig(&mq->mq_recv_cv, &mq->mq_mtx, t);
819 if (error || (mqattr->mq_flags & MQ_UNLINKED)) {
820 error = (error == EWOULDBLOCK) ? ETIMEDOUT : error;
821 goto error;
822 }
823 }
824 KASSERT(mqattr->mq_curmsgs < mqattr->mq_maxmsg);
825
826 /*
827 * Insert message into the queue, according to the priority.
828 * Note the difference between index and priority.
829 */
830 if (__predict_true(msg_prio < MQ_PQSIZE)) {
831 u_int idx = MQ_PQSIZE - msg_prio;
832
833 KASSERT(idx != MQ_PQRESQ);
834 TAILQ_INSERT_TAIL(&mq->mq_head[idx], msg, msg_queue);
835 mq->mq_bitmap |= (1 << --idx);
836 } else {
837 mqueue_linear_insert(mq, msg);
838 }
839
840 /* Check for the notify */
841 if (mqattr->mq_curmsgs == 0 && mq->mq_notify_proc &&
842 (mqattr->mq_flags & MQ_RECEIVE) == 0 &&
843 mq->mq_sig_notify.sigev_notify == SIGEV_SIGNAL) {
844 /* Initialize the signal */
845 KSI_INIT(&ksi);
846 ksi.ksi_signo = mq->mq_sig_notify.sigev_signo;
847 ksi.ksi_code = SI_MESGQ;
848 ksi.ksi_value = mq->mq_sig_notify.sigev_value;
849 /* Unregister the process */
850 notify = mq->mq_notify_proc;
851 mq->mq_notify_proc = NULL;
852 }
853
854 /* Increment the counter and signal waiter, if any */
855 mqattr->mq_curmsgs++;
856 cv_signal(&mq->mq_send_cv);
857
858 /* Ready for receiving now */
859 selnotify(&mq->mq_rsel, POLLIN | POLLRDNORM, 0);
860 error:
861 mutex_exit(&mq->mq_mtx);
862 fd_putfile((int)mqdes);
863
864 if (error) {
865 mqueue_freemsg(msg, size);
866 } else if (notify) {
867 /* Send the notify, if needed */
868 mutex_enter(proc_lock);
869 kpsignal(notify, &ksi, NULL);
870 mutex_exit(proc_lock);
871 }
872 return error;
873 }
874
875 int
876 sys_mq_send(struct lwp *l, const struct sys_mq_send_args *uap,
877 register_t *retval)
878 {
879 /* {
880 syscallarg(mqd_t) mqdes;
881 syscallarg(const char *) msg_ptr;
882 syscallarg(size_t) msg_len;
883 syscallarg(unsigned) msg_prio;
884 } */
885
886 return mq_send1(SCARG(uap, mqdes), SCARG(uap, msg_ptr),
887 SCARG(uap, msg_len), SCARG(uap, msg_prio), NULL);
888 }
889
890 int
891 sys___mq_timedsend50(struct lwp *l, const struct sys___mq_timedsend50_args *uap,
892 register_t *retval)
893 {
894 /* {
895 syscallarg(mqd_t) mqdes;
896 syscallarg(const char *) msg_ptr;
897 syscallarg(size_t) msg_len;
898 syscallarg(unsigned) msg_prio;
899 syscallarg(const struct timespec *) abs_timeout;
900 } */
901 struct timespec ts, *tsp;
902 int error;
903
904 /* Get and convert time value */
905 if (SCARG(uap, abs_timeout)) {
906 error = copyin(SCARG(uap, abs_timeout), &ts, sizeof(ts));
907 if (error)
908 return error;
909 tsp = &ts;
910 } else {
911 tsp = NULL;
912 }
913
914 return mq_send1(SCARG(uap, mqdes), SCARG(uap, msg_ptr),
915 SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp);
916 }
917
918 int
919 sys_mq_notify(struct lwp *l, const struct sys_mq_notify_args *uap,
920 register_t *retval)
921 {
922 /* {
923 syscallarg(mqd_t) mqdes;
924 syscallarg(const struct sigevent *) notification;
925 } */
926 struct mqueue *mq;
927 struct sigevent sig;
928 int error;
929
930 if (SCARG(uap, notification)) {
931 /* Get the signal from user-space */
932 error = copyin(SCARG(uap, notification), &sig,
933 sizeof(struct sigevent));
934 if (error)
935 return error;
936 if (sig.sigev_notify == SIGEV_SIGNAL &&
937 (sig.sigev_signo <=0 || sig.sigev_signo >= NSIG))
938 return EINVAL;
939 }
940
941 error = mqueue_get(SCARG(uap, mqdes), 0, &mq);
942 if (error) {
943 return error;
944 }
945 if (SCARG(uap, notification)) {
946 /* Register notification: set the signal and target process */
947 if (mq->mq_notify_proc == NULL) {
948 memcpy(&mq->mq_sig_notify, &sig,
949 sizeof(struct sigevent));
950 mq->mq_notify_proc = l->l_proc;
951 } else {
952 /* Fail if someone else already registered */
953 error = EBUSY;
954 }
955 } else {
956 /* Unregister the notification */
957 mq->mq_notify_proc = NULL;
958 }
959 mutex_exit(&mq->mq_mtx);
960 fd_putfile((int)SCARG(uap, mqdes));
961
962 return error;
963 }
964
965 int
966 sys_mq_getattr(struct lwp *l, const struct sys_mq_getattr_args *uap,
967 register_t *retval)
968 {
969 /* {
970 syscallarg(mqd_t) mqdes;
971 syscallarg(struct mq_attr *) mqstat;
972 } */
973 struct mqueue *mq;
974 struct mq_attr attr;
975 int error;
976
977 error = mqueue_get(SCARG(uap, mqdes), 0, &mq);
978 if (error) {
979 return error;
980 }
981 memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr));
982 mutex_exit(&mq->mq_mtx);
983 fd_putfile((int)SCARG(uap, mqdes));
984
985 return copyout(&attr, SCARG(uap, mqstat), sizeof(struct mq_attr));
986 }
987
988 int
989 sys_mq_setattr(struct lwp *l, const struct sys_mq_setattr_args *uap,
990 register_t *retval)
991 {
992 /* {
993 syscallarg(mqd_t) mqdes;
994 syscallarg(const struct mq_attr *) mqstat;
995 syscallarg(struct mq_attr *) omqstat;
996 } */
997 struct mqueue *mq;
998 struct mq_attr attr;
999 int error, nonblock;
1000
1001 error = copyin(SCARG(uap, mqstat), &attr, sizeof(struct mq_attr));
1002 if (error)
1003 return error;
1004 nonblock = (attr.mq_flags & O_NONBLOCK);
1005
1006 error = mqueue_get(SCARG(uap, mqdes), 0, &mq);
1007 if (error) {
1008 return error;
1009 }
1010
1011 /* Copy the old attributes, if needed */
1012 if (SCARG(uap, omqstat)) {
1013 memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr));
1014 }
1015
1016 /* Ignore everything, except O_NONBLOCK */
1017 if (nonblock)
1018 mq->mq_attrib.mq_flags |= O_NONBLOCK;
1019 else
1020 mq->mq_attrib.mq_flags &= ~O_NONBLOCK;
1021
1022 mutex_exit(&mq->mq_mtx);
1023 fd_putfile((int)SCARG(uap, mqdes));
1024
1025 /*
1026 * Copy the data to the user-space.
1027 * Note: According to POSIX, the new attributes should not be set in
1028 * case of fail - this would be violated.
1029 */
1030 if (SCARG(uap, omqstat))
1031 error = copyout(&attr, SCARG(uap, omqstat),
1032 sizeof(struct mq_attr));
1033
1034 return error;
1035 }
1036
1037 int
1038 sys_mq_unlink(struct lwp *l, const struct sys_mq_unlink_args *uap,
1039 register_t *retval)
1040 {
1041 /* {
1042 syscallarg(const char *) name;
1043 } */
1044 mqueue_t *mq;
1045 char *name;
1046 int error, refcnt = 0;
1047
1048 /* Get the name from the user-space */
1049 name = kmem_alloc(MQ_NAMELEN, KM_SLEEP);
1050 error = copyinstr(SCARG(uap, name), name, MQ_NAMELEN - 1, NULL);
1051 if (error) {
1052 kmem_free(name, MQ_NAMELEN);
1053 return error;
1054 }
1055
1056 mutex_enter(&mqlist_lock);
1057 mq = mqueue_lookup(name);
1058 if (mq == NULL) {
1059 error = ENOENT;
1060 goto err;
1061 }
1062 KASSERT(mutex_owned(&mq->mq_mtx));
1063
1064 /* Verify permissions. */
1065 if (kauth_cred_geteuid(l->l_cred) != mq->mq_euid &&
1066 kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, NULL)) {
1067 mutex_exit(&mq->mq_mtx);
1068 error = EACCES;
1069 goto err;
1070 }
1071
1072 /* Remove and destroy if no references. */
1073 LIST_REMOVE(mq, mq_list);
1074 refcnt = mq->mq_refcnt;
1075 if (refcnt) {
1076 /* Mark as unlinked, if there are references. */
1077 mq->mq_attrib.mq_flags |= MQ_UNLINKED;
1078 }
1079
1080 /* Wake up waiters, if there are any. */
1081 cv_broadcast(&mq->mq_send_cv);
1082 cv_broadcast(&mq->mq_recv_cv);
1083
1084 selnotify(&mq->mq_rsel, POLLHUP, 0);
1085 selnotify(&mq->mq_wsel, POLLHUP, 0);
1086
1087 mutex_exit(&mq->mq_mtx);
1088 err:
1089 mutex_exit(&mqlist_lock);
1090 /*
1091 * If last reference - destroy the message queue. Otherwise,
1092 * the last mq_close() call will do that.
1093 */
1094 if (!error && refcnt == 0) {
1095 mqueue_destroy(mq);
1096 }
1097 kmem_free(name, MQ_NAMELEN);
1098
1099 return error;
1100 }
1101
1102 /*
1103 * System control nodes.
1104 */
1105 static int
1106 mqueue_sysctl_init(void)
1107 {
1108 const struct sysctlnode *node = NULL;
1109
1110 mqsysctl_log = NULL;
1111
1112 sysctl_createv(&mqsysctl_log, 0, NULL, NULL,
1113 CTLFLAG_PERMANENT,
1114 CTLTYPE_NODE, "kern", NULL,
1115 NULL, 0, NULL, 0,
1116 CTL_KERN, CTL_EOL);
1117 sysctl_createv(&mqsysctl_log, 0, NULL, NULL,
1118 CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
1119 CTLTYPE_INT, "posix_msg",
1120 SYSCTL_DESCR("Version of IEEE Std 1003.1 and its "
1121 "Message Passing option to which the "
1122 "system attempts to conform"),
1123 NULL, _POSIX_MESSAGE_PASSING, NULL, 0,
1124 CTL_KERN, CTL_CREATE, CTL_EOL);
1125 sysctl_createv(&mqsysctl_log, 0, NULL, &node,
1126 CTLFLAG_PERMANENT,
1127 CTLTYPE_NODE, "mqueue",
1128 SYSCTL_DESCR("Message queue options"),
1129 NULL, 0, NULL, 0,
1130 CTL_KERN, CTL_CREATE, CTL_EOL);
1131
1132 if (node == NULL)
1133 return ENXIO;
1134
1135 sysctl_createv(&mqsysctl_log, 0, &node, NULL,
1136 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
1137 CTLTYPE_INT, "mq_open_max",
1138 SYSCTL_DESCR("Maximal number of message queue descriptors "
1139 "that process could open"),
1140 NULL, 0, &mq_open_max, 0,
1141 CTL_CREATE, CTL_EOL);
1142 sysctl_createv(&mqsysctl_log, 0, &node, NULL,
1143 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
1144 CTLTYPE_INT, "mq_prio_max",
1145 SYSCTL_DESCR("Maximal priority of the message"),
1146 NULL, 0, &mq_prio_max, 0,
1147 CTL_CREATE, CTL_EOL);
1148 sysctl_createv(&mqsysctl_log, 0, &node, NULL,
1149 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
1150 CTLTYPE_INT, "mq_max_msgsize",
1151 SYSCTL_DESCR("Maximal allowed size of the message"),
1152 NULL, 0, &mq_max_msgsize, 0,
1153 CTL_CREATE, CTL_EOL);
1154 sysctl_createv(&mqsysctl_log, 0, &node, NULL,
1155 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
1156 CTLTYPE_INT, "mq_def_maxmsg",
1157 SYSCTL_DESCR("Default maximal message count"),
1158 NULL, 0, &mq_def_maxmsg, 0,
1159 CTL_CREATE, CTL_EOL);
1160 sysctl_createv(&mqsysctl_log, 0, &node, NULL,
1161 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
1162 CTLTYPE_INT, "mq_max_maxmsg",
1163 SYSCTL_DESCR("Maximal allowed message count"),
1164 NULL, 0, &mq_max_maxmsg, 0,
1165 CTL_CREATE, CTL_EOL);
1166
1167 return 0;
1168 }
1169
1170 /*
1171 * Debugging.
1172 */
1173 #if defined(DDB)
1174
1175 void
1176 mqueue_print_list(void (*pr)(const char *, ...))
1177 {
1178 struct mqueue *mq;
1179
1180 (*pr)("Global list of the message queues:\n");
1181 (*pr)("%20s %10s %8s %8s %3s %4s %4s %4s\n",
1182 "Name", "Ptr", "Mode", "Flags", "Ref",
1183 "MaxMsg", "MsgSze", "CurMsg");
1184 LIST_FOREACH(mq, &mqueue_head, mq_list) {
1185 (*pr)("%20s %10p %8x %8x %3u %6lu %6lu %6lu\n",
1186 mq->mq_name, mq, mq->mq_mode,
1187 mq->mq_attrib.mq_flags, mq->mq_refcnt,
1188 mq->mq_attrib.mq_maxmsg, mq->mq_attrib.mq_msgsize,
1189 mq->mq_attrib.mq_curmsgs);
1190 }
1191 }
1192
1193 #endif /* defined(DDB) */
1194