1 /* $NetBSD: sys_mqueue.c,v 1.33 2011/04/25 11:39:42 martin 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.33 2011/04/25 11:39:42 martin 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