1 /* $NetBSD: sys_mqueue.c,v 1.24 2009/07/19 02:50:44 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.24 2009/07/19 02:50:44 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 * Converter 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 int error; 305 306 /* 307 * According to POSIX, validation check is needed only in case of 308 * blocking. Thus, set the invalid value right now, and fail latter. 309 */ 310 error = itimespecfix(ts); 311 *timo = (error == 0) ? tstohz(ts) : -1; 312 313 return 0; 314 } 315 316 static int 317 mq_stat_fop(file_t *fp, struct stat *st) 318 { 319 struct mqueue *mq = fp->f_data; 320 321 memset(st, 0, sizeof(*st)); 322 323 mutex_enter(&mq->mq_mtx); 324 st->st_mode = mq->mq_mode; 325 st->st_uid = mq->mq_euid; 326 st->st_gid = mq->mq_egid; 327 st->st_atimespec = mq->mq_atime; 328 st->st_mtimespec = mq->mq_mtime; 329 st->st_ctimespec = st->st_birthtimespec = mq->mq_btime; 330 st->st_uid = kauth_cred_geteuid(fp->f_cred); 331 st->st_gid = kauth_cred_getegid(fp->f_cred); 332 mutex_exit(&mq->mq_mtx); 333 334 return 0; 335 } 336 337 static int 338 mq_poll_fop(file_t *fp, int events) 339 { 340 struct mqueue *mq = fp->f_data; 341 struct mq_attr *mqattr; 342 int revents = 0; 343 344 mutex_enter(&mq->mq_mtx); 345 mqattr = &mq->mq_attrib; 346 if (events & (POLLIN | POLLRDNORM)) { 347 /* Ready for receiving, if there are messages in the queue */ 348 if (mqattr->mq_curmsgs) 349 revents |= (POLLIN | POLLRDNORM); 350 else 351 selrecord(curlwp, &mq->mq_rsel); 352 } 353 if (events & (POLLOUT | POLLWRNORM)) { 354 /* Ready for sending, if the message queue is not full */ 355 if (mqattr->mq_curmsgs < mqattr->mq_maxmsg) 356 revents |= (POLLOUT | POLLWRNORM); 357 else 358 selrecord(curlwp, &mq->mq_wsel); 359 } 360 mutex_exit(&mq->mq_mtx); 361 362 return revents; 363 } 364 365 static int 366 mq_close_fop(file_t *fp) 367 { 368 struct proc *p = curproc; 369 struct mqueue *mq = fp->f_data; 370 bool destroy; 371 372 mutex_enter(&mqlist_mtx); 373 mutex_enter(&mq->mq_mtx); 374 375 /* Decrease the counters */ 376 p->p_mqueue_cnt--; 377 mq->mq_refcnt--; 378 379 /* Remove notification if registered for this process */ 380 if (mq->mq_notify_proc == p) 381 mq->mq_notify_proc = NULL; 382 383 /* 384 * If this is the last reference and mqueue is marked for unlink, 385 * remove and later destroy the message queue. 386 */ 387 if (mq->mq_refcnt == 0 && (mq->mq_attrib.mq_flags & MQ_UNLINK)) { 388 LIST_REMOVE(mq, mq_list); 389 destroy = true; 390 } else 391 destroy = false; 392 393 mutex_exit(&mq->mq_mtx); 394 mutex_exit(&mqlist_mtx); 395 396 if (destroy) 397 mqueue_destroy(mq); 398 399 return 0; 400 } 401 402 static int 403 mqueue_access(struct mqueue *mq, mode_t mode, kauth_cred_t cred) 404 { 405 406 if (genfs_can_access(VNON, mq->mq_mode, mq->mq_euid, 407 mq->mq_egid, mode, cred)) { 408 return EACCES; 409 } 410 411 return 0; 412 } 413 414 /* 415 * General mqueue system calls. 416 */ 417 418 int 419 sys_mq_open(struct lwp *l, const struct sys_mq_open_args *uap, 420 register_t *retval) 421 { 422 /* { 423 syscallarg(const char *) name; 424 syscallarg(int) oflag; 425 syscallarg(mode_t) mode; 426 syscallarg(struct mq_attr) attr; 427 } */ 428 struct proc *p = l->l_proc; 429 struct mqueue *mq, *mq_new = NULL; 430 file_t *fp; 431 char *name; 432 int mqd, error, oflag; 433 434 oflag = SCARG(uap, oflag); 435 436 /* Get the name from the user-space */ 437 name = kmem_zalloc(MQ_NAMELEN, KM_SLEEP); 438 error = copyinstr(SCARG(uap, name), name, MQ_NAMELEN - 1, NULL); 439 if (error) { 440 kmem_free(name, MQ_NAMELEN); 441 return error; 442 } 443 444 if (oflag & O_CREAT) { 445 struct cwdinfo *cwdi = p->p_cwdi; 446 struct mq_attr attr; 447 u_int i; 448 449 /* Check the limit */ 450 if (p->p_mqueue_cnt == mq_open_max) { 451 kmem_free(name, MQ_NAMELEN); 452 return EMFILE; 453 } 454 455 /* Empty name is invalid */ 456 if (name[0] == '\0') { 457 kmem_free(name, MQ_NAMELEN); 458 return EINVAL; 459 } 460 461 /* Check for mqueue attributes */ 462 if (SCARG(uap, attr)) { 463 error = copyin(SCARG(uap, attr), &attr, 464 sizeof(struct mq_attr)); 465 if (error) { 466 kmem_free(name, MQ_NAMELEN); 467 return error; 468 } 469 if (attr.mq_maxmsg <= 0 || attr.mq_msgsize <= 0 || 470 attr.mq_msgsize > mq_max_msgsize) { 471 kmem_free(name, MQ_NAMELEN); 472 return EINVAL; 473 } 474 attr.mq_curmsgs = 0; 475 } else { 476 memset(&attr, 0, sizeof(struct mq_attr)); 477 attr.mq_maxmsg = mq_def_maxmsg; 478 attr.mq_msgsize = 479 MQ_DEF_MSGSIZE - sizeof(struct mq_msg); 480 } 481 482 /* 483 * Allocate new mqueue, initialize data structures, 484 * copy the name, attributes and set the flag. 485 */ 486 mq_new = kmem_zalloc(sizeof(struct mqueue), KM_SLEEP); 487 488 mutex_init(&mq_new->mq_mtx, MUTEX_DEFAULT, IPL_NONE); 489 cv_init(&mq_new->mq_send_cv, "mqsendcv"); 490 cv_init(&mq_new->mq_recv_cv, "mqrecvcv"); 491 for (i = 0; i < (MQ_PQSIZE + 1); i++) { 492 TAILQ_INIT(&mq_new->mq_head[i]); 493 } 494 selinit(&mq_new->mq_rsel); 495 selinit(&mq_new->mq_wsel); 496 497 strlcpy(mq_new->mq_name, name, MQ_NAMELEN); 498 memcpy(&mq_new->mq_attrib, &attr, sizeof(struct mq_attr)); 499 500 CTASSERT((O_MASK & (MQ_UNLINK | MQ_RECEIVE)) == 0); 501 mq_new->mq_attrib.mq_flags = (O_MASK & oflag); 502 503 /* Store mode and effective UID with GID */ 504 mq_new->mq_mode = ((SCARG(uap, mode) & 505 ~cwdi->cwdi_cmask) & ALLPERMS) & ~S_ISTXT; 506 mq_new->mq_euid = kauth_cred_geteuid(l->l_cred); 507 mq_new->mq_egid = kauth_cred_getegid(l->l_cred); 508 } 509 510 /* Allocate file structure and descriptor */ 511 error = fd_allocfile(&fp, &mqd); 512 if (error) { 513 if (mq_new) 514 mqueue_destroy(mq_new); 515 kmem_free(name, MQ_NAMELEN); 516 return error; 517 } 518 fp->f_type = DTYPE_MQUEUE; 519 fp->f_flag = FFLAGS(oflag) & (FREAD | FWRITE); 520 fp->f_ops = &mqops; 521 522 /* Look up for mqueue with such name */ 523 mutex_enter(&mqlist_mtx); 524 mq = mqueue_lookup(name); 525 if (mq) { 526 mode_t acc_mode; 527 528 KASSERT(mutex_owned(&mq->mq_mtx)); 529 530 /* Check if mqueue is not marked as unlinking */ 531 if (mq->mq_attrib.mq_flags & MQ_UNLINK) { 532 error = EACCES; 533 goto exit; 534 } 535 536 /* Fail if O_EXCL is set, and mqueue already exists */ 537 if ((oflag & O_CREAT) && (oflag & O_EXCL)) { 538 error = EEXIST; 539 goto exit; 540 } 541 542 /* 543 * Check the permissions. Note the difference between 544 * VREAD/VWRITE and FREAD/FWRITE. 545 */ 546 acc_mode = 0; 547 if (fp->f_flag & FREAD) { 548 acc_mode |= VREAD; 549 } 550 if (fp->f_flag & FWRITE) { 551 acc_mode |= VWRITE; 552 } 553 if (mqueue_access(mq, acc_mode, l->l_cred) != 0) { 554 error = EACCES; 555 goto exit; 556 } 557 } else { 558 /* Fail if mqueue neither exists, nor we create it */ 559 if ((oflag & O_CREAT) == 0) { 560 mutex_exit(&mqlist_mtx); 561 KASSERT(mq_new == NULL); 562 fd_abort(p, fp, mqd); 563 kmem_free(name, MQ_NAMELEN); 564 return ENOENT; 565 } 566 567 /* Check the limit */ 568 if (p->p_mqueue_cnt == mq_open_max) { 569 error = EMFILE; 570 goto exit; 571 } 572 573 /* Insert the queue to the list */ 574 mq = mq_new; 575 mutex_enter(&mq->mq_mtx); 576 LIST_INSERT_HEAD(&mqueue_head, mq, mq_list); 577 mq_new = NULL; 578 getnanotime(&mq->mq_btime); 579 mq->mq_atime = mq->mq_mtime = mq->mq_btime; 580 } 581 582 /* Increase the counters, and make descriptor ready */ 583 p->p_mqueue_cnt++; 584 mq->mq_refcnt++; 585 fp->f_data = mq; 586 exit: 587 mutex_exit(&mq->mq_mtx); 588 mutex_exit(&mqlist_mtx); 589 590 if (mq_new) 591 mqueue_destroy(mq_new); 592 if (error) { 593 fd_abort(p, fp, mqd); 594 } else { 595 fd_affix(p, fp, mqd); 596 *retval = mqd; 597 } 598 kmem_free(name, MQ_NAMELEN); 599 600 return error; 601 } 602 603 int 604 sys_mq_close(struct lwp *l, const struct sys_mq_close_args *uap, 605 register_t *retval) 606 { 607 608 return sys_close(l, (const void *)uap, retval); 609 } 610 611 /* 612 * Primary mq_receive1() function. 613 */ 614 int 615 mq_receive1(lwp_t *l, mqd_t mqdes, void *msg_ptr, size_t msg_len, 616 unsigned *msg_prio, int t, ssize_t *mlen) 617 { 618 file_t *fp = NULL; 619 struct mqueue *mq; 620 struct mq_msg *msg = NULL; 621 struct mq_attr *mqattr; 622 u_int idx; 623 int error; 624 625 /* Get the message queue */ 626 error = mqueue_get(mqdes, &fp); 627 if (error) { 628 return error; 629 } 630 mq = fp->f_data; 631 if ((fp->f_flag & FREAD) == 0) { 632 error = EBADF; 633 goto error; 634 } 635 getnanotime(&mq->mq_atime); 636 mqattr = &mq->mq_attrib; 637 638 /* Check the message size limits */ 639 if (msg_len < mqattr->mq_msgsize) { 640 error = EMSGSIZE; 641 goto error; 642 } 643 644 /* Check if queue is empty */ 645 while (mqattr->mq_curmsgs == 0) { 646 if (mqattr->mq_flags & O_NONBLOCK) { 647 error = EAGAIN; 648 goto error; 649 } 650 if (t < 0) { 651 error = EINVAL; 652 goto error; 653 } 654 /* 655 * Block until someone sends the message. 656 * While doing this, notification should not be sent. 657 */ 658 mqattr->mq_flags |= MQ_RECEIVE; 659 error = cv_timedwait_sig(&mq->mq_send_cv, &mq->mq_mtx, t); 660 mqattr->mq_flags &= ~MQ_RECEIVE; 661 if (error || (mqattr->mq_flags & MQ_UNLINK)) { 662 error = (error == EWOULDBLOCK) ? ETIMEDOUT : EINTR; 663 goto error; 664 } 665 } 666 667 /* 668 * Find the highest priority message, and remove it from the queue. 669 * At first, reserved queue is checked, bitmap is next. 670 */ 671 msg = TAILQ_FIRST(&mq->mq_head[MQ_PQRESQ]); 672 if (__predict_true(msg == NULL)) { 673 idx = ffs(mq->mq_bitmap); 674 msg = TAILQ_FIRST(&mq->mq_head[idx]); 675 KASSERT(msg != NULL); 676 } else { 677 idx = MQ_PQRESQ; 678 } 679 TAILQ_REMOVE(&mq->mq_head[idx], msg, msg_queue); 680 681 /* Unmark the bit, if last message. */ 682 if (__predict_true(idx) && TAILQ_EMPTY(&mq->mq_head[idx])) { 683 KASSERT((MQ_PQSIZE - idx) == msg->msg_prio); 684 mq->mq_bitmap &= ~(1 << --idx); 685 } 686 687 /* Decrement the counter and signal waiter, if any */ 688 mqattr->mq_curmsgs--; 689 cv_signal(&mq->mq_recv_cv); 690 691 /* Ready for sending now */ 692 selnotify(&mq->mq_wsel, POLLOUT | POLLWRNORM, 0); 693 error: 694 mutex_exit(&mq->mq_mtx); 695 fd_putfile((int)mqdes); 696 if (error) 697 return error; 698 699 /* 700 * Copy the data to the user-space. 701 * Note: According to POSIX, no message should be removed from the 702 * queue in case of fail - this would be violated. 703 */ 704 *mlen = msg->msg_len; 705 error = copyout(msg->msg_ptr, msg_ptr, msg->msg_len); 706 if (error == 0 && msg_prio) 707 error = copyout(&msg->msg_prio, msg_prio, sizeof(unsigned)); 708 mqueue_freemsg(msg, sizeof(struct mq_msg) + msg->msg_len); 709 710 return error; 711 } 712 713 int 714 sys_mq_receive(struct lwp *l, const struct sys_mq_receive_args *uap, 715 register_t *retval) 716 { 717 /* { 718 syscallarg(mqd_t) mqdes; 719 syscallarg(char *) msg_ptr; 720 syscallarg(size_t) msg_len; 721 syscallarg(unsigned *) msg_prio; 722 } */ 723 int error; 724 ssize_t mlen; 725 726 error = mq_receive1(l, SCARG(uap, mqdes), SCARG(uap, msg_ptr), 727 SCARG(uap, msg_len), SCARG(uap, msg_prio), 0, &mlen); 728 if (error == 0) 729 *retval = mlen; 730 731 return error; 732 } 733 734 int 735 sys___mq_timedreceive50(struct lwp *l, 736 const struct sys___mq_timedreceive50_args *uap, register_t *retval) 737 { 738 /* { 739 syscallarg(mqd_t) mqdes; 740 syscallarg(char *) msg_ptr; 741 syscallarg(size_t) msg_len; 742 syscallarg(unsigned *) msg_prio; 743 syscallarg(const struct timespec *) abs_timeout; 744 } */ 745 int error, t; 746 ssize_t mlen; 747 struct timespec ts; 748 749 /* Get and convert time value */ 750 if (SCARG(uap, abs_timeout)) { 751 error = copyin(SCARG(uap, abs_timeout), &ts, sizeof(ts)); 752 if (error) 753 return error; 754 755 error = abstimeout2timo(&ts, &t); 756 if (error) 757 return error; 758 } else 759 t = 0; 760 761 error = mq_receive1(l, SCARG(uap, mqdes), SCARG(uap, msg_ptr), 762 SCARG(uap, msg_len), SCARG(uap, msg_prio), t, &mlen); 763 if (error == 0) 764 *retval = mlen; 765 766 return error; 767 } 768 769 /* 770 * Primary mq_send1() function. 771 */ 772 int 773 mq_send1(lwp_t *l, mqd_t mqdes, const char *msg_ptr, size_t msg_len, 774 unsigned msg_prio, int t) 775 { 776 file_t *fp = NULL; 777 struct mqueue *mq; 778 struct mq_msg *msg; 779 struct mq_attr *mqattr; 780 struct proc *notify = NULL; 781 ksiginfo_t ksi; 782 size_t size; 783 int error; 784 785 /* Check the priority range */ 786 if (msg_prio >= mq_prio_max) 787 return EINVAL; 788 789 /* Allocate a new message */ 790 size = sizeof(struct mq_msg) + msg_len; 791 if (size > mq_max_msgsize) 792 return EMSGSIZE; 793 794 if (size > MQ_DEF_MSGSIZE) { 795 msg = kmem_alloc(size, KM_SLEEP); 796 } else { 797 msg = pool_cache_get(mqmsg_cache, PR_WAITOK); 798 } 799 800 /* Get the data from user-space */ 801 error = copyin(msg_ptr, msg->msg_ptr, msg_len); 802 if (error) { 803 mqueue_freemsg(msg, size); 804 return error; 805 } 806 msg->msg_len = msg_len; 807 msg->msg_prio = msg_prio; 808 809 /* Get the mqueue */ 810 error = mqueue_get(mqdes, &fp); 811 if (error) { 812 mqueue_freemsg(msg, size); 813 return error; 814 } 815 mq = fp->f_data; 816 if ((fp->f_flag & FWRITE) == 0) { 817 error = EBADF; 818 goto error; 819 } 820 getnanotime(&mq->mq_mtime); 821 mqattr = &mq->mq_attrib; 822 823 /* Check the message size limit */ 824 if (msg_len <= 0 || msg_len > mqattr->mq_msgsize) { 825 error = EMSGSIZE; 826 goto error; 827 } 828 829 /* Check if queue is full */ 830 while (mqattr->mq_curmsgs >= mqattr->mq_maxmsg) { 831 if (mqattr->mq_flags & O_NONBLOCK) { 832 error = EAGAIN; 833 goto error; 834 } 835 if (t < 0) { 836 error = EINVAL; 837 goto error; 838 } 839 /* Block until queue becomes available */ 840 error = cv_timedwait_sig(&mq->mq_recv_cv, &mq->mq_mtx, t); 841 if (error || (mqattr->mq_flags & MQ_UNLINK)) { 842 error = (error == EWOULDBLOCK) ? ETIMEDOUT : error; 843 goto error; 844 } 845 } 846 KASSERT(mqattr->mq_curmsgs < mqattr->mq_maxmsg); 847 848 /* 849 * Insert message into the queue, according to the priority. 850 * Note the difference between index and priority. 851 */ 852 if (__predict_true(msg_prio < MQ_PQSIZE)) { 853 u_int idx = MQ_PQSIZE - msg_prio; 854 855 KASSERT(idx != MQ_PQRESQ); 856 TAILQ_INSERT_TAIL(&mq->mq_head[idx], msg, msg_queue); 857 mq->mq_bitmap |= (1 << --idx); 858 } else { 859 mqueue_linear_insert(mq, msg); 860 } 861 862 /* Check for the notify */ 863 if (mqattr->mq_curmsgs == 0 && mq->mq_notify_proc && 864 (mqattr->mq_flags & MQ_RECEIVE) == 0) { 865 /* Initialize the signal */ 866 KSI_INIT(&ksi); 867 ksi.ksi_signo = mq->mq_sig_notify.sigev_signo; 868 ksi.ksi_code = SI_MESGQ; 869 ksi.ksi_value = mq->mq_sig_notify.sigev_value; 870 /* Unregister the process */ 871 notify = mq->mq_notify_proc; 872 mq->mq_notify_proc = NULL; 873 } 874 875 /* Increment the counter and signal waiter, if any */ 876 mqattr->mq_curmsgs++; 877 cv_signal(&mq->mq_send_cv); 878 879 /* Ready for receiving now */ 880 selnotify(&mq->mq_rsel, POLLIN | POLLRDNORM, 0); 881 error: 882 mutex_exit(&mq->mq_mtx); 883 fd_putfile((int)mqdes); 884 885 if (error) { 886 mqueue_freemsg(msg, size); 887 } else if (notify) { 888 /* Send the notify, if needed */ 889 mutex_enter(proc_lock); 890 kpsignal(notify, &ksi, NULL); 891 mutex_exit(proc_lock); 892 } 893 return error; 894 } 895 896 int 897 sys_mq_send(struct lwp *l, const struct sys_mq_send_args *uap, 898 register_t *retval) 899 { 900 /* { 901 syscallarg(mqd_t) mqdes; 902 syscallarg(const char *) msg_ptr; 903 syscallarg(size_t) msg_len; 904 syscallarg(unsigned) msg_prio; 905 } */ 906 907 return mq_send1(l, SCARG(uap, mqdes), SCARG(uap, msg_ptr), 908 SCARG(uap, msg_len), SCARG(uap, msg_prio), 0); 909 } 910 911 int 912 sys___mq_timedsend50(struct lwp *l, const struct sys___mq_timedsend50_args *uap, 913 register_t *retval) 914 { 915 /* { 916 syscallarg(mqd_t) mqdes; 917 syscallarg(const char *) msg_ptr; 918 syscallarg(size_t) msg_len; 919 syscallarg(unsigned) msg_prio; 920 syscallarg(const struct timespec *) abs_timeout; 921 } */ 922 int t; 923 struct timespec ts; 924 int error; 925 926 /* Get and convert time value */ 927 if (SCARG(uap, abs_timeout)) { 928 error = copyin(SCARG(uap, abs_timeout), &ts, sizeof(ts)); 929 if (error) 930 return error; 931 error = abstimeout2timo(&ts, &t); 932 if (error) 933 return error; 934 } else 935 t = 0; 936 937 return mq_send1(l, SCARG(uap, mqdes), SCARG(uap, msg_ptr), 938 SCARG(uap, msg_len), SCARG(uap, msg_prio), t); 939 } 940 941 int 942 sys_mq_notify(struct lwp *l, const struct sys_mq_notify_args *uap, 943 register_t *retval) 944 { 945 /* { 946 syscallarg(mqd_t) mqdes; 947 syscallarg(const struct sigevent *) notification; 948 } */ 949 file_t *fp = NULL; 950 struct mqueue *mq; 951 struct sigevent sig; 952 int error; 953 954 if (SCARG(uap, notification)) { 955 /* Get the signal from user-space */ 956 error = copyin(SCARG(uap, notification), &sig, 957 sizeof(struct sigevent)); 958 if (error) 959 return error; 960 } 961 962 error = mqueue_get(SCARG(uap, mqdes), &fp); 963 if (error) 964 return error; 965 mq = fp->f_data; 966 967 if (SCARG(uap, notification)) { 968 /* Register notification: set the signal and target process */ 969 if (mq->mq_notify_proc == NULL) { 970 memcpy(&mq->mq_sig_notify, &sig, 971 sizeof(struct sigevent)); 972 mq->mq_notify_proc = l->l_proc; 973 } else { 974 /* Fail if someone else already registered */ 975 error = EBUSY; 976 } 977 } else { 978 /* Unregister the notification */ 979 mq->mq_notify_proc = NULL; 980 } 981 mutex_exit(&mq->mq_mtx); 982 fd_putfile((int)SCARG(uap, mqdes)); 983 984 return error; 985 } 986 987 int 988 sys_mq_getattr(struct lwp *l, const struct sys_mq_getattr_args *uap, 989 register_t *retval) 990 { 991 /* { 992 syscallarg(mqd_t) mqdes; 993 syscallarg(struct mq_attr *) mqstat; 994 } */ 995 file_t *fp = NULL; 996 struct mqueue *mq; 997 struct mq_attr attr; 998 int error; 999 1000 /* Get the message queue */ 1001 error = mqueue_get(SCARG(uap, mqdes), &fp); 1002 if (error) 1003 return error; 1004 mq = fp->f_data; 1005 memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr)); 1006 mutex_exit(&mq->mq_mtx); 1007 fd_putfile((int)SCARG(uap, mqdes)); 1008 1009 return copyout(&attr, SCARG(uap, mqstat), sizeof(struct mq_attr)); 1010 } 1011 1012 int 1013 sys_mq_setattr(struct lwp *l, const struct sys_mq_setattr_args *uap, 1014 register_t *retval) 1015 { 1016 /* { 1017 syscallarg(mqd_t) mqdes; 1018 syscallarg(const struct mq_attr *) mqstat; 1019 syscallarg(struct mq_attr *) omqstat; 1020 } */ 1021 file_t *fp = NULL; 1022 struct mqueue *mq; 1023 struct mq_attr attr; 1024 int error, nonblock; 1025 1026 error = copyin(SCARG(uap, mqstat), &attr, sizeof(struct mq_attr)); 1027 if (error) 1028 return error; 1029 nonblock = (attr.mq_flags & O_NONBLOCK); 1030 1031 /* Get the message queue */ 1032 error = mqueue_get(SCARG(uap, mqdes), &fp); 1033 if (error) 1034 return error; 1035 mq = fp->f_data; 1036 1037 /* Copy the old attributes, if needed */ 1038 if (SCARG(uap, omqstat)) { 1039 memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr)); 1040 } 1041 1042 /* Ignore everything, except O_NONBLOCK */ 1043 if (nonblock) 1044 mq->mq_attrib.mq_flags |= O_NONBLOCK; 1045 else 1046 mq->mq_attrib.mq_flags &= ~O_NONBLOCK; 1047 1048 mutex_exit(&mq->mq_mtx); 1049 fd_putfile((int)SCARG(uap, mqdes)); 1050 1051 /* 1052 * Copy the data to the user-space. 1053 * Note: According to POSIX, the new attributes should not be set in 1054 * case of fail - this would be violated. 1055 */ 1056 if (SCARG(uap, omqstat)) 1057 error = copyout(&attr, SCARG(uap, omqstat), 1058 sizeof(struct mq_attr)); 1059 1060 return error; 1061 } 1062 1063 int 1064 sys_mq_unlink(struct lwp *l, const struct sys_mq_unlink_args *uap, 1065 register_t *retval) 1066 { 1067 /* { 1068 syscallarg(const char *) name; 1069 } */ 1070 struct mqueue *mq; 1071 char *name; 1072 int error, refcnt = 0; 1073 1074 /* Get the name from the user-space */ 1075 name = kmem_zalloc(MQ_NAMELEN, KM_SLEEP); 1076 error = copyinstr(SCARG(uap, name), name, MQ_NAMELEN - 1, NULL); 1077 if (error) { 1078 kmem_free(name, MQ_NAMELEN); 1079 return error; 1080 } 1081 1082 /* Lookup for this file */ 1083 mutex_enter(&mqlist_mtx); 1084 mq = mqueue_lookup(name); 1085 if (mq == NULL) { 1086 error = ENOENT; 1087 goto error; 1088 } 1089 1090 /* Check the permissions */ 1091 if (kauth_cred_geteuid(l->l_cred) != mq->mq_euid && 1092 kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, NULL)) { 1093 mutex_exit(&mq->mq_mtx); 1094 error = EACCES; 1095 goto error; 1096 } 1097 1098 /* Mark message queue as unlinking, before leaving the window */ 1099 mq->mq_attrib.mq_flags |= MQ_UNLINK; 1100 1101 /* Wake up all waiters, if there are such */ 1102 cv_broadcast(&mq->mq_send_cv); 1103 cv_broadcast(&mq->mq_recv_cv); 1104 1105 selnotify(&mq->mq_rsel, POLLHUP, 0); 1106 selnotify(&mq->mq_wsel, POLLHUP, 0); 1107 1108 refcnt = mq->mq_refcnt; 1109 if (refcnt == 0) 1110 LIST_REMOVE(mq, mq_list); 1111 1112 mutex_exit(&mq->mq_mtx); 1113 error: 1114 mutex_exit(&mqlist_mtx); 1115 1116 /* 1117 * If there are no references - destroy the message 1118 * queue, otherwise, the last mq_close() will do that. 1119 */ 1120 if (error == 0 && refcnt == 0) 1121 mqueue_destroy(mq); 1122 1123 kmem_free(name, MQ_NAMELEN); 1124 return error; 1125 } 1126 1127 /* 1128 * System control nodes. 1129 */ 1130 1131 SYSCTL_SETUP(sysctl_mqueue_setup, "sysctl mqueue setup") 1132 { 1133 const struct sysctlnode *node = NULL; 1134 1135 sysctl_createv(clog, 0, NULL, NULL, 1136 CTLFLAG_PERMANENT, 1137 CTLTYPE_NODE, "kern", NULL, 1138 NULL, 0, NULL, 0, 1139 CTL_KERN, CTL_EOL); 1140 sysctl_createv(clog, 0, NULL, NULL, 1141 CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE, 1142 CTLTYPE_INT, "posix_msg", 1143 SYSCTL_DESCR("Version of IEEE Std 1003.1 and its " 1144 "Message Passing option to which the " 1145 "system attempts to conform"), 1146 NULL, _POSIX_MESSAGE_PASSING, NULL, 0, 1147 CTL_KERN, CTL_CREATE, CTL_EOL); 1148 sysctl_createv(clog, 0, NULL, &node, 1149 CTLFLAG_PERMANENT, 1150 CTLTYPE_NODE, "mqueue", 1151 SYSCTL_DESCR("Message queue options"), 1152 NULL, 0, NULL, 0, 1153 CTL_KERN, CTL_CREATE, CTL_EOL); 1154 1155 if (node == NULL) 1156 return; 1157 1158 sysctl_createv(clog, 0, &node, NULL, 1159 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 1160 CTLTYPE_INT, "mq_open_max", 1161 SYSCTL_DESCR("Maximal number of message queue descriptors " 1162 "that process could open"), 1163 NULL, 0, &mq_open_max, 0, 1164 CTL_CREATE, CTL_EOL); 1165 sysctl_createv(clog, 0, &node, NULL, 1166 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 1167 CTLTYPE_INT, "mq_prio_max", 1168 SYSCTL_DESCR("Maximal priority of the message"), 1169 NULL, 0, &mq_prio_max, 0, 1170 CTL_CREATE, CTL_EOL); 1171 sysctl_createv(clog, 0, &node, NULL, 1172 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 1173 CTLTYPE_INT, "mq_max_msgsize", 1174 SYSCTL_DESCR("Maximal allowed size of the message"), 1175 NULL, 0, &mq_max_msgsize, 0, 1176 CTL_CREATE, CTL_EOL); 1177 sysctl_createv(clog, 0, &node, NULL, 1178 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 1179 CTLTYPE_INT, "mq_def_maxmsg", 1180 SYSCTL_DESCR("Default maximal message count"), 1181 NULL, 0, &mq_def_maxmsg, 0, 1182 CTL_CREATE, CTL_EOL); 1183 } 1184 1185 /* 1186 * Debugging. 1187 */ 1188 #if defined(DDB) 1189 1190 void 1191 mqueue_print_list(void (*pr)(const char *, ...)) 1192 { 1193 struct mqueue *mq; 1194 1195 (*pr)("Global list of the message queues:\n"); 1196 (*pr)("%20s %10s %8s %8s %3s %4s %4s %4s\n", 1197 "Name", "Ptr", "Mode", "Flags", "Ref", 1198 "MaxMsg", "MsgSze", "CurMsg"); 1199 LIST_FOREACH(mq, &mqueue_head, mq_list) { 1200 (*pr)("%20s %10p %8x %8x %3u %6lu %6lu %6lu\n", 1201 mq->mq_name, mq, mq->mq_mode, 1202 mq->mq_attrib.mq_flags, mq->mq_refcnt, 1203 mq->mq_attrib.mq_maxmsg, mq->mq_attrib.mq_msgsize, 1204 mq->mq_attrib.mq_curmsgs); 1205 } 1206 } 1207 1208 #endif /* defined(DDB) */ 1209