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