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