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