1 /* $NetBSD: sys_mqueue.c,v 1.11 2008/07/02 20:06:09 rmind 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.11 2008/07/02 20:06:09 rmind 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 = FFLAGS(oflag) & (FREAD | FWRITE); 385 fp->f_ops = &mqops; 386 387 /* Look up for mqueue with such name */ 388 mutex_enter(&mqlist_mtx); 389 mq = mqueue_lookup(name); 390 if (mq) { 391 const int acc_mode = (oflag & O_RDWR) ? (VREAD | VWRITE) : 392 ((oflag & O_RDONLY) ? VREAD : VWRITE); 393 394 KASSERT(mutex_owned(&mq->mq_mtx)); 395 /* Check if mqueue is not marked as unlinking */ 396 if (mq->mq_attrib.mq_flags & MQ_UNLINK) { 397 error = EACCES; 398 goto exit; 399 } 400 /* Fail if O_EXCL is set, and mqueue already exists */ 401 if ((oflag & O_CREAT) && (oflag & O_EXCL)) { 402 error = EEXIST; 403 goto exit; 404 } 405 /* Check the permission */ 406 if (mqueue_access(l, mq, acc_mode)) { 407 error = EACCES; 408 goto exit; 409 } 410 } else { 411 /* Fail if mqueue neither exists, nor we create it */ 412 if ((oflag & O_CREAT) == 0) { 413 mutex_exit(&mqlist_mtx); 414 KASSERT(mq_new == NULL); 415 fd_abort(p, fp, mqd); 416 kmem_free(name, MQ_NAMELEN); 417 return ENOENT; 418 } 419 420 /* Check the limit */ 421 if (p->p_mqueue_cnt == mq_open_max) { 422 error = EMFILE; 423 goto exit; 424 } 425 426 /* Insert the queue to the list */ 427 mq = mq_new; 428 mutex_enter(&mq->mq_mtx); 429 LIST_INSERT_HEAD(&mqueue_head, mq, mq_list); 430 mq_new = NULL; 431 } 432 433 /* Increase the counters, and make descriptor ready */ 434 p->p_mqueue_cnt++; 435 mq->mq_refcnt++; 436 fp->f_data = mq; 437 exit: 438 mutex_exit(&mq->mq_mtx); 439 mutex_exit(&mqlist_mtx); 440 441 if (mq_new) 442 mqueue_destroy(mq_new); 443 if (error) { 444 fd_abort(p, fp, mqd); 445 } else { 446 fd_affix(p, fp, mqd); 447 *retval = mqd; 448 } 449 kmem_free(name, MQ_NAMELEN); 450 451 return error; 452 } 453 454 int 455 sys_mq_close(struct lwp *l, const struct sys_mq_close_args *uap, 456 register_t *retval) 457 { 458 459 return sys_close(l, (const void *)uap, retval); 460 } 461 462 /* 463 * Primary mq_receive1() function. 464 */ 465 static int 466 mq_receive1(struct lwp *l, mqd_t mqdes, void *msg_ptr, size_t msg_len, 467 unsigned *msg_prio, int t, ssize_t *mlen) 468 { 469 file_t *fp = NULL; 470 struct mqueue *mq; 471 struct mq_msg *msg = NULL; 472 int error; 473 474 /* Get the message queue */ 475 error = mqueue_get(l, mqdes, VREAD, &fp); 476 if (error) 477 return error; 478 mq = fp->f_data; 479 480 /* Check the message size limits */ 481 if (msg_len < mq->mq_attrib.mq_msgsize) { 482 error = EMSGSIZE; 483 goto error; 484 } 485 486 /* Check if queue is empty */ 487 while (TAILQ_EMPTY(&mq->mq_head)) { 488 if (mq->mq_attrib.mq_flags & O_NONBLOCK) { 489 error = EAGAIN; 490 goto error; 491 } 492 if (t < 0) { 493 error = EINVAL; 494 goto error; 495 } 496 /* 497 * Block until someone sends the message. 498 * While doing this, notification should not be sent. 499 */ 500 mq->mq_attrib.mq_flags |= MQ_RECEIVE; 501 error = cv_timedwait_sig(&mq->mq_send_cv, &mq->mq_mtx, t); 502 mq->mq_attrib.mq_flags &= ~MQ_RECEIVE; 503 if (error || (mq->mq_attrib.mq_flags & MQ_UNLINK)) { 504 error = (error == EWOULDBLOCK) ? ETIMEDOUT : EINTR; 505 goto error; 506 } 507 } 508 509 /* Remove the message from the queue */ 510 msg = TAILQ_FIRST(&mq->mq_head); 511 KASSERT(msg != NULL); 512 TAILQ_REMOVE(&mq->mq_head, msg, msg_queue); 513 514 /* Decrement the counter and signal waiter, if any */ 515 mq->mq_attrib.mq_curmsgs--; 516 cv_signal(&mq->mq_recv_cv); 517 518 /* Ready for sending now */ 519 selnotify(&mq->mq_wsel, POLLOUT | POLLWRNORM, 0); 520 error: 521 mutex_exit(&mq->mq_mtx); 522 fd_putfile((int)mqdes); 523 if (error) 524 return error; 525 526 /* 527 * Copy the data to the user-space. 528 * Note: According to POSIX, no message should be removed from the 529 * queue in case of fail - this would be violated. 530 */ 531 *mlen = msg->msg_len; 532 error = copyout(msg->msg_ptr, msg_ptr, msg->msg_len); 533 if (error == 0 && msg_prio) 534 error = copyout(&msg->msg_prio, msg_prio, sizeof(unsigned)); 535 mqueue_freemsg(msg, sizeof(struct mq_msg) + msg->msg_len); 536 537 return error; 538 } 539 540 int 541 sys_mq_receive(struct lwp *l, const struct sys_mq_receive_args *uap, 542 register_t *retval) 543 { 544 /* { 545 syscallarg(mqd_t) mqdes; 546 syscallarg(char *) msg_ptr; 547 syscallarg(size_t) msg_len; 548 syscallarg(unsigned *) msg_prio; 549 } */ 550 int error; 551 ssize_t mlen; 552 553 error = mq_receive1(l, SCARG(uap, mqdes), SCARG(uap, msg_ptr), 554 SCARG(uap, msg_len), SCARG(uap, msg_prio), 0, &mlen); 555 if (error == 0) 556 *retval = mlen; 557 558 return error; 559 } 560 561 int 562 sys_mq_timedreceive(struct lwp *l, const struct sys_mq_timedreceive_args *uap, 563 register_t *retval) 564 { 565 /* { 566 syscallarg(mqd_t) mqdes; 567 syscallarg(char *) msg_ptr; 568 syscallarg(size_t) msg_len; 569 syscallarg(unsigned *) msg_prio; 570 syscallarg(const struct timespec *) abs_timeout; 571 } */ 572 int error, t; 573 ssize_t mlen; 574 575 /* Get and convert time value */ 576 if (SCARG(uap, abs_timeout)) { 577 error = abstimeout2timo(SCARG(uap, abs_timeout), &t); 578 if (error) 579 return error; 580 } else 581 t = 0; 582 583 error = mq_receive1(l, SCARG(uap, mqdes), SCARG(uap, msg_ptr), 584 SCARG(uap, msg_len), SCARG(uap, msg_prio), t, &mlen); 585 if (error == 0) 586 *retval = mlen; 587 588 return error; 589 } 590 591 /* 592 * Primary mq_send1() function. 593 */ 594 static int 595 mq_send1(struct lwp *l, mqd_t mqdes, const char *msg_ptr, size_t msg_len, 596 unsigned msg_prio, int t) 597 { 598 file_t *fp = NULL; 599 struct mqueue *mq; 600 struct mq_msg *msg, *pos_msg; 601 struct proc *notify = NULL; 602 ksiginfo_t ksi; 603 size_t size; 604 int error; 605 606 /* Check the priority range */ 607 if (msg_prio >= mq_prio_max) 608 return EINVAL; 609 610 /* Allocate a new message */ 611 size = sizeof(struct mq_msg) + msg_len; 612 if (size > mq_max_msgsize) 613 return EMSGSIZE; 614 615 if (size > MQ_DEF_MSGSIZE) 616 msg = kmem_alloc(size, KM_SLEEP); 617 else 618 msg = pool_cache_get(mqmsg_cache, PR_WAITOK); 619 620 /* Get the data from user-space */ 621 error = copyin(msg_ptr, msg->msg_ptr, msg_len); 622 if (error) { 623 mqueue_freemsg(msg, size); 624 return error; 625 } 626 msg->msg_len = msg_len; 627 msg->msg_prio = msg_prio; 628 629 /* Get the mqueue */ 630 error = mqueue_get(l, mqdes, VWRITE, &fp); 631 if (error) { 632 mqueue_freemsg(msg, size); 633 return error; 634 } 635 mq = fp->f_data; 636 637 /* Check the message size limit */ 638 if (msg_len <= 0 || msg_len > mq->mq_attrib.mq_msgsize) { 639 error = EMSGSIZE; 640 goto error; 641 } 642 643 /* Check if queue is full */ 644 while (mq->mq_attrib.mq_curmsgs >= mq->mq_attrib.mq_maxmsg) { 645 if (mq->mq_attrib.mq_flags & O_NONBLOCK) { 646 error = EAGAIN; 647 goto error; 648 } 649 if (t < 0) { 650 error = EINVAL; 651 goto error; 652 } 653 /* Block until queue becomes available */ 654 error = cv_timedwait_sig(&mq->mq_recv_cv, &mq->mq_mtx, t); 655 if (error || (mq->mq_attrib.mq_flags & MQ_UNLINK)) { 656 error = (error == EWOULDBLOCK) ? ETIMEDOUT : error; 657 goto error; 658 } 659 } 660 KASSERT(mq->mq_attrib.mq_curmsgs < mq->mq_attrib.mq_maxmsg); 661 662 /* Insert message into the queue, according to the priority */ 663 TAILQ_FOREACH(pos_msg, &mq->mq_head, msg_queue) 664 if (msg->msg_prio > pos_msg->msg_prio) 665 break; 666 if (pos_msg == NULL) 667 TAILQ_INSERT_TAIL(&mq->mq_head, msg, msg_queue); 668 else 669 TAILQ_INSERT_BEFORE(pos_msg, msg, msg_queue); 670 671 /* Check for the notify */ 672 if (mq->mq_attrib.mq_curmsgs == 0 && mq->mq_notify_proc && 673 (mq->mq_attrib.mq_flags & MQ_RECEIVE) == 0) { 674 /* Initialize the signal */ 675 KSI_INIT(&ksi); 676 ksi.ksi_signo = mq->mq_sig_notify.sigev_signo; 677 ksi.ksi_code = SI_MESGQ; 678 ksi.ksi_value = mq->mq_sig_notify.sigev_value; 679 /* Unregister the process */ 680 notify = mq->mq_notify_proc; 681 mq->mq_notify_proc = NULL; 682 } 683 684 /* Increment the counter and signal waiter, if any */ 685 mq->mq_attrib.mq_curmsgs++; 686 cv_signal(&mq->mq_send_cv); 687 688 /* Ready for receiving now */ 689 selnotify(&mq->mq_rsel, POLLIN | POLLRDNORM, 0); 690 error: 691 mutex_exit(&mq->mq_mtx); 692 fd_putfile((int)mqdes); 693 694 if (error) { 695 mqueue_freemsg(msg, size); 696 } else if (notify) { 697 /* Send the notify, if needed */ 698 mutex_enter(proc_lock); 699 kpsignal(notify, &ksi, NULL); 700 mutex_exit(proc_lock); 701 } 702 703 return error; 704 } 705 706 int 707 sys_mq_send(struct lwp *l, const struct sys_mq_send_args *uap, 708 register_t *retval) 709 { 710 /* { 711 syscallarg(mqd_t) mqdes; 712 syscallarg(const char *) msg_ptr; 713 syscallarg(size_t) msg_len; 714 syscallarg(unsigned) msg_prio; 715 } */ 716 717 return mq_send1(l, SCARG(uap, mqdes), SCARG(uap, msg_ptr), 718 SCARG(uap, msg_len), SCARG(uap, msg_prio), 0); 719 } 720 721 int 722 sys_mq_timedsend(struct lwp *l, const struct sys_mq_timedsend_args *uap, 723 register_t *retval) 724 { 725 /* { 726 syscallarg(mqd_t) mqdes; 727 syscallarg(const char *) msg_ptr; 728 syscallarg(size_t) msg_len; 729 syscallarg(unsigned) msg_prio; 730 syscallarg(const struct timespec *) abs_timeout; 731 } */ 732 int t; 733 734 /* Get and convert time value */ 735 if (SCARG(uap, abs_timeout)) { 736 int error = abstimeout2timo(SCARG(uap, abs_timeout), &t); 737 if (error) 738 return error; 739 } else 740 t = 0; 741 742 return mq_send1(l, SCARG(uap, mqdes), SCARG(uap, msg_ptr), 743 SCARG(uap, msg_len), SCARG(uap, msg_prio), t); 744 } 745 746 int 747 sys_mq_notify(struct lwp *l, const struct sys_mq_notify_args *uap, 748 register_t *retval) 749 { 750 /* { 751 syscallarg(mqd_t) mqdes; 752 syscallarg(const struct sigevent *) notification; 753 } */ 754 file_t *fp = NULL; 755 struct mqueue *mq; 756 struct sigevent sig; 757 int error; 758 759 if (SCARG(uap, notification)) { 760 /* Get the signal from user-space */ 761 error = copyin(SCARG(uap, notification), &sig, 762 sizeof(struct sigevent)); 763 if (error) 764 return error; 765 } 766 767 error = mqueue_get(l, SCARG(uap, mqdes), VNOVAL, &fp); 768 if (error) 769 return error; 770 mq = fp->f_data; 771 772 if (SCARG(uap, notification)) { 773 /* Register notification: set the signal and target process */ 774 if (mq->mq_notify_proc == NULL) { 775 memcpy(&mq->mq_sig_notify, &sig, 776 sizeof(struct sigevent)); 777 mq->mq_notify_proc = l->l_proc; 778 } else { 779 /* Fail if someone else already registered */ 780 error = EBUSY; 781 } 782 } else { 783 /* Unregister the notification */ 784 mq->mq_notify_proc = NULL; 785 } 786 mutex_exit(&mq->mq_mtx); 787 fd_putfile((int)SCARG(uap, mqdes)); 788 789 return error; 790 } 791 792 int 793 sys_mq_getattr(struct lwp *l, const struct sys_mq_getattr_args *uap, 794 register_t *retval) 795 { 796 /* { 797 syscallarg(mqd_t) mqdes; 798 syscallarg(struct mq_attr *) mqstat; 799 } */ 800 file_t *fp = NULL; 801 struct mqueue *mq; 802 struct mq_attr attr; 803 int error; 804 805 /* Get the message queue */ 806 error = mqueue_get(l, SCARG(uap, mqdes), VNOVAL, &fp); 807 if (error) 808 return error; 809 mq = fp->f_data; 810 memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr)); 811 mutex_exit(&mq->mq_mtx); 812 fd_putfile((int)SCARG(uap, mqdes)); 813 814 return copyout(&attr, SCARG(uap, mqstat), sizeof(struct mq_attr)); 815 } 816 817 int 818 sys_mq_setattr(struct lwp *l, const struct sys_mq_setattr_args *uap, 819 register_t *retval) 820 { 821 /* { 822 syscallarg(mqd_t) mqdes; 823 syscallarg(const struct mq_attr *) mqstat; 824 syscallarg(struct mq_attr *) omqstat; 825 } */ 826 file_t *fp = NULL; 827 struct mqueue *mq; 828 struct mq_attr attr; 829 int error, nonblock; 830 831 error = copyin(SCARG(uap, mqstat), &attr, sizeof(struct mq_attr)); 832 if (error) 833 return error; 834 nonblock = (attr.mq_flags & O_NONBLOCK); 835 836 /* Get the message queue */ 837 error = mqueue_get(l, SCARG(uap, mqdes), VNOVAL, &fp); 838 if (error) 839 return error; 840 mq = fp->f_data; 841 842 /* Copy the old attributes, if needed */ 843 if (SCARG(uap, omqstat)) 844 memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr)); 845 846 /* Ignore everything, except O_NONBLOCK */ 847 if (nonblock) 848 mq->mq_attrib.mq_flags |= O_NONBLOCK; 849 else 850 mq->mq_attrib.mq_flags &= ~O_NONBLOCK; 851 852 mutex_exit(&mq->mq_mtx); 853 fd_putfile((int)SCARG(uap, mqdes)); 854 855 /* 856 * Copy the data to the user-space. 857 * Note: According to POSIX, the new attributes should not be set in 858 * case of fail - this would be violated. 859 */ 860 if (SCARG(uap, omqstat)) 861 error = copyout(&attr, SCARG(uap, omqstat), 862 sizeof(struct mq_attr)); 863 864 return error; 865 } 866 867 int 868 sys_mq_unlink(struct lwp *l, const struct sys_mq_unlink_args *uap, 869 register_t *retval) 870 { 871 /* { 872 syscallarg(const char *) name; 873 } */ 874 struct mqueue *mq; 875 char *name; 876 int error, refcnt = 0; 877 878 /* Get the name from the user-space */ 879 name = kmem_zalloc(MQ_NAMELEN, KM_SLEEP); 880 error = copyinstr(SCARG(uap, name), name, MQ_NAMELEN - 1, NULL); 881 if (error) { 882 kmem_free(name, MQ_NAMELEN); 883 return error; 884 } 885 886 /* Lookup for this file */ 887 mutex_enter(&mqlist_mtx); 888 mq = mqueue_lookup(name); 889 if (mq == NULL) { 890 error = ENOENT; 891 goto error; 892 } 893 894 /* Check the permissions */ 895 if (mqueue_access(l, mq, VWRITE)) { 896 mutex_exit(&mq->mq_mtx); 897 error = EACCES; 898 goto error; 899 } 900 901 /* Mark message queue as unlinking, before leaving the window */ 902 mq->mq_attrib.mq_flags |= MQ_UNLINK; 903 904 /* Wake up all waiters, if there are such */ 905 cv_broadcast(&mq->mq_send_cv); 906 cv_broadcast(&mq->mq_recv_cv); 907 908 selnotify(&mq->mq_rsel, POLLHUP, 0); 909 selnotify(&mq->mq_wsel, POLLHUP, 0); 910 911 refcnt = mq->mq_refcnt; 912 if (refcnt == 0) 913 LIST_REMOVE(mq, mq_list); 914 915 mutex_exit(&mq->mq_mtx); 916 error: 917 mutex_exit(&mqlist_mtx); 918 919 /* 920 * If there are no references - destroy the message 921 * queue, otherwise, the last mq_close() will do that. 922 */ 923 if (error == 0 && refcnt == 0) 924 mqueue_destroy(mq); 925 926 kmem_free(name, MQ_NAMELEN); 927 return error; 928 } 929 930 /* 931 * SysCtl. 932 */ 933 934 SYSCTL_SETUP(sysctl_mqueue_setup, "sysctl mqueue setup") 935 { 936 const struct sysctlnode *node = NULL; 937 938 sysctl_createv(clog, 0, NULL, NULL, 939 CTLFLAG_PERMANENT, 940 CTLTYPE_NODE, "kern", NULL, 941 NULL, 0, NULL, 0, 942 CTL_KERN, CTL_EOL); 943 sysctl_createv(clog, 0, NULL, NULL, 944 CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE, 945 CTLTYPE_INT, "posix_msg", 946 SYSCTL_DESCR("Version of IEEE Std 1003.1 and its " 947 "Message Passing option to which the " 948 "system attempts to conform"), 949 NULL, _POSIX_MESSAGE_PASSING, NULL, 0, 950 CTL_KERN, CTL_CREATE, CTL_EOL); 951 sysctl_createv(clog, 0, NULL, &node, 952 CTLFLAG_PERMANENT, 953 CTLTYPE_NODE, "mqueue", 954 SYSCTL_DESCR("Message queue options"), 955 NULL, 0, NULL, 0, 956 CTL_KERN, CTL_CREATE, CTL_EOL); 957 958 if (node == NULL) 959 return; 960 961 sysctl_createv(clog, 0, &node, NULL, 962 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 963 CTLTYPE_INT, "mq_open_max", 964 SYSCTL_DESCR("Maximal number of message queue descriptors " 965 "that process could open"), 966 NULL, 0, &mq_open_max, 0, 967 CTL_CREATE, CTL_EOL); 968 sysctl_createv(clog, 0, &node, NULL, 969 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 970 CTLTYPE_INT, "mq_prio_max", 971 SYSCTL_DESCR("Maximal priority of the message"), 972 NULL, 0, &mq_prio_max, 0, 973 CTL_CREATE, CTL_EOL); 974 sysctl_createv(clog, 0, &node, NULL, 975 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 976 CTLTYPE_INT, "mq_max_msgsize", 977 SYSCTL_DESCR("Maximal allowed size of the message"), 978 NULL, 0, &mq_max_msgsize, 0, 979 CTL_CREATE, CTL_EOL); 980 sysctl_createv(clog, 0, &node, NULL, 981 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 982 CTLTYPE_INT, "mq_def_maxmsg", 983 SYSCTL_DESCR("Default maximal message count"), 984 NULL, 0, &mq_def_maxmsg, 0, 985 CTL_CREATE, CTL_EOL); 986 } 987 988 /* 989 * Debugging. 990 */ 991 #if defined(DDB) 992 993 void 994 mqueue_print_list(void (*pr)(const char *, ...)) 995 { 996 struct mqueue *mq; 997 998 (*pr)("Global list of the message queues:\n"); 999 (*pr)("%20s %10s %8s %8s %3s %4s %4s %4s\n", 1000 "Name", "Ptr", "Mode", "Flags", "Ref", 1001 "MaxMsg", "MsgSze", "CurMsg"); 1002 LIST_FOREACH(mq, &mqueue_head, mq_list) { 1003 (*pr)("%20s %10p %8x %8x %3u %6lu %6lu %6lu\n", 1004 mq->mq_name, mq, mq->mq_mode, 1005 mq->mq_attrib.mq_flags, mq->mq_refcnt, 1006 mq->mq_attrib.mq_maxmsg, mq->mq_attrib.mq_msgsize, 1007 mq->mq_attrib.mq_curmsgs); 1008 } 1009 } 1010 1011 #endif /* defined(DDB) */ 1012