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