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