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