kernel - use new td_ucred in numerous places
[dragonfly.git] / sys / kern / sys_mqueue.c
CommitLineData
f2df0f7c
SK
1/* $NetBSD: sys_mqueue.c,v 1.16 2009/04/11 23:05:26 christos Exp $ */
2
3/*
4 * Copyright (c) 2007, 2008 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) and proc_t::p_mqueue_cnt
36 * counter are protected by mqlist_mtx lock. The very message queue and
37 * its members are protected by mqueue::mq_mtx.
38 *
39 * Lock order:
40 * mqlist_mtx
41 * -> mqueue::mq_mtx
42 */
43
f2df0f7c
SK
44#include <stdbool.h>
45#include <sys/param.h>
46#include <sys/types.h>
47#include <sys/errno.h>
48#include <sys/fcntl.h>
49#include <sys/file.h>
50#include <sys/filedesc.h>
51#include <sys/ucred.h>
52#include <sys/priv.h>
53#include <sys/kernel.h>
54#include <sys/malloc.h>
55#include <sys/mqueue.h>
56#include <sys/objcache.h>
57#include <sys/poll.h>
58#include <sys/proc.h>
59#include <sys/queue.h>
60#include <sys/select.h>
61#include <sys/serialize.h>
62#include <sys/signal.h>
63#include <sys/signalvar.h>
64#include <sys/spinlock.h>
65#include <sys/spinlock2.h>
66#include <sys/stat.h>
67#include <sys/sysctl.h>
68#include <sys/sysproto.h>
69#include <sys/systm.h>
70#include <sys/lock.h>
71#include <sys/unistd.h>
72#include <sys/vnode.h>
73
74/* System-wide limits. */
75static u_int mq_open_max = MQ_OPEN_MAX;
76static u_int mq_prio_max = MQ_PRIO_MAX;
77static u_int mq_max_msgsize = 16 * MQ_DEF_MSGSIZE;
78static u_int mq_def_maxmsg = 32;
79
80struct lock mqlist_mtx;
81static struct objcache * mqmsg_cache;
82static LIST_HEAD(, mqueue) mqueue_head =
83 LIST_HEAD_INITIALIZER(mqueue_head);
84
85typedef struct file file_t; /* XXX: Should we put this in sys/types.h ? */
86
87/* Function prototypes */
88static int mq_poll_fop(file_t *, int, struct ucred *cred);
89static int mq_stat_fop(file_t *, struct stat *, struct ucred *cred);
90static int mq_close_fop(file_t *);
91
92/* Some time-related utility functions */
93static int itimespecfix(struct timespec *ts);
94static int tstohz(const struct timespec *ts);
95
96/* File operations vector */
97static struct fileops mqops = {
98 .fo_read = badfo_readwrite,
99 .fo_write = badfo_readwrite,
100 .fo_ioctl = badfo_ioctl,
101 .fo_poll = mq_poll_fop,
102 .fo_stat = mq_stat_fop,
103 .fo_close = mq_close_fop,
104 .fo_kqfilter = badfo_kqfilter,
105 .fo_shutdown = badfo_shutdown
106};
107
108/* Define a new malloc type for message queues */
109MALLOC_DECLARE(M_MQBUF);
110MALLOC_DEFINE(M_MQBUF, "mqueues", "Buffers to message queues");
111
112/* Malloc arguments for object cache */
113struct objcache_malloc_args mqueue_malloc_args = {
114 sizeof(struct mqueue), M_MQBUF };
115
116/* Spinlock around the process list */
117extern struct spinlock allproc_spin;
118
119/*
120 * Initialize POSIX message queue subsystem.
121 */
122void
123mqueue_sysinit(void)
124{
125 mqmsg_cache = objcache_create("mqmsg_cache",
126 0, /* infinite depot's capacity */
127 0, /* default magazine's capacity */
128 NULL, /* constructor */
129 NULL, /* deconstructor */
130 NULL,
131 objcache_malloc_alloc,
132 objcache_malloc_free,
133 &mqueue_malloc_args);
134
135 lockinit(&mqlist_mtx, "mqlist_mtx", 0, LK_CANRECURSE);
136}
137
138/*
139 * Free the message.
140 */
141static void
142mqueue_freemsg(struct mq_msg *msg, const size_t size)
143{
144
145 if (size > MQ_DEF_MSGSIZE)
146 kfree(msg, M_MQBUF);
147 else
148 objcache_put(mqmsg_cache, msg);
149}
150
151/*
152 * Destroy the message queue.
153 */
154static void
155mqueue_destroy(struct mqueue *mq)
156{
157 struct mq_msg *msg;
158 size_t msz;
159 u_int i;
160
161 /* Note MQ_PQSIZE + 1. */
162 for (i = 0; i < MQ_PQSIZE + 1; i++) {
163 while ((msg = TAILQ_FIRST(&mq->mq_head[i])) != NULL) {
164 TAILQ_REMOVE(&mq->mq_head[i], msg, msg_queue);
165 msz = sizeof(struct mq_msg) + msg->msg_len;
166 mqueue_freemsg(msg, msz);
167 }
168 }
169 lockuninit(&mq->mq_mtx);
170 kfree(mq, M_MQBUF);
171}
172
173/*
174 * Lookup for file name in general list of message queues.
175 * => locks the message queue
176 */
177static void *
178mqueue_lookup(char *name)
179{
180 struct mqueue *mq;
181
182 KKASSERT(lockstatus(&mqlist_mtx, curthread));
183
184 LIST_FOREACH(mq, &mqueue_head, mq_list) {
185 if (strncmp(mq->mq_name, name, MQ_NAMELEN) == 0) {
186 lockmgr(&mq->mq_mtx, LK_EXCLUSIVE);
187 return mq;
188 }
189 }
190
191 return NULL;
192}
193
194/*
195 * mqueue_get: get the mqueue from the descriptor.
196 * => locks the message queue, if found.
197 * => hold a reference on the file descriptor.
198 */
199static int
200mqueue_get(struct lwp *l, mqd_t mqd, file_t **fpr)
201{
202 struct mqueue *mq;
203 file_t *fp;
204
205 fp = holdfp(curproc->p_fd, (int)mqd, -1); /* XXX: Why -1 ? */
206 if (__predict_false(fp == NULL))
207 return EBADF;
208
209 if (__predict_false(fp->f_type != DTYPE_MQUEUE)) {
210 fdrop(fp);
211 return EBADF;
212 }
213 mq = fp->f_data;
214 lockmgr(&mq->mq_mtx, LK_EXCLUSIVE);
215
216 *fpr = fp;
217 return 0;
218}
219
220/*
221 * mqueue_linear_insert: perform linear insert according to the message
222 * priority into the reserved queue (MQ_PQRESQ). Reserved queue is a
223 * sorted list used only when mq_prio_max is increased via sysctl.
224 */
225static inline void
226mqueue_linear_insert(struct mqueue *mq, struct mq_msg *msg)
227{
228 struct mq_msg *mit;
229
230 TAILQ_FOREACH(mit, &mq->mq_head[MQ_PQRESQ], msg_queue) {
231 if (msg->msg_prio > mit->msg_prio)
232 break;
233 }
234 if (mit == NULL) {
235 TAILQ_INSERT_TAIL(&mq->mq_head[MQ_PQRESQ], msg, msg_queue);
236 } else {
237 TAILQ_INSERT_BEFORE(mit, msg, msg_queue);
238 }
239}
240
241/*
242 * Validate input.
243 */
244int
245itimespecfix(struct timespec *ts)
246{
247 if (ts->tv_sec < 0 || ts->tv_nsec < 0 || ts->tv_nsec >= 1000000000)
248 return (EINVAL);
249 if (ts->tv_sec == 0 && ts->tv_nsec != 0 && ts->tv_nsec < tick * 1000)
250 ts->tv_nsec = tick * 1000;
251 return (0);
252}
253
254/*
255 * Compute number of ticks in the specified amount of time.
256 */
257int
258tstohz(const struct timespec *ts)
259{
260 struct timeval tv;
261
262 /*
263 * usec has great enough resolution for hz, so convert to a
264 * timeval and use tvtohz() above.
265 */
266 TIMESPEC_TO_TIMEVAL(&tv, ts);
267 return tvtohz_high(&tv); /* XXX Why _high() and not _low() ? */
268}
269
270/*
271 * Converter from struct timespec to the ticks.
272 * Used by mq_timedreceive(), mq_timedsend().
273 */
274int
275abstimeout2timo(struct timespec *ts, int *timo)
276{
277 struct timespec tsd;
278 int error;
279
280 getnanotime(&tsd);
281 timespecsub(ts, &tsd);
282 if (ts->tv_sec < 0 || (ts->tv_sec == 0 && ts->tv_nsec <= 0)) {
283 return ETIMEDOUT;
284 }
285 error = itimespecfix(ts);
286 if (error) {
287 return error;
288 }
289 *timo = tstohz(ts);
290 KKASSERT(*timo != 0);
291
292 return 0;
293}
294
295static int
296mq_stat_fop(file_t *fp, struct stat *st, struct ucred *cred)
297{
298 struct mqueue *mq = fp->f_data;
299
300 (void)memset(st, 0, sizeof(*st));
301
302 lockmgr(&mq->mq_mtx, LK_EXCLUSIVE);
303 st->st_mode = mq->mq_mode;
304 st->st_uid = mq->mq_euid;
305 st->st_gid = mq->mq_egid;
306 st->st_atimespec = mq->mq_atime;
307 st->st_mtimespec = mq->mq_mtime;
308 /*st->st_ctimespec = st->st_birthtimespec = mq->mq_btime;*/
309 st->st_uid = fp->f_cred->cr_uid;
310 st->st_gid = fp->f_cred->cr_svgid;
311 lockmgr(&mq->mq_mtx, LK_RELEASE);
312
313 return 0;
314}
315
316static int
317mq_poll_fop(file_t *fp, int events, struct ucred *cred)
318{
319 struct mqueue *mq = fp->f_data;
320 int revents = 0;
321
322 lockmgr(&mq->mq_mtx, LK_EXCLUSIVE);
323 if (events & (POLLIN | POLLRDNORM)) {
324 /* Ready for receiving, if there are messages in the queue */
325 if (mq->mq_attrib.mq_curmsgs)
326 revents |= (POLLIN | POLLRDNORM);
327 else
328 selrecord(curthread, &mq->mq_rsel);
329 }
330 if (events & (POLLOUT | POLLWRNORM)) {
331 /* Ready for sending, if the message queue is not full */
332 if (mq->mq_attrib.mq_curmsgs < mq->mq_attrib.mq_maxmsg)
333 revents |= (POLLOUT | POLLWRNORM);
334 else
335 selrecord(curthread, &mq->mq_wsel);
336 }
337 lockmgr(&mq->mq_mtx, LK_RELEASE);
338
339 return revents;
340}
341
342static int
343mq_close_fop(file_t *fp)
344{
345 struct proc *p = curproc;
346 struct mqueue *mq = fp->f_data;
347 bool destroy;
348
349 lockmgr(&mqlist_mtx, LK_EXCLUSIVE);
350 lockmgr(&mq->mq_mtx, LK_EXCLUSIVE);
351
352 /* Decrease the counters */
353 p->p_mqueue_cnt--;
354 mq->mq_refcnt--;
355
356 /* Remove notification if registered for this process */
357 if (mq->mq_notify_proc == p)
358 mq->mq_notify_proc = NULL;
359
360 /*
361 * If this is the last reference and mqueue is marked for unlink,
362 * remove and later destroy the message queue.
363 */
364 if (mq->mq_refcnt == 0 && (mq->mq_attrib.mq_flags & MQ_UNLINK)) {
365 LIST_REMOVE(mq, mq_list);
366 destroy = true;
367 } else
368 destroy = false;
369
370 lockmgr(&mq->mq_mtx, LK_RELEASE);
371 lockmgr(&mqlist_mtx, LK_RELEASE);
372
373 if (destroy)
374 mqueue_destroy(mq);
375
376 return 0;
377}
378
379/*
380 * General mqueue system calls.
381 */
382
383int
384sys_mq_open(struct mq_open_args *uap)
385{
386 /* {
387 syscallarg(const char *) name;
388 syscallarg(int) oflag;
389 syscallarg(mode_t) mode;
390 syscallarg(struct mq_attr) attr;
391 } */
9910d07b
MD
392 struct thread *td = curthread;
393 struct proc *p = td->td_proc;
f2df0f7c
SK
394 struct mqueue *mq, *mq_new = NULL;
395 file_t *fp;
396 char *name;
397 int mqd, error, oflag;
398
399 /* Check access mode flags */
400 oflag = SCARG(uap, oflag);
401 if ((oflag & O_ACCMODE) == (O_WRONLY | O_RDWR)) {
402 return EINVAL;
403 }
404
405 /* Get the name from the user-space */
406 name = kmalloc(MQ_NAMELEN, M_MQBUF, M_WAITOK | M_ZERO);
407 error = copyinstr(SCARG(uap, name), name, MQ_NAMELEN - 1, NULL);
408 if (error) {
409 kfree(name, M_MQBUF);
410 return error;
411 }
412
413 if (oflag & O_CREAT) {
414 struct mq_attr attr;
415 u_int i;
416
417 /* Check the limit */
418 if (p->p_mqueue_cnt == mq_open_max) {
419 kfree(name, M_MQBUF);
420 return EMFILE;
421 }
422
423 /* Empty name is invalid */
424 if (name[0] == '\0') {
425 kfree(name, M_MQBUF);
426 return EINVAL;
427 }
428
429 /* Check for mqueue attributes */
430 if (SCARG(uap, attr)) {
431 error = copyin(SCARG(uap, attr), &attr,
432 sizeof(struct mq_attr));
433 if (error) {
434 kfree(name, M_MQBUF);
435 return error;
436 }
437 if (attr.mq_maxmsg <= 0 || attr.mq_msgsize <= 0 ||
438 attr.mq_msgsize > mq_max_msgsize) {
439 kfree(name, M_MQBUF);
440 return EINVAL;
441 }
442 attr.mq_curmsgs = 0;
443 } else {
444 memset(&attr, 0, sizeof(struct mq_attr));
445 attr.mq_maxmsg = mq_def_maxmsg;
446 attr.mq_msgsize =
447 MQ_DEF_MSGSIZE - sizeof(struct mq_msg);
448 }
449
450 /*
451 * Allocate new mqueue, initialize data structures,
452 * copy the name, attributes and set the flag.
453 */
454 mq_new = kmalloc(sizeof(struct mqueue), M_MQBUF, M_WAITOK | M_ZERO);
455
456 lockinit(&mq_new->mq_mtx, "mq_new->mq_mtx", 0, LK_CANRECURSE);
457 for (i = 0; i < (MQ_PQSIZE + 1); i++) {
458 TAILQ_INIT(&mq_new->mq_head[i]);
459 }
460
461 strlcpy(mq_new->mq_name, name, MQ_NAMELEN);
462 memcpy(&mq_new->mq_attrib, &attr, sizeof(struct mq_attr));
463
464 /*CTASSERT((O_MASK & (MQ_UNLINK | MQ_RECEIVE)) == 0);*/
465 /* mq_new->mq_attrib.mq_flags = (O_MASK & oflag); */
466 mq_new->mq_attrib.mq_flags = oflag;
467
468 /* Store mode and effective UID with GID */
469 mq_new->mq_mode = ((SCARG(uap, mode) &
470 ~p->p_fd->fd_cmask) & ALLPERMS) & ~S_ISTXT;
9910d07b
MD
471 mq_new->mq_euid = td->td_ucred->cr_uid;
472 mq_new->mq_egid = td->td_ucred->cr_svgid;
f2df0f7c
SK
473 }
474
475 /* Allocate file structure and descriptor */
476 error = falloc(curproc, &fp, &mqd);
477 if (error) {
478 if (mq_new)
479 mqueue_destroy(mq_new);
480 kfree(name, M_MQBUF);
481 return error;
482 }
483 fp->f_type = DTYPE_MQUEUE;
484 fp->f_flag = FFLAGS(oflag) & (FREAD | FWRITE);
485 fp->f_ops = &mqops;
486
487 /* Look up for mqueue with such name */
488 lockmgr(&mqlist_mtx, LK_EXCLUSIVE);
489 mq = mqueue_lookup(name);
490 if (mq) {
491 int acc_mode;
492
493 KKASSERT(lockstatus(&mq->mq_mtx, curthread));
494
495 /* Check if mqueue is not marked as unlinking */
496 if (mq->mq_attrib.mq_flags & MQ_UNLINK) {
497 error = EACCES;
498 goto exit;
499 }
500 /* Fail if O_EXCL is set, and mqueue already exists */
501 if ((oflag & O_CREAT) && (oflag & O_EXCL)) {
502 error = EEXIST;
503 goto exit;
504 }
505
506 /*
507 * Check the permissions. Note the difference between
508 * VREAD/VWRITE and FREAD/FWRITE.
509 */
510 acc_mode = 0;
511 if (fp->f_flag & FREAD) {
512 acc_mode |= VREAD;
513 }
514 if (fp->f_flag & FWRITE) {
515 acc_mode |= VWRITE;
516 }
517 if (vaccess(VNON, mq->mq_mode, mq->mq_euid, mq->mq_egid,
9910d07b 518 acc_mode, td->td_ucred)) {
f2df0f7c
SK
519
520 error = EACCES;
521 goto exit;
522 }
523 } else {
524 /* Fail if mqueue neither exists, nor we create it */
525 if ((oflag & O_CREAT) == 0) {
526 lockmgr(&mqlist_mtx, LK_RELEASE);
527 KKASSERT(mq_new == NULL);
528 fsetfd(curproc, NULL, mqd);
529 fp->f_ops = &badfileops;
530 fdrop(fp);
531 kfree(name, M_MQBUF);
532 return ENOENT;
533 }
534
535 /* Check the limit */
536 if (p->p_mqueue_cnt == mq_open_max) {
537 error = EMFILE;
538 goto exit;
539 }
540
541 /* Insert the queue to the list */
542 mq = mq_new;
543 lockmgr(&mq->mq_mtx, LK_EXCLUSIVE);
544 LIST_INSERT_HEAD(&mqueue_head, mq, mq_list);
545 mq_new = NULL;
546 getnanotime(&mq->mq_btime);
547 mq->mq_atime = mq->mq_mtime = mq->mq_btime;
548 }
549
550 /* Increase the counters, and make descriptor ready */
551 p->p_mqueue_cnt++;
552 mq->mq_refcnt++;
553 fp->f_data = mq;
554exit:
555 lockmgr(&mq->mq_mtx, LK_RELEASE);
556 lockmgr(&mqlist_mtx, LK_RELEASE);
557
558 if (mq_new)
559 mqueue_destroy(mq_new);
560 if (error) {
561 fsetfd(curproc, NULL, mqd);
562 fp->f_ops = &badfileops;
563 } else {
564 fsetfd(p, fp, mqd);
565 uap->sysmsg_result = mqd;
566 }
567 fdrop(fp);
568 kfree(name, M_MQBUF);
569
570 return error;
571}
572
573int
574sys_mq_close(struct mq_close_args *uap)
575{
576 return sys_close((void *)uap);
577}
578
579/*
580 * Primary mq_receive1() function.
581 */
582int
583mq_receive1(struct lwp *l, mqd_t mqdes, void *msg_ptr, size_t msg_len,
584 unsigned *msg_prio, struct timespec *ts, ssize_t *mlen)
585{
586 file_t *fp = NULL;
587 struct mqueue *mq;
588 struct mq_msg *msg = NULL;
589 struct mq_attr *mqattr;
590 u_int idx;
591 int error;
592
593 /* Get the message queue */
594 error = mqueue_get(l, mqdes, &fp);
595 if (error) {
596 return error;
597 }
598 mq = fp->f_data;
599 if ((fp->f_flag & FREAD) == 0) {
600 error = EBADF;
601 goto error;
602 }
603 getnanotime(&mq->mq_atime);
604 mqattr = &mq->mq_attrib;
605
606 /* Check the message size limits */
607 if (msg_len < mqattr->mq_msgsize) {
608 error = EMSGSIZE;
609 goto error;
610 }
611
612 /* Check if queue is empty */
613 while (mqattr->mq_curmsgs == 0) {
614 int t;
615
616 if (mqattr->mq_flags & O_NONBLOCK) {
617 error = EAGAIN;
618 goto error;
619 }
620 error = abstimeout2timo(ts, &t);
621 if (error) {
622 goto error;
623 }
624 /*
625 * Block until someone sends the message.
626 * While doing this, notification should not be sent.
627 */
628 mqattr->mq_flags |= MQ_RECEIVE;
629 error = tsleep(&mq->mq_send_cv, PCATCH, "mqsend", t);
630 mqattr->mq_flags &= ~MQ_RECEIVE;
631 if (error || (mqattr->mq_flags & MQ_UNLINK)) {
632 error = (error == EWOULDBLOCK) ? ETIMEDOUT : EINTR;
633 goto error;
634 }
635 }
636
637
638 /*
639 * Find the highest priority message, and remove it from the queue.
640 * At first, reserved queue is checked, bitmap is next.
641 */
642 msg = TAILQ_FIRST(&mq->mq_head[MQ_PQRESQ]);
643 if (__predict_true(msg == NULL)) {
644 idx = ffs(mq->mq_bitmap);
645 msg = TAILQ_FIRST(&mq->mq_head[idx]);
646 KKASSERT(msg != NULL);
647 } else {
648 idx = MQ_PQRESQ;
649 }
650 TAILQ_REMOVE(&mq->mq_head[idx], msg, msg_queue);
651
652 /* Unmark the bit, if last message. */
653 if (__predict_true(idx) && TAILQ_EMPTY(&mq->mq_head[idx])) {
654 KKASSERT((MQ_PQSIZE - idx) == msg->msg_prio);
655 mq->mq_bitmap &= ~(1 << --idx);
656 }
657
658 /* Decrement the counter and signal waiter, if any */
659 mqattr->mq_curmsgs--;
660 wakeup_one(&mq->mq_recv_cv);
661
662 /* Ready for sending now */
663 selwakeup(&mq->mq_wsel);
664error:
665 lockmgr(&mq->mq_mtx, LK_RELEASE);
666 fdrop(fp);
667 if (error)
668 return error;
669
670 /*
671 * Copy the data to the user-space.
672 * Note: According to POSIX, no message should be removed from the
673 * queue in case of fail - this would be violated.
674 */
675 *mlen = msg->msg_len;
676 error = copyout(msg->msg_ptr, msg_ptr, msg->msg_len);
677 if (error == 0 && msg_prio)
678 error = copyout(&msg->msg_prio, msg_prio, sizeof(unsigned));
679 mqueue_freemsg(msg, sizeof(struct mq_msg) + msg->msg_len);
680
681 return error;
682}
683
684int
685sys_mq_receive(struct mq_receive_args *uap)
686{
687 /* {
688 syscallarg(mqd_t) mqdes;
689 syscallarg(char *) msg_ptr;
690 syscallarg(size_t) msg_len;
691 syscallarg(unsigned *) msg_prio;
692 } */
693 ssize_t mlen;
694 int error;
695
696 error = mq_receive1(curthread->td_lwp, SCARG(uap, mqdes), SCARG(uap, msg_ptr),
697 SCARG(uap, msg_len), SCARG(uap, msg_prio), 0, &mlen);
698 if (error == 0)
699 uap->sysmsg_result = mlen;
700
701 return error;
702}
703
704int
705sys_mq_timedreceive(struct mq_timedreceive_args *uap)
706{
707 /* {
708 syscallarg(mqd_t) mqdes;
709 syscallarg(char *) msg_ptr;
710 syscallarg(size_t) msg_len;
711 syscallarg(unsigned *) msg_prio;
712 syscallarg(const struct timespec *) abs_timeout;
713 } */
714 int error;
715 ssize_t mlen;
716 struct timespec ts, *tsp;
717
718 /* Get and convert time value */
719 if (SCARG(uap, abs_timeout)) {
720 error = copyin(SCARG(uap, abs_timeout), &ts, sizeof(ts));
721 if (error)
722 return error;
723 tsp = &ts;
724 } else {
725 tsp = NULL;
726 }
727
728 error = mq_receive1(curthread->td_lwp, SCARG(uap, mqdes), SCARG(uap, msg_ptr),
729 SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp, &mlen);
730 if (error == 0)
731 uap->sysmsg_result = mlen;
732
733 return error;
734}
735
736/*
737 * Primary mq_send1() function.
738 */
739int
740mq_send1(struct lwp *l, mqd_t mqdes, const char *msg_ptr, size_t msg_len,
741 unsigned msg_prio, struct timespec *ts)
742{
743 file_t *fp = NULL;
744 struct mqueue *mq;
745 struct mq_msg *msg;
746 struct mq_attr *mqattr;
747 struct proc *notify = NULL;
748 /*ksiginfo_t ksi;*/
749 size_t size;
750 int error;
751
752 /* Check the priority range */
753 if (msg_prio >= mq_prio_max)
754 return EINVAL;
755
756 /* Allocate a new message */
757 size = sizeof(struct mq_msg) + msg_len;
758 if (size > mq_max_msgsize)
759 return EMSGSIZE;
760
761 if (size > MQ_DEF_MSGSIZE) {
762 msg = kmalloc(size, M_MQBUF, M_WAITOK);
763 } else {
764 msg = objcache_get(mqmsg_cache, M_WAITOK);
765 }
766
767 /* Get the data from user-space */
768 error = copyin(msg_ptr, msg->msg_ptr, msg_len);
769 if (error) {
770 mqueue_freemsg(msg, size);
771 return error;
772 }
773 msg->msg_len = msg_len;
774 msg->msg_prio = msg_prio;
775
776 /* Get the mqueue */
777 error = mqueue_get(l, mqdes, &fp);
778 if (error) {
779 mqueue_freemsg(msg, size);
780 return error;
781 }
782 mq = fp->f_data;
783 if ((fp->f_flag & FWRITE) == 0) {
784 error = EBADF;
785 goto error;
786 }
787 getnanotime(&mq->mq_mtime);
788 mqattr = &mq->mq_attrib;
789
790 /* Check the message size limit */
791 if (msg_len <= 0 || msg_len > mqattr->mq_msgsize) {
792 error = EMSGSIZE;
793 goto error;
794 }
795
796 /* Check if queue is full */
797 while (mqattr->mq_curmsgs >= mqattr->mq_maxmsg) {
798 int t;
799
800 if (mqattr->mq_flags & O_NONBLOCK) {
801 error = EAGAIN;
802 goto error;
803 }
804 error = abstimeout2timo(ts, &t);
805 if (error) {
806 goto error;
807 }
808 /* Block until queue becomes available */
809 error = tsleep(&mq->mq_recv_cv, PCATCH, "mqrecv", t);
810 if (error || (mqattr->mq_flags & MQ_UNLINK)) {
811 error = (error == EWOULDBLOCK) ? ETIMEDOUT : error;
812 goto error;
813 }
814 }
815 KKASSERT(mq->mq_attrib.mq_curmsgs < mq->mq_attrib.mq_maxmsg);
816
817 /*
818 * Insert message into the queue, according to the priority.
819 * Note the difference between index and priority.
820 */
821 if (__predict_true(msg_prio < MQ_PQSIZE)) {
822 u_int idx = MQ_PQSIZE - msg_prio;
823
824 KKASSERT(idx != MQ_PQRESQ);
825 TAILQ_INSERT_TAIL(&mq->mq_head[idx], msg, msg_queue);
826 mq->mq_bitmap |= (1 << --idx);
827 } else {
828 mqueue_linear_insert(mq, msg);
829 }
830
831 /* Check for the notify */
832 if (mqattr->mq_curmsgs == 0 && mq->mq_notify_proc &&
833 (mqattr->mq_flags & MQ_RECEIVE) == 0) {
834 /* Initialize the signal */
835 /*KSI_INIT(&ksi);*/
836 /*ksi.ksi_signo = mq->mq_sig_notify.sigev_signo;*/
837 /*ksi.ksi_code = SI_MESGQ;*/
838 /*ksi.ksi_value = mq->mq_sig_notify.sigev_value;*/
839 /* Unregister the process */
840 notify = mq->mq_notify_proc;
841 mq->mq_notify_proc = NULL;
842 }
843
844 /* Increment the counter and signal waiter, if any */
845 mqattr->mq_curmsgs++;
846 wakeup_one(&mq->mq_send_cv);
847
848 /* Ready for receiving now */
849 selwakeup(&mq->mq_rsel);
850error:
f2df0f7c
SK
851 lockmgr(&mq->mq_mtx, LK_RELEASE);
852 fdrop(fp);
853
854 if (error) {
855 mqueue_freemsg(msg, size);
856 } else if (notify) {
857 /* Send the notify, if needed */
858 spin_lock_wr(&allproc_spin);
859 /*kpsignal(notify, &ksi, NULL);*/
860 ksignal(notify, mq->mq_sig_notify.sigev_signo);
861 spin_unlock_wr(&allproc_spin);
862 }
863
864 return error;
865}
866
867int
868sys_mq_send(struct mq_send_args *uap)
869{
870 /* {
871 syscallarg(mqd_t) mqdes;
872 syscallarg(const char *) msg_ptr;
873 syscallarg(size_t) msg_len;
874 syscallarg(unsigned) msg_prio;
875 } */
876
877 return mq_send1(curthread->td_lwp, SCARG(uap, mqdes), SCARG(uap, msg_ptr),
878 SCARG(uap, msg_len), SCARG(uap, msg_prio), 0);
879}
880
881int
882sys_mq_timedsend(struct mq_timedsend_args *uap)
883{
884 /* {
885 syscallarg(mqd_t) mqdes;
886 syscallarg(const char *) msg_ptr;
887 syscallarg(size_t) msg_len;
888 syscallarg(unsigned) msg_prio;
889 syscallarg(const struct timespec *) abs_timeout;
890 } */
891 struct timespec ts, *tsp;
892 int error;
893
894 /* Get and convert time value */
895 if (SCARG(uap, abs_timeout)) {
896 error = copyin(SCARG(uap, abs_timeout), &ts, sizeof(ts));
897 if (error)
898 return error;
899 tsp = &ts;
900 } else {
901 tsp = NULL;
902 }
903
904 return mq_send1(curthread->td_lwp, SCARG(uap, mqdes), SCARG(uap, msg_ptr),
905 SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp);
906}
907
908int
909sys_mq_notify(struct mq_notify_args *uap)
910{
911 /* {
912 syscallarg(mqd_t) mqdes;
913 syscallarg(const struct sigevent *) notification;
914 } */
915 file_t *fp = NULL;
916 struct mqueue *mq;
917 struct sigevent sig;
918 int error;
919
920 if (SCARG(uap, notification)) {
921 /* Get the signal from user-space */
922 error = copyin(SCARG(uap, notification), &sig,
923 sizeof(struct sigevent));
924 if (error)
925 return error;
926 }
927
928 error = mqueue_get(curthread->td_lwp, SCARG(uap, mqdes), &fp);
929 if (error)
930 return error;
931 mq = fp->f_data;
932
933 if (SCARG(uap, notification)) {
934 /* Register notification: set the signal and target process */
935 if (mq->mq_notify_proc == NULL) {
936 memcpy(&mq->mq_sig_notify, &sig,
937 sizeof(struct sigevent));
938 mq->mq_notify_proc = curproc;
939 } else {
940 /* Fail if someone else already registered */
941 error = EBUSY;
942 }
943 } else {
944 /* Unregister the notification */
945 mq->mq_notify_proc = NULL;
946 }
947 lockmgr(&mq->mq_mtx, LK_RELEASE);
948 fdrop(fp);
949
950 return error;
951}
952
953int
954sys_mq_getattr(struct mq_getattr_args *uap)
955{
956 /* {
957 syscallarg(mqd_t) mqdes;
958 syscallarg(struct mq_attr *) mqstat;
959 } */
960 file_t *fp = NULL;
961 struct mqueue *mq;
962 struct mq_attr attr;
963 int error;
964
965 /* Get the message queue */
766730da 966 error = mqueue_get(curthread->td_lwp, SCARG(uap, mqdes), &fp);
f2df0f7c
SK
967 if (error)
968 return error;
969 mq = fp->f_data;
970 memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr));
971 lockmgr(&mq->mq_mtx, LK_RELEASE);
972 fdrop(fp);
973
974 return copyout(&attr, SCARG(uap, mqstat), sizeof(struct mq_attr));
975}
976
977int
978sys_mq_setattr(struct mq_setattr_args *uap)
979{
980 /* {
981 syscallarg(mqd_t) mqdes;
982 syscallarg(const struct mq_attr *) mqstat;
983 syscallarg(struct mq_attr *) omqstat;
984 } */
985 file_t *fp = NULL;
986 struct mqueue *mq;
987 struct mq_attr attr;
988 int error, nonblock;
989
990 error = copyin(SCARG(uap, mqstat), &attr, sizeof(struct mq_attr));
991 if (error)
992 return error;
993 nonblock = (attr.mq_flags & O_NONBLOCK);
994
995 /* Get the message queue */
766730da 996 error = mqueue_get(curthread->td_lwp, SCARG(uap, mqdes), &fp);
f2df0f7c
SK
997 if (error)
998 return error;
999 mq = fp->f_data;
1000
1001 /* Copy the old attributes, if needed */
1002 if (SCARG(uap, omqstat))
1003 memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr));
1004
1005 /* Ignore everything, except O_NONBLOCK */
1006 if (nonblock)
1007 mq->mq_attrib.mq_flags |= O_NONBLOCK;
1008 else
1009 mq->mq_attrib.mq_flags &= ~O_NONBLOCK;
1010
1011 lockmgr(&mq->mq_mtx, LK_RELEASE);
1012 fdrop(fp);
1013
1014 /*
1015 * Copy the data to the user-space.
1016 * Note: According to POSIX, the new attributes should not be set in
1017 * case of fail - this would be violated.
1018 */
1019 if (SCARG(uap, omqstat))
1020 error = copyout(&attr, SCARG(uap, omqstat),
1021 sizeof(struct mq_attr));
1022
1023 return error;
1024}
1025
1026int
1027sys_mq_unlink(struct mq_unlink_args *uap)
1028{
1029 /* {
1030 syscallarg(const char *) name;
1031 } */
9910d07b 1032 struct thread *td = curthread;
f2df0f7c
SK
1033 struct mqueue *mq;
1034 char *name;
1035 int error, refcnt = 0;
1036
1037 /* Get the name from the user-space */
1038 name = kmalloc(MQ_NAMELEN, M_MQBUF, M_WAITOK | M_ZERO);
1039 error = copyinstr(SCARG(uap, name), name, MQ_NAMELEN - 1, NULL);
1040 if (error) {
1041 kfree(name, M_MQBUF);
1042 return error;
1043 }
1044
1045 /* Lookup for this file */
1046 lockmgr(&mqlist_mtx, LK_EXCLUSIVE);
1047 mq = mqueue_lookup(name);
1048 if (mq == NULL) {
1049 error = ENOENT;
1050 goto error;
1051 }
1052
1053 /* Check the permissions */
9910d07b
MD
1054 if (td->td_ucred->cr_uid != mq->mq_euid &&
1055 priv_check(td, PRIV_ROOT) != 0) {
f2df0f7c
SK
1056 lockmgr(&mq->mq_mtx, LK_RELEASE);
1057 error = EACCES;
1058 goto error;
1059 }
1060
1061 /* Mark message queue as unlinking, before leaving the window */
1062 mq->mq_attrib.mq_flags |= MQ_UNLINK;
1063
1064 /* Wake up all waiters, if there are such */
1065 wakeup(&mq->mq_send_cv);
1066 wakeup(&mq->mq_recv_cv);
1067
1068 selwakeup(&mq->mq_rsel);
1069 selwakeup(&mq->mq_wsel);
1070
1071 refcnt = mq->mq_refcnt;
1072 if (refcnt == 0)
1073 LIST_REMOVE(mq, mq_list);
1074
1075 lockmgr(&mq->mq_mtx, LK_RELEASE);
1076error:
1077 lockmgr(&mqlist_mtx, LK_RELEASE);
1078
1079 /*
1080 * If there are no references - destroy the message
1081 * queue, otherwise, the last mq_close() will do that.
1082 */
1083 if (error == 0 && refcnt == 0)
1084 mqueue_destroy(mq);
1085
1086 kfree(name, M_MQBUF);
1087 return error;
1088}
1089
1090/*
1091 * SysCtl.
1092 */
1093SYSCTL_NODE(_kern, OID_AUTO, mqueue,
1094 CTLFLAG_RW, 0, "Message queue options");
1095
1096SYSCTL_INT(_kern_mqueue, OID_AUTO, mq_open_max,
1097 CTLFLAG_RW, &mq_open_max, 0,
1098 "Maximal number of message queue descriptors per process");
1099
1100SYSCTL_INT(_kern_mqueue, OID_AUTO, mq_prio_max,
1101 CTLFLAG_RW, &mq_prio_max, 0,
1102 "Maximal priority of the message");
1103
1104SYSCTL_INT(_kern_mqueue, OID_AUTO, mq_max_msgsize,
1105 CTLFLAG_RW, &mq_max_msgsize, 0,
1106 "Maximal allowed size of the message");
1107
1108SYSCTL_INT(_kern_mqueue, OID_AUTO, mq_def_maxmsg,
1109 CTLFLAG_RW, &mq_def_maxmsg, 0,
1110 "Default maximal message count");
1111
1112SYSINIT(sys_mqueue_init, SI_SUB_PRE_DRIVERS, SI_ORDER_ANY, mqueue_sysinit, NULL);