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