1 /* $NetBSD: sys_mqueue.c,v 1.13 2009/01/11 02:45:52 christos 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.13 2009/01/11 02:45:52 christos 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 int 221 abstimeout2timo(struct timespec *ts, int *timo) 222 { 223 int error; 224 225 /* 226 * According to POSIX, validation check is needed only in case of 227 * blocking. Thus, set the invalid value right now, and fail latter. 228 */ 229 error = itimespecfix(ts); 230 *timo = (error == 0) ? tstohz(ts) : -1; 231 232 return 0; 233 } 234 235 static int 236 mq_poll_fop(file_t *fp, int events) 237 { 238 struct mqueue *mq = fp->f_data; 239 int revents = 0; 240 241 mutex_enter(&mq->mq_mtx); 242 if (events & (POLLIN | POLLRDNORM)) { 243 /* Ready for receiving, if there are messages in the queue */ 244 if (mq->mq_attrib.mq_curmsgs) 245 revents |= (POLLIN | POLLRDNORM); 246 else 247 selrecord(curlwp, &mq->mq_rsel); 248 } 249 if (events & (POLLOUT | POLLWRNORM)) { 250 /* Ready for sending, if the message queue is not full */ 251 if (mq->mq_attrib.mq_curmsgs < mq->mq_attrib.mq_maxmsg) 252 revents |= (POLLOUT | POLLWRNORM); 253 else 254 selrecord(curlwp, &mq->mq_wsel); 255 } 256 mutex_exit(&mq->mq_mtx); 257 258 return revents; 259 } 260 261 static int 262 mq_close_fop(file_t *fp) 263 { 264 struct proc *p = curproc; 265 struct mqueue *mq = fp->f_data; 266 bool destroy; 267 268 mutex_enter(&mqlist_mtx); 269 mutex_enter(&mq->mq_mtx); 270 271 /* Decrease the counters */ 272 p->p_mqueue_cnt--; 273 mq->mq_refcnt--; 274 275 /* Remove notification if registered for this process */ 276 if (mq->mq_notify_proc == p) 277 mq->mq_notify_proc = NULL; 278 279 /* 280 * If this is the last reference and mqueue is marked for unlink, 281 * remove and later destroy the message queue. 282 */ 283 if (mq->mq_refcnt == 0 && (mq->mq_attrib.mq_flags & MQ_UNLINK)) { 284 LIST_REMOVE(mq, mq_list); 285 destroy = true; 286 } else 287 destroy = false; 288 289 mutex_exit(&mq->mq_mtx); 290 mutex_exit(&mqlist_mtx); 291 292 if (destroy) 293 mqueue_destroy(mq); 294 295 return 0; 296 } 297 298 /* 299 * General mqueue system calls. 300 */ 301 302 int 303 sys_mq_open(struct lwp *l, const struct sys_mq_open_args *uap, 304 register_t *retval) 305 { 306 /* { 307 syscallarg(const char *) name; 308 syscallarg(int) oflag; 309 syscallarg(mode_t) mode; 310 syscallarg(struct mq_attr) attr; 311 } */ 312 struct proc *p = l->l_proc; 313 struct mqueue *mq, *mq_new = NULL; 314 file_t *fp; 315 char *name; 316 int mqd, error, oflag; 317 318 /* Check access mode flags */ 319 oflag = SCARG(uap, oflag); 320 if ((oflag & O_ACCMODE) == 0) 321 return EINVAL; 322 323 /* Get the name from the user-space */ 324 name = kmem_zalloc(MQ_NAMELEN, KM_SLEEP); 325 error = copyinstr(SCARG(uap, name), name, MQ_NAMELEN - 1, NULL); 326 if (error) { 327 kmem_free(name, MQ_NAMELEN); 328 return error; 329 } 330 331 if (oflag & O_CREAT) { 332 struct cwdinfo *cwdi = p->p_cwdi; 333 struct mq_attr attr; 334 335 /* Check the limit */ 336 if (p->p_mqueue_cnt == mq_open_max) { 337 kmem_free(name, MQ_NAMELEN); 338 return EMFILE; 339 } 340 341 /* Check for mqueue attributes */ 342 if (SCARG(uap, attr)) { 343 error = copyin(SCARG(uap, attr), &attr, 344 sizeof(struct mq_attr)); 345 if (error) { 346 kmem_free(name, MQ_NAMELEN); 347 return error; 348 } 349 if (attr.mq_maxmsg <= 0 || attr.mq_msgsize <= 0 || 350 attr.mq_msgsize > mq_max_msgsize) { 351 kmem_free(name, MQ_NAMELEN); 352 return EINVAL; 353 } 354 attr.mq_curmsgs = 0; 355 } else { 356 memset(&attr, 0, sizeof(struct mq_attr)); 357 attr.mq_maxmsg = mq_def_maxmsg; 358 attr.mq_msgsize = 359 MQ_DEF_MSGSIZE - sizeof(struct mq_msg); 360 } 361 362 /* 363 * Allocate new mqueue, initialize data structures, 364 * copy the name, attributes and set the flag. 365 */ 366 mq_new = kmem_zalloc(sizeof(struct mqueue), KM_SLEEP); 367 368 mutex_init(&mq_new->mq_mtx, MUTEX_DEFAULT, IPL_NONE); 369 cv_init(&mq_new->mq_send_cv, "mqsendcv"); 370 cv_init(&mq_new->mq_recv_cv, "mqrecvcv"); 371 TAILQ_INIT(&mq_new->mq_head); 372 selinit(&mq_new->mq_rsel); 373 selinit(&mq_new->mq_wsel); 374 375 strlcpy(mq_new->mq_name, name, MQ_NAMELEN); 376 memcpy(&mq_new->mq_attrib, &attr, sizeof(struct mq_attr)); 377 mq_new->mq_attrib.mq_flags = oflag; 378 379 /* Store mode and effective UID with GID */ 380 mq_new->mq_mode = ((SCARG(uap, mode) & 381 ~cwdi->cwdi_cmask) & ALLPERMS) & ~S_ISTXT; 382 mq_new->mq_euid = kauth_cred_geteuid(l->l_cred); 383 mq_new->mq_egid = kauth_cred_getegid(l->l_cred); 384 } 385 386 /* Allocate file structure and descriptor */ 387 error = fd_allocfile(&fp, &mqd); 388 if (error) { 389 if (mq_new) 390 mqueue_destroy(mq_new); 391 kmem_free(name, MQ_NAMELEN); 392 return error; 393 } 394 fp->f_type = DTYPE_MQUEUE; 395 fp->f_flag = FFLAGS(oflag) & (FREAD | FWRITE); 396 fp->f_ops = &mqops; 397 398 /* Look up for mqueue with such name */ 399 mutex_enter(&mqlist_mtx); 400 mq = mqueue_lookup(name); 401 if (mq) { 402 KASSERT(mutex_owned(&mq->mq_mtx)); 403 404 /* Check if mqueue is not marked as unlinking */ 405 if (mq->mq_attrib.mq_flags & MQ_UNLINK) { 406 error = EACCES; 407 goto exit; 408 } 409 /* Fail if O_EXCL is set, and mqueue already exists */ 410 if ((oflag & O_CREAT) && (oflag & O_EXCL)) { 411 error = EEXIST; 412 goto exit; 413 } 414 /* Check the permission */ 415 if (mqueue_access(l, mq, fp->f_flag)) { 416 error = EACCES; 417 goto exit; 418 } 419 } else { 420 /* Fail if mqueue neither exists, nor we create it */ 421 if ((oflag & O_CREAT) == 0) { 422 mutex_exit(&mqlist_mtx); 423 KASSERT(mq_new == NULL); 424 fd_abort(p, fp, mqd); 425 kmem_free(name, MQ_NAMELEN); 426 return ENOENT; 427 } 428 429 /* Check the limit */ 430 if (p->p_mqueue_cnt == mq_open_max) { 431 error = EMFILE; 432 goto exit; 433 } 434 435 /* Insert the queue to the list */ 436 mq = mq_new; 437 mutex_enter(&mq->mq_mtx); 438 LIST_INSERT_HEAD(&mqueue_head, mq, mq_list); 439 mq_new = NULL; 440 } 441 442 /* Increase the counters, and make descriptor ready */ 443 p->p_mqueue_cnt++; 444 mq->mq_refcnt++; 445 fp->f_data = mq; 446 exit: 447 mutex_exit(&mq->mq_mtx); 448 mutex_exit(&mqlist_mtx); 449 450 if (mq_new) 451 mqueue_destroy(mq_new); 452 if (error) { 453 fd_abort(p, fp, mqd); 454 } else { 455 fd_affix(p, fp, mqd); 456 *retval = mqd; 457 } 458 kmem_free(name, MQ_NAMELEN); 459 460 return error; 461 } 462 463 int 464 sys_mq_close(struct lwp *l, const struct sys_mq_close_args *uap, 465 register_t *retval) 466 { 467 468 return sys_close(l, (const void *)uap, retval); 469 } 470 471 /* 472 * Primary mq_receive1() function. 473 */ 474 int 475 mq_receive1(struct lwp *l, mqd_t mqdes, void *msg_ptr, size_t msg_len, 476 unsigned *msg_prio, int t, ssize_t *mlen) 477 { 478 file_t *fp = NULL; 479 struct mqueue *mq; 480 struct mq_msg *msg = NULL; 481 int error; 482 483 /* Get the message queue */ 484 error = mqueue_get(l, mqdes, FREAD, &fp); 485 if (error) 486 return error; 487 mq = fp->f_data; 488 489 /* Check the message size limits */ 490 if (msg_len < mq->mq_attrib.mq_msgsize) { 491 error = EMSGSIZE; 492 goto error; 493 } 494 495 /* Check if queue is empty */ 496 while (TAILQ_EMPTY(&mq->mq_head)) { 497 if (mq->mq_attrib.mq_flags & O_NONBLOCK) { 498 error = EAGAIN; 499 goto error; 500 } 501 if (t < 0) { 502 error = EINVAL; 503 goto error; 504 } 505 /* 506 * Block until someone sends the message. 507 * While doing this, notification should not be sent. 508 */ 509 mq->mq_attrib.mq_flags |= MQ_RECEIVE; 510 error = cv_timedwait_sig(&mq->mq_send_cv, &mq->mq_mtx, t); 511 mq->mq_attrib.mq_flags &= ~MQ_RECEIVE; 512 if (error || (mq->mq_attrib.mq_flags & MQ_UNLINK)) { 513 error = (error == EWOULDBLOCK) ? ETIMEDOUT : EINTR; 514 goto error; 515 } 516 } 517 518 /* Remove the message from the queue */ 519 msg = TAILQ_FIRST(&mq->mq_head); 520 KASSERT(msg != NULL); 521 TAILQ_REMOVE(&mq->mq_head, msg, msg_queue); 522 523 /* Decrement the counter and signal waiter, if any */ 524 mq->mq_attrib.mq_curmsgs--; 525 cv_signal(&mq->mq_recv_cv); 526 527 /* Ready for sending now */ 528 selnotify(&mq->mq_wsel, POLLOUT | POLLWRNORM, 0); 529 error: 530 mutex_exit(&mq->mq_mtx); 531 fd_putfile((int)mqdes); 532 if (error) 533 return error; 534 535 /* 536 * Copy the data to the user-space. 537 * Note: According to POSIX, no message should be removed from the 538 * queue in case of fail - this would be violated. 539 */ 540 *mlen = msg->msg_len; 541 error = copyout(msg->msg_ptr, msg_ptr, msg->msg_len); 542 if (error == 0 && msg_prio) 543 error = copyout(&msg->msg_prio, msg_prio, sizeof(unsigned)); 544 mqueue_freemsg(msg, sizeof(struct mq_msg) + msg->msg_len); 545 546 return error; 547 } 548 549 int 550 sys_mq_receive(struct lwp *l, const struct sys_mq_receive_args *uap, 551 register_t *retval) 552 { 553 /* { 554 syscallarg(mqd_t) mqdes; 555 syscallarg(char *) msg_ptr; 556 syscallarg(size_t) msg_len; 557 syscallarg(unsigned *) msg_prio; 558 } */ 559 int error; 560 ssize_t mlen; 561 562 error = mq_receive1(l, SCARG(uap, mqdes), SCARG(uap, msg_ptr), 563 SCARG(uap, msg_len), SCARG(uap, msg_prio), 0, &mlen); 564 if (error == 0) 565 *retval = mlen; 566 567 return error; 568 } 569 570 int 571 sys___mq_timedreceive50(struct lwp *l, 572 const struct sys___mq_timedreceive50_args *uap, register_t *retval) 573 { 574 /* { 575 syscallarg(mqd_t) mqdes; 576 syscallarg(char *) msg_ptr; 577 syscallarg(size_t) msg_len; 578 syscallarg(unsigned *) msg_prio; 579 syscallarg(const struct timespec *) abs_timeout; 580 } */ 581 int error, t; 582 ssize_t mlen; 583 struct timespec ts; 584 585 /* Get and convert time value */ 586 if (SCARG(uap, abs_timeout)) { 587 error = copyin(SCARG(uap, abs_timeout), &ts, sizeof(ts)); 588 if (error) 589 return error; 590 591 error = abstimeout2timo(&ts, &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 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_timedsend50(struct lwp *l, const struct sys___mq_timedsend50_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 struct timespec ts; 748 int error; 749 750 /* Get and convert time value */ 751 if (SCARG(uap, abs_timeout)) { 752 error = copyin(SCARG(uap, abs_timeout), &ts, sizeof(ts)); 753 if (error) 754 return error; 755 error = abstimeout2timo(&ts, &t); 756 if (error) 757 return error; 758 } else 759 t = 0; 760 761 return mq_send1(l, SCARG(uap, mqdes), SCARG(uap, msg_ptr), 762 SCARG(uap, msg_len), SCARG(uap, msg_prio), t); 763 } 764 765 int 766 sys_mq_notify(struct lwp *l, const struct sys_mq_notify_args *uap, 767 register_t *retval) 768 { 769 /* { 770 syscallarg(mqd_t) mqdes; 771 syscallarg(const struct sigevent *) notification; 772 } */ 773 file_t *fp = NULL; 774 struct mqueue *mq; 775 struct sigevent sig; 776 int error; 777 778 if (SCARG(uap, notification)) { 779 /* Get the signal from user-space */ 780 error = copyin(SCARG(uap, notification), &sig, 781 sizeof(struct sigevent)); 782 if (error) 783 return error; 784 } 785 786 error = mqueue_get(l, SCARG(uap, mqdes), FNOVAL, &fp); 787 if (error) 788 return error; 789 mq = fp->f_data; 790 791 if (SCARG(uap, notification)) { 792 /* Register notification: set the signal and target process */ 793 if (mq->mq_notify_proc == NULL) { 794 memcpy(&mq->mq_sig_notify, &sig, 795 sizeof(struct sigevent)); 796 mq->mq_notify_proc = l->l_proc; 797 } else { 798 /* Fail if someone else already registered */ 799 error = EBUSY; 800 } 801 } else { 802 /* Unregister the notification */ 803 mq->mq_notify_proc = NULL; 804 } 805 mutex_exit(&mq->mq_mtx); 806 fd_putfile((int)SCARG(uap, mqdes)); 807 808 return error; 809 } 810 811 int 812 sys_mq_getattr(struct lwp *l, const struct sys_mq_getattr_args *uap, 813 register_t *retval) 814 { 815 /* { 816 syscallarg(mqd_t) mqdes; 817 syscallarg(struct mq_attr *) mqstat; 818 } */ 819 file_t *fp = NULL; 820 struct mqueue *mq; 821 struct mq_attr attr; 822 int error; 823 824 /* Get the message queue */ 825 error = mqueue_get(l, SCARG(uap, mqdes), FNOVAL, &fp); 826 if (error) 827 return error; 828 mq = fp->f_data; 829 memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr)); 830 mutex_exit(&mq->mq_mtx); 831 fd_putfile((int)SCARG(uap, mqdes)); 832 833 return copyout(&attr, SCARG(uap, mqstat), sizeof(struct mq_attr)); 834 } 835 836 int 837 sys_mq_setattr(struct lwp *l, const struct sys_mq_setattr_args *uap, 838 register_t *retval) 839 { 840 /* { 841 syscallarg(mqd_t) mqdes; 842 syscallarg(const struct mq_attr *) mqstat; 843 syscallarg(struct mq_attr *) omqstat; 844 } */ 845 file_t *fp = NULL; 846 struct mqueue *mq; 847 struct mq_attr attr; 848 int error, nonblock; 849 850 error = copyin(SCARG(uap, mqstat), &attr, sizeof(struct mq_attr)); 851 if (error) 852 return error; 853 nonblock = (attr.mq_flags & O_NONBLOCK); 854 855 /* Get the message queue */ 856 error = mqueue_get(l, SCARG(uap, mqdes), FNOVAL, &fp); 857 if (error) 858 return error; 859 mq = fp->f_data; 860 861 /* Copy the old attributes, if needed */ 862 if (SCARG(uap, omqstat)) 863 memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr)); 864 865 /* Ignore everything, except O_NONBLOCK */ 866 if (nonblock) 867 mq->mq_attrib.mq_flags |= O_NONBLOCK; 868 else 869 mq->mq_attrib.mq_flags &= ~O_NONBLOCK; 870 871 mutex_exit(&mq->mq_mtx); 872 fd_putfile((int)SCARG(uap, mqdes)); 873 874 /* 875 * Copy the data to the user-space. 876 * Note: According to POSIX, the new attributes should not be set in 877 * case of fail - this would be violated. 878 */ 879 if (SCARG(uap, omqstat)) 880 error = copyout(&attr, SCARG(uap, omqstat), 881 sizeof(struct mq_attr)); 882 883 return error; 884 } 885 886 int 887 sys_mq_unlink(struct lwp *l, const struct sys_mq_unlink_args *uap, 888 register_t *retval) 889 { 890 /* { 891 syscallarg(const char *) name; 892 } */ 893 struct mqueue *mq; 894 char *name; 895 int error, refcnt = 0; 896 897 /* Get the name from the user-space */ 898 name = kmem_zalloc(MQ_NAMELEN, KM_SLEEP); 899 error = copyinstr(SCARG(uap, name), name, MQ_NAMELEN - 1, NULL); 900 if (error) { 901 kmem_free(name, MQ_NAMELEN); 902 return error; 903 } 904 905 /* Lookup for this file */ 906 mutex_enter(&mqlist_mtx); 907 mq = mqueue_lookup(name); 908 if (mq == NULL) { 909 error = ENOENT; 910 goto error; 911 } 912 913 /* Check the permissions */ 914 if (mqueue_access(l, mq, FWRITE)) { 915 mutex_exit(&mq->mq_mtx); 916 error = EACCES; 917 goto error; 918 } 919 920 /* Mark message queue as unlinking, before leaving the window */ 921 mq->mq_attrib.mq_flags |= MQ_UNLINK; 922 923 /* Wake up all waiters, if there are such */ 924 cv_broadcast(&mq->mq_send_cv); 925 cv_broadcast(&mq->mq_recv_cv); 926 927 selnotify(&mq->mq_rsel, POLLHUP, 0); 928 selnotify(&mq->mq_wsel, POLLHUP, 0); 929 930 refcnt = mq->mq_refcnt; 931 if (refcnt == 0) 932 LIST_REMOVE(mq, mq_list); 933 934 mutex_exit(&mq->mq_mtx); 935 error: 936 mutex_exit(&mqlist_mtx); 937 938 /* 939 * If there are no references - destroy the message 940 * queue, otherwise, the last mq_close() will do that. 941 */ 942 if (error == 0 && refcnt == 0) 943 mqueue_destroy(mq); 944 945 kmem_free(name, MQ_NAMELEN); 946 return error; 947 } 948 949 /* 950 * SysCtl. 951 */ 952 953 SYSCTL_SETUP(sysctl_mqueue_setup, "sysctl mqueue setup") 954 { 955 const struct sysctlnode *node = NULL; 956 957 sysctl_createv(clog, 0, NULL, NULL, 958 CTLFLAG_PERMANENT, 959 CTLTYPE_NODE, "kern", NULL, 960 NULL, 0, NULL, 0, 961 CTL_KERN, CTL_EOL); 962 sysctl_createv(clog, 0, NULL, NULL, 963 CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE, 964 CTLTYPE_INT, "posix_msg", 965 SYSCTL_DESCR("Version of IEEE Std 1003.1 and its " 966 "Message Passing option to which the " 967 "system attempts to conform"), 968 NULL, _POSIX_MESSAGE_PASSING, NULL, 0, 969 CTL_KERN, CTL_CREATE, CTL_EOL); 970 sysctl_createv(clog, 0, NULL, &node, 971 CTLFLAG_PERMANENT, 972 CTLTYPE_NODE, "mqueue", 973 SYSCTL_DESCR("Message queue options"), 974 NULL, 0, NULL, 0, 975 CTL_KERN, CTL_CREATE, CTL_EOL); 976 977 if (node == NULL) 978 return; 979 980 sysctl_createv(clog, 0, &node, NULL, 981 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 982 CTLTYPE_INT, "mq_open_max", 983 SYSCTL_DESCR("Maximal number of message queue descriptors " 984 "that process could open"), 985 NULL, 0, &mq_open_max, 0, 986 CTL_CREATE, CTL_EOL); 987 sysctl_createv(clog, 0, &node, NULL, 988 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 989 CTLTYPE_INT, "mq_prio_max", 990 SYSCTL_DESCR("Maximal priority of the message"), 991 NULL, 0, &mq_prio_max, 0, 992 CTL_CREATE, CTL_EOL); 993 sysctl_createv(clog, 0, &node, NULL, 994 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 995 CTLTYPE_INT, "mq_max_msgsize", 996 SYSCTL_DESCR("Maximal allowed size of the message"), 997 NULL, 0, &mq_max_msgsize, 0, 998 CTL_CREATE, CTL_EOL); 999 sysctl_createv(clog, 0, &node, NULL, 1000 CTLFLAG_PERMANENT | CTLFLAG_READWRITE, 1001 CTLTYPE_INT, "mq_def_maxmsg", 1002 SYSCTL_DESCR("Default maximal message count"), 1003 NULL, 0, &mq_def_maxmsg, 0, 1004 CTL_CREATE, CTL_EOL); 1005 } 1006 1007 /* 1008 * Debugging. 1009 */ 1010 #if defined(DDB) 1011 1012 void 1013 mqueue_print_list(void (*pr)(const char *, ...)) 1014 { 1015 struct mqueue *mq; 1016 1017 (*pr)("Global list of the message queues:\n"); 1018 (*pr)("%20s %10s %8s %8s %3s %4s %4s %4s\n", 1019 "Name", "Ptr", "Mode", "Flags", "Ref", 1020 "MaxMsg", "MsgSze", "CurMsg"); 1021 LIST_FOREACH(mq, &mqueue_head, mq_list) { 1022 (*pr)("%20s %10p %8x %8x %3u %6lu %6lu %6lu\n", 1023 mq->mq_name, mq, mq->mq_mode, 1024 mq->mq_attrib.mq_flags, mq->mq_refcnt, 1025 mq->mq_attrib.mq_maxmsg, mq->mq_attrib.mq_msgsize, 1026 mq->mq_attrib.mq_curmsgs); 1027 } 1028 } 1029 1030 #endif /* defined(DDB) */ 1031