uipc_mqueue.c revision 321020
1/*- 2 * Copyright (c) 2005 David Xu <davidxu@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 */ 27 28/* 29 * POSIX message queue implementation. 30 * 31 * 1) A mqueue filesystem can be mounted, each message queue appears 32 * in mounted directory, user can change queue's permission and 33 * ownership, or remove a queue. Manually creating a file in the 34 * directory causes a message queue to be created in the kernel with 35 * default message queue attributes applied and same name used, this 36 * method is not advocated since mq_open syscall allows user to specify 37 * different attributes. Also the file system can be mounted multiple 38 * times at different mount points but shows same contents. 39 * 40 * 2) Standard POSIX message queue API. The syscalls do not use vfs layer, 41 * but directly operate on internal data structure, this allows user to 42 * use the IPC facility without having to mount mqueue file system. 43 */ 44 45#include <sys/cdefs.h> 46__FBSDID("$FreeBSD: stable/10/sys/kern/uipc_mqueue.c 321020 2017-07-15 17:25:40Z dchagin $"); 47 48#include "opt_capsicum.h" 49#include "opt_compat.h" 50 51#include <sys/param.h> 52#include <sys/kernel.h> 53#include <sys/systm.h> 54#include <sys/limits.h> 55#include <sys/buf.h> 56#include <sys/capsicum.h> 57#include <sys/dirent.h> 58#include <sys/event.h> 59#include <sys/eventhandler.h> 60#include <sys/fcntl.h> 61#include <sys/file.h> 62#include <sys/filedesc.h> 63#include <sys/lock.h> 64#include <sys/malloc.h> 65#include <sys/module.h> 66#include <sys/mount.h> 67#include <sys/mqueue.h> 68#include <sys/mutex.h> 69#include <sys/namei.h> 70#include <sys/posix4.h> 71#include <sys/poll.h> 72#include <sys/priv.h> 73#include <sys/proc.h> 74#include <sys/queue.h> 75#include <sys/sysproto.h> 76#include <sys/stat.h> 77#include <sys/syscall.h> 78#include <sys/syscallsubr.h> 79#include <sys/sysent.h> 80#include <sys/sx.h> 81#include <sys/sysctl.h> 82#include <sys/taskqueue.h> 83#include <sys/unistd.h> 84#include <sys/vnode.h> 85#include <machine/atomic.h> 86 87FEATURE(p1003_1b_mqueue, "POSIX P1003.1B message queues support"); 88 89/* 90 * Limits and constants 91 */ 92#define MQFS_NAMELEN NAME_MAX 93#define MQFS_DELEN (8 + MQFS_NAMELEN) 94 95/* node types */ 96typedef enum { 97 mqfstype_none = 0, 98 mqfstype_root, 99 mqfstype_dir, 100 mqfstype_this, 101 mqfstype_parent, 102 mqfstype_file, 103 mqfstype_symlink, 104} mqfs_type_t; 105 106struct mqfs_node; 107 108/* 109 * mqfs_info: describes a mqfs instance 110 */ 111struct mqfs_info { 112 struct sx mi_lock; 113 struct mqfs_node *mi_root; 114 struct unrhdr *mi_unrhdr; 115}; 116 117struct mqfs_vdata { 118 LIST_ENTRY(mqfs_vdata) mv_link; 119 struct mqfs_node *mv_node; 120 struct vnode *mv_vnode; 121 struct task mv_task; 122}; 123 124/* 125 * mqfs_node: describes a node (file or directory) within a mqfs 126 */ 127struct mqfs_node { 128 char mn_name[MQFS_NAMELEN+1]; 129 struct mqfs_info *mn_info; 130 struct mqfs_node *mn_parent; 131 LIST_HEAD(,mqfs_node) mn_children; 132 LIST_ENTRY(mqfs_node) mn_sibling; 133 LIST_HEAD(,mqfs_vdata) mn_vnodes; 134 int mn_refcount; 135 mqfs_type_t mn_type; 136 int mn_deleted; 137 uint32_t mn_fileno; 138 void *mn_data; 139 struct timespec mn_birth; 140 struct timespec mn_ctime; 141 struct timespec mn_atime; 142 struct timespec mn_mtime; 143 uid_t mn_uid; 144 gid_t mn_gid; 145 int mn_mode; 146}; 147 148#define VTON(vp) (((struct mqfs_vdata *)((vp)->v_data))->mv_node) 149#define VTOMQ(vp) ((struct mqueue *)(VTON(vp)->mn_data)) 150#define VFSTOMQFS(m) ((struct mqfs_info *)((m)->mnt_data)) 151#define FPTOMQ(fp) ((struct mqueue *)(((struct mqfs_node *) \ 152 (fp)->f_data)->mn_data)) 153 154TAILQ_HEAD(msgq, mqueue_msg); 155 156struct mqueue; 157 158struct mqueue_notifier { 159 LIST_ENTRY(mqueue_notifier) nt_link; 160 struct sigevent nt_sigev; 161 ksiginfo_t nt_ksi; 162 struct proc *nt_proc; 163}; 164 165struct mqueue { 166 struct mtx mq_mutex; 167 int mq_flags; 168 long mq_maxmsg; 169 long mq_msgsize; 170 long mq_curmsgs; 171 long mq_totalbytes; 172 struct msgq mq_msgq; 173 int mq_receivers; 174 int mq_senders; 175 struct selinfo mq_rsel; 176 struct selinfo mq_wsel; 177 struct mqueue_notifier *mq_notifier; 178}; 179 180#define MQ_RSEL 0x01 181#define MQ_WSEL 0x02 182 183struct mqueue_msg { 184 TAILQ_ENTRY(mqueue_msg) msg_link; 185 unsigned int msg_prio; 186 unsigned int msg_size; 187 /* following real data... */ 188}; 189 190static SYSCTL_NODE(_kern, OID_AUTO, mqueue, CTLFLAG_RW, 0, 191 "POSIX real time message queue"); 192 193static int default_maxmsg = 10; 194static int default_msgsize = 1024; 195 196static int maxmsg = 100; 197SYSCTL_INT(_kern_mqueue, OID_AUTO, maxmsg, CTLFLAG_RW, 198 &maxmsg, 0, "Default maximum messages in queue"); 199static int maxmsgsize = 16384; 200SYSCTL_INT(_kern_mqueue, OID_AUTO, maxmsgsize, CTLFLAG_RW, 201 &maxmsgsize, 0, "Default maximum message size"); 202static int maxmq = 100; 203SYSCTL_INT(_kern_mqueue, OID_AUTO, maxmq, CTLFLAG_RW, 204 &maxmq, 0, "maximum message queues"); 205static int curmq = 0; 206SYSCTL_INT(_kern_mqueue, OID_AUTO, curmq, CTLFLAG_RW, 207 &curmq, 0, "current message queue number"); 208static int unloadable = 0; 209static MALLOC_DEFINE(M_MQUEUEDATA, "mqdata", "mqueue data"); 210 211static eventhandler_tag exit_tag; 212 213/* Only one instance per-system */ 214static struct mqfs_info mqfs_data; 215static uma_zone_t mqnode_zone; 216static uma_zone_t mqueue_zone; 217static uma_zone_t mvdata_zone; 218static uma_zone_t mqnoti_zone; 219static struct vop_vector mqfs_vnodeops; 220static struct fileops mqueueops; 221 222/* 223 * Directory structure construction and manipulation 224 */ 225#ifdef notyet 226static struct mqfs_node *mqfs_create_dir(struct mqfs_node *parent, 227 const char *name, int namelen, struct ucred *cred, int mode); 228static struct mqfs_node *mqfs_create_link(struct mqfs_node *parent, 229 const char *name, int namelen, struct ucred *cred, int mode); 230#endif 231 232static struct mqfs_node *mqfs_create_file(struct mqfs_node *parent, 233 const char *name, int namelen, struct ucred *cred, int mode); 234static int mqfs_destroy(struct mqfs_node *mn); 235static void mqfs_fileno_alloc(struct mqfs_info *mi, struct mqfs_node *mn); 236static void mqfs_fileno_free(struct mqfs_info *mi, struct mqfs_node *mn); 237static int mqfs_allocv(struct mount *mp, struct vnode **vpp, struct mqfs_node *pn); 238 239/* 240 * Message queue construction and maniplation 241 */ 242static struct mqueue *mqueue_alloc(const struct mq_attr *attr); 243static void mqueue_free(struct mqueue *mq); 244static int mqueue_send(struct mqueue *mq, const char *msg_ptr, 245 size_t msg_len, unsigned msg_prio, int waitok, 246 const struct timespec *abs_timeout); 247static int mqueue_receive(struct mqueue *mq, char *msg_ptr, 248 size_t msg_len, unsigned *msg_prio, int waitok, 249 const struct timespec *abs_timeout); 250static int _mqueue_send(struct mqueue *mq, struct mqueue_msg *msg, 251 int timo); 252static int _mqueue_recv(struct mqueue *mq, struct mqueue_msg **msg, 253 int timo); 254static void mqueue_send_notification(struct mqueue *mq); 255static void mqueue_fdclose(struct thread *td, int fd, struct file *fp); 256static void mq_proc_exit(void *arg, struct proc *p); 257 258/* 259 * kqueue filters 260 */ 261static void filt_mqdetach(struct knote *kn); 262static int filt_mqread(struct knote *kn, long hint); 263static int filt_mqwrite(struct knote *kn, long hint); 264 265struct filterops mq_rfiltops = { 266 .f_isfd = 1, 267 .f_detach = filt_mqdetach, 268 .f_event = filt_mqread, 269}; 270struct filterops mq_wfiltops = { 271 .f_isfd = 1, 272 .f_detach = filt_mqdetach, 273 .f_event = filt_mqwrite, 274}; 275 276/* 277 * Initialize fileno bitmap 278 */ 279static void 280mqfs_fileno_init(struct mqfs_info *mi) 281{ 282 struct unrhdr *up; 283 284 up = new_unrhdr(1, INT_MAX, NULL); 285 mi->mi_unrhdr = up; 286} 287 288/* 289 * Tear down fileno bitmap 290 */ 291static void 292mqfs_fileno_uninit(struct mqfs_info *mi) 293{ 294 struct unrhdr *up; 295 296 up = mi->mi_unrhdr; 297 mi->mi_unrhdr = NULL; 298 delete_unrhdr(up); 299} 300 301/* 302 * Allocate a file number 303 */ 304static void 305mqfs_fileno_alloc(struct mqfs_info *mi, struct mqfs_node *mn) 306{ 307 /* make sure our parent has a file number */ 308 if (mn->mn_parent && !mn->mn_parent->mn_fileno) 309 mqfs_fileno_alloc(mi, mn->mn_parent); 310 311 switch (mn->mn_type) { 312 case mqfstype_root: 313 case mqfstype_dir: 314 case mqfstype_file: 315 case mqfstype_symlink: 316 mn->mn_fileno = alloc_unr(mi->mi_unrhdr); 317 break; 318 case mqfstype_this: 319 KASSERT(mn->mn_parent != NULL, 320 ("mqfstype_this node has no parent")); 321 mn->mn_fileno = mn->mn_parent->mn_fileno; 322 break; 323 case mqfstype_parent: 324 KASSERT(mn->mn_parent != NULL, 325 ("mqfstype_parent node has no parent")); 326 if (mn->mn_parent == mi->mi_root) { 327 mn->mn_fileno = mn->mn_parent->mn_fileno; 328 break; 329 } 330 KASSERT(mn->mn_parent->mn_parent != NULL, 331 ("mqfstype_parent node has no grandparent")); 332 mn->mn_fileno = mn->mn_parent->mn_parent->mn_fileno; 333 break; 334 default: 335 KASSERT(0, 336 ("mqfs_fileno_alloc() called for unknown type node: %d", 337 mn->mn_type)); 338 break; 339 } 340} 341 342/* 343 * Release a file number 344 */ 345static void 346mqfs_fileno_free(struct mqfs_info *mi, struct mqfs_node *mn) 347{ 348 switch (mn->mn_type) { 349 case mqfstype_root: 350 case mqfstype_dir: 351 case mqfstype_file: 352 case mqfstype_symlink: 353 free_unr(mi->mi_unrhdr, mn->mn_fileno); 354 break; 355 case mqfstype_this: 356 case mqfstype_parent: 357 /* ignore these, as they don't "own" their file number */ 358 break; 359 default: 360 KASSERT(0, 361 ("mqfs_fileno_free() called for unknown type node: %d", 362 mn->mn_type)); 363 break; 364 } 365} 366 367static __inline struct mqfs_node * 368mqnode_alloc(void) 369{ 370 return uma_zalloc(mqnode_zone, M_WAITOK | M_ZERO); 371} 372 373static __inline void 374mqnode_free(struct mqfs_node *node) 375{ 376 uma_zfree(mqnode_zone, node); 377} 378 379static __inline void 380mqnode_addref(struct mqfs_node *node) 381{ 382 atomic_fetchadd_int(&node->mn_refcount, 1); 383} 384 385static __inline void 386mqnode_release(struct mqfs_node *node) 387{ 388 struct mqfs_info *mqfs; 389 int old, exp; 390 391 mqfs = node->mn_info; 392 old = atomic_fetchadd_int(&node->mn_refcount, -1); 393 if (node->mn_type == mqfstype_dir || 394 node->mn_type == mqfstype_root) 395 exp = 3; /* include . and .. */ 396 else 397 exp = 1; 398 if (old == exp) { 399 int locked = sx_xlocked(&mqfs->mi_lock); 400 if (!locked) 401 sx_xlock(&mqfs->mi_lock); 402 mqfs_destroy(node); 403 if (!locked) 404 sx_xunlock(&mqfs->mi_lock); 405 } 406} 407 408/* 409 * Add a node to a directory 410 */ 411static int 412mqfs_add_node(struct mqfs_node *parent, struct mqfs_node *node) 413{ 414 KASSERT(parent != NULL, ("%s(): parent is NULL", __func__)); 415 KASSERT(parent->mn_info != NULL, 416 ("%s(): parent has no mn_info", __func__)); 417 KASSERT(parent->mn_type == mqfstype_dir || 418 parent->mn_type == mqfstype_root, 419 ("%s(): parent is not a directory", __func__)); 420 421 node->mn_info = parent->mn_info; 422 node->mn_parent = parent; 423 LIST_INIT(&node->mn_children); 424 LIST_INIT(&node->mn_vnodes); 425 LIST_INSERT_HEAD(&parent->mn_children, node, mn_sibling); 426 mqnode_addref(parent); 427 return (0); 428} 429 430static struct mqfs_node * 431mqfs_create_node(const char *name, int namelen, struct ucred *cred, int mode, 432 int nodetype) 433{ 434 struct mqfs_node *node; 435 436 node = mqnode_alloc(); 437 strncpy(node->mn_name, name, namelen); 438 node->mn_type = nodetype; 439 node->mn_refcount = 1; 440 vfs_timestamp(&node->mn_birth); 441 node->mn_ctime = node->mn_atime = node->mn_mtime 442 = node->mn_birth; 443 node->mn_uid = cred->cr_uid; 444 node->mn_gid = cred->cr_gid; 445 node->mn_mode = mode; 446 return (node); 447} 448 449/* 450 * Create a file 451 */ 452static struct mqfs_node * 453mqfs_create_file(struct mqfs_node *parent, const char *name, int namelen, 454 struct ucred *cred, int mode) 455{ 456 struct mqfs_node *node; 457 458 node = mqfs_create_node(name, namelen, cred, mode, mqfstype_file); 459 if (mqfs_add_node(parent, node) != 0) { 460 mqnode_free(node); 461 return (NULL); 462 } 463 return (node); 464} 465 466/* 467 * Add . and .. to a directory 468 */ 469static int 470mqfs_fixup_dir(struct mqfs_node *parent) 471{ 472 struct mqfs_node *dir; 473 474 dir = mqnode_alloc(); 475 dir->mn_name[0] = '.'; 476 dir->mn_type = mqfstype_this; 477 dir->mn_refcount = 1; 478 if (mqfs_add_node(parent, dir) != 0) { 479 mqnode_free(dir); 480 return (-1); 481 } 482 483 dir = mqnode_alloc(); 484 dir->mn_name[0] = dir->mn_name[1] = '.'; 485 dir->mn_type = mqfstype_parent; 486 dir->mn_refcount = 1; 487 488 if (mqfs_add_node(parent, dir) != 0) { 489 mqnode_free(dir); 490 return (-1); 491 } 492 493 return (0); 494} 495 496#ifdef notyet 497 498/* 499 * Create a directory 500 */ 501static struct mqfs_node * 502mqfs_create_dir(struct mqfs_node *parent, const char *name, int namelen, 503 struct ucred *cred, int mode) 504{ 505 struct mqfs_node *node; 506 507 node = mqfs_create_node(name, namelen, cred, mode, mqfstype_dir); 508 if (mqfs_add_node(parent, node) != 0) { 509 mqnode_free(node); 510 return (NULL); 511 } 512 513 if (mqfs_fixup_dir(node) != 0) { 514 mqfs_destroy(node); 515 return (NULL); 516 } 517 return (node); 518} 519 520/* 521 * Create a symlink 522 */ 523static struct mqfs_node * 524mqfs_create_link(struct mqfs_node *parent, const char *name, int namelen, 525 struct ucred *cred, int mode) 526{ 527 struct mqfs_node *node; 528 529 node = mqfs_create_node(name, namelen, cred, mode, mqfstype_symlink); 530 if (mqfs_add_node(parent, node) != 0) { 531 mqnode_free(node); 532 return (NULL); 533 } 534 return (node); 535} 536 537#endif 538 539/* 540 * Destroy a node or a tree of nodes 541 */ 542static int 543mqfs_destroy(struct mqfs_node *node) 544{ 545 struct mqfs_node *parent; 546 547 KASSERT(node != NULL, 548 ("%s(): node is NULL", __func__)); 549 KASSERT(node->mn_info != NULL, 550 ("%s(): node has no mn_info", __func__)); 551 552 /* destroy children */ 553 if (node->mn_type == mqfstype_dir || node->mn_type == mqfstype_root) 554 while (! LIST_EMPTY(&node->mn_children)) 555 mqfs_destroy(LIST_FIRST(&node->mn_children)); 556 557 /* unlink from parent */ 558 if ((parent = node->mn_parent) != NULL) { 559 KASSERT(parent->mn_info == node->mn_info, 560 ("%s(): parent has different mn_info", __func__)); 561 LIST_REMOVE(node, mn_sibling); 562 } 563 564 if (node->mn_fileno != 0) 565 mqfs_fileno_free(node->mn_info, node); 566 if (node->mn_data != NULL) 567 mqueue_free(node->mn_data); 568 mqnode_free(node); 569 return (0); 570} 571 572/* 573 * Mount a mqfs instance 574 */ 575static int 576mqfs_mount(struct mount *mp) 577{ 578 struct statfs *sbp; 579 580 if (mp->mnt_flag & MNT_UPDATE) 581 return (EOPNOTSUPP); 582 583 mp->mnt_data = &mqfs_data; 584 MNT_ILOCK(mp); 585 mp->mnt_flag |= MNT_LOCAL; 586 MNT_IUNLOCK(mp); 587 vfs_getnewfsid(mp); 588 589 sbp = &mp->mnt_stat; 590 vfs_mountedfrom(mp, "mqueue"); 591 sbp->f_bsize = PAGE_SIZE; 592 sbp->f_iosize = PAGE_SIZE; 593 sbp->f_blocks = 1; 594 sbp->f_bfree = 0; 595 sbp->f_bavail = 0; 596 sbp->f_files = 1; 597 sbp->f_ffree = 0; 598 return (0); 599} 600 601/* 602 * Unmount a mqfs instance 603 */ 604static int 605mqfs_unmount(struct mount *mp, int mntflags) 606{ 607 int error; 608 609 error = vflush(mp, 0, (mntflags & MNT_FORCE) ? FORCECLOSE : 0, 610 curthread); 611 return (error); 612} 613 614/* 615 * Return a root vnode 616 */ 617static int 618mqfs_root(struct mount *mp, int flags, struct vnode **vpp) 619{ 620 struct mqfs_info *mqfs; 621 int ret; 622 623 mqfs = VFSTOMQFS(mp); 624 ret = mqfs_allocv(mp, vpp, mqfs->mi_root); 625 return (ret); 626} 627 628/* 629 * Return filesystem stats 630 */ 631static int 632mqfs_statfs(struct mount *mp, struct statfs *sbp) 633{ 634 /* XXX update statistics */ 635 return (0); 636} 637 638/* 639 * Initialize a mqfs instance 640 */ 641static int 642mqfs_init(struct vfsconf *vfc) 643{ 644 struct mqfs_node *root; 645 struct mqfs_info *mi; 646 647 mqnode_zone = uma_zcreate("mqnode", sizeof(struct mqfs_node), 648 NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 649 mqueue_zone = uma_zcreate("mqueue", sizeof(struct mqueue), 650 NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 651 mvdata_zone = uma_zcreate("mvdata", 652 sizeof(struct mqfs_vdata), NULL, NULL, NULL, 653 NULL, UMA_ALIGN_PTR, 0); 654 mqnoti_zone = uma_zcreate("mqnotifier", sizeof(struct mqueue_notifier), 655 NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 656 mi = &mqfs_data; 657 sx_init(&mi->mi_lock, "mqfs lock"); 658 /* set up the root diretory */ 659 root = mqfs_create_node("/", 1, curthread->td_ucred, 01777, 660 mqfstype_root); 661 root->mn_info = mi; 662 LIST_INIT(&root->mn_children); 663 LIST_INIT(&root->mn_vnodes); 664 mi->mi_root = root; 665 mqfs_fileno_init(mi); 666 mqfs_fileno_alloc(mi, root); 667 mqfs_fixup_dir(root); 668 exit_tag = EVENTHANDLER_REGISTER(process_exit, mq_proc_exit, NULL, 669 EVENTHANDLER_PRI_ANY); 670 mq_fdclose = mqueue_fdclose; 671 p31b_setcfg(CTL_P1003_1B_MESSAGE_PASSING, _POSIX_MESSAGE_PASSING); 672 return (0); 673} 674 675/* 676 * Destroy a mqfs instance 677 */ 678static int 679mqfs_uninit(struct vfsconf *vfc) 680{ 681 struct mqfs_info *mi; 682 683 if (!unloadable) 684 return (EOPNOTSUPP); 685 EVENTHANDLER_DEREGISTER(process_exit, exit_tag); 686 mi = &mqfs_data; 687 mqfs_destroy(mi->mi_root); 688 mi->mi_root = NULL; 689 mqfs_fileno_uninit(mi); 690 sx_destroy(&mi->mi_lock); 691 uma_zdestroy(mqnode_zone); 692 uma_zdestroy(mqueue_zone); 693 uma_zdestroy(mvdata_zone); 694 uma_zdestroy(mqnoti_zone); 695 return (0); 696} 697 698/* 699 * task routine 700 */ 701static void 702do_recycle(void *context, int pending __unused) 703{ 704 struct vnode *vp = (struct vnode *)context; 705 706 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 707 vrecycle(vp); 708 VOP_UNLOCK(vp, 0); 709 vdrop(vp); 710} 711 712/* 713 * Allocate a vnode 714 */ 715static int 716mqfs_allocv(struct mount *mp, struct vnode **vpp, struct mqfs_node *pn) 717{ 718 struct mqfs_vdata *vd; 719 struct mqfs_info *mqfs; 720 struct vnode *newvpp; 721 int error; 722 723 mqfs = pn->mn_info; 724 *vpp = NULL; 725 sx_xlock(&mqfs->mi_lock); 726 LIST_FOREACH(vd, &pn->mn_vnodes, mv_link) { 727 if (vd->mv_vnode->v_mount == mp) { 728 vhold(vd->mv_vnode); 729 break; 730 } 731 } 732 733 if (vd != NULL) { 734found: 735 *vpp = vd->mv_vnode; 736 sx_xunlock(&mqfs->mi_lock); 737 error = vget(*vpp, LK_RETRY | LK_EXCLUSIVE, curthread); 738 vdrop(*vpp); 739 return (error); 740 } 741 sx_xunlock(&mqfs->mi_lock); 742 743 error = getnewvnode("mqueue", mp, &mqfs_vnodeops, &newvpp); 744 if (error) 745 return (error); 746 vn_lock(newvpp, LK_EXCLUSIVE | LK_RETRY); 747 error = insmntque(newvpp, mp); 748 if (error != 0) 749 return (error); 750 751 sx_xlock(&mqfs->mi_lock); 752 /* 753 * Check if it has already been allocated 754 * while we were blocked. 755 */ 756 LIST_FOREACH(vd, &pn->mn_vnodes, mv_link) { 757 if (vd->mv_vnode->v_mount == mp) { 758 vhold(vd->mv_vnode); 759 sx_xunlock(&mqfs->mi_lock); 760 761 vgone(newvpp); 762 vput(newvpp); 763 goto found; 764 } 765 } 766 767 *vpp = newvpp; 768 769 vd = uma_zalloc(mvdata_zone, M_WAITOK); 770 (*vpp)->v_data = vd; 771 vd->mv_vnode = *vpp; 772 vd->mv_node = pn; 773 TASK_INIT(&vd->mv_task, 0, do_recycle, *vpp); 774 LIST_INSERT_HEAD(&pn->mn_vnodes, vd, mv_link); 775 mqnode_addref(pn); 776 switch (pn->mn_type) { 777 case mqfstype_root: 778 (*vpp)->v_vflag = VV_ROOT; 779 /* fall through */ 780 case mqfstype_dir: 781 case mqfstype_this: 782 case mqfstype_parent: 783 (*vpp)->v_type = VDIR; 784 break; 785 case mqfstype_file: 786 (*vpp)->v_type = VREG; 787 break; 788 case mqfstype_symlink: 789 (*vpp)->v_type = VLNK; 790 break; 791 case mqfstype_none: 792 KASSERT(0, ("mqfs_allocf called for null node\n")); 793 default: 794 panic("%s has unexpected type: %d", pn->mn_name, pn->mn_type); 795 } 796 sx_xunlock(&mqfs->mi_lock); 797 return (0); 798} 799 800/* 801 * Search a directory entry 802 */ 803static struct mqfs_node * 804mqfs_search(struct mqfs_node *pd, const char *name, int len) 805{ 806 struct mqfs_node *pn; 807 808 sx_assert(&pd->mn_info->mi_lock, SX_LOCKED); 809 LIST_FOREACH(pn, &pd->mn_children, mn_sibling) { 810 if (strncmp(pn->mn_name, name, len) == 0 && 811 pn->mn_name[len] == '\0') 812 return (pn); 813 } 814 return (NULL); 815} 816 817/* 818 * Look up a file or directory. 819 */ 820static int 821mqfs_lookupx(struct vop_cachedlookup_args *ap) 822{ 823 struct componentname *cnp; 824 struct vnode *dvp, **vpp; 825 struct mqfs_node *pd; 826 struct mqfs_node *pn; 827 struct mqfs_info *mqfs; 828 int nameiop, flags, error, namelen; 829 char *pname; 830 struct thread *td; 831 832 cnp = ap->a_cnp; 833 vpp = ap->a_vpp; 834 dvp = ap->a_dvp; 835 pname = cnp->cn_nameptr; 836 namelen = cnp->cn_namelen; 837 td = cnp->cn_thread; 838 flags = cnp->cn_flags; 839 nameiop = cnp->cn_nameiop; 840 pd = VTON(dvp); 841 pn = NULL; 842 mqfs = pd->mn_info; 843 *vpp = NULLVP; 844 845 if (dvp->v_type != VDIR) 846 return (ENOTDIR); 847 848 error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, cnp->cn_thread); 849 if (error) 850 return (error); 851 852 /* shortcut: check if the name is too long */ 853 if (cnp->cn_namelen >= MQFS_NAMELEN) 854 return (ENOENT); 855 856 /* self */ 857 if (namelen == 1 && pname[0] == '.') { 858 if ((flags & ISLASTCN) && nameiop != LOOKUP) 859 return (EINVAL); 860 pn = pd; 861 *vpp = dvp; 862 VREF(dvp); 863 return (0); 864 } 865 866 /* parent */ 867 if (cnp->cn_flags & ISDOTDOT) { 868 if (dvp->v_vflag & VV_ROOT) 869 return (EIO); 870 if ((flags & ISLASTCN) && nameiop != LOOKUP) 871 return (EINVAL); 872 VOP_UNLOCK(dvp, 0); 873 KASSERT(pd->mn_parent, ("non-root directory has no parent")); 874 pn = pd->mn_parent; 875 error = mqfs_allocv(dvp->v_mount, vpp, pn); 876 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 877 return (error); 878 } 879 880 /* named node */ 881 sx_xlock(&mqfs->mi_lock); 882 pn = mqfs_search(pd, pname, namelen); 883 if (pn != NULL) 884 mqnode_addref(pn); 885 sx_xunlock(&mqfs->mi_lock); 886 887 /* found */ 888 if (pn != NULL) { 889 /* DELETE */ 890 if (nameiop == DELETE && (flags & ISLASTCN)) { 891 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 892 if (error) { 893 mqnode_release(pn); 894 return (error); 895 } 896 if (*vpp == dvp) { 897 VREF(dvp); 898 *vpp = dvp; 899 mqnode_release(pn); 900 return (0); 901 } 902 } 903 904 /* allocate vnode */ 905 error = mqfs_allocv(dvp->v_mount, vpp, pn); 906 mqnode_release(pn); 907 if (error == 0 && cnp->cn_flags & MAKEENTRY) 908 cache_enter(dvp, *vpp, cnp); 909 return (error); 910 } 911 912 /* not found */ 913 914 /* will create a new entry in the directory ? */ 915 if ((nameiop == CREATE || nameiop == RENAME) && (flags & LOCKPARENT) 916 && (flags & ISLASTCN)) { 917 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 918 if (error) 919 return (error); 920 cnp->cn_flags |= SAVENAME; 921 return (EJUSTRETURN); 922 } 923 return (ENOENT); 924} 925 926#if 0 927struct vop_lookup_args { 928 struct vop_generic_args a_gen; 929 struct vnode *a_dvp; 930 struct vnode **a_vpp; 931 struct componentname *a_cnp; 932}; 933#endif 934 935/* 936 * vnode lookup operation 937 */ 938static int 939mqfs_lookup(struct vop_cachedlookup_args *ap) 940{ 941 int rc; 942 943 rc = mqfs_lookupx(ap); 944 return (rc); 945} 946 947#if 0 948struct vop_create_args { 949 struct vnode *a_dvp; 950 struct vnode **a_vpp; 951 struct componentname *a_cnp; 952 struct vattr *a_vap; 953}; 954#endif 955 956/* 957 * vnode creation operation 958 */ 959static int 960mqfs_create(struct vop_create_args *ap) 961{ 962 struct mqfs_info *mqfs = VFSTOMQFS(ap->a_dvp->v_mount); 963 struct componentname *cnp = ap->a_cnp; 964 struct mqfs_node *pd; 965 struct mqfs_node *pn; 966 struct mqueue *mq; 967 int error; 968 969 pd = VTON(ap->a_dvp); 970 if (pd->mn_type != mqfstype_root && pd->mn_type != mqfstype_dir) 971 return (ENOTDIR); 972 mq = mqueue_alloc(NULL); 973 if (mq == NULL) 974 return (EAGAIN); 975 sx_xlock(&mqfs->mi_lock); 976 if ((cnp->cn_flags & HASBUF) == 0) 977 panic("%s: no name", __func__); 978 pn = mqfs_create_file(pd, cnp->cn_nameptr, cnp->cn_namelen, 979 cnp->cn_cred, ap->a_vap->va_mode); 980 if (pn == NULL) { 981 sx_xunlock(&mqfs->mi_lock); 982 error = ENOSPC; 983 } else { 984 mqnode_addref(pn); 985 sx_xunlock(&mqfs->mi_lock); 986 error = mqfs_allocv(ap->a_dvp->v_mount, ap->a_vpp, pn); 987 mqnode_release(pn); 988 if (error) 989 mqfs_destroy(pn); 990 else 991 pn->mn_data = mq; 992 } 993 if (error) 994 mqueue_free(mq); 995 return (error); 996} 997 998/* 999 * Remove an entry 1000 */ 1001static 1002int do_unlink(struct mqfs_node *pn, struct ucred *ucred) 1003{ 1004 struct mqfs_node *parent; 1005 struct mqfs_vdata *vd; 1006 int error = 0; 1007 1008 sx_assert(&pn->mn_info->mi_lock, SX_LOCKED); 1009 1010 if (ucred->cr_uid != pn->mn_uid && 1011 (error = priv_check_cred(ucred, PRIV_MQ_ADMIN, 0)) != 0) 1012 error = EACCES; 1013 else if (!pn->mn_deleted) { 1014 parent = pn->mn_parent; 1015 pn->mn_parent = NULL; 1016 pn->mn_deleted = 1; 1017 LIST_REMOVE(pn, mn_sibling); 1018 LIST_FOREACH(vd, &pn->mn_vnodes, mv_link) { 1019 cache_purge(vd->mv_vnode); 1020 vhold(vd->mv_vnode); 1021 taskqueue_enqueue(taskqueue_thread, &vd->mv_task); 1022 } 1023 mqnode_release(pn); 1024 mqnode_release(parent); 1025 } else 1026 error = ENOENT; 1027 return (error); 1028} 1029 1030#if 0 1031struct vop_remove_args { 1032 struct vnode *a_dvp; 1033 struct vnode *a_vp; 1034 struct componentname *a_cnp; 1035}; 1036#endif 1037 1038/* 1039 * vnode removal operation 1040 */ 1041static int 1042mqfs_remove(struct vop_remove_args *ap) 1043{ 1044 struct mqfs_info *mqfs = VFSTOMQFS(ap->a_dvp->v_mount); 1045 struct mqfs_node *pn; 1046 int error; 1047 1048 if (ap->a_vp->v_type == VDIR) 1049 return (EPERM); 1050 pn = VTON(ap->a_vp); 1051 sx_xlock(&mqfs->mi_lock); 1052 error = do_unlink(pn, ap->a_cnp->cn_cred); 1053 sx_xunlock(&mqfs->mi_lock); 1054 return (error); 1055} 1056 1057#if 0 1058struct vop_inactive_args { 1059 struct vnode *a_vp; 1060 struct thread *a_td; 1061}; 1062#endif 1063 1064static int 1065mqfs_inactive(struct vop_inactive_args *ap) 1066{ 1067 struct mqfs_node *pn = VTON(ap->a_vp); 1068 1069 if (pn->mn_deleted) 1070 vrecycle(ap->a_vp); 1071 return (0); 1072} 1073 1074#if 0 1075struct vop_reclaim_args { 1076 struct vop_generic_args a_gen; 1077 struct vnode *a_vp; 1078 struct thread *a_td; 1079}; 1080#endif 1081 1082static int 1083mqfs_reclaim(struct vop_reclaim_args *ap) 1084{ 1085 struct mqfs_info *mqfs = VFSTOMQFS(ap->a_vp->v_mount); 1086 struct vnode *vp = ap->a_vp; 1087 struct mqfs_node *pn; 1088 struct mqfs_vdata *vd; 1089 1090 vd = vp->v_data; 1091 pn = vd->mv_node; 1092 sx_xlock(&mqfs->mi_lock); 1093 vp->v_data = NULL; 1094 LIST_REMOVE(vd, mv_link); 1095 uma_zfree(mvdata_zone, vd); 1096 mqnode_release(pn); 1097 sx_xunlock(&mqfs->mi_lock); 1098 return (0); 1099} 1100 1101#if 0 1102struct vop_open_args { 1103 struct vop_generic_args a_gen; 1104 struct vnode *a_vp; 1105 int a_mode; 1106 struct ucred *a_cred; 1107 struct thread *a_td; 1108 struct file *a_fp; 1109}; 1110#endif 1111 1112static int 1113mqfs_open(struct vop_open_args *ap) 1114{ 1115 return (0); 1116} 1117 1118#if 0 1119struct vop_close_args { 1120 struct vop_generic_args a_gen; 1121 struct vnode *a_vp; 1122 int a_fflag; 1123 struct ucred *a_cred; 1124 struct thread *a_td; 1125}; 1126#endif 1127 1128static int 1129mqfs_close(struct vop_close_args *ap) 1130{ 1131 return (0); 1132} 1133 1134#if 0 1135struct vop_access_args { 1136 struct vop_generic_args a_gen; 1137 struct vnode *a_vp; 1138 accmode_t a_accmode; 1139 struct ucred *a_cred; 1140 struct thread *a_td; 1141}; 1142#endif 1143 1144/* 1145 * Verify permissions 1146 */ 1147static int 1148mqfs_access(struct vop_access_args *ap) 1149{ 1150 struct vnode *vp = ap->a_vp; 1151 struct vattr vattr; 1152 int error; 1153 1154 error = VOP_GETATTR(vp, &vattr, ap->a_cred); 1155 if (error) 1156 return (error); 1157 error = vaccess(vp->v_type, vattr.va_mode, vattr.va_uid, 1158 vattr.va_gid, ap->a_accmode, ap->a_cred, NULL); 1159 return (error); 1160} 1161 1162#if 0 1163struct vop_getattr_args { 1164 struct vop_generic_args a_gen; 1165 struct vnode *a_vp; 1166 struct vattr *a_vap; 1167 struct ucred *a_cred; 1168}; 1169#endif 1170 1171/* 1172 * Get file attributes 1173 */ 1174static int 1175mqfs_getattr(struct vop_getattr_args *ap) 1176{ 1177 struct vnode *vp = ap->a_vp; 1178 struct mqfs_node *pn = VTON(vp); 1179 struct vattr *vap = ap->a_vap; 1180 int error = 0; 1181 1182 vap->va_type = vp->v_type; 1183 vap->va_mode = pn->mn_mode; 1184 vap->va_nlink = 1; 1185 vap->va_uid = pn->mn_uid; 1186 vap->va_gid = pn->mn_gid; 1187 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 1188 vap->va_fileid = pn->mn_fileno; 1189 vap->va_size = 0; 1190 vap->va_blocksize = PAGE_SIZE; 1191 vap->va_bytes = vap->va_size = 0; 1192 vap->va_atime = pn->mn_atime; 1193 vap->va_mtime = pn->mn_mtime; 1194 vap->va_ctime = pn->mn_ctime; 1195 vap->va_birthtime = pn->mn_birth; 1196 vap->va_gen = 0; 1197 vap->va_flags = 0; 1198 vap->va_rdev = NODEV; 1199 vap->va_bytes = 0; 1200 vap->va_filerev = 0; 1201 return (error); 1202} 1203 1204#if 0 1205struct vop_setattr_args { 1206 struct vop_generic_args a_gen; 1207 struct vnode *a_vp; 1208 struct vattr *a_vap; 1209 struct ucred *a_cred; 1210}; 1211#endif 1212/* 1213 * Set attributes 1214 */ 1215static int 1216mqfs_setattr(struct vop_setattr_args *ap) 1217{ 1218 struct mqfs_node *pn; 1219 struct vattr *vap; 1220 struct vnode *vp; 1221 struct thread *td; 1222 int c, error; 1223 uid_t uid; 1224 gid_t gid; 1225 1226 td = curthread; 1227 vap = ap->a_vap; 1228 vp = ap->a_vp; 1229 if ((vap->va_type != VNON) || 1230 (vap->va_nlink != VNOVAL) || 1231 (vap->va_fsid != VNOVAL) || 1232 (vap->va_fileid != VNOVAL) || 1233 (vap->va_blocksize != VNOVAL) || 1234 (vap->va_flags != VNOVAL && vap->va_flags != 0) || 1235 (vap->va_rdev != VNOVAL) || 1236 ((int)vap->va_bytes != VNOVAL) || 1237 (vap->va_gen != VNOVAL)) { 1238 return (EINVAL); 1239 } 1240 1241 pn = VTON(vp); 1242 1243 error = c = 0; 1244 if (vap->va_uid == (uid_t)VNOVAL) 1245 uid = pn->mn_uid; 1246 else 1247 uid = vap->va_uid; 1248 if (vap->va_gid == (gid_t)VNOVAL) 1249 gid = pn->mn_gid; 1250 else 1251 gid = vap->va_gid; 1252 1253 if (uid != pn->mn_uid || gid != pn->mn_gid) { 1254 /* 1255 * To modify the ownership of a file, must possess VADMIN 1256 * for that file. 1257 */ 1258 if ((error = VOP_ACCESS(vp, VADMIN, ap->a_cred, td))) 1259 return (error); 1260 1261 /* 1262 * XXXRW: Why is there a privilege check here: shouldn't the 1263 * check in VOP_ACCESS() be enough? Also, are the group bits 1264 * below definitely right? 1265 */ 1266 if (((ap->a_cred->cr_uid != pn->mn_uid) || uid != pn->mn_uid || 1267 (gid != pn->mn_gid && !groupmember(gid, ap->a_cred))) && 1268 (error = priv_check(td, PRIV_MQ_ADMIN)) != 0) 1269 return (error); 1270 pn->mn_uid = uid; 1271 pn->mn_gid = gid; 1272 c = 1; 1273 } 1274 1275 if (vap->va_mode != (mode_t)VNOVAL) { 1276 if ((ap->a_cred->cr_uid != pn->mn_uid) && 1277 (error = priv_check(td, PRIV_MQ_ADMIN))) 1278 return (error); 1279 pn->mn_mode = vap->va_mode; 1280 c = 1; 1281 } 1282 1283 if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { 1284 /* See the comment in ufs_vnops::ufs_setattr(). */ 1285 if ((error = VOP_ACCESS(vp, VADMIN, ap->a_cred, td)) && 1286 ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || 1287 (error = VOP_ACCESS(vp, VWRITE, ap->a_cred, td)))) 1288 return (error); 1289 if (vap->va_atime.tv_sec != VNOVAL) { 1290 pn->mn_atime = vap->va_atime; 1291 } 1292 if (vap->va_mtime.tv_sec != VNOVAL) { 1293 pn->mn_mtime = vap->va_mtime; 1294 } 1295 c = 1; 1296 } 1297 if (c) { 1298 vfs_timestamp(&pn->mn_ctime); 1299 } 1300 return (0); 1301} 1302 1303#if 0 1304struct vop_read_args { 1305 struct vop_generic_args a_gen; 1306 struct vnode *a_vp; 1307 struct uio *a_uio; 1308 int a_ioflag; 1309 struct ucred *a_cred; 1310}; 1311#endif 1312 1313/* 1314 * Read from a file 1315 */ 1316static int 1317mqfs_read(struct vop_read_args *ap) 1318{ 1319 char buf[80]; 1320 struct vnode *vp = ap->a_vp; 1321 struct uio *uio = ap->a_uio; 1322 struct mqfs_node *pn; 1323 struct mqueue *mq; 1324 int len, error; 1325 1326 if (vp->v_type != VREG) 1327 return (EINVAL); 1328 1329 pn = VTON(vp); 1330 mq = VTOMQ(vp); 1331 snprintf(buf, sizeof(buf), 1332 "QSIZE:%-10ld MAXMSG:%-10ld CURMSG:%-10ld MSGSIZE:%-10ld\n", 1333 mq->mq_totalbytes, 1334 mq->mq_maxmsg, 1335 mq->mq_curmsgs, 1336 mq->mq_msgsize); 1337 buf[sizeof(buf)-1] = '\0'; 1338 len = strlen(buf); 1339 error = uiomove_frombuf(buf, len, uio); 1340 return (error); 1341} 1342 1343#if 0 1344struct vop_readdir_args { 1345 struct vop_generic_args a_gen; 1346 struct vnode *a_vp; 1347 struct uio *a_uio; 1348 struct ucred *a_cred; 1349 int *a_eofflag; 1350 int *a_ncookies; 1351 u_long **a_cookies; 1352}; 1353#endif 1354 1355/* 1356 * Return directory entries. 1357 */ 1358static int 1359mqfs_readdir(struct vop_readdir_args *ap) 1360{ 1361 struct vnode *vp; 1362 struct mqfs_info *mi; 1363 struct mqfs_node *pd; 1364 struct mqfs_node *pn; 1365 struct dirent entry; 1366 struct uio *uio; 1367 int *tmp_ncookies = NULL; 1368 off_t offset; 1369 int error, i; 1370 1371 vp = ap->a_vp; 1372 mi = VFSTOMQFS(vp->v_mount); 1373 pd = VTON(vp); 1374 uio = ap->a_uio; 1375 1376 if (vp->v_type != VDIR) 1377 return (ENOTDIR); 1378 1379 if (uio->uio_offset < 0) 1380 return (EINVAL); 1381 1382 if (ap->a_ncookies != NULL) { 1383 tmp_ncookies = ap->a_ncookies; 1384 *ap->a_ncookies = 0; 1385 ap->a_ncookies = NULL; 1386 } 1387 1388 error = 0; 1389 offset = 0; 1390 1391 sx_xlock(&mi->mi_lock); 1392 1393 LIST_FOREACH(pn, &pd->mn_children, mn_sibling) { 1394 entry.d_reclen = sizeof(entry); 1395 if (!pn->mn_fileno) 1396 mqfs_fileno_alloc(mi, pn); 1397 entry.d_fileno = pn->mn_fileno; 1398 for (i = 0; i < MQFS_NAMELEN - 1 && pn->mn_name[i] != '\0'; ++i) 1399 entry.d_name[i] = pn->mn_name[i]; 1400 entry.d_name[i] = 0; 1401 entry.d_namlen = i; 1402 switch (pn->mn_type) { 1403 case mqfstype_root: 1404 case mqfstype_dir: 1405 case mqfstype_this: 1406 case mqfstype_parent: 1407 entry.d_type = DT_DIR; 1408 break; 1409 case mqfstype_file: 1410 entry.d_type = DT_REG; 1411 break; 1412 case mqfstype_symlink: 1413 entry.d_type = DT_LNK; 1414 break; 1415 default: 1416 panic("%s has unexpected node type: %d", pn->mn_name, 1417 pn->mn_type); 1418 } 1419 if (entry.d_reclen > uio->uio_resid) 1420 break; 1421 if (offset >= uio->uio_offset) { 1422 error = vfs_read_dirent(ap, &entry, offset); 1423 if (error) 1424 break; 1425 } 1426 offset += entry.d_reclen; 1427 } 1428 sx_xunlock(&mi->mi_lock); 1429 1430 uio->uio_offset = offset; 1431 1432 if (tmp_ncookies != NULL) 1433 ap->a_ncookies = tmp_ncookies; 1434 1435 return (error); 1436} 1437 1438#ifdef notyet 1439 1440#if 0 1441struct vop_mkdir_args { 1442 struct vnode *a_dvp; 1443 struvt vnode **a_vpp; 1444 struvt componentname *a_cnp; 1445 struct vattr *a_vap; 1446}; 1447#endif 1448 1449/* 1450 * Create a directory. 1451 */ 1452static int 1453mqfs_mkdir(struct vop_mkdir_args *ap) 1454{ 1455 struct mqfs_info *mqfs = VFSTOMQFS(ap->a_dvp->v_mount); 1456 struct componentname *cnp = ap->a_cnp; 1457 struct mqfs_node *pd = VTON(ap->a_dvp); 1458 struct mqfs_node *pn; 1459 int error; 1460 1461 if (pd->mn_type != mqfstype_root && pd->mn_type != mqfstype_dir) 1462 return (ENOTDIR); 1463 sx_xlock(&mqfs->mi_lock); 1464 if ((cnp->cn_flags & HASBUF) == 0) 1465 panic("%s: no name", __func__); 1466 pn = mqfs_create_dir(pd, cnp->cn_nameptr, cnp->cn_namelen, 1467 ap->a_vap->cn_cred, ap->a_vap->va_mode); 1468 if (pn != NULL) 1469 mqnode_addref(pn); 1470 sx_xunlock(&mqfs->mi_lock); 1471 if (pn == NULL) { 1472 error = ENOSPC; 1473 } else { 1474 error = mqfs_allocv(ap->a_dvp->v_mount, ap->a_vpp, pn); 1475 mqnode_release(pn); 1476 } 1477 return (error); 1478} 1479 1480#if 0 1481struct vop_rmdir_args { 1482 struct vnode *a_dvp; 1483 struct vnode *a_vp; 1484 struct componentname *a_cnp; 1485}; 1486#endif 1487 1488/* 1489 * Remove a directory. 1490 */ 1491static int 1492mqfs_rmdir(struct vop_rmdir_args *ap) 1493{ 1494 struct mqfs_info *mqfs = VFSTOMQFS(ap->a_dvp->v_mount); 1495 struct mqfs_node *pn = VTON(ap->a_vp); 1496 struct mqfs_node *pt; 1497 1498 if (pn->mn_type != mqfstype_dir) 1499 return (ENOTDIR); 1500 1501 sx_xlock(&mqfs->mi_lock); 1502 if (pn->mn_deleted) { 1503 sx_xunlock(&mqfs->mi_lock); 1504 return (ENOENT); 1505 } 1506 1507 pt = LIST_FIRST(&pn->mn_children); 1508 pt = LIST_NEXT(pt, mn_sibling); 1509 pt = LIST_NEXT(pt, mn_sibling); 1510 if (pt != NULL) { 1511 sx_xunlock(&mqfs->mi_lock); 1512 return (ENOTEMPTY); 1513 } 1514 pt = pn->mn_parent; 1515 pn->mn_parent = NULL; 1516 pn->mn_deleted = 1; 1517 LIST_REMOVE(pn, mn_sibling); 1518 mqnode_release(pn); 1519 mqnode_release(pt); 1520 sx_xunlock(&mqfs->mi_lock); 1521 cache_purge(ap->a_vp); 1522 return (0); 1523} 1524 1525#endif /* notyet */ 1526 1527/* 1528 * Allocate a message queue 1529 */ 1530static struct mqueue * 1531mqueue_alloc(const struct mq_attr *attr) 1532{ 1533 struct mqueue *mq; 1534 1535 if (curmq >= maxmq) 1536 return (NULL); 1537 mq = uma_zalloc(mqueue_zone, M_WAITOK | M_ZERO); 1538 TAILQ_INIT(&mq->mq_msgq); 1539 if (attr != NULL) { 1540 mq->mq_maxmsg = attr->mq_maxmsg; 1541 mq->mq_msgsize = attr->mq_msgsize; 1542 } else { 1543 mq->mq_maxmsg = default_maxmsg; 1544 mq->mq_msgsize = default_msgsize; 1545 } 1546 mtx_init(&mq->mq_mutex, "mqueue lock", NULL, MTX_DEF); 1547 knlist_init_mtx(&mq->mq_rsel.si_note, &mq->mq_mutex); 1548 knlist_init_mtx(&mq->mq_wsel.si_note, &mq->mq_mutex); 1549 atomic_add_int(&curmq, 1); 1550 return (mq); 1551} 1552 1553/* 1554 * Destroy a message queue 1555 */ 1556static void 1557mqueue_free(struct mqueue *mq) 1558{ 1559 struct mqueue_msg *msg; 1560 1561 while ((msg = TAILQ_FIRST(&mq->mq_msgq)) != NULL) { 1562 TAILQ_REMOVE(&mq->mq_msgq, msg, msg_link); 1563 free(msg, M_MQUEUEDATA); 1564 } 1565 1566 mtx_destroy(&mq->mq_mutex); 1567 seldrain(&mq->mq_rsel); 1568 seldrain(&mq->mq_wsel); 1569 knlist_destroy(&mq->mq_rsel.si_note); 1570 knlist_destroy(&mq->mq_wsel.si_note); 1571 uma_zfree(mqueue_zone, mq); 1572 atomic_add_int(&curmq, -1); 1573} 1574 1575/* 1576 * Load a message from user space 1577 */ 1578static struct mqueue_msg * 1579mqueue_loadmsg(const char *msg_ptr, size_t msg_size, int msg_prio) 1580{ 1581 struct mqueue_msg *msg; 1582 size_t len; 1583 int error; 1584 1585 len = sizeof(struct mqueue_msg) + msg_size; 1586 msg = malloc(len, M_MQUEUEDATA, M_WAITOK); 1587 error = copyin(msg_ptr, ((char *)msg) + sizeof(struct mqueue_msg), 1588 msg_size); 1589 if (error) { 1590 free(msg, M_MQUEUEDATA); 1591 msg = NULL; 1592 } else { 1593 msg->msg_size = msg_size; 1594 msg->msg_prio = msg_prio; 1595 } 1596 return (msg); 1597} 1598 1599/* 1600 * Save a message to user space 1601 */ 1602static int 1603mqueue_savemsg(struct mqueue_msg *msg, char *msg_ptr, int *msg_prio) 1604{ 1605 int error; 1606 1607 error = copyout(((char *)msg) + sizeof(*msg), msg_ptr, 1608 msg->msg_size); 1609 if (error == 0 && msg_prio != NULL) 1610 error = copyout(&msg->msg_prio, msg_prio, sizeof(int)); 1611 return (error); 1612} 1613 1614/* 1615 * Free a message's memory 1616 */ 1617static __inline void 1618mqueue_freemsg(struct mqueue_msg *msg) 1619{ 1620 free(msg, M_MQUEUEDATA); 1621} 1622 1623/* 1624 * Send a message. if waitok is false, thread will not be 1625 * blocked if there is no data in queue, otherwise, absolute 1626 * time will be checked. 1627 */ 1628int 1629mqueue_send(struct mqueue *mq, const char *msg_ptr, 1630 size_t msg_len, unsigned msg_prio, int waitok, 1631 const struct timespec *abs_timeout) 1632{ 1633 struct mqueue_msg *msg; 1634 struct timespec ts, ts2; 1635 struct timeval tv; 1636 int error; 1637 1638 if (msg_prio >= MQ_PRIO_MAX) 1639 return (EINVAL); 1640 if (msg_len > mq->mq_msgsize) 1641 return (EMSGSIZE); 1642 msg = mqueue_loadmsg(msg_ptr, msg_len, msg_prio); 1643 if (msg == NULL) 1644 return (EFAULT); 1645 1646 /* O_NONBLOCK case */ 1647 if (!waitok) { 1648 error = _mqueue_send(mq, msg, -1); 1649 if (error) 1650 goto bad; 1651 return (0); 1652 } 1653 1654 /* we allow a null timeout (wait forever) */ 1655 if (abs_timeout == NULL) { 1656 error = _mqueue_send(mq, msg, 0); 1657 if (error) 1658 goto bad; 1659 return (0); 1660 } 1661 1662 /* send it before checking time */ 1663 error = _mqueue_send(mq, msg, -1); 1664 if (error == 0) 1665 return (0); 1666 1667 if (error != EAGAIN) 1668 goto bad; 1669 1670 if (abs_timeout->tv_nsec >= 1000000000 || abs_timeout->tv_nsec < 0) { 1671 error = EINVAL; 1672 goto bad; 1673 } 1674 for (;;) { 1675 ts2 = *abs_timeout; 1676 getnanotime(&ts); 1677 timespecsub(&ts2, &ts); 1678 if (ts2.tv_sec < 0 || (ts2.tv_sec == 0 && ts2.tv_nsec <= 0)) { 1679 error = ETIMEDOUT; 1680 break; 1681 } 1682 TIMESPEC_TO_TIMEVAL(&tv, &ts2); 1683 error = _mqueue_send(mq, msg, tvtohz(&tv)); 1684 if (error != ETIMEDOUT) 1685 break; 1686 } 1687 if (error == 0) 1688 return (0); 1689bad: 1690 mqueue_freemsg(msg); 1691 return (error); 1692} 1693 1694/* 1695 * Common routine to send a message 1696 */ 1697static int 1698_mqueue_send(struct mqueue *mq, struct mqueue_msg *msg, int timo) 1699{ 1700 struct mqueue_msg *msg2; 1701 int error = 0; 1702 1703 mtx_lock(&mq->mq_mutex); 1704 while (mq->mq_curmsgs >= mq->mq_maxmsg && error == 0) { 1705 if (timo < 0) { 1706 mtx_unlock(&mq->mq_mutex); 1707 return (EAGAIN); 1708 } 1709 mq->mq_senders++; 1710 error = msleep(&mq->mq_senders, &mq->mq_mutex, 1711 PCATCH, "mqsend", timo); 1712 mq->mq_senders--; 1713 if (error == EAGAIN) 1714 error = ETIMEDOUT; 1715 } 1716 if (mq->mq_curmsgs >= mq->mq_maxmsg) { 1717 mtx_unlock(&mq->mq_mutex); 1718 return (error); 1719 } 1720 error = 0; 1721 if (TAILQ_EMPTY(&mq->mq_msgq)) { 1722 TAILQ_INSERT_HEAD(&mq->mq_msgq, msg, msg_link); 1723 } else { 1724 if (msg->msg_prio <= TAILQ_LAST(&mq->mq_msgq, msgq)->msg_prio) { 1725 TAILQ_INSERT_TAIL(&mq->mq_msgq, msg, msg_link); 1726 } else { 1727 TAILQ_FOREACH(msg2, &mq->mq_msgq, msg_link) { 1728 if (msg2->msg_prio < msg->msg_prio) 1729 break; 1730 } 1731 TAILQ_INSERT_BEFORE(msg2, msg, msg_link); 1732 } 1733 } 1734 mq->mq_curmsgs++; 1735 mq->mq_totalbytes += msg->msg_size; 1736 if (mq->mq_receivers) 1737 wakeup_one(&mq->mq_receivers); 1738 else if (mq->mq_notifier != NULL) 1739 mqueue_send_notification(mq); 1740 if (mq->mq_flags & MQ_RSEL) { 1741 mq->mq_flags &= ~MQ_RSEL; 1742 selwakeup(&mq->mq_rsel); 1743 } 1744 KNOTE_LOCKED(&mq->mq_rsel.si_note, 0); 1745 mtx_unlock(&mq->mq_mutex); 1746 return (0); 1747} 1748 1749/* 1750 * Send realtime a signal to process which registered itself 1751 * successfully by mq_notify. 1752 */ 1753static void 1754mqueue_send_notification(struct mqueue *mq) 1755{ 1756 struct mqueue_notifier *nt; 1757 struct thread *td; 1758 struct proc *p; 1759 int error; 1760 1761 mtx_assert(&mq->mq_mutex, MA_OWNED); 1762 nt = mq->mq_notifier; 1763 if (nt->nt_sigev.sigev_notify != SIGEV_NONE) { 1764 p = nt->nt_proc; 1765 error = sigev_findtd(p, &nt->nt_sigev, &td); 1766 if (error) { 1767 mq->mq_notifier = NULL; 1768 return; 1769 } 1770 if (!KSI_ONQ(&nt->nt_ksi)) { 1771 ksiginfo_set_sigev(&nt->nt_ksi, &nt->nt_sigev); 1772 tdsendsignal(p, td, nt->nt_ksi.ksi_signo, &nt->nt_ksi); 1773 } 1774 PROC_UNLOCK(p); 1775 } 1776 mq->mq_notifier = NULL; 1777} 1778 1779/* 1780 * Get a message. if waitok is false, thread will not be 1781 * blocked if there is no data in queue, otherwise, absolute 1782 * time will be checked. 1783 */ 1784int 1785mqueue_receive(struct mqueue *mq, char *msg_ptr, 1786 size_t msg_len, unsigned *msg_prio, int waitok, 1787 const struct timespec *abs_timeout) 1788{ 1789 struct mqueue_msg *msg; 1790 struct timespec ts, ts2; 1791 struct timeval tv; 1792 int error; 1793 1794 if (msg_len < mq->mq_msgsize) 1795 return (EMSGSIZE); 1796 1797 /* O_NONBLOCK case */ 1798 if (!waitok) { 1799 error = _mqueue_recv(mq, &msg, -1); 1800 if (error) 1801 return (error); 1802 goto received; 1803 } 1804 1805 /* we allow a null timeout (wait forever). */ 1806 if (abs_timeout == NULL) { 1807 error = _mqueue_recv(mq, &msg, 0); 1808 if (error) 1809 return (error); 1810 goto received; 1811 } 1812 1813 /* try to get a message before checking time */ 1814 error = _mqueue_recv(mq, &msg, -1); 1815 if (error == 0) 1816 goto received; 1817 1818 if (error != EAGAIN) 1819 return (error); 1820 1821 if (abs_timeout->tv_nsec >= 1000000000 || abs_timeout->tv_nsec < 0) { 1822 error = EINVAL; 1823 return (error); 1824 } 1825 1826 for (;;) { 1827 ts2 = *abs_timeout; 1828 getnanotime(&ts); 1829 timespecsub(&ts2, &ts); 1830 if (ts2.tv_sec < 0 || (ts2.tv_sec == 0 && ts2.tv_nsec <= 0)) { 1831 error = ETIMEDOUT; 1832 return (error); 1833 } 1834 TIMESPEC_TO_TIMEVAL(&tv, &ts2); 1835 error = _mqueue_recv(mq, &msg, tvtohz(&tv)); 1836 if (error == 0) 1837 break; 1838 if (error != ETIMEDOUT) 1839 return (error); 1840 } 1841 1842received: 1843 error = mqueue_savemsg(msg, msg_ptr, msg_prio); 1844 if (error == 0) { 1845 curthread->td_retval[0] = msg->msg_size; 1846 curthread->td_retval[1] = 0; 1847 } 1848 mqueue_freemsg(msg); 1849 return (error); 1850} 1851 1852/* 1853 * Common routine to receive a message 1854 */ 1855static int 1856_mqueue_recv(struct mqueue *mq, struct mqueue_msg **msg, int timo) 1857{ 1858 int error = 0; 1859 1860 mtx_lock(&mq->mq_mutex); 1861 while ((*msg = TAILQ_FIRST(&mq->mq_msgq)) == NULL && error == 0) { 1862 if (timo < 0) { 1863 mtx_unlock(&mq->mq_mutex); 1864 return (EAGAIN); 1865 } 1866 mq->mq_receivers++; 1867 error = msleep(&mq->mq_receivers, &mq->mq_mutex, 1868 PCATCH, "mqrecv", timo); 1869 mq->mq_receivers--; 1870 if (error == EAGAIN) 1871 error = ETIMEDOUT; 1872 } 1873 if (*msg != NULL) { 1874 error = 0; 1875 TAILQ_REMOVE(&mq->mq_msgq, *msg, msg_link); 1876 mq->mq_curmsgs--; 1877 mq->mq_totalbytes -= (*msg)->msg_size; 1878 if (mq->mq_senders) 1879 wakeup_one(&mq->mq_senders); 1880 if (mq->mq_flags & MQ_WSEL) { 1881 mq->mq_flags &= ~MQ_WSEL; 1882 selwakeup(&mq->mq_wsel); 1883 } 1884 KNOTE_LOCKED(&mq->mq_wsel.si_note, 0); 1885 } 1886 if (mq->mq_notifier != NULL && mq->mq_receivers == 0 && 1887 !TAILQ_EMPTY(&mq->mq_msgq)) { 1888 mqueue_send_notification(mq); 1889 } 1890 mtx_unlock(&mq->mq_mutex); 1891 return (error); 1892} 1893 1894static __inline struct mqueue_notifier * 1895notifier_alloc(void) 1896{ 1897 return (uma_zalloc(mqnoti_zone, M_WAITOK | M_ZERO)); 1898} 1899 1900static __inline void 1901notifier_free(struct mqueue_notifier *p) 1902{ 1903 uma_zfree(mqnoti_zone, p); 1904} 1905 1906static struct mqueue_notifier * 1907notifier_search(struct proc *p, int fd) 1908{ 1909 struct mqueue_notifier *nt; 1910 1911 LIST_FOREACH(nt, &p->p_mqnotifier, nt_link) { 1912 if (nt->nt_ksi.ksi_mqd == fd) 1913 break; 1914 } 1915 return (nt); 1916} 1917 1918static __inline void 1919notifier_insert(struct proc *p, struct mqueue_notifier *nt) 1920{ 1921 LIST_INSERT_HEAD(&p->p_mqnotifier, nt, nt_link); 1922} 1923 1924static __inline void 1925notifier_delete(struct proc *p, struct mqueue_notifier *nt) 1926{ 1927 LIST_REMOVE(nt, nt_link); 1928 notifier_free(nt); 1929} 1930 1931static void 1932notifier_remove(struct proc *p, struct mqueue *mq, int fd) 1933{ 1934 struct mqueue_notifier *nt; 1935 1936 mtx_assert(&mq->mq_mutex, MA_OWNED); 1937 PROC_LOCK(p); 1938 nt = notifier_search(p, fd); 1939 if (nt != NULL) { 1940 if (mq->mq_notifier == nt) 1941 mq->mq_notifier = NULL; 1942 sigqueue_take(&nt->nt_ksi); 1943 notifier_delete(p, nt); 1944 } 1945 PROC_UNLOCK(p); 1946} 1947 1948static int 1949kern_kmq_open(struct thread *td, const char *upath, int flags, mode_t mode, 1950 const struct mq_attr *attr) 1951{ 1952 char path[MQFS_NAMELEN + 1]; 1953 struct mqfs_node *pn; 1954 struct filedesc *fdp; 1955 struct file *fp; 1956 struct mqueue *mq; 1957 int fd, error, len, cmode; 1958 1959 fdp = td->td_proc->p_fd; 1960 cmode = (((mode & ~fdp->fd_cmask) & ALLPERMS) & ~S_ISTXT); 1961 mq = NULL; 1962 if ((flags & O_CREAT) != 0 && attr != NULL) { 1963 if (attr->mq_maxmsg <= 0 || attr->mq_maxmsg > maxmsg) 1964 return (EINVAL); 1965 if (attr->mq_msgsize <= 0 || attr->mq_msgsize > maxmsgsize) 1966 return (EINVAL); 1967 } 1968 1969 error = copyinstr(upath, path, MQFS_NAMELEN + 1, NULL); 1970 if (error) 1971 return (error); 1972 1973 /* 1974 * The first character of name must be a slash (/) character 1975 * and the remaining characters of name cannot include any slash 1976 * characters. 1977 */ 1978 len = strlen(path); 1979 if (len < 2 || path[0] != '/' || strchr(path + 1, '/') != NULL) 1980 return (EINVAL); 1981 1982 error = falloc(td, &fp, &fd, O_CLOEXEC); 1983 if (error) 1984 return (error); 1985 1986 sx_xlock(&mqfs_data.mi_lock); 1987 pn = mqfs_search(mqfs_data.mi_root, path + 1, len - 1); 1988 if (pn == NULL) { 1989 if (!(flags & O_CREAT)) { 1990 error = ENOENT; 1991 } else { 1992 mq = mqueue_alloc(attr); 1993 if (mq == NULL) { 1994 error = ENFILE; 1995 } else { 1996 pn = mqfs_create_file(mqfs_data.mi_root, 1997 path + 1, len - 1, td->td_ucred, 1998 cmode); 1999 if (pn == NULL) { 2000 error = ENOSPC; 2001 mqueue_free(mq); 2002 } 2003 } 2004 } 2005 2006 if (error == 0) { 2007 pn->mn_data = mq; 2008 } 2009 } else { 2010 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) { 2011 error = EEXIST; 2012 } else { 2013 accmode_t accmode = 0; 2014 2015 if (flags & FREAD) 2016 accmode |= VREAD; 2017 if (flags & FWRITE) 2018 accmode |= VWRITE; 2019 error = vaccess(VREG, pn->mn_mode, pn->mn_uid, 2020 pn->mn_gid, accmode, td->td_ucred, NULL); 2021 } 2022 } 2023 2024 if (error) { 2025 sx_xunlock(&mqfs_data.mi_lock); 2026 fdclose(td, fp, fd); 2027 fdrop(fp, td); 2028 return (error); 2029 } 2030 2031 mqnode_addref(pn); 2032 sx_xunlock(&mqfs_data.mi_lock); 2033 2034 finit(fp, flags & (FREAD | FWRITE | O_NONBLOCK), DTYPE_MQUEUE, pn, 2035 &mqueueops); 2036 2037 td->td_retval[0] = fd; 2038 fdrop(fp, td); 2039 return (0); 2040} 2041 2042/* 2043 * Syscall to open a message queue. 2044 */ 2045int 2046sys_kmq_open(struct thread *td, struct kmq_open_args *uap) 2047{ 2048 struct mq_attr attr; 2049 int flags, error; 2050 2051 if ((uap->flags & O_ACCMODE) == O_ACCMODE || uap->flags & O_EXEC) 2052 return (EINVAL); 2053 flags = FFLAGS(uap->flags); 2054 if ((flags & O_CREAT) != 0 && uap->attr != NULL) { 2055 error = copyin(uap->attr, &attr, sizeof(attr)); 2056 if (error) 2057 return (error); 2058 } 2059 return (kern_kmq_open(td, uap->path, flags, uap->mode, 2060 uap->attr != NULL ? &attr : NULL)); 2061} 2062 2063/* 2064 * Syscall to unlink a message queue. 2065 */ 2066int 2067sys_kmq_unlink(struct thread *td, struct kmq_unlink_args *uap) 2068{ 2069 char path[MQFS_NAMELEN+1]; 2070 struct mqfs_node *pn; 2071 int error, len; 2072 2073 error = copyinstr(uap->path, path, MQFS_NAMELEN + 1, NULL); 2074 if (error) 2075 return (error); 2076 2077 len = strlen(path); 2078 if (len < 2 || path[0] != '/' || strchr(path + 1, '/') != NULL) 2079 return (EINVAL); 2080 2081 sx_xlock(&mqfs_data.mi_lock); 2082 pn = mqfs_search(mqfs_data.mi_root, path + 1, len - 1); 2083 if (pn != NULL) 2084 error = do_unlink(pn, td->td_ucred); 2085 else 2086 error = ENOENT; 2087 sx_xunlock(&mqfs_data.mi_lock); 2088 return (error); 2089} 2090 2091typedef int (*_fgetf)(struct thread *, int, cap_rights_t *, struct file **); 2092 2093/* 2094 * Get message queue by giving file slot 2095 */ 2096static int 2097_getmq(struct thread *td, int fd, cap_rights_t *rightsp, _fgetf func, 2098 struct file **fpp, struct mqfs_node **ppn, struct mqueue **pmq) 2099{ 2100 struct mqfs_node *pn; 2101 int error; 2102 2103 error = func(td, fd, rightsp, fpp); 2104 if (error) 2105 return (error); 2106 if (&mqueueops != (*fpp)->f_ops) { 2107 fdrop(*fpp, td); 2108 return (EBADF); 2109 } 2110 pn = (*fpp)->f_data; 2111 if (ppn) 2112 *ppn = pn; 2113 if (pmq) 2114 *pmq = pn->mn_data; 2115 return (0); 2116} 2117 2118static __inline int 2119getmq(struct thread *td, int fd, struct file **fpp, struct mqfs_node **ppn, 2120 struct mqueue **pmq) 2121{ 2122 cap_rights_t rights; 2123 2124 return _getmq(td, fd, cap_rights_init(&rights, CAP_EVENT), fget, 2125 fpp, ppn, pmq); 2126} 2127 2128static __inline int 2129getmq_read(struct thread *td, int fd, struct file **fpp, 2130 struct mqfs_node **ppn, struct mqueue **pmq) 2131{ 2132 cap_rights_t rights; 2133 2134 return _getmq(td, fd, cap_rights_init(&rights, CAP_READ), fget_read, 2135 fpp, ppn, pmq); 2136} 2137 2138static __inline int 2139getmq_write(struct thread *td, int fd, struct file **fpp, 2140 struct mqfs_node **ppn, struct mqueue **pmq) 2141{ 2142 cap_rights_t rights; 2143 2144 return _getmq(td, fd, cap_rights_init(&rights, CAP_WRITE), fget_write, 2145 fpp, ppn, pmq); 2146} 2147 2148static int 2149kern_kmq_setattr(struct thread *td, int mqd, const struct mq_attr *attr, 2150 struct mq_attr *oattr) 2151{ 2152 struct mqueue *mq; 2153 struct file *fp; 2154 u_int oflag, flag; 2155 int error; 2156 2157 if (attr != NULL && (attr->mq_flags & ~O_NONBLOCK) != 0) 2158 return (EINVAL); 2159 error = getmq(td, mqd, &fp, NULL, &mq); 2160 if (error) 2161 return (error); 2162 oattr->mq_maxmsg = mq->mq_maxmsg; 2163 oattr->mq_msgsize = mq->mq_msgsize; 2164 oattr->mq_curmsgs = mq->mq_curmsgs; 2165 if (attr != NULL) { 2166 do { 2167 oflag = flag = fp->f_flag; 2168 flag &= ~O_NONBLOCK; 2169 flag |= (attr->mq_flags & O_NONBLOCK); 2170 } while (atomic_cmpset_int(&fp->f_flag, oflag, flag) == 0); 2171 } else 2172 oflag = fp->f_flag; 2173 oattr->mq_flags = (O_NONBLOCK & oflag); 2174 fdrop(fp, td); 2175 return (error); 2176} 2177 2178int 2179sys_kmq_setattr(struct thread *td, struct kmq_setattr_args *uap) 2180{ 2181 struct mq_attr attr, oattr; 2182 int error; 2183 2184 if (uap->attr != NULL) { 2185 error = copyin(uap->attr, &attr, sizeof(attr)); 2186 if (error != 0) 2187 return (error); 2188 } 2189 error = kern_kmq_setattr(td, uap->mqd, uap->attr != NULL ? &attr : NULL, 2190 &oattr); 2191 if (error == 0 && uap->oattr != NULL) { 2192 bzero(oattr.__reserved, sizeof(oattr.__reserved)); 2193 error = copyout(&oattr, uap->oattr, sizeof(oattr)); 2194 } 2195 return (error); 2196} 2197 2198int 2199sys_kmq_timedreceive(struct thread *td, struct kmq_timedreceive_args *uap) 2200{ 2201 struct mqueue *mq; 2202 struct file *fp; 2203 struct timespec *abs_timeout, ets; 2204 int error; 2205 int waitok; 2206 2207 error = getmq_read(td, uap->mqd, &fp, NULL, &mq); 2208 if (error) 2209 return (error); 2210 if (uap->abs_timeout != NULL) { 2211 error = copyin(uap->abs_timeout, &ets, sizeof(ets)); 2212 if (error != 0) 2213 return (error); 2214 abs_timeout = &ets; 2215 } else 2216 abs_timeout = NULL; 2217 waitok = !(fp->f_flag & O_NONBLOCK); 2218 error = mqueue_receive(mq, uap->msg_ptr, uap->msg_len, 2219 uap->msg_prio, waitok, abs_timeout); 2220 fdrop(fp, td); 2221 return (error); 2222} 2223 2224int 2225sys_kmq_timedsend(struct thread *td, struct kmq_timedsend_args *uap) 2226{ 2227 struct mqueue *mq; 2228 struct file *fp; 2229 struct timespec *abs_timeout, ets; 2230 int error, waitok; 2231 2232 error = getmq_write(td, uap->mqd, &fp, NULL, &mq); 2233 if (error) 2234 return (error); 2235 if (uap->abs_timeout != NULL) { 2236 error = copyin(uap->abs_timeout, &ets, sizeof(ets)); 2237 if (error != 0) 2238 return (error); 2239 abs_timeout = &ets; 2240 } else 2241 abs_timeout = NULL; 2242 waitok = !(fp->f_flag & O_NONBLOCK); 2243 error = mqueue_send(mq, uap->msg_ptr, uap->msg_len, 2244 uap->msg_prio, waitok, abs_timeout); 2245 fdrop(fp, td); 2246 return (error); 2247} 2248 2249static int 2250kern_kmq_notify(struct thread *td, int mqd, struct sigevent *sigev) 2251{ 2252#ifdef CAPABILITIES 2253 cap_rights_t rights; 2254#endif 2255 struct filedesc *fdp; 2256 struct proc *p; 2257 struct mqueue *mq; 2258 struct file *fp, *fp2; 2259 struct mqueue_notifier *nt, *newnt = NULL; 2260 int error; 2261 2262 if (sigev != NULL) { 2263 if (sigev->sigev_notify != SIGEV_SIGNAL && 2264 sigev->sigev_notify != SIGEV_THREAD_ID && 2265 sigev->sigev_notify != SIGEV_NONE) 2266 return (EINVAL); 2267 if ((sigev->sigev_notify == SIGEV_SIGNAL || 2268 sigev->sigev_notify == SIGEV_THREAD_ID) && 2269 !_SIG_VALID(sigev->sigev_signo)) 2270 return (EINVAL); 2271 } 2272 p = td->td_proc; 2273 fdp = td->td_proc->p_fd; 2274 error = getmq(td, mqd, &fp, NULL, &mq); 2275 if (error) 2276 return (error); 2277again: 2278 FILEDESC_SLOCK(fdp); 2279 fp2 = fget_locked(fdp, mqd); 2280 if (fp2 == NULL) { 2281 FILEDESC_SUNLOCK(fdp); 2282 error = EBADF; 2283 goto out; 2284 } 2285#ifdef CAPABILITIES 2286 error = cap_check(cap_rights(fdp, mqd), 2287 cap_rights_init(&rights, CAP_EVENT)); 2288 if (error) { 2289 FILEDESC_SUNLOCK(fdp); 2290 goto out; 2291 } 2292#endif 2293 if (fp2 != fp) { 2294 FILEDESC_SUNLOCK(fdp); 2295 error = EBADF; 2296 goto out; 2297 } 2298 mtx_lock(&mq->mq_mutex); 2299 FILEDESC_SUNLOCK(fdp); 2300 if (sigev != NULL) { 2301 if (mq->mq_notifier != NULL) { 2302 error = EBUSY; 2303 } else { 2304 PROC_LOCK(p); 2305 nt = notifier_search(p, mqd); 2306 if (nt == NULL) { 2307 if (newnt == NULL) { 2308 PROC_UNLOCK(p); 2309 mtx_unlock(&mq->mq_mutex); 2310 newnt = notifier_alloc(); 2311 goto again; 2312 } 2313 } 2314 2315 if (nt != NULL) { 2316 sigqueue_take(&nt->nt_ksi); 2317 if (newnt != NULL) { 2318 notifier_free(newnt); 2319 newnt = NULL; 2320 } 2321 } else { 2322 nt = newnt; 2323 newnt = NULL; 2324 ksiginfo_init(&nt->nt_ksi); 2325 nt->nt_ksi.ksi_flags |= KSI_INS | KSI_EXT; 2326 nt->nt_ksi.ksi_code = SI_MESGQ; 2327 nt->nt_proc = p; 2328 nt->nt_ksi.ksi_mqd = mqd; 2329 notifier_insert(p, nt); 2330 } 2331 nt->nt_sigev = *sigev; 2332 mq->mq_notifier = nt; 2333 PROC_UNLOCK(p); 2334 /* 2335 * if there is no receivers and message queue 2336 * is not empty, we should send notification 2337 * as soon as possible. 2338 */ 2339 if (mq->mq_receivers == 0 && 2340 !TAILQ_EMPTY(&mq->mq_msgq)) 2341 mqueue_send_notification(mq); 2342 } 2343 } else { 2344 notifier_remove(p, mq, mqd); 2345 } 2346 mtx_unlock(&mq->mq_mutex); 2347 2348out: 2349 fdrop(fp, td); 2350 if (newnt != NULL) 2351 notifier_free(newnt); 2352 return (error); 2353} 2354 2355int 2356sys_kmq_notify(struct thread *td, struct kmq_notify_args *uap) 2357{ 2358 struct sigevent ev, *evp; 2359 int error; 2360 2361 if (uap->sigev == NULL) { 2362 evp = NULL; 2363 } else { 2364 error = copyin(uap->sigev, &ev, sizeof(ev)); 2365 if (error != 0) 2366 return (error); 2367 evp = &ev; 2368 } 2369 return (kern_kmq_notify(td, uap->mqd, evp)); 2370} 2371 2372static void 2373mqueue_fdclose(struct thread *td, int fd, struct file *fp) 2374{ 2375 struct filedesc *fdp; 2376 struct mqueue *mq; 2377 2378 fdp = td->td_proc->p_fd; 2379 FILEDESC_LOCK_ASSERT(fdp); 2380 2381 if (fp->f_ops == &mqueueops) { 2382 mq = FPTOMQ(fp); 2383 mtx_lock(&mq->mq_mutex); 2384 notifier_remove(td->td_proc, mq, fd); 2385 2386 /* have to wakeup thread in same process */ 2387 if (mq->mq_flags & MQ_RSEL) { 2388 mq->mq_flags &= ~MQ_RSEL; 2389 selwakeup(&mq->mq_rsel); 2390 } 2391 if (mq->mq_flags & MQ_WSEL) { 2392 mq->mq_flags &= ~MQ_WSEL; 2393 selwakeup(&mq->mq_wsel); 2394 } 2395 mtx_unlock(&mq->mq_mutex); 2396 } 2397} 2398 2399static void 2400mq_proc_exit(void *arg __unused, struct proc *p) 2401{ 2402 struct filedesc *fdp; 2403 struct file *fp; 2404 struct mqueue *mq; 2405 int i; 2406 2407 fdp = p->p_fd; 2408 FILEDESC_SLOCK(fdp); 2409 for (i = 0; i < fdp->fd_nfiles; ++i) { 2410 fp = fget_locked(fdp, i); 2411 if (fp != NULL && fp->f_ops == &mqueueops) { 2412 mq = FPTOMQ(fp); 2413 mtx_lock(&mq->mq_mutex); 2414 notifier_remove(p, FPTOMQ(fp), i); 2415 mtx_unlock(&mq->mq_mutex); 2416 } 2417 } 2418 FILEDESC_SUNLOCK(fdp); 2419 KASSERT(LIST_EMPTY(&p->p_mqnotifier), ("mq notifiers left")); 2420} 2421 2422static int 2423mqf_read(struct file *fp, struct uio *uio, struct ucred *active_cred, 2424 int flags, struct thread *td) 2425{ 2426 return (EOPNOTSUPP); 2427} 2428 2429static int 2430mqf_write(struct file *fp, struct uio *uio, struct ucred *active_cred, 2431 int flags, struct thread *td) 2432{ 2433 return (EOPNOTSUPP); 2434} 2435 2436static int 2437mqf_truncate(struct file *fp, off_t length, struct ucred *active_cred, 2438 struct thread *td) 2439{ 2440 2441 return (EINVAL); 2442} 2443 2444static int 2445mqf_ioctl(struct file *fp, u_long cmd, void *data, 2446 struct ucred *active_cred, struct thread *td) 2447{ 2448 return (ENOTTY); 2449} 2450 2451static int 2452mqf_poll(struct file *fp, int events, struct ucred *active_cred, 2453 struct thread *td) 2454{ 2455 struct mqueue *mq = FPTOMQ(fp); 2456 int revents = 0; 2457 2458 mtx_lock(&mq->mq_mutex); 2459 if (events & (POLLIN | POLLRDNORM)) { 2460 if (mq->mq_curmsgs) { 2461 revents |= events & (POLLIN | POLLRDNORM); 2462 } else { 2463 mq->mq_flags |= MQ_RSEL; 2464 selrecord(td, &mq->mq_rsel); 2465 } 2466 } 2467 if (events & POLLOUT) { 2468 if (mq->mq_curmsgs < mq->mq_maxmsg) 2469 revents |= POLLOUT; 2470 else { 2471 mq->mq_flags |= MQ_WSEL; 2472 selrecord(td, &mq->mq_wsel); 2473 } 2474 } 2475 mtx_unlock(&mq->mq_mutex); 2476 return (revents); 2477} 2478 2479static int 2480mqf_close(struct file *fp, struct thread *td) 2481{ 2482 struct mqfs_node *pn; 2483 2484 fp->f_ops = &badfileops; 2485 pn = fp->f_data; 2486 fp->f_data = NULL; 2487 sx_xlock(&mqfs_data.mi_lock); 2488 mqnode_release(pn); 2489 sx_xunlock(&mqfs_data.mi_lock); 2490 return (0); 2491} 2492 2493static int 2494mqf_stat(struct file *fp, struct stat *st, struct ucred *active_cred, 2495 struct thread *td) 2496{ 2497 struct mqfs_node *pn = fp->f_data; 2498 2499 bzero(st, sizeof *st); 2500 sx_xlock(&mqfs_data.mi_lock); 2501 st->st_atim = pn->mn_atime; 2502 st->st_mtim = pn->mn_mtime; 2503 st->st_ctim = pn->mn_ctime; 2504 st->st_birthtim = pn->mn_birth; 2505 st->st_uid = pn->mn_uid; 2506 st->st_gid = pn->mn_gid; 2507 st->st_mode = S_IFIFO | pn->mn_mode; 2508 sx_xunlock(&mqfs_data.mi_lock); 2509 return (0); 2510} 2511 2512static int 2513mqf_chmod(struct file *fp, mode_t mode, struct ucred *active_cred, 2514 struct thread *td) 2515{ 2516 struct mqfs_node *pn; 2517 int error; 2518 2519 error = 0; 2520 pn = fp->f_data; 2521 sx_xlock(&mqfs_data.mi_lock); 2522 error = vaccess(VREG, pn->mn_mode, pn->mn_uid, pn->mn_gid, VADMIN, 2523 active_cred, NULL); 2524 if (error != 0) 2525 goto out; 2526 pn->mn_mode = mode & ACCESSPERMS; 2527out: 2528 sx_xunlock(&mqfs_data.mi_lock); 2529 return (error); 2530} 2531 2532static int 2533mqf_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred, 2534 struct thread *td) 2535{ 2536 struct mqfs_node *pn; 2537 int error; 2538 2539 error = 0; 2540 pn = fp->f_data; 2541 sx_xlock(&mqfs_data.mi_lock); 2542 if (uid == (uid_t)-1) 2543 uid = pn->mn_uid; 2544 if (gid == (gid_t)-1) 2545 gid = pn->mn_gid; 2546 if (((uid != pn->mn_uid && uid != active_cred->cr_uid) || 2547 (gid != pn->mn_gid && !groupmember(gid, active_cred))) && 2548 (error = priv_check_cred(active_cred, PRIV_VFS_CHOWN, 0))) 2549 goto out; 2550 pn->mn_uid = uid; 2551 pn->mn_gid = gid; 2552out: 2553 sx_xunlock(&mqfs_data.mi_lock); 2554 return (error); 2555} 2556 2557static int 2558mqf_kqfilter(struct file *fp, struct knote *kn) 2559{ 2560 struct mqueue *mq = FPTOMQ(fp); 2561 int error = 0; 2562 2563 if (kn->kn_filter == EVFILT_READ) { 2564 kn->kn_fop = &mq_rfiltops; 2565 knlist_add(&mq->mq_rsel.si_note, kn, 0); 2566 } else if (kn->kn_filter == EVFILT_WRITE) { 2567 kn->kn_fop = &mq_wfiltops; 2568 knlist_add(&mq->mq_wsel.si_note, kn, 0); 2569 } else 2570 error = EINVAL; 2571 return (error); 2572} 2573 2574static void 2575filt_mqdetach(struct knote *kn) 2576{ 2577 struct mqueue *mq = FPTOMQ(kn->kn_fp); 2578 2579 if (kn->kn_filter == EVFILT_READ) 2580 knlist_remove(&mq->mq_rsel.si_note, kn, 0); 2581 else if (kn->kn_filter == EVFILT_WRITE) 2582 knlist_remove(&mq->mq_wsel.si_note, kn, 0); 2583 else 2584 panic("filt_mqdetach"); 2585} 2586 2587static int 2588filt_mqread(struct knote *kn, long hint) 2589{ 2590 struct mqueue *mq = FPTOMQ(kn->kn_fp); 2591 2592 mtx_assert(&mq->mq_mutex, MA_OWNED); 2593 return (mq->mq_curmsgs != 0); 2594} 2595 2596static int 2597filt_mqwrite(struct knote *kn, long hint) 2598{ 2599 struct mqueue *mq = FPTOMQ(kn->kn_fp); 2600 2601 mtx_assert(&mq->mq_mutex, MA_OWNED); 2602 return (mq->mq_curmsgs < mq->mq_maxmsg); 2603} 2604 2605static struct fileops mqueueops = { 2606 .fo_read = mqf_read, 2607 .fo_write = mqf_write, 2608 .fo_truncate = mqf_truncate, 2609 .fo_ioctl = mqf_ioctl, 2610 .fo_poll = mqf_poll, 2611 .fo_kqfilter = mqf_kqfilter, 2612 .fo_stat = mqf_stat, 2613 .fo_chmod = mqf_chmod, 2614 .fo_chown = mqf_chown, 2615 .fo_close = mqf_close, 2616 .fo_sendfile = invfo_sendfile, 2617}; 2618 2619static struct vop_vector mqfs_vnodeops = { 2620 .vop_default = &default_vnodeops, 2621 .vop_access = mqfs_access, 2622 .vop_cachedlookup = mqfs_lookup, 2623 .vop_lookup = vfs_cache_lookup, 2624 .vop_reclaim = mqfs_reclaim, 2625 .vop_create = mqfs_create, 2626 .vop_remove = mqfs_remove, 2627 .vop_inactive = mqfs_inactive, 2628 .vop_open = mqfs_open, 2629 .vop_close = mqfs_close, 2630 .vop_getattr = mqfs_getattr, 2631 .vop_setattr = mqfs_setattr, 2632 .vop_read = mqfs_read, 2633 .vop_write = VOP_EOPNOTSUPP, 2634 .vop_readdir = mqfs_readdir, 2635 .vop_mkdir = VOP_EOPNOTSUPP, 2636 .vop_rmdir = VOP_EOPNOTSUPP 2637}; 2638 2639static struct vfsops mqfs_vfsops = { 2640 .vfs_init = mqfs_init, 2641 .vfs_uninit = mqfs_uninit, 2642 .vfs_mount = mqfs_mount, 2643 .vfs_unmount = mqfs_unmount, 2644 .vfs_root = mqfs_root, 2645 .vfs_statfs = mqfs_statfs, 2646}; 2647 2648static struct vfsconf mqueuefs_vfsconf = { 2649 .vfc_version = VFS_VERSION, 2650 .vfc_name = "mqueuefs", 2651 .vfc_vfsops = &mqfs_vfsops, 2652 .vfc_typenum = -1, 2653 .vfc_flags = VFCF_SYNTHETIC 2654}; 2655 2656static struct syscall_helper_data mq_syscalls[] = { 2657 SYSCALL_INIT_HELPER(kmq_open), 2658 SYSCALL_INIT_HELPER(kmq_setattr), 2659 SYSCALL_INIT_HELPER(kmq_timedsend), 2660 SYSCALL_INIT_HELPER(kmq_timedreceive), 2661 SYSCALL_INIT_HELPER(kmq_notify), 2662 SYSCALL_INIT_HELPER(kmq_unlink), 2663 SYSCALL_INIT_LAST 2664}; 2665 2666#ifdef COMPAT_FREEBSD32 2667#include <compat/freebsd32/freebsd32.h> 2668#include <compat/freebsd32/freebsd32_proto.h> 2669#include <compat/freebsd32/freebsd32_signal.h> 2670#include <compat/freebsd32/freebsd32_syscall.h> 2671#include <compat/freebsd32/freebsd32_util.h> 2672 2673static void 2674mq_attr_from32(const struct mq_attr32 *from, struct mq_attr *to) 2675{ 2676 2677 to->mq_flags = from->mq_flags; 2678 to->mq_maxmsg = from->mq_maxmsg; 2679 to->mq_msgsize = from->mq_msgsize; 2680 to->mq_curmsgs = from->mq_curmsgs; 2681} 2682 2683static void 2684mq_attr_to32(const struct mq_attr *from, struct mq_attr32 *to) 2685{ 2686 2687 to->mq_flags = from->mq_flags; 2688 to->mq_maxmsg = from->mq_maxmsg; 2689 to->mq_msgsize = from->mq_msgsize; 2690 to->mq_curmsgs = from->mq_curmsgs; 2691} 2692 2693int 2694freebsd32_kmq_open(struct thread *td, struct freebsd32_kmq_open_args *uap) 2695{ 2696 struct mq_attr attr; 2697 struct mq_attr32 attr32; 2698 int flags, error; 2699 2700 if ((uap->flags & O_ACCMODE) == O_ACCMODE || uap->flags & O_EXEC) 2701 return (EINVAL); 2702 flags = FFLAGS(uap->flags); 2703 if ((flags & O_CREAT) != 0 && uap->attr != NULL) { 2704 error = copyin(uap->attr, &attr32, sizeof(attr32)); 2705 if (error) 2706 return (error); 2707 mq_attr_from32(&attr32, &attr); 2708 } 2709 return (kern_kmq_open(td, uap->path, flags, uap->mode, 2710 uap->attr != NULL ? &attr : NULL)); 2711} 2712 2713int 2714freebsd32_kmq_setattr(struct thread *td, struct freebsd32_kmq_setattr_args *uap) 2715{ 2716 struct mq_attr attr, oattr; 2717 struct mq_attr32 attr32, oattr32; 2718 int error; 2719 2720 if (uap->attr != NULL) { 2721 error = copyin(uap->attr, &attr32, sizeof(attr32)); 2722 if (error != 0) 2723 return (error); 2724 mq_attr_from32(&attr32, &attr); 2725 } 2726 error = kern_kmq_setattr(td, uap->mqd, uap->attr != NULL ? &attr : NULL, 2727 &oattr); 2728 if (error == 0 && uap->oattr != NULL) { 2729 mq_attr_to32(&oattr, &oattr32); 2730 bzero(oattr32.__reserved, sizeof(oattr32.__reserved)); 2731 error = copyout(&oattr32, uap->oattr, sizeof(oattr32)); 2732 } 2733 return (error); 2734} 2735 2736int 2737freebsd32_kmq_timedsend(struct thread *td, 2738 struct freebsd32_kmq_timedsend_args *uap) 2739{ 2740 struct mqueue *mq; 2741 struct file *fp; 2742 struct timespec32 ets32; 2743 struct timespec *abs_timeout, ets; 2744 int error; 2745 int waitok; 2746 2747 error = getmq_write(td, uap->mqd, &fp, NULL, &mq); 2748 if (error) 2749 return (error); 2750 if (uap->abs_timeout != NULL) { 2751 error = copyin(uap->abs_timeout, &ets32, sizeof(ets32)); 2752 if (error != 0) 2753 return (error); 2754 CP(ets32, ets, tv_sec); 2755 CP(ets32, ets, tv_nsec); 2756 abs_timeout = &ets; 2757 } else 2758 abs_timeout = NULL; 2759 waitok = !(fp->f_flag & O_NONBLOCK); 2760 error = mqueue_send(mq, uap->msg_ptr, uap->msg_len, 2761 uap->msg_prio, waitok, abs_timeout); 2762 fdrop(fp, td); 2763 return (error); 2764} 2765 2766int 2767freebsd32_kmq_timedreceive(struct thread *td, 2768 struct freebsd32_kmq_timedreceive_args *uap) 2769{ 2770 struct mqueue *mq; 2771 struct file *fp; 2772 struct timespec32 ets32; 2773 struct timespec *abs_timeout, ets; 2774 int error, waitok; 2775 2776 error = getmq_read(td, uap->mqd, &fp, NULL, &mq); 2777 if (error) 2778 return (error); 2779 if (uap->abs_timeout != NULL) { 2780 error = copyin(uap->abs_timeout, &ets32, sizeof(ets32)); 2781 if (error != 0) 2782 return (error); 2783 CP(ets32, ets, tv_sec); 2784 CP(ets32, ets, tv_nsec); 2785 abs_timeout = &ets; 2786 } else 2787 abs_timeout = NULL; 2788 waitok = !(fp->f_flag & O_NONBLOCK); 2789 error = mqueue_receive(mq, uap->msg_ptr, uap->msg_len, 2790 uap->msg_prio, waitok, abs_timeout); 2791 fdrop(fp, td); 2792 return (error); 2793} 2794 2795int 2796freebsd32_kmq_notify(struct thread *td, struct freebsd32_kmq_notify_args *uap) 2797{ 2798 struct sigevent ev, *evp; 2799 struct sigevent32 ev32; 2800 int error; 2801 2802 if (uap->sigev == NULL) { 2803 evp = NULL; 2804 } else { 2805 error = copyin(uap->sigev, &ev32, sizeof(ev32)); 2806 if (error != 0) 2807 return (error); 2808 error = convert_sigevent32(&ev32, &ev); 2809 if (error != 0) 2810 return (error); 2811 evp = &ev; 2812 } 2813 return (kern_kmq_notify(td, uap->mqd, evp)); 2814} 2815 2816static struct syscall_helper_data mq32_syscalls[] = { 2817 SYSCALL32_INIT_HELPER(freebsd32_kmq_open), 2818 SYSCALL32_INIT_HELPER(freebsd32_kmq_setattr), 2819 SYSCALL32_INIT_HELPER(freebsd32_kmq_timedsend), 2820 SYSCALL32_INIT_HELPER(freebsd32_kmq_timedreceive), 2821 SYSCALL32_INIT_HELPER(freebsd32_kmq_notify), 2822 SYSCALL32_INIT_HELPER_COMPAT(kmq_unlink), 2823 SYSCALL_INIT_LAST 2824}; 2825#endif 2826 2827static int 2828mqinit(void) 2829{ 2830 int error; 2831 2832 error = syscall_helper_register(mq_syscalls); 2833 if (error != 0) 2834 return (error); 2835#ifdef COMPAT_FREEBSD32 2836 error = syscall32_helper_register(mq32_syscalls); 2837 if (error != 0) 2838 return (error); 2839#endif 2840 return (0); 2841} 2842 2843static int 2844mqunload(void) 2845{ 2846 2847#ifdef COMPAT_FREEBSD32 2848 syscall32_helper_unregister(mq32_syscalls); 2849#endif 2850 syscall_helper_unregister(mq_syscalls); 2851 return (0); 2852} 2853 2854static int 2855mq_modload(struct module *module, int cmd, void *arg) 2856{ 2857 int error = 0; 2858 2859 error = vfs_modevent(module, cmd, arg); 2860 if (error != 0) 2861 return (error); 2862 2863 switch (cmd) { 2864 case MOD_LOAD: 2865 error = mqinit(); 2866 if (error != 0) 2867 mqunload(); 2868 break; 2869 case MOD_UNLOAD: 2870 error = mqunload(); 2871 break; 2872 default: 2873 break; 2874 } 2875 return (error); 2876} 2877 2878static moduledata_t mqueuefs_mod = { 2879 "mqueuefs", 2880 mq_modload, 2881 &mqueuefs_vfsconf 2882}; 2883DECLARE_MODULE(mqueuefs, mqueuefs_mod, SI_SUB_VFS, SI_ORDER_MIDDLE); 2884MODULE_VERSION(mqueuefs, 1); 2885