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