1 /* $NetBSD: sys_mqueue.c,v 1.16 2009/04/11 23:05:26 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 <stdbool.h> 45 #include <sys/param.h> 46 #include <sys/types.h> 47 #include <sys/errno.h> 48 #include <sys/fcntl.h> 49 #include <sys/file.h> 50 #include <sys/filedesc.h> 51 #include <sys/ucred.h> 52 #include <sys/priv.h> 53 #include <sys/kernel.h> 54 #include <sys/malloc.h> 55 #include <sys/mplock2.h> 56 #include <sys/mqueue.h> 57 #include <sys/objcache.h> 58 #include <sys/poll.h> 59 #include <sys/proc.h> 60 #include <sys/queue.h> 61 #include <sys/select.h> 62 #include <sys/serialize.h> 63 #include <sys/signal.h> 64 #include <sys/signalvar.h> 65 #include <sys/spinlock.h> 66 #include <sys/spinlock2.h> 67 #include <sys/stat.h> 68 #include <sys/sysctl.h> 69 #include <sys/sysproto.h> 70 #include <sys/systm.h> 71 #include <sys/lock.h> 72 #include <sys/unistd.h> 73 #include <sys/vnode.h> 74 75 /* System-wide limits. */ 76 static u_int mq_open_max = MQ_OPEN_MAX; 77 static u_int mq_prio_max = MQ_PRIO_MAX; 78 static u_int mq_max_msgsize = 16 * MQ_DEF_MSGSIZE; 79 static u_int mq_def_maxmsg = 32; 80 static u_int mq_max_maxmsg = 16 * 32; 81 82 struct lock mqlist_mtx; 83 static struct objcache * mqmsg_cache; 84 static LIST_HEAD(, mqueue) mqueue_head = 85 LIST_HEAD_INITIALIZER(mqueue_head); 86 87 typedef struct file file_t; /* XXX: Should we put this in sys/types.h ? */ 88 89 /* Function prototypes */ 90 static int mq_poll_fop(file_t *, int, struct ucred *cred); 91 static int mq_stat_fop(file_t *, struct stat *, struct ucred *cred); 92 static int mq_close_fop(file_t *); 93 94 /* Some time-related utility functions */ 95 static int itimespecfix(struct timespec *ts); 96 static int tstohz(const struct timespec *ts); 97 98 /* File operations vector */ 99 static struct fileops mqops = { 100 .fo_read = badfo_readwrite, 101 .fo_write = badfo_readwrite, 102 .fo_ioctl = badfo_ioctl, 103 .fo_poll = mq_poll_fop, 104 .fo_stat = mq_stat_fop, 105 .fo_close = mq_close_fop, 106 .fo_kqfilter = badfo_kqfilter, 107 .fo_shutdown = badfo_shutdown 108 }; 109 110 /* Define a new malloc type for message queues */ 111 MALLOC_DECLARE(M_MQBUF); 112 MALLOC_DEFINE(M_MQBUF, "mqueues", "Buffers to message queues"); 113 114 /* Malloc arguments for object cache */ 115 struct objcache_malloc_args mqueue_malloc_args = { 116 sizeof(struct mqueue), M_MQBUF }; 117 118 /* 119 * Initialize POSIX message queue subsystem. 120 */ 121 void 122 mqueue_sysinit(void) 123 { 124 mqmsg_cache = objcache_create("mqmsg_cache", 125 0, /* infinite depot's capacity */ 126 0, /* default magazine's capacity */ 127 NULL, /* constructor */ 128 NULL, /* deconstructor */ 129 NULL, 130 objcache_malloc_alloc, 131 objcache_malloc_free, 132 &mqueue_malloc_args); 133 134 lockinit(&mqlist_mtx, "mqlist_mtx", 0, LK_CANRECURSE); 135 } 136 137 /* 138 * Free the message. 139 */ 140 static void 141 mqueue_freemsg(struct mq_msg *msg, const size_t size) 142 { 143 144 if (size > MQ_DEF_MSGSIZE) { 145 kfree(msg, M_MQBUF); 146 } else { 147 objcache_put(mqmsg_cache, msg); 148 } 149 } 150 151 /* 152 * Destroy the message queue. 153 */ 154 static void 155 mqueue_destroy(struct mqueue *mq) 156 { 157 struct mq_msg *msg; 158 size_t msz; 159 u_int i; 160 161 /* Note MQ_PQSIZE + 1. */ 162 for (i = 0; i < MQ_PQSIZE + 1; i++) { 163 while ((msg = TAILQ_FIRST(&mq->mq_head[i])) != NULL) { 164 TAILQ_REMOVE(&mq->mq_head[i], msg, msg_queue); 165 msz = sizeof(struct mq_msg) + msg->msg_len; 166 mqueue_freemsg(msg, msz); 167 } 168 } 169 lockuninit(&mq->mq_mtx); 170 kfree(mq, M_MQBUF); 171 } 172 173 /* 174 * Lookup for file name in general list of message queues. 175 * => locks the message queue 176 */ 177 static void * 178 mqueue_lookup(char *name) 179 { 180 struct mqueue *mq; 181 182 KKASSERT(lockstatus(&mqlist_mtx, curthread)); 183 184 LIST_FOREACH(mq, &mqueue_head, mq_list) { 185 if (strncmp(mq->mq_name, name, MQ_NAMELEN) == 0) { 186 lockmgr(&mq->mq_mtx, LK_EXCLUSIVE); 187 return mq; 188 } 189 } 190 191 return NULL; 192 } 193 194 /* 195 * mqueue_get: get the mqueue from the descriptor. 196 * => locks the message queue, if found. 197 * => holds a reference on the file descriptor. 198 */ 199 static int 200 mqueue_get(struct lwp *l, mqd_t mqd, file_t **fpr) 201 { 202 struct mqueue *mq; 203 file_t *fp; 204 205 fp = holdfp(curproc->p_fd, (int)mqd, -1); /* XXX: Why -1 ? */ 206 if (__predict_false(fp == NULL)) 207 return EBADF; 208 209 if (__predict_false(fp->f_type != DTYPE_MQUEUE)) { 210 fdrop(fp); 211 return EBADF; 212 } 213 mq = fp->f_data; 214 lockmgr(&mq->mq_mtx, LK_EXCLUSIVE); 215 216 *fpr = fp; 217 return 0; 218 } 219 220 /* 221 * mqueue_linear_insert: perform linear insert according to the message 222 * priority into the reserved queue (MQ_PQRESQ). Reserved queue is a 223 * sorted list used only when mq_prio_max is increased via sysctl. 224 */ 225 static inline void 226 mqueue_linear_insert(struct mqueue *mq, struct mq_msg *msg) 227 { 228 struct mq_msg *mit; 229 230 TAILQ_FOREACH(mit, &mq->mq_head[MQ_PQRESQ], msg_queue) { 231 if (msg->msg_prio > mit->msg_prio) 232 break; 233 } 234 if (mit == NULL) { 235 TAILQ_INSERT_TAIL(&mq->mq_head[MQ_PQRESQ], msg, msg_queue); 236 } else { 237 TAILQ_INSERT_BEFORE(mit, msg, msg_queue); 238 } 239 } 240 241 /* 242 * Validate input. 243 */ 244 int 245 itimespecfix(struct timespec *ts) 246 { 247 if (ts->tv_sec < 0 || ts->tv_nsec < 0 || ts->tv_nsec >= 1000000000) 248 return (EINVAL); 249 if (ts->tv_sec == 0 && ts->tv_nsec != 0 && ts->tv_nsec < nstick) 250 ts->tv_nsec = nstick; 251 return (0); 252 } 253 254 /* 255 * Compute number of ticks in the specified amount of time. 256 */ 257 int 258 tstohz(const struct timespec *ts) 259 { 260 struct timeval tv; 261 262 /* 263 * usec has great enough resolution for hz, so convert to a 264 * timeval and use tvtohz() above. 265 */ 266 TIMESPEC_TO_TIMEVAL(&tv, ts); 267 return tvtohz_high(&tv); /* XXX Why _high() and not _low() ? */ 268 } 269 270 /* 271 * Converter from struct timespec to the ticks. 272 * Used by mq_timedreceive(), mq_timedsend(). 273 */ 274 int 275 abstimeout2timo(struct timespec *ts, int *timo) 276 { 277 struct timespec tsd; 278 int error; 279 280 error = itimespecfix(ts); 281 if (error) { 282 return error; 283 } 284 getnanotime(&tsd); 285 timespecsub(ts, &tsd); 286 if (ts->tv_sec < 0 || (ts->tv_sec == 0 && ts->tv_nsec <= 0)) { 287 return ETIMEDOUT; 288 } 289 *timo = tstohz(ts); 290 KKASSERT(*timo != 0); 291 292 return 0; 293 } 294 295 static int 296 mq_stat_fop(file_t *fp, struct stat *st, struct ucred *cred) 297 { 298 struct mqueue *mq = fp->f_data; 299 300 (void)memset(st, 0, sizeof(*st)); 301 302 lockmgr(&mq->mq_mtx, LK_EXCLUSIVE); 303 st->st_mode = mq->mq_mode; 304 st->st_uid = mq->mq_euid; 305 st->st_gid = mq->mq_egid; 306 st->st_atimespec = mq->mq_atime; 307 st->st_mtimespec = mq->mq_mtime; 308 /*st->st_ctimespec = st->st_birthtimespec = mq->mq_btime;*/ 309 st->st_uid = fp->f_cred->cr_uid; 310 st->st_gid = fp->f_cred->cr_svgid; 311 lockmgr(&mq->mq_mtx, LK_RELEASE); 312 313 return 0; 314 } 315 316 static int 317 mq_poll_fop(file_t *fp, int events, struct ucred *cred) 318 { 319 struct mqueue *mq = fp->f_data; 320 struct mq_attr *mqattr; 321 int revents = 0; 322 323 lockmgr(&mq->mq_mtx, LK_EXCLUSIVE); 324 mqattr = &mq->mq_attrib; 325 if (events & (POLLIN | POLLRDNORM)) { 326 /* Ready for receiving, if there are messages in the queue */ 327 if (mqattr->mq_curmsgs) 328 revents |= (POLLIN | POLLRDNORM); 329 else 330 selrecord(curthread, &mq->mq_rsel); 331 } 332 if (events & (POLLOUT | POLLWRNORM)) { 333 /* Ready for sending, if the message queue is not full */ 334 if (mqattr->mq_curmsgs < mqattr->mq_maxmsg) 335 revents |= (POLLOUT | POLLWRNORM); 336 else 337 selrecord(curthread, &mq->mq_wsel); 338 } 339 lockmgr(&mq->mq_mtx, LK_RELEASE); 340 341 return revents; 342 } 343 344 static int 345 mq_close_fop(file_t *fp) 346 { 347 struct proc *p = curproc; 348 struct mqueue *mq = fp->f_data; 349 bool destroy; 350 351 lockmgr(&mqlist_mtx, LK_EXCLUSIVE); 352 lockmgr(&mq->mq_mtx, LK_EXCLUSIVE); 353 354 /* Decrease the counters */ 355 p->p_mqueue_cnt--; 356 mq->mq_refcnt--; 357 358 /* Remove notification if registered for this process */ 359 if (mq->mq_notify_proc == p) 360 mq->mq_notify_proc = NULL; 361 362 /* 363 * If this is the last reference and mqueue is marked for unlink, 364 * remove and later destroy the message queue. 365 */ 366 if (mq->mq_refcnt == 0 && (mq->mq_attrib.mq_flags & MQ_UNLINK)) { 367 LIST_REMOVE(mq, mq_list); 368 destroy = true; 369 } else 370 destroy = false; 371 372 lockmgr(&mq->mq_mtx, LK_RELEASE); 373 lockmgr(&mqlist_mtx, LK_RELEASE); 374 375 if (destroy) 376 mqueue_destroy(mq); 377 378 return 0; 379 } 380 381 /* 382 * General mqueue system calls. 383 */ 384 385 int 386 sys_mq_open(struct mq_open_args *uap) 387 { 388 /* { 389 syscallarg(const char *) name; 390 syscallarg(int) oflag; 391 syscallarg(mode_t) mode; 392 syscallarg(struct mq_attr) attr; 393 } */ 394 struct thread *td = curthread; 395 struct proc *p = td->td_proc; 396 struct filedesc *fdp = p->p_fd; 397 struct mqueue *mq, *mq_new = NULL; 398 file_t *fp; 399 char *name; 400 int mqd, error, oflag; 401 402 /* Check access mode flags */ 403 oflag = SCARG(uap, oflag); 404 if ((oflag & O_ACCMODE) == (O_WRONLY | O_RDWR)) { 405 return EINVAL; 406 } 407 408 /* Get the name from the user-space */ 409 name = kmalloc(MQ_NAMELEN, M_MQBUF, M_WAITOK | M_ZERO); 410 error = copyinstr(SCARG(uap, name), name, MQ_NAMELEN - 1, NULL); 411 if (error) { 412 kfree(name, M_MQBUF); 413 return error; 414 } 415 416 if (oflag & O_CREAT) { 417 struct mq_attr attr; 418 u_int i; 419 420 /* Check the limit */ 421 if (p->p_mqueue_cnt == mq_open_max) { 422 kfree(name, M_MQBUF); 423 return EMFILE; 424 } 425 426 /* Empty name is invalid */ 427 if (name[0] == '\0') { 428 kfree(name, M_MQBUF); 429 return EINVAL; 430 } 431 432 /* Check for mqueue attributes */ 433 if (SCARG(uap, attr)) { 434 error = copyin(SCARG(uap, attr), &attr, 435 sizeof(struct mq_attr)); 436 if (error) { 437 kfree(name, M_MQBUF); 438 return error; 439 } 440 if (attr.mq_maxmsg <= 0 || 441 attr.mq_maxmsg > mq_max_maxmsg || 442 attr.mq_msgsize <= 0 || 443 attr.mq_msgsize > mq_max_msgsize) { 444 kfree(name, M_MQBUF); 445 return EINVAL; 446 } 447 attr.mq_curmsgs = 0; 448 } else { 449 memset(&attr, 0, sizeof(struct mq_attr)); 450 attr.mq_maxmsg = mq_def_maxmsg; 451 attr.mq_msgsize = 452 MQ_DEF_MSGSIZE - sizeof(struct mq_msg); 453 } 454 455 /* 456 * Allocate new mqueue, initialize data structures, 457 * copy the name, attributes and set the flag. 458 */ 459 mq_new = kmalloc(sizeof(struct mqueue), M_MQBUF, M_WAITOK | M_ZERO); 460 461 lockinit(&mq_new->mq_mtx, "mq_new->mq_mtx", 0, LK_CANRECURSE); 462 for (i = 0; i < (MQ_PQSIZE + 1); i++) { 463 TAILQ_INIT(&mq_new->mq_head[i]); 464 } 465 466 strlcpy(mq_new->mq_name, name, MQ_NAMELEN); 467 memcpy(&mq_new->mq_attrib, &attr, sizeof(struct mq_attr)); 468 469 /*CTASSERT((O_MASK & (MQ_UNLINK | MQ_RECEIVE)) == 0);*/ 470 /* mq_new->mq_attrib.mq_flags = (O_MASK & oflag); */ 471 mq_new->mq_attrib.mq_flags = oflag; 472 473 /* Store mode and effective UID with GID */ 474 mq_new->mq_mode = ((SCARG(uap, mode) & 475 ~p->p_fd->fd_cmask) & ALLPERMS) & ~S_ISTXT; 476 mq_new->mq_euid = td->td_ucred->cr_uid; 477 mq_new->mq_egid = td->td_ucred->cr_svgid; 478 } 479 480 /* Allocate file structure and descriptor */ 481 error = falloc(td->td_lwp, &fp, &mqd); 482 if (error) { 483 if (mq_new) 484 mqueue_destroy(mq_new); 485 kfree(name, M_MQBUF); 486 return error; 487 } 488 fp->f_type = DTYPE_MQUEUE; 489 fp->f_flag = FFLAGS(oflag) & (FREAD | FWRITE); 490 fp->f_ops = &mqops; 491 492 /* Look up for mqueue with such name */ 493 lockmgr(&mqlist_mtx, LK_EXCLUSIVE); 494 mq = mqueue_lookup(name); 495 if (mq) { 496 int acc_mode; 497 498 KKASSERT(lockstatus(&mq->mq_mtx, curthread)); 499 500 /* Check if mqueue is not marked as unlinking */ 501 if (mq->mq_attrib.mq_flags & MQ_UNLINK) { 502 error = EACCES; 503 goto exit; 504 } 505 /* Fail if O_EXCL is set, and mqueue already exists */ 506 if ((oflag & O_CREAT) && (oflag & O_EXCL)) { 507 error = EEXIST; 508 goto exit; 509 } 510 511 /* 512 * Check the permissions. Note the difference between 513 * VREAD/VWRITE and FREAD/FWRITE. 514 */ 515 acc_mode = 0; 516 if (fp->f_flag & FREAD) { 517 acc_mode |= VREAD; 518 } 519 if (fp->f_flag & FWRITE) { 520 acc_mode |= VWRITE; 521 } 522 if (vaccess(VNON, mq->mq_mode, mq->mq_euid, mq->mq_egid, 523 acc_mode, td->td_ucred)) { 524 525 error = EACCES; 526 goto exit; 527 } 528 } else { 529 /* Fail if mqueue neither exists, nor we create it */ 530 if ((oflag & O_CREAT) == 0) { 531 lockmgr(&mqlist_mtx, LK_RELEASE); 532 KKASSERT(mq_new == NULL); 533 fsetfd(fdp, NULL, mqd); 534 fp->f_ops = &badfileops; 535 fdrop(fp); 536 kfree(name, M_MQBUF); 537 return ENOENT; 538 } 539 540 /* Check the limit */ 541 if (p->p_mqueue_cnt == mq_open_max) { 542 error = EMFILE; 543 goto exit; 544 } 545 546 /* Insert the queue to the list */ 547 mq = mq_new; 548 lockmgr(&mq->mq_mtx, LK_EXCLUSIVE); 549 LIST_INSERT_HEAD(&mqueue_head, mq, mq_list); 550 mq_new = NULL; 551 getnanotime(&mq->mq_btime); 552 mq->mq_atime = mq->mq_mtime = mq->mq_btime; 553 } 554 555 /* Increase the counters, and make descriptor ready */ 556 p->p_mqueue_cnt++; 557 mq->mq_refcnt++; 558 fp->f_data = mq; 559 exit: 560 lockmgr(&mq->mq_mtx, LK_RELEASE); 561 lockmgr(&mqlist_mtx, LK_RELEASE); 562 563 if (mq_new) 564 mqueue_destroy(mq_new); 565 if (error) { 566 fsetfd(fdp, NULL, mqd); 567 fp->f_ops = &badfileops; 568 } else { 569 fsetfd(fdp, fp, mqd); 570 uap->sysmsg_result = mqd; 571 } 572 fdrop(fp); 573 kfree(name, M_MQBUF); 574 575 return error; 576 } 577 578 int 579 sys_mq_close(struct mq_close_args *uap) 580 { 581 return sys_close((void *)uap); 582 } 583 584 /* 585 * Primary mq_receive1() function. 586 */ 587 int 588 mq_receive1(struct lwp *l, mqd_t mqdes, void *msg_ptr, size_t msg_len, 589 unsigned *msg_prio, struct timespec *ts, ssize_t *mlen) 590 { 591 file_t *fp = NULL; 592 struct mqueue *mq; 593 struct mq_msg *msg = NULL; 594 struct mq_attr *mqattr; 595 u_int idx; 596 int error; 597 598 /* Get the message queue */ 599 error = mqueue_get(l, mqdes, &fp); 600 if (error) { 601 return error; 602 } 603 mq = fp->f_data; 604 if ((fp->f_flag & FREAD) == 0) { 605 error = EBADF; 606 goto error; 607 } 608 getnanotime(&mq->mq_atime); 609 mqattr = &mq->mq_attrib; 610 611 /* Check the message size limits */ 612 if (msg_len < mqattr->mq_msgsize) { 613 error = EMSGSIZE; 614 goto error; 615 } 616 617 /* Check if queue is empty */ 618 while (mqattr->mq_curmsgs == 0) { 619 int t; 620 621 if (mqattr->mq_flags & O_NONBLOCK) { 622 error = EAGAIN; 623 goto error; 624 } 625 if (ts) { 626 error = abstimeout2timo(ts, &t); 627 if (error) 628 goto error; 629 } else 630 t = 0; 631 /* 632 * Block until someone sends the message. 633 * While doing this, notification should not be sent. 634 */ 635 mqattr->mq_flags |= MQ_RECEIVE; 636 error = lksleep(&mq->mq_send_cv, &mq->mq_mtx, PCATCH, "mqsend", t); 637 mqattr->mq_flags &= ~MQ_RECEIVE; 638 if (error || (mqattr->mq_flags & MQ_UNLINK)) { 639 error = (error == EWOULDBLOCK) ? ETIMEDOUT : EINTR; 640 goto error; 641 } 642 } 643 644 645 /* 646 * Find the highest priority message, and remove it from the queue. 647 * At first, reserved queue is checked, bitmap is next. 648 */ 649 msg = TAILQ_FIRST(&mq->mq_head[MQ_PQRESQ]); 650 if (__predict_true(msg == NULL)) { 651 idx = ffs(mq->mq_bitmap); 652 msg = TAILQ_FIRST(&mq->mq_head[idx]); 653 KKASSERT(msg != NULL); 654 } else { 655 idx = MQ_PQRESQ; 656 } 657 TAILQ_REMOVE(&mq->mq_head[idx], msg, msg_queue); 658 659 /* Unmark the bit, if last message. */ 660 if (__predict_true(idx) && TAILQ_EMPTY(&mq->mq_head[idx])) { 661 KKASSERT((MQ_PQSIZE - idx) == msg->msg_prio); 662 mq->mq_bitmap &= ~(1 << --idx); 663 } 664 665 /* Decrement the counter and signal waiter, if any */ 666 mqattr->mq_curmsgs--; 667 wakeup_one(&mq->mq_recv_cv); 668 669 /* Ready for sending now */ 670 get_mplock(); 671 selwakeup(&mq->mq_wsel); 672 rel_mplock(); 673 error: 674 lockmgr(&mq->mq_mtx, LK_RELEASE); 675 fdrop(fp); 676 if (error) 677 return error; 678 679 /* 680 * Copy the data to the user-space. 681 * Note: According to POSIX, no message should be removed from the 682 * queue in case of fail - this would be violated. 683 */ 684 *mlen = msg->msg_len; 685 error = copyout(msg->msg_ptr, msg_ptr, msg->msg_len); 686 if (error == 0 && msg_prio) 687 error = copyout(&msg->msg_prio, msg_prio, sizeof(unsigned)); 688 mqueue_freemsg(msg, sizeof(struct mq_msg) + msg->msg_len); 689 690 return error; 691 } 692 693 int 694 sys_mq_receive(struct mq_receive_args *uap) 695 { 696 /* { 697 syscallarg(mqd_t) mqdes; 698 syscallarg(char *) msg_ptr; 699 syscallarg(size_t) msg_len; 700 syscallarg(unsigned *) msg_prio; 701 } */ 702 ssize_t mlen; 703 int error; 704 705 error = mq_receive1(curthread->td_lwp, SCARG(uap, mqdes), SCARG(uap, msg_ptr), 706 SCARG(uap, msg_len), SCARG(uap, msg_prio), 0, &mlen); 707 if (error == 0) 708 uap->sysmsg_result = mlen; 709 710 return error; 711 } 712 713 int 714 sys_mq_timedreceive(struct mq_timedreceive_args *uap) 715 { 716 /* { 717 syscallarg(mqd_t) mqdes; 718 syscallarg(char *) msg_ptr; 719 syscallarg(size_t) msg_len; 720 syscallarg(unsigned *) msg_prio; 721 syscallarg(const struct timespec *) abs_timeout; 722 } */ 723 int error; 724 ssize_t mlen; 725 struct timespec ts, *tsp; 726 727 /* Get and convert time value */ 728 if (SCARG(uap, abs_timeout)) { 729 error = copyin(SCARG(uap, abs_timeout), &ts, sizeof(ts)); 730 if (error) 731 return error; 732 tsp = &ts; 733 } else { 734 tsp = NULL; 735 } 736 737 error = mq_receive1(curthread->td_lwp, SCARG(uap, mqdes), SCARG(uap, msg_ptr), 738 SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp, &mlen); 739 if (error == 0) 740 uap->sysmsg_result = mlen; 741 742 return error; 743 } 744 745 /* 746 * Primary mq_send1() function. 747 */ 748 int 749 mq_send1(struct lwp *l, mqd_t mqdes, const char *msg_ptr, size_t msg_len, 750 unsigned msg_prio, struct timespec *ts) 751 { 752 file_t *fp = NULL; 753 struct mqueue *mq; 754 struct mq_msg *msg; 755 struct mq_attr *mqattr; 756 struct proc *notify = NULL; 757 /*ksiginfo_t ksi;*/ 758 size_t size; 759 int error; 760 761 /* Check the priority range */ 762 if (msg_prio >= mq_prio_max) 763 return EINVAL; 764 765 /* Allocate a new message */ 766 size = sizeof(struct mq_msg) + msg_len; 767 if (size > mq_max_msgsize) 768 return EMSGSIZE; 769 770 if (size > MQ_DEF_MSGSIZE) { 771 msg = kmalloc(size, M_MQBUF, M_WAITOK); 772 } else { 773 msg = objcache_get(mqmsg_cache, M_WAITOK); 774 } 775 776 /* Get the data from user-space */ 777 error = copyin(msg_ptr, msg->msg_ptr, msg_len); 778 if (error) { 779 mqueue_freemsg(msg, size); 780 return error; 781 } 782 msg->msg_len = msg_len; 783 msg->msg_prio = msg_prio; 784 785 /* Get the mqueue */ 786 error = mqueue_get(l, mqdes, &fp); 787 if (error) { 788 mqueue_freemsg(msg, size); 789 return error; 790 } 791 mq = fp->f_data; 792 if ((fp->f_flag & FWRITE) == 0) { 793 error = EBADF; 794 goto error; 795 } 796 getnanotime(&mq->mq_mtime); 797 mqattr = &mq->mq_attrib; 798 799 /* Check the message size limit */ 800 if (msg_len <= 0 || msg_len > mqattr->mq_msgsize) { 801 error = EMSGSIZE; 802 goto error; 803 } 804 805 /* Check if queue is full */ 806 while (mqattr->mq_curmsgs >= mqattr->mq_maxmsg) { 807 int t; 808 809 if (mqattr->mq_flags & O_NONBLOCK) { 810 error = EAGAIN; 811 goto error; 812 } 813 if (ts) { 814 error = abstimeout2timo(ts, &t); 815 if (error) 816 goto error; 817 } else 818 t = 0; 819 /* Block until queue becomes available */ 820 error = lksleep(&mq->mq_recv_cv, &mq->mq_mtx, PCATCH, "mqrecv", t); 821 if (error || (mqattr->mq_flags & MQ_UNLINK)) { 822 error = (error == EWOULDBLOCK) ? ETIMEDOUT : error; 823 goto error; 824 } 825 } 826 KKASSERT(mq->mq_attrib.mq_curmsgs < mq->mq_attrib.mq_maxmsg); 827 828 /* 829 * Insert message into the queue, according to the priority. 830 * Note the difference between index and priority. 831 */ 832 if (__predict_true(msg_prio < MQ_PQSIZE)) { 833 u_int idx = MQ_PQSIZE - msg_prio; 834 835 KKASSERT(idx != MQ_PQRESQ); 836 TAILQ_INSERT_TAIL(&mq->mq_head[idx], msg, msg_queue); 837 mq->mq_bitmap |= (1 << --idx); 838 } else { 839 mqueue_linear_insert(mq, msg); 840 } 841 842 /* Check for the notify */ 843 if (mqattr->mq_curmsgs == 0 && mq->mq_notify_proc && 844 (mqattr->mq_flags & MQ_RECEIVE) == 0 && 845 mq->mq_sig_notify.sigev_notify == SIGEV_SIGNAL) { 846 /* Initialize the signal */ 847 /*KSI_INIT(&ksi);*/ 848 /*ksi.ksi_signo = mq->mq_sig_notify.sigev_signo;*/ 849 /*ksi.ksi_code = SI_MESGQ;*/ 850 /*ksi.ksi_value = mq->mq_sig_notify.sigev_value;*/ 851 /* Unregister the process */ 852 notify = mq->mq_notify_proc; 853 mq->mq_notify_proc = NULL; 854 } 855 856 /* Increment the counter and signal waiter, if any */ 857 mqattr->mq_curmsgs++; 858 wakeup_one(&mq->mq_send_cv); 859 860 /* Ready for receiving now */ 861 get_mplock(); 862 selwakeup(&mq->mq_rsel); 863 rel_mplock(); 864 error: 865 lockmgr(&mq->mq_mtx, LK_RELEASE); 866 fdrop(fp); 867 868 if (error) { 869 mqueue_freemsg(msg, size); 870 } else if (notify) { 871 /* Send the notify, if needed */ 872 lwkt_gettoken(&proc_token); 873 /*kpsignal(notify, &ksi, NULL);*/ 874 ksignal(notify, mq->mq_sig_notify.sigev_signo); 875 lwkt_reltoken(&proc_token); 876 } 877 878 return error; 879 } 880 881 int 882 sys_mq_send(struct mq_send_args *uap) 883 { 884 /* { 885 syscallarg(mqd_t) mqdes; 886 syscallarg(const char *) msg_ptr; 887 syscallarg(size_t) msg_len; 888 syscallarg(unsigned) msg_prio; 889 } */ 890 891 return mq_send1(curthread->td_lwp, SCARG(uap, mqdes), SCARG(uap, msg_ptr), 892 SCARG(uap, msg_len), SCARG(uap, msg_prio), 0); 893 } 894 895 int 896 sys_mq_timedsend(struct mq_timedsend_args *uap) 897 { 898 /* { 899 syscallarg(mqd_t) mqdes; 900 syscallarg(const char *) msg_ptr; 901 syscallarg(size_t) msg_len; 902 syscallarg(unsigned) msg_prio; 903 syscallarg(const struct timespec *) abs_timeout; 904 } */ 905 struct timespec ts, *tsp; 906 int error; 907 908 /* Get and convert time value */ 909 if (SCARG(uap, abs_timeout)) { 910 error = copyin(SCARG(uap, abs_timeout), &ts, sizeof(ts)); 911 if (error) 912 return error; 913 tsp = &ts; 914 } else { 915 tsp = NULL; 916 } 917 918 return mq_send1(curthread->td_lwp, SCARG(uap, mqdes), SCARG(uap, msg_ptr), 919 SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp); 920 } 921 922 int 923 sys_mq_notify(struct mq_notify_args *uap) 924 { 925 /* { 926 syscallarg(mqd_t) mqdes; 927 syscallarg(const struct sigevent *) notification; 928 } */ 929 file_t *fp = NULL; 930 struct mqueue *mq; 931 struct sigevent sig; 932 int error; 933 934 if (SCARG(uap, notification)) { 935 /* Get the signal from user-space */ 936 error = copyin(SCARG(uap, notification), &sig, 937 sizeof(struct sigevent)); 938 if (error) 939 return error; 940 if (sig.sigev_notify == SIGEV_SIGNAL && 941 (sig.sigev_signo <= 0 || sig.sigev_signo >= NSIG)) 942 return EINVAL; 943 } 944 945 error = mqueue_get(curthread->td_lwp, SCARG(uap, mqdes), &fp); 946 if (error) 947 return error; 948 mq = fp->f_data; 949 950 if (SCARG(uap, notification)) { 951 /* Register notification: set the signal and target process */ 952 if (mq->mq_notify_proc == NULL) { 953 memcpy(&mq->mq_sig_notify, &sig, 954 sizeof(struct sigevent)); 955 mq->mq_notify_proc = curproc; 956 } else { 957 /* Fail if someone else already registered */ 958 error = EBUSY; 959 } 960 } else { 961 /* Unregister the notification */ 962 mq->mq_notify_proc = NULL; 963 } 964 lockmgr(&mq->mq_mtx, LK_RELEASE); 965 fdrop(fp); 966 967 return error; 968 } 969 970 int 971 sys_mq_getattr(struct mq_getattr_args *uap) 972 { 973 /* { 974 syscallarg(mqd_t) mqdes; 975 syscallarg(struct mq_attr *) mqstat; 976 } */ 977 file_t *fp = NULL; 978 struct mqueue *mq; 979 struct mq_attr attr; 980 int error; 981 982 /* Get the message queue */ 983 error = mqueue_get(curthread->td_lwp, SCARG(uap, mqdes), &fp); 984 if (error) 985 return error; 986 mq = fp->f_data; 987 memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr)); 988 lockmgr(&mq->mq_mtx, LK_RELEASE); 989 fdrop(fp); 990 991 return copyout(&attr, SCARG(uap, mqstat), sizeof(struct mq_attr)); 992 } 993 994 int 995 sys_mq_setattr(struct mq_setattr_args *uap) 996 { 997 /* { 998 syscallarg(mqd_t) mqdes; 999 syscallarg(const struct mq_attr *) mqstat; 1000 syscallarg(struct mq_attr *) omqstat; 1001 } */ 1002 file_t *fp = NULL; 1003 struct mqueue *mq; 1004 struct mq_attr attr; 1005 int error, nonblock; 1006 1007 error = copyin(SCARG(uap, mqstat), &attr, sizeof(struct mq_attr)); 1008 if (error) 1009 return error; 1010 nonblock = (attr.mq_flags & O_NONBLOCK); 1011 1012 /* Get the message queue */ 1013 error = mqueue_get(curthread->td_lwp, SCARG(uap, mqdes), &fp); 1014 if (error) 1015 return error; 1016 mq = fp->f_data; 1017 1018 /* Copy the old attributes, if needed */ 1019 if (SCARG(uap, omqstat)) { 1020 memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr)); 1021 } 1022 1023 /* Ignore everything, except O_NONBLOCK */ 1024 if (nonblock) 1025 mq->mq_attrib.mq_flags |= O_NONBLOCK; 1026 else 1027 mq->mq_attrib.mq_flags &= ~O_NONBLOCK; 1028 1029 lockmgr(&mq->mq_mtx, LK_RELEASE); 1030 fdrop(fp); 1031 1032 /* 1033 * Copy the data to the user-space. 1034 * Note: According to POSIX, the new attributes should not be set in 1035 * case of fail - this would be violated. 1036 */ 1037 if (SCARG(uap, omqstat)) 1038 error = copyout(&attr, SCARG(uap, omqstat), 1039 sizeof(struct mq_attr)); 1040 1041 return error; 1042 } 1043 1044 int 1045 sys_mq_unlink(struct mq_unlink_args *uap) 1046 { 1047 /* { 1048 syscallarg(const char *) name; 1049 } */ 1050 struct thread *td = curthread; 1051 struct mqueue *mq; 1052 char *name; 1053 int error, refcnt = 0; 1054 1055 /* Get the name from the user-space */ 1056 name = kmalloc(MQ_NAMELEN, M_MQBUF, M_WAITOK | M_ZERO); 1057 error = copyinstr(SCARG(uap, name), name, MQ_NAMELEN - 1, NULL); 1058 if (error) { 1059 kfree(name, M_MQBUF); 1060 return error; 1061 } 1062 1063 /* Lookup for this file */ 1064 lockmgr(&mqlist_mtx, LK_EXCLUSIVE); 1065 mq = mqueue_lookup(name); 1066 if (mq == NULL) { 1067 error = ENOENT; 1068 goto error; 1069 } 1070 1071 /* Check the permissions */ 1072 if (td->td_ucred->cr_uid != mq->mq_euid && 1073 priv_check(td, PRIV_ROOT) != 0) { 1074 lockmgr(&mq->mq_mtx, LK_RELEASE); 1075 error = EACCES; 1076 goto error; 1077 } 1078 1079 /* Mark message queue as unlinking, before leaving the window */ 1080 mq->mq_attrib.mq_flags |= MQ_UNLINK; 1081 1082 /* Wake up all waiters, if there are such */ 1083 wakeup(&mq->mq_send_cv); 1084 wakeup(&mq->mq_recv_cv); 1085 1086 get_mplock(); 1087 selwakeup(&mq->mq_rsel); 1088 selwakeup(&mq->mq_wsel); 1089 rel_mplock(); 1090 1091 refcnt = mq->mq_refcnt; 1092 if (refcnt == 0) 1093 LIST_REMOVE(mq, mq_list); 1094 1095 lockmgr(&mq->mq_mtx, LK_RELEASE); 1096 error: 1097 lockmgr(&mqlist_mtx, LK_RELEASE); 1098 1099 /* 1100 * If there are no references - destroy the message 1101 * queue, otherwise, the last mq_close() will do that. 1102 */ 1103 if (error == 0 && refcnt == 0) 1104 mqueue_destroy(mq); 1105 1106 kfree(name, M_MQBUF); 1107 return error; 1108 } 1109 1110 /* 1111 * SysCtl. 1112 */ 1113 SYSCTL_NODE(_kern, OID_AUTO, mqueue, 1114 CTLFLAG_RW, 0, "Message queue options"); 1115 1116 SYSCTL_INT(_kern_mqueue, OID_AUTO, mq_open_max, 1117 CTLFLAG_RW, &mq_open_max, 0, 1118 "Maximal number of message queue descriptors per process"); 1119 1120 SYSCTL_INT(_kern_mqueue, OID_AUTO, mq_prio_max, 1121 CTLFLAG_RW, &mq_prio_max, 0, 1122 "Maximal priority of the message"); 1123 1124 SYSCTL_INT(_kern_mqueue, OID_AUTO, mq_max_msgsize, 1125 CTLFLAG_RW, &mq_max_msgsize, 0, 1126 "Maximal allowed size of the message"); 1127 1128 SYSCTL_INT(_kern_mqueue, OID_AUTO, mq_def_maxmsg, 1129 CTLFLAG_RW, &mq_def_maxmsg, 0, 1130 "Default maximal message count"); 1131 1132 SYSCTL_INT(_kern_mqueue, OID_AUTO, mq_max_maxmsg, 1133 CTLFLAG_RW, &mq_max_maxmsg, 0, 1134 "Maximal allowed message count"); 1135 1136 SYSINIT(sys_mqueue_init, SI_SUB_PRE_DRIVERS, SI_ORDER_ANY, mqueue_sysinit, NULL); 1137