1152825Sdavidxu/*- 2152825Sdavidxu * Copyright (c) 2005 David Xu <davidxu@freebsd.org> 3152825Sdavidxu * All rights reserved. 4152825Sdavidxu * 5152825Sdavidxu * Redistribution and use in source and binary forms, with or without 6152825Sdavidxu * modification, are permitted provided that the following conditions 7152825Sdavidxu * are met: 8152825Sdavidxu * 1. Redistributions of source code must retain the above copyright 9152825Sdavidxu * notice, this list of conditions and the following disclaimer. 10152825Sdavidxu * 2. Redistributions in binary form must reproduce the above copyright 11152825Sdavidxu * notice, this list of conditions and the following disclaimer in the 12152825Sdavidxu * documentation and/or other materials provided with the distribution. 13152825Sdavidxu * 14152825Sdavidxu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15152825Sdavidxu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16152825Sdavidxu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17152825Sdavidxu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18152825Sdavidxu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19152825Sdavidxu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20152825Sdavidxu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21152825Sdavidxu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22152825Sdavidxu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23152825Sdavidxu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24152825Sdavidxu * SUCH DAMAGE. 25152825Sdavidxu * 26152825Sdavidxu */ 27152825Sdavidxu 28152825Sdavidxu/* 29152825Sdavidxu * POSIX message queue implementation. 30152825Sdavidxu * 31152825Sdavidxu * 1) A mqueue filesystem can be mounted, each message queue appears 32152825Sdavidxu * in mounted directory, user can change queue's permission and 33152825Sdavidxu * ownership, or remove a queue. Manually creating a file in the 34152825Sdavidxu * directory causes a message queue to be created in the kernel with 35152825Sdavidxu * default message queue attributes applied and same name used, this 36152825Sdavidxu * method is not advocated since mq_open syscall allows user to specify 37152825Sdavidxu * different attributes. Also the file system can be mounted multiple 38152825Sdavidxu * times at different mount points but shows same contents. 39152825Sdavidxu * 40152825Sdavidxu * 2) Standard POSIX message queue API. The syscalls do not use vfs layer, 41152825Sdavidxu * but directly operate on internal data structure, this allows user to 42152825Sdavidxu * use the IPC facility without having to mount mqueue file system. 43152825Sdavidxu */ 44152825Sdavidxu 45152825Sdavidxu#include <sys/cdefs.h> 46152825Sdavidxu__FBSDID("$FreeBSD: releng/11.0/sys/kern/uipc_mqueue.c 298567 2016-04-25 04:36:54Z jamie $"); 47152825Sdavidxu 48247602Spjd#include "opt_capsicum.h" 49205325Skib#include "opt_compat.h" 50205325Skib 51152825Sdavidxu#include <sys/param.h> 52152825Sdavidxu#include <sys/kernel.h> 53152825Sdavidxu#include <sys/systm.h> 54152825Sdavidxu#include <sys/limits.h> 55297936Sjamie#include <sys/malloc.h> 56152825Sdavidxu#include <sys/buf.h> 57263233Srwatson#include <sys/capsicum.h> 58152825Sdavidxu#include <sys/dirent.h> 59152825Sdavidxu#include <sys/event.h> 60152948Sdavidxu#include <sys/eventhandler.h> 61152825Sdavidxu#include <sys/fcntl.h> 62153019Sdavidxu#include <sys/file.h> 63152825Sdavidxu#include <sys/filedesc.h> 64297936Sjamie#include <sys/jail.h> 65152825Sdavidxu#include <sys/lock.h> 66152825Sdavidxu#include <sys/module.h> 67152825Sdavidxu#include <sys/mount.h> 68152825Sdavidxu#include <sys/mqueue.h> 69152825Sdavidxu#include <sys/mutex.h> 70152825Sdavidxu#include <sys/namei.h> 71164184Strhodes#include <sys/posix4.h> 72152825Sdavidxu#include <sys/poll.h> 73164033Srwatson#include <sys/priv.h> 74152825Sdavidxu#include <sys/proc.h> 75152825Sdavidxu#include <sys/queue.h> 76152825Sdavidxu#include <sys/sysproto.h> 77152825Sdavidxu#include <sys/stat.h> 78152825Sdavidxu#include <sys/syscall.h> 79152825Sdavidxu#include <sys/syscallsubr.h> 80153019Sdavidxu#include <sys/sysent.h> 81152825Sdavidxu#include <sys/sx.h> 82152825Sdavidxu#include <sys/sysctl.h> 83152825Sdavidxu#include <sys/taskqueue.h> 84152825Sdavidxu#include <sys/unistd.h> 85271976Sjhb#include <sys/user.h> 86152825Sdavidxu#include <sys/vnode.h> 87152825Sdavidxu#include <machine/atomic.h> 88152825Sdavidxu 89219028SnetchildFEATURE(p1003_1b_mqueue, "POSIX P1003.1B message queues support"); 90219028Snetchild 91152825Sdavidxu/* 92152825Sdavidxu * Limits and constants 93152825Sdavidxu */ 94152825Sdavidxu#define MQFS_NAMELEN NAME_MAX 95152825Sdavidxu#define MQFS_DELEN (8 + MQFS_NAMELEN) 96152825Sdavidxu 97152825Sdavidxu/* node types */ 98152825Sdavidxutypedef enum { 99152825Sdavidxu mqfstype_none = 0, 100152825Sdavidxu mqfstype_root, 101152825Sdavidxu mqfstype_dir, 102152825Sdavidxu mqfstype_this, 103152825Sdavidxu mqfstype_parent, 104152825Sdavidxu mqfstype_file, 105152825Sdavidxu mqfstype_symlink, 106152825Sdavidxu} mqfs_type_t; 107152825Sdavidxu 108152825Sdavidxustruct mqfs_node; 109152825Sdavidxu 110152825Sdavidxu/* 111152825Sdavidxu * mqfs_info: describes a mqfs instance 112152825Sdavidxu */ 113152825Sdavidxustruct mqfs_info { 114152825Sdavidxu struct sx mi_lock; 115152825Sdavidxu struct mqfs_node *mi_root; 116152825Sdavidxu struct unrhdr *mi_unrhdr; 117152825Sdavidxu}; 118152825Sdavidxu 119152825Sdavidxustruct mqfs_vdata { 120152825Sdavidxu LIST_ENTRY(mqfs_vdata) mv_link; 121152825Sdavidxu struct mqfs_node *mv_node; 122152825Sdavidxu struct vnode *mv_vnode; 123152825Sdavidxu struct task mv_task; 124152825Sdavidxu}; 125152825Sdavidxu 126152825Sdavidxu/* 127152825Sdavidxu * mqfs_node: describes a node (file or directory) within a mqfs 128152825Sdavidxu */ 129152825Sdavidxustruct mqfs_node { 130152825Sdavidxu char mn_name[MQFS_NAMELEN+1]; 131152825Sdavidxu struct mqfs_info *mn_info; 132152825Sdavidxu struct mqfs_node *mn_parent; 133152825Sdavidxu LIST_HEAD(,mqfs_node) mn_children; 134152825Sdavidxu LIST_ENTRY(mqfs_node) mn_sibling; 135152825Sdavidxu LIST_HEAD(,mqfs_vdata) mn_vnodes; 136297936Sjamie const void *mn_pr_root; 137152825Sdavidxu int mn_refcount; 138152825Sdavidxu mqfs_type_t mn_type; 139152825Sdavidxu int mn_deleted; 140209390Sed uint32_t mn_fileno; 141152825Sdavidxu void *mn_data; 142152825Sdavidxu struct timespec mn_birth; 143152825Sdavidxu struct timespec mn_ctime; 144152825Sdavidxu struct timespec mn_atime; 145152825Sdavidxu struct timespec mn_mtime; 146152825Sdavidxu uid_t mn_uid; 147152825Sdavidxu gid_t mn_gid; 148152825Sdavidxu int mn_mode; 149152825Sdavidxu}; 150152825Sdavidxu 151152825Sdavidxu#define VTON(vp) (((struct mqfs_vdata *)((vp)->v_data))->mv_node) 152152825Sdavidxu#define VTOMQ(vp) ((struct mqueue *)(VTON(vp)->mn_data)) 153152825Sdavidxu#define VFSTOMQFS(m) ((struct mqfs_info *)((m)->mnt_data)) 154152948Sdavidxu#define FPTOMQ(fp) ((struct mqueue *)(((struct mqfs_node *) \ 155152948Sdavidxu (fp)->f_data)->mn_data)) 156152948Sdavidxu 157152825SdavidxuTAILQ_HEAD(msgq, mqueue_msg); 158152825Sdavidxu 159152825Sdavidxustruct mqueue; 160152948Sdavidxu 161152948Sdavidxustruct mqueue_notifier { 162152948Sdavidxu LIST_ENTRY(mqueue_notifier) nt_link; 163152948Sdavidxu struct sigevent nt_sigev; 164152948Sdavidxu ksiginfo_t nt_ksi; 165152948Sdavidxu struct proc *nt_proc; 166152825Sdavidxu}; 167152825Sdavidxu 168152825Sdavidxustruct mqueue { 169152825Sdavidxu struct mtx mq_mutex; 170152825Sdavidxu int mq_flags; 171152825Sdavidxu long mq_maxmsg; 172152825Sdavidxu long mq_msgsize; 173152825Sdavidxu long mq_curmsgs; 174152825Sdavidxu long mq_totalbytes; 175152825Sdavidxu struct msgq mq_msgq; 176152825Sdavidxu int mq_receivers; 177152825Sdavidxu int mq_senders; 178152825Sdavidxu struct selinfo mq_rsel; 179152825Sdavidxu struct selinfo mq_wsel; 180152948Sdavidxu struct mqueue_notifier *mq_notifier; 181152825Sdavidxu}; 182152825Sdavidxu 183152825Sdavidxu#define MQ_RSEL 0x01 184152825Sdavidxu#define MQ_WSEL 0x02 185152825Sdavidxu 186152825Sdavidxustruct mqueue_msg { 187152825Sdavidxu TAILQ_ENTRY(mqueue_msg) msg_link; 188152825Sdavidxu unsigned int msg_prio; 189152825Sdavidxu unsigned int msg_size; 190152825Sdavidxu /* following real data... */ 191152825Sdavidxu}; 192152825Sdavidxu 193227309Sedstatic SYSCTL_NODE(_kern, OID_AUTO, mqueue, CTLFLAG_RW, 0, 194152825Sdavidxu "POSIX real time message queue"); 195152825Sdavidxu 196152825Sdavidxustatic int default_maxmsg = 10; 197152825Sdavidxustatic int default_msgsize = 1024; 198152825Sdavidxu 199153099Sdavidxustatic int maxmsg = 100; 200152825SdavidxuSYSCTL_INT(_kern_mqueue, OID_AUTO, maxmsg, CTLFLAG_RW, 201152825Sdavidxu &maxmsg, 0, "Default maximum messages in queue"); 202152825Sdavidxustatic int maxmsgsize = 16384; 203152825SdavidxuSYSCTL_INT(_kern_mqueue, OID_AUTO, maxmsgsize, CTLFLAG_RW, 204152825Sdavidxu &maxmsgsize, 0, "Default maximum message size"); 205152825Sdavidxustatic int maxmq = 100; 206152825SdavidxuSYSCTL_INT(_kern_mqueue, OID_AUTO, maxmq, CTLFLAG_RW, 207152825Sdavidxu &maxmq, 0, "maximum message queues"); 208152825Sdavidxustatic int curmq = 0; 209152825SdavidxuSYSCTL_INT(_kern_mqueue, OID_AUTO, curmq, CTLFLAG_RW, 210152825Sdavidxu &curmq, 0, "current message queue number"); 211152825Sdavidxustatic int unloadable = 0; 212152825Sdavidxustatic MALLOC_DEFINE(M_MQUEUEDATA, "mqdata", "mqueue data"); 213152825Sdavidxu 214152948Sdavidxustatic eventhandler_tag exit_tag; 215152948Sdavidxu 216152825Sdavidxu/* Only one instance per-system */ 217152825Sdavidxustatic struct mqfs_info mqfs_data; 218152825Sdavidxustatic uma_zone_t mqnode_zone; 219152825Sdavidxustatic uma_zone_t mqueue_zone; 220152825Sdavidxustatic uma_zone_t mvdata_zone; 221152948Sdavidxustatic uma_zone_t mqnoti_zone; 222152825Sdavidxustatic struct vop_vector mqfs_vnodeops; 223152825Sdavidxustatic struct fileops mqueueops; 224297936Sjamiestatic unsigned mqfs_osd_jail_slot; 225152825Sdavidxu 226152825Sdavidxu/* 227152825Sdavidxu * Directory structure construction and manipulation 228152825Sdavidxu */ 229152825Sdavidxu#ifdef notyet 230152825Sdavidxustatic struct mqfs_node *mqfs_create_dir(struct mqfs_node *parent, 231155889Sdavidxu const char *name, int namelen, struct ucred *cred, int mode); 232153254Sdavidxustatic struct mqfs_node *mqfs_create_link(struct mqfs_node *parent, 233155889Sdavidxu const char *name, int namelen, struct ucred *cred, int mode); 234152825Sdavidxu#endif 235152825Sdavidxu 236152825Sdavidxustatic struct mqfs_node *mqfs_create_file(struct mqfs_node *parent, 237155889Sdavidxu const char *name, int namelen, struct ucred *cred, int mode); 238152825Sdavidxustatic int mqfs_destroy(struct mqfs_node *mn); 239152825Sdavidxustatic void mqfs_fileno_alloc(struct mqfs_info *mi, struct mqfs_node *mn); 240152825Sdavidxustatic void mqfs_fileno_free(struct mqfs_info *mi, struct mqfs_node *mn); 241152825Sdavidxustatic int mqfs_allocv(struct mount *mp, struct vnode **vpp, struct mqfs_node *pn); 242298567Sjamiestatic int mqfs_prison_remove(void *obj, void *data); 243152825Sdavidxu 244152825Sdavidxu/* 245152825Sdavidxu * Message queue construction and maniplation 246152825Sdavidxu */ 247152825Sdavidxustatic struct mqueue *mqueue_alloc(const struct mq_attr *attr); 248152825Sdavidxustatic void mqueue_free(struct mqueue *mq); 249152825Sdavidxustatic int mqueue_send(struct mqueue *mq, const char *msg_ptr, 250152825Sdavidxu size_t msg_len, unsigned msg_prio, int waitok, 251152825Sdavidxu const struct timespec *abs_timeout); 252152825Sdavidxustatic int mqueue_receive(struct mqueue *mq, char *msg_ptr, 253152825Sdavidxu size_t msg_len, unsigned *msg_prio, int waitok, 254152825Sdavidxu const struct timespec *abs_timeout); 255152825Sdavidxustatic int _mqueue_send(struct mqueue *mq, struct mqueue_msg *msg, 256152825Sdavidxu int timo); 257152825Sdavidxustatic int _mqueue_recv(struct mqueue *mq, struct mqueue_msg **msg, 258152825Sdavidxu int timo); 259152825Sdavidxustatic void mqueue_send_notification(struct mqueue *mq); 260152948Sdavidxustatic void mqueue_fdclose(struct thread *td, int fd, struct file *fp); 261152948Sdavidxustatic void mq_proc_exit(void *arg, struct proc *p); 262152825Sdavidxu 263152948Sdavidxu/* 264152948Sdavidxu * kqueue filters 265152948Sdavidxu */ 266152825Sdavidxustatic void filt_mqdetach(struct knote *kn); 267152825Sdavidxustatic int filt_mqread(struct knote *kn, long hint); 268152825Sdavidxustatic int filt_mqwrite(struct knote *kn, long hint); 269152825Sdavidxu 270197134Srwatsonstruct filterops mq_rfiltops = { 271197134Srwatson .f_isfd = 1, 272197134Srwatson .f_detach = filt_mqdetach, 273197134Srwatson .f_event = filt_mqread, 274197134Srwatson}; 275197134Srwatsonstruct filterops mq_wfiltops = { 276197134Srwatson .f_isfd = 1, 277197134Srwatson .f_detach = filt_mqdetach, 278197134Srwatson .f_event = filt_mqwrite, 279197134Srwatson}; 280152825Sdavidxu 281152825Sdavidxu/* 282152825Sdavidxu * Initialize fileno bitmap 283152825Sdavidxu */ 284152825Sdavidxustatic void 285152825Sdavidxumqfs_fileno_init(struct mqfs_info *mi) 286152825Sdavidxu{ 287152825Sdavidxu struct unrhdr *up; 288152825Sdavidxu 289152825Sdavidxu up = new_unrhdr(1, INT_MAX, NULL); 290152825Sdavidxu mi->mi_unrhdr = up; 291152825Sdavidxu} 292152825Sdavidxu 293152825Sdavidxu/* 294152825Sdavidxu * Tear down fileno bitmap 295152825Sdavidxu */ 296152825Sdavidxustatic void 297152825Sdavidxumqfs_fileno_uninit(struct mqfs_info *mi) 298152825Sdavidxu{ 299152825Sdavidxu struct unrhdr *up; 300152825Sdavidxu 301152825Sdavidxu up = mi->mi_unrhdr; 302152825Sdavidxu mi->mi_unrhdr = NULL; 303152825Sdavidxu delete_unrhdr(up); 304152825Sdavidxu} 305152825Sdavidxu 306152825Sdavidxu/* 307152825Sdavidxu * Allocate a file number 308152825Sdavidxu */ 309152948Sdavidxustatic void 310152825Sdavidxumqfs_fileno_alloc(struct mqfs_info *mi, struct mqfs_node *mn) 311152825Sdavidxu{ 312152825Sdavidxu /* make sure our parent has a file number */ 313152825Sdavidxu if (mn->mn_parent && !mn->mn_parent->mn_fileno) 314152825Sdavidxu mqfs_fileno_alloc(mi, mn->mn_parent); 315152825Sdavidxu 316152825Sdavidxu switch (mn->mn_type) { 317152825Sdavidxu case mqfstype_root: 318152825Sdavidxu case mqfstype_dir: 319152825Sdavidxu case mqfstype_file: 320152825Sdavidxu case mqfstype_symlink: 321152825Sdavidxu mn->mn_fileno = alloc_unr(mi->mi_unrhdr); 322152825Sdavidxu break; 323152825Sdavidxu case mqfstype_this: 324152825Sdavidxu KASSERT(mn->mn_parent != NULL, 325152825Sdavidxu ("mqfstype_this node has no parent")); 326152825Sdavidxu mn->mn_fileno = mn->mn_parent->mn_fileno; 327152825Sdavidxu break; 328152825Sdavidxu case mqfstype_parent: 329152825Sdavidxu KASSERT(mn->mn_parent != NULL, 330152825Sdavidxu ("mqfstype_parent node has no parent")); 331152825Sdavidxu if (mn->mn_parent == mi->mi_root) { 332152825Sdavidxu mn->mn_fileno = mn->mn_parent->mn_fileno; 333152825Sdavidxu break; 334152825Sdavidxu } 335152825Sdavidxu KASSERT(mn->mn_parent->mn_parent != NULL, 336152825Sdavidxu ("mqfstype_parent node has no grandparent")); 337152825Sdavidxu mn->mn_fileno = mn->mn_parent->mn_parent->mn_fileno; 338152825Sdavidxu break; 339152825Sdavidxu default: 340152825Sdavidxu KASSERT(0, 341152825Sdavidxu ("mqfs_fileno_alloc() called for unknown type node: %d", 342152825Sdavidxu mn->mn_type)); 343152825Sdavidxu break; 344152825Sdavidxu } 345152825Sdavidxu} 346152825Sdavidxu 347152825Sdavidxu/* 348152825Sdavidxu * Release a file number 349152825Sdavidxu */ 350152948Sdavidxustatic void 351152825Sdavidxumqfs_fileno_free(struct mqfs_info *mi, struct mqfs_node *mn) 352152825Sdavidxu{ 353152825Sdavidxu switch (mn->mn_type) { 354152825Sdavidxu case mqfstype_root: 355152825Sdavidxu case mqfstype_dir: 356152825Sdavidxu case mqfstype_file: 357152825Sdavidxu case mqfstype_symlink: 358152825Sdavidxu free_unr(mi->mi_unrhdr, mn->mn_fileno); 359152825Sdavidxu break; 360152825Sdavidxu case mqfstype_this: 361152825Sdavidxu case mqfstype_parent: 362152825Sdavidxu /* ignore these, as they don't "own" their file number */ 363152825Sdavidxu break; 364152825Sdavidxu default: 365152825Sdavidxu KASSERT(0, 366152825Sdavidxu ("mqfs_fileno_free() called for unknown type node: %d", 367152825Sdavidxu mn->mn_type)); 368152825Sdavidxu break; 369152825Sdavidxu } 370152825Sdavidxu} 371152825Sdavidxu 372152825Sdavidxustatic __inline struct mqfs_node * 373152825Sdavidxumqnode_alloc(void) 374152825Sdavidxu{ 375152825Sdavidxu return uma_zalloc(mqnode_zone, M_WAITOK | M_ZERO); 376152825Sdavidxu} 377152825Sdavidxu 378152825Sdavidxustatic __inline void 379152825Sdavidxumqnode_free(struct mqfs_node *node) 380152825Sdavidxu{ 381152825Sdavidxu uma_zfree(mqnode_zone, node); 382152825Sdavidxu} 383152825Sdavidxu 384152825Sdavidxustatic __inline void 385152825Sdavidxumqnode_addref(struct mqfs_node *node) 386152825Sdavidxu{ 387152825Sdavidxu atomic_fetchadd_int(&node->mn_refcount, 1); 388152825Sdavidxu} 389152825Sdavidxu 390152825Sdavidxustatic __inline void 391152825Sdavidxumqnode_release(struct mqfs_node *node) 392152825Sdavidxu{ 393182782Sdavidxu struct mqfs_info *mqfs; 394152825Sdavidxu int old, exp; 395152825Sdavidxu 396182782Sdavidxu mqfs = node->mn_info; 397152825Sdavidxu old = atomic_fetchadd_int(&node->mn_refcount, -1); 398152825Sdavidxu if (node->mn_type == mqfstype_dir || 399152825Sdavidxu node->mn_type == mqfstype_root) 400152825Sdavidxu exp = 3; /* include . and .. */ 401152825Sdavidxu else 402152825Sdavidxu exp = 1; 403182782Sdavidxu if (old == exp) { 404182782Sdavidxu int locked = sx_xlocked(&mqfs->mi_lock); 405182782Sdavidxu if (!locked) 406182782Sdavidxu sx_xlock(&mqfs->mi_lock); 407152825Sdavidxu mqfs_destroy(node); 408182782Sdavidxu if (!locked) 409182782Sdavidxu sx_xunlock(&mqfs->mi_lock); 410182782Sdavidxu } 411152825Sdavidxu} 412152825Sdavidxu 413152825Sdavidxu/* 414152825Sdavidxu * Add a node to a directory 415152825Sdavidxu */ 416152825Sdavidxustatic int 417152825Sdavidxumqfs_add_node(struct mqfs_node *parent, struct mqfs_node *node) 418152825Sdavidxu{ 419152825Sdavidxu KASSERT(parent != NULL, ("%s(): parent is NULL", __func__)); 420152825Sdavidxu KASSERT(parent->mn_info != NULL, 421152825Sdavidxu ("%s(): parent has no mn_info", __func__)); 422152825Sdavidxu KASSERT(parent->mn_type == mqfstype_dir || 423152825Sdavidxu parent->mn_type == mqfstype_root, 424152825Sdavidxu ("%s(): parent is not a directory", __func__)); 425152825Sdavidxu 426152825Sdavidxu node->mn_info = parent->mn_info; 427152825Sdavidxu node->mn_parent = parent; 428152825Sdavidxu LIST_INIT(&node->mn_children); 429152825Sdavidxu LIST_INIT(&node->mn_vnodes); 430152825Sdavidxu LIST_INSERT_HEAD(&parent->mn_children, node, mn_sibling); 431152825Sdavidxu mqnode_addref(parent); 432152825Sdavidxu return (0); 433152825Sdavidxu} 434152825Sdavidxu 435155889Sdavidxustatic struct mqfs_node * 436155889Sdavidxumqfs_create_node(const char *name, int namelen, struct ucred *cred, int mode, 437155889Sdavidxu int nodetype) 438155889Sdavidxu{ 439155889Sdavidxu struct mqfs_node *node; 440155889Sdavidxu 441155889Sdavidxu node = mqnode_alloc(); 442155889Sdavidxu strncpy(node->mn_name, name, namelen); 443297936Sjamie node->mn_pr_root = cred->cr_prison->pr_root; 444155889Sdavidxu node->mn_type = nodetype; 445155889Sdavidxu node->mn_refcount = 1; 446182782Sdavidxu vfs_timestamp(&node->mn_birth); 447155889Sdavidxu node->mn_ctime = node->mn_atime = node->mn_mtime 448155889Sdavidxu = node->mn_birth; 449155889Sdavidxu node->mn_uid = cred->cr_uid; 450155889Sdavidxu node->mn_gid = cred->cr_gid; 451155889Sdavidxu node->mn_mode = mode; 452155889Sdavidxu return (node); 453155889Sdavidxu} 454155889Sdavidxu 455152825Sdavidxu/* 456155889Sdavidxu * Create a file 457155889Sdavidxu */ 458155889Sdavidxustatic struct mqfs_node * 459155889Sdavidxumqfs_create_file(struct mqfs_node *parent, const char *name, int namelen, 460155889Sdavidxu struct ucred *cred, int mode) 461155889Sdavidxu{ 462155889Sdavidxu struct mqfs_node *node; 463155889Sdavidxu 464155889Sdavidxu node = mqfs_create_node(name, namelen, cred, mode, mqfstype_file); 465155889Sdavidxu if (mqfs_add_node(parent, node) != 0) { 466155889Sdavidxu mqnode_free(node); 467155889Sdavidxu return (NULL); 468155889Sdavidxu } 469155889Sdavidxu return (node); 470155889Sdavidxu} 471155889Sdavidxu 472155889Sdavidxu/* 473152825Sdavidxu * Add . and .. to a directory 474152825Sdavidxu */ 475152825Sdavidxustatic int 476152825Sdavidxumqfs_fixup_dir(struct mqfs_node *parent) 477152825Sdavidxu{ 478152825Sdavidxu struct mqfs_node *dir; 479152825Sdavidxu 480152825Sdavidxu dir = mqnode_alloc(); 481152825Sdavidxu dir->mn_name[0] = '.'; 482152825Sdavidxu dir->mn_type = mqfstype_this; 483152825Sdavidxu dir->mn_refcount = 1; 484152825Sdavidxu if (mqfs_add_node(parent, dir) != 0) { 485152825Sdavidxu mqnode_free(dir); 486152825Sdavidxu return (-1); 487152825Sdavidxu } 488152825Sdavidxu 489152825Sdavidxu dir = mqnode_alloc(); 490152825Sdavidxu dir->mn_name[0] = dir->mn_name[1] = '.'; 491152825Sdavidxu dir->mn_type = mqfstype_parent; 492152825Sdavidxu dir->mn_refcount = 1; 493152825Sdavidxu 494152825Sdavidxu if (mqfs_add_node(parent, dir) != 0) { 495152825Sdavidxu mqnode_free(dir); 496152825Sdavidxu return (-1); 497152825Sdavidxu } 498152825Sdavidxu 499152825Sdavidxu return (0); 500152825Sdavidxu} 501152825Sdavidxu 502152825Sdavidxu#ifdef notyet 503152825Sdavidxu 504152825Sdavidxu/* 505152825Sdavidxu * Create a directory 506152825Sdavidxu */ 507152948Sdavidxustatic struct mqfs_node * 508155889Sdavidxumqfs_create_dir(struct mqfs_node *parent, const char *name, int namelen, 509155889Sdavidxu struct ucred *cred, int mode) 510152825Sdavidxu{ 511155889Sdavidxu struct mqfs_node *node; 512152825Sdavidxu 513155889Sdavidxu node = mqfs_create_node(name, namelen, cred, mode, mqfstype_dir); 514155889Sdavidxu if (mqfs_add_node(parent, node) != 0) { 515155889Sdavidxu mqnode_free(node); 516152825Sdavidxu return (NULL); 517152825Sdavidxu } 518152825Sdavidxu 519155889Sdavidxu if (mqfs_fixup_dir(node) != 0) { 520155889Sdavidxu mqfs_destroy(node); 521152825Sdavidxu return (NULL); 522152825Sdavidxu } 523155889Sdavidxu return (node); 524152825Sdavidxu} 525152948Sdavidxu 526152948Sdavidxu/* 527152948Sdavidxu * Create a symlink 528152948Sdavidxu */ 529152948Sdavidxustatic struct mqfs_node * 530155889Sdavidxumqfs_create_link(struct mqfs_node *parent, const char *name, int namelen, 531155889Sdavidxu struct ucred *cred, int mode) 532152948Sdavidxu{ 533152948Sdavidxu struct mqfs_node *node; 534152948Sdavidxu 535155889Sdavidxu node = mqfs_create_node(name, namelen, cred, mode, mqfstype_symlink); 536152825Sdavidxu if (mqfs_add_node(parent, node) != 0) { 537152825Sdavidxu mqnode_free(node); 538152825Sdavidxu return (NULL); 539152825Sdavidxu } 540152825Sdavidxu return (node); 541152825Sdavidxu} 542152825Sdavidxu 543155889Sdavidxu#endif 544155889Sdavidxu 545152825Sdavidxu/* 546152825Sdavidxu * Destroy a node or a tree of nodes 547152825Sdavidxu */ 548152948Sdavidxustatic int 549152825Sdavidxumqfs_destroy(struct mqfs_node *node) 550152825Sdavidxu{ 551152825Sdavidxu struct mqfs_node *parent; 552152825Sdavidxu 553152825Sdavidxu KASSERT(node != NULL, 554152825Sdavidxu ("%s(): node is NULL", __func__)); 555152825Sdavidxu KASSERT(node->mn_info != NULL, 556152825Sdavidxu ("%s(): node has no mn_info", __func__)); 557152825Sdavidxu 558152825Sdavidxu /* destroy children */ 559152825Sdavidxu if (node->mn_type == mqfstype_dir || node->mn_type == mqfstype_root) 560152825Sdavidxu while (! LIST_EMPTY(&node->mn_children)) 561152825Sdavidxu mqfs_destroy(LIST_FIRST(&node->mn_children)); 562152825Sdavidxu 563152825Sdavidxu /* unlink from parent */ 564152825Sdavidxu if ((parent = node->mn_parent) != NULL) { 565152825Sdavidxu KASSERT(parent->mn_info == node->mn_info, 566152825Sdavidxu ("%s(): parent has different mn_info", __func__)); 567152825Sdavidxu LIST_REMOVE(node, mn_sibling); 568152825Sdavidxu } 569152825Sdavidxu 570152825Sdavidxu if (node->mn_fileno != 0) 571152825Sdavidxu mqfs_fileno_free(node->mn_info, node); 572152825Sdavidxu if (node->mn_data != NULL) 573152825Sdavidxu mqueue_free(node->mn_data); 574152825Sdavidxu mqnode_free(node); 575152825Sdavidxu return (0); 576152825Sdavidxu} 577152825Sdavidxu 578152825Sdavidxu/* 579152825Sdavidxu * Mount a mqfs instance 580152825Sdavidxu */ 581152825Sdavidxustatic int 582191990Sattiliomqfs_mount(struct mount *mp) 583152825Sdavidxu{ 584152825Sdavidxu struct statfs *sbp; 585152825Sdavidxu 586152825Sdavidxu if (mp->mnt_flag & MNT_UPDATE) 587152825Sdavidxu return (EOPNOTSUPP); 588152825Sdavidxu 589152825Sdavidxu mp->mnt_data = &mqfs_data; 590162647Stegge MNT_ILOCK(mp); 591152825Sdavidxu mp->mnt_flag |= MNT_LOCAL; 592162647Stegge MNT_IUNLOCK(mp); 593152825Sdavidxu vfs_getnewfsid(mp); 594152825Sdavidxu 595152825Sdavidxu sbp = &mp->mnt_stat; 596152825Sdavidxu vfs_mountedfrom(mp, "mqueue"); 597152825Sdavidxu sbp->f_bsize = PAGE_SIZE; 598152825Sdavidxu sbp->f_iosize = PAGE_SIZE; 599152825Sdavidxu sbp->f_blocks = 1; 600152825Sdavidxu sbp->f_bfree = 0; 601152825Sdavidxu sbp->f_bavail = 0; 602152825Sdavidxu sbp->f_files = 1; 603152825Sdavidxu sbp->f_ffree = 0; 604152825Sdavidxu return (0); 605152825Sdavidxu} 606152825Sdavidxu 607152825Sdavidxu/* 608152825Sdavidxu * Unmount a mqfs instance 609152825Sdavidxu */ 610152825Sdavidxustatic int 611191990Sattiliomqfs_unmount(struct mount *mp, int mntflags) 612152825Sdavidxu{ 613152825Sdavidxu int error; 614152825Sdavidxu 615191990Sattilio error = vflush(mp, 0, (mntflags & MNT_FORCE) ? FORCECLOSE : 0, 616191990Sattilio curthread); 617152825Sdavidxu return (error); 618152825Sdavidxu} 619152825Sdavidxu 620152825Sdavidxu/* 621152825Sdavidxu * Return a root vnode 622152825Sdavidxu */ 623152825Sdavidxustatic int 624191990Sattiliomqfs_root(struct mount *mp, int flags, struct vnode **vpp) 625152825Sdavidxu{ 626152825Sdavidxu struct mqfs_info *mqfs; 627152825Sdavidxu int ret; 628152825Sdavidxu 629152825Sdavidxu mqfs = VFSTOMQFS(mp); 630152825Sdavidxu ret = mqfs_allocv(mp, vpp, mqfs->mi_root); 631152825Sdavidxu return (ret); 632152825Sdavidxu} 633152825Sdavidxu 634152825Sdavidxu/* 635152825Sdavidxu * Return filesystem stats 636152825Sdavidxu */ 637152825Sdavidxustatic int 638191990Sattiliomqfs_statfs(struct mount *mp, struct statfs *sbp) 639152825Sdavidxu{ 640152825Sdavidxu /* XXX update statistics */ 641152825Sdavidxu return (0); 642152825Sdavidxu} 643152825Sdavidxu 644152825Sdavidxu/* 645152825Sdavidxu * Initialize a mqfs instance 646152825Sdavidxu */ 647152825Sdavidxustatic int 648152825Sdavidxumqfs_init(struct vfsconf *vfc) 649152825Sdavidxu{ 650152825Sdavidxu struct mqfs_node *root; 651152825Sdavidxu struct mqfs_info *mi; 652297936Sjamie osd_method_t methods[PR_MAXMETHOD] = { 653298567Sjamie [PR_METHOD_REMOVE] = mqfs_prison_remove, 654297936Sjamie }; 655152825Sdavidxu 656152825Sdavidxu mqnode_zone = uma_zcreate("mqnode", sizeof(struct mqfs_node), 657152825Sdavidxu NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 658152825Sdavidxu mqueue_zone = uma_zcreate("mqueue", sizeof(struct mqueue), 659152825Sdavidxu NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 660152825Sdavidxu mvdata_zone = uma_zcreate("mvdata", 661152825Sdavidxu sizeof(struct mqfs_vdata), NULL, NULL, NULL, 662152825Sdavidxu NULL, UMA_ALIGN_PTR, 0); 663152948Sdavidxu mqnoti_zone = uma_zcreate("mqnotifier", sizeof(struct mqueue_notifier), 664152825Sdavidxu NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 665152825Sdavidxu mi = &mqfs_data; 666152825Sdavidxu sx_init(&mi->mi_lock, "mqfs lock"); 667152825Sdavidxu /* set up the root diretory */ 668155889Sdavidxu root = mqfs_create_node("/", 1, curthread->td_ucred, 01777, 669155889Sdavidxu mqfstype_root); 670152825Sdavidxu root->mn_info = mi; 671152825Sdavidxu LIST_INIT(&root->mn_children); 672152825Sdavidxu LIST_INIT(&root->mn_vnodes); 673152825Sdavidxu mi->mi_root = root; 674152825Sdavidxu mqfs_fileno_init(mi); 675152825Sdavidxu mqfs_fileno_alloc(mi, root); 676152825Sdavidxu mqfs_fixup_dir(root); 677152948Sdavidxu exit_tag = EVENTHANDLER_REGISTER(process_exit, mq_proc_exit, NULL, 678152948Sdavidxu EVENTHANDLER_PRI_ANY); 679152948Sdavidxu mq_fdclose = mqueue_fdclose; 680153019Sdavidxu p31b_setcfg(CTL_P1003_1B_MESSAGE_PASSING, _POSIX_MESSAGE_PASSING); 681298567Sjamie mqfs_osd_jail_slot = osd_jail_register(NULL, methods); 682152825Sdavidxu return (0); 683152825Sdavidxu} 684152825Sdavidxu 685152825Sdavidxu/* 686152825Sdavidxu * Destroy a mqfs instance 687152825Sdavidxu */ 688152825Sdavidxustatic int 689152825Sdavidxumqfs_uninit(struct vfsconf *vfc) 690152825Sdavidxu{ 691152825Sdavidxu struct mqfs_info *mi; 692152825Sdavidxu 693152825Sdavidxu if (!unloadable) 694152825Sdavidxu return (EOPNOTSUPP); 695298567Sjamie osd_jail_deregister(mqfs_osd_jail_slot); 696152948Sdavidxu EVENTHANDLER_DEREGISTER(process_exit, exit_tag); 697152825Sdavidxu mi = &mqfs_data; 698152825Sdavidxu mqfs_destroy(mi->mi_root); 699152825Sdavidxu mi->mi_root = NULL; 700152825Sdavidxu mqfs_fileno_uninit(mi); 701152825Sdavidxu sx_destroy(&mi->mi_lock); 702152948Sdavidxu uma_zdestroy(mqnode_zone); 703152948Sdavidxu uma_zdestroy(mqueue_zone); 704152948Sdavidxu uma_zdestroy(mvdata_zone); 705152948Sdavidxu uma_zdestroy(mqnoti_zone); 706152825Sdavidxu return (0); 707152825Sdavidxu} 708152825Sdavidxu 709152825Sdavidxu/* 710152825Sdavidxu * task routine 711152825Sdavidxu */ 712152825Sdavidxustatic void 713152825Sdavidxudo_recycle(void *context, int pending __unused) 714152825Sdavidxu{ 715152825Sdavidxu struct vnode *vp = (struct vnode *)context; 716152825Sdavidxu 717234607Strasz vrecycle(vp); 718152825Sdavidxu vdrop(vp); 719152825Sdavidxu} 720152825Sdavidxu 721152825Sdavidxu/* 722152825Sdavidxu * Allocate a vnode 723152825Sdavidxu */ 724152948Sdavidxustatic int 725152825Sdavidxumqfs_allocv(struct mount *mp, struct vnode **vpp, struct mqfs_node *pn) 726152825Sdavidxu{ 727152825Sdavidxu struct mqfs_vdata *vd; 728182782Sdavidxu struct mqfs_info *mqfs; 729182782Sdavidxu struct vnode *newvpp; 730152825Sdavidxu int error; 731152825Sdavidxu 732182782Sdavidxu mqfs = pn->mn_info; 733182782Sdavidxu *vpp = NULL; 734182782Sdavidxu sx_xlock(&mqfs->mi_lock); 735152825Sdavidxu LIST_FOREACH(vd, &pn->mn_vnodes, mv_link) { 736182782Sdavidxu if (vd->mv_vnode->v_mount == mp) { 737182782Sdavidxu vhold(vd->mv_vnode); 738152825Sdavidxu break; 739182782Sdavidxu } 740152825Sdavidxu } 741152825Sdavidxu 742152825Sdavidxu if (vd != NULL) { 743182782Sdavidxufound: 744177726Sjeff *vpp = vd->mv_vnode; 745182782Sdavidxu sx_xunlock(&mqfs->mi_lock); 746182782Sdavidxu error = vget(*vpp, LK_RETRY | LK_EXCLUSIVE, curthread); 747182782Sdavidxu vdrop(*vpp); 748182782Sdavidxu return (error); 749152825Sdavidxu } 750182782Sdavidxu sx_xunlock(&mqfs->mi_lock); 751152825Sdavidxu 752182782Sdavidxu error = getnewvnode("mqueue", mp, &mqfs_vnodeops, &newvpp); 753152825Sdavidxu if (error) 754152825Sdavidxu return (error); 755182782Sdavidxu vn_lock(newvpp, LK_EXCLUSIVE | LK_RETRY); 756182782Sdavidxu error = insmntque(newvpp, mp); 757182782Sdavidxu if (error != 0) 758167497Stegge return (error); 759182782Sdavidxu 760182782Sdavidxu sx_xlock(&mqfs->mi_lock); 761182782Sdavidxu /* 762182782Sdavidxu * Check if it has already been allocated 763182782Sdavidxu * while we were blocked. 764182782Sdavidxu */ 765182782Sdavidxu LIST_FOREACH(vd, &pn->mn_vnodes, mv_link) { 766182782Sdavidxu if (vd->mv_vnode->v_mount == mp) { 767182782Sdavidxu vhold(vd->mv_vnode); 768182782Sdavidxu sx_xunlock(&mqfs->mi_lock); 769182782Sdavidxu 770182782Sdavidxu vgone(newvpp); 771182782Sdavidxu vput(newvpp); 772182782Sdavidxu goto found; 773182782Sdavidxu } 774167497Stegge } 775182782Sdavidxu 776182782Sdavidxu *vpp = newvpp; 777182782Sdavidxu 778152825Sdavidxu vd = uma_zalloc(mvdata_zone, M_WAITOK); 779152825Sdavidxu (*vpp)->v_data = vd; 780152825Sdavidxu vd->mv_vnode = *vpp; 781152825Sdavidxu vd->mv_node = pn; 782152825Sdavidxu TASK_INIT(&vd->mv_task, 0, do_recycle, *vpp); 783152825Sdavidxu LIST_INSERT_HEAD(&pn->mn_vnodes, vd, mv_link); 784152825Sdavidxu mqnode_addref(pn); 785152825Sdavidxu switch (pn->mn_type) { 786152825Sdavidxu case mqfstype_root: 787152825Sdavidxu (*vpp)->v_vflag = VV_ROOT; 788152825Sdavidxu /* fall through */ 789152825Sdavidxu case mqfstype_dir: 790152825Sdavidxu case mqfstype_this: 791152825Sdavidxu case mqfstype_parent: 792152825Sdavidxu (*vpp)->v_type = VDIR; 793152825Sdavidxu break; 794152825Sdavidxu case mqfstype_file: 795152825Sdavidxu (*vpp)->v_type = VREG; 796152825Sdavidxu break; 797152825Sdavidxu case mqfstype_symlink: 798152825Sdavidxu (*vpp)->v_type = VLNK; 799152825Sdavidxu break; 800152825Sdavidxu case mqfstype_none: 801152825Sdavidxu KASSERT(0, ("mqfs_allocf called for null node\n")); 802152825Sdavidxu default: 803152825Sdavidxu panic("%s has unexpected type: %d", pn->mn_name, pn->mn_type); 804152825Sdavidxu } 805182782Sdavidxu sx_xunlock(&mqfs->mi_lock); 806152825Sdavidxu return (0); 807152825Sdavidxu} 808152825Sdavidxu 809152825Sdavidxu/* 810152825Sdavidxu * Search a directory entry 811152825Sdavidxu */ 812152825Sdavidxustatic struct mqfs_node * 813297936Sjamiemqfs_search(struct mqfs_node *pd, const char *name, int len, struct ucred *cred) 814152825Sdavidxu{ 815152825Sdavidxu struct mqfs_node *pn; 816297936Sjamie const void *pr_root; 817152825Sdavidxu 818182782Sdavidxu sx_assert(&pd->mn_info->mi_lock, SX_LOCKED); 819297936Sjamie pr_root = cred->cr_prison->pr_root; 820152825Sdavidxu LIST_FOREACH(pn, &pd->mn_children, mn_sibling) { 821297936Sjamie /* Only match names within the same prison root directory */ 822297936Sjamie if ((pn->mn_pr_root == NULL || pn->mn_pr_root == pr_root) && 823297936Sjamie strncmp(pn->mn_name, name, len) == 0 && 824185385Sed pn->mn_name[len] == '\0') 825152825Sdavidxu return (pn); 826152825Sdavidxu } 827152825Sdavidxu return (NULL); 828152825Sdavidxu} 829152825Sdavidxu 830152825Sdavidxu/* 831167232Srwatson * Look up a file or directory. 832152825Sdavidxu */ 833152825Sdavidxustatic int 834152825Sdavidxumqfs_lookupx(struct vop_cachedlookup_args *ap) 835152825Sdavidxu{ 836152825Sdavidxu struct componentname *cnp; 837152825Sdavidxu struct vnode *dvp, **vpp; 838152825Sdavidxu struct mqfs_node *pd; 839152825Sdavidxu struct mqfs_node *pn; 840182782Sdavidxu struct mqfs_info *mqfs; 841152825Sdavidxu int nameiop, flags, error, namelen; 842152825Sdavidxu char *pname; 843152825Sdavidxu struct thread *td; 844152825Sdavidxu 845152825Sdavidxu cnp = ap->a_cnp; 846152825Sdavidxu vpp = ap->a_vpp; 847152825Sdavidxu dvp = ap->a_dvp; 848152825Sdavidxu pname = cnp->cn_nameptr; 849152825Sdavidxu namelen = cnp->cn_namelen; 850152825Sdavidxu td = cnp->cn_thread; 851152825Sdavidxu flags = cnp->cn_flags; 852152825Sdavidxu nameiop = cnp->cn_nameiop; 853152825Sdavidxu pd = VTON(dvp); 854152825Sdavidxu pn = NULL; 855182782Sdavidxu mqfs = pd->mn_info; 856152825Sdavidxu *vpp = NULLVP; 857152825Sdavidxu 858152825Sdavidxu if (dvp->v_type != VDIR) 859152825Sdavidxu return (ENOTDIR); 860152825Sdavidxu 861152825Sdavidxu error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, cnp->cn_thread); 862152825Sdavidxu if (error) 863152825Sdavidxu return (error); 864152825Sdavidxu 865152825Sdavidxu /* shortcut: check if the name is too long */ 866152825Sdavidxu if (cnp->cn_namelen >= MQFS_NAMELEN) 867152825Sdavidxu return (ENOENT); 868152825Sdavidxu 869152825Sdavidxu /* self */ 870152825Sdavidxu if (namelen == 1 && pname[0] == '.') { 871152825Sdavidxu if ((flags & ISLASTCN) && nameiop != LOOKUP) 872152825Sdavidxu return (EINVAL); 873152825Sdavidxu pn = pd; 874152825Sdavidxu *vpp = dvp; 875152825Sdavidxu VREF(dvp); 876152825Sdavidxu return (0); 877152825Sdavidxu } 878152825Sdavidxu 879152825Sdavidxu /* parent */ 880152825Sdavidxu if (cnp->cn_flags & ISDOTDOT) { 881152825Sdavidxu if (dvp->v_vflag & VV_ROOT) 882152825Sdavidxu return (EIO); 883152825Sdavidxu if ((flags & ISLASTCN) && nameiop != LOOKUP) 884152825Sdavidxu return (EINVAL); 885175294Sattilio VOP_UNLOCK(dvp, 0); 886152825Sdavidxu KASSERT(pd->mn_parent, ("non-root directory has no parent")); 887152825Sdavidxu pn = pd->mn_parent; 888152825Sdavidxu error = mqfs_allocv(dvp->v_mount, vpp, pn); 889175202Sattilio vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); 890152825Sdavidxu return (error); 891152825Sdavidxu } 892152825Sdavidxu 893152825Sdavidxu /* named node */ 894182782Sdavidxu sx_xlock(&mqfs->mi_lock); 895297936Sjamie pn = mqfs_search(pd, pname, namelen, cnp->cn_cred); 896182782Sdavidxu if (pn != NULL) 897182782Sdavidxu mqnode_addref(pn); 898182782Sdavidxu sx_xunlock(&mqfs->mi_lock); 899152825Sdavidxu 900152825Sdavidxu /* found */ 901152825Sdavidxu if (pn != NULL) { 902152825Sdavidxu /* DELETE */ 903152825Sdavidxu if (nameiop == DELETE && (flags & ISLASTCN)) { 904152825Sdavidxu error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 905182782Sdavidxu if (error) { 906182782Sdavidxu mqnode_release(pn); 907152825Sdavidxu return (error); 908182782Sdavidxu } 909152825Sdavidxu if (*vpp == dvp) { 910152825Sdavidxu VREF(dvp); 911152825Sdavidxu *vpp = dvp; 912182782Sdavidxu mqnode_release(pn); 913152825Sdavidxu return (0); 914152825Sdavidxu } 915152825Sdavidxu } 916152825Sdavidxu 917152825Sdavidxu /* allocate vnode */ 918152825Sdavidxu error = mqfs_allocv(dvp->v_mount, vpp, pn); 919182782Sdavidxu mqnode_release(pn); 920152825Sdavidxu if (error == 0 && cnp->cn_flags & MAKEENTRY) 921152825Sdavidxu cache_enter(dvp, *vpp, cnp); 922152825Sdavidxu return (error); 923152825Sdavidxu } 924152825Sdavidxu 925152825Sdavidxu /* not found */ 926152825Sdavidxu 927152825Sdavidxu /* will create a new entry in the directory ? */ 928152825Sdavidxu if ((nameiop == CREATE || nameiop == RENAME) && (flags & LOCKPARENT) 929152825Sdavidxu && (flags & ISLASTCN)) { 930152825Sdavidxu error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 931152825Sdavidxu if (error) 932152825Sdavidxu return (error); 933152825Sdavidxu cnp->cn_flags |= SAVENAME; 934152825Sdavidxu return (EJUSTRETURN); 935152825Sdavidxu } 936152825Sdavidxu return (ENOENT); 937152825Sdavidxu} 938152825Sdavidxu 939152825Sdavidxu#if 0 940152825Sdavidxustruct vop_lookup_args { 941152825Sdavidxu struct vop_generic_args a_gen; 942152825Sdavidxu struct vnode *a_dvp; 943152825Sdavidxu struct vnode **a_vpp; 944152825Sdavidxu struct componentname *a_cnp; 945152825Sdavidxu}; 946152825Sdavidxu#endif 947152825Sdavidxu 948152825Sdavidxu/* 949152825Sdavidxu * vnode lookup operation 950152825Sdavidxu */ 951152825Sdavidxustatic int 952152825Sdavidxumqfs_lookup(struct vop_cachedlookup_args *ap) 953152825Sdavidxu{ 954152825Sdavidxu int rc; 955152825Sdavidxu 956152825Sdavidxu rc = mqfs_lookupx(ap); 957152825Sdavidxu return (rc); 958152825Sdavidxu} 959152825Sdavidxu 960152825Sdavidxu#if 0 961152825Sdavidxustruct vop_create_args { 962152825Sdavidxu struct vnode *a_dvp; 963152825Sdavidxu struct vnode **a_vpp; 964152825Sdavidxu struct componentname *a_cnp; 965152825Sdavidxu struct vattr *a_vap; 966152825Sdavidxu}; 967152825Sdavidxu#endif 968152825Sdavidxu 969152825Sdavidxu/* 970152825Sdavidxu * vnode creation operation 971152825Sdavidxu */ 972152825Sdavidxustatic int 973152825Sdavidxumqfs_create(struct vop_create_args *ap) 974152825Sdavidxu{ 975152825Sdavidxu struct mqfs_info *mqfs = VFSTOMQFS(ap->a_dvp->v_mount); 976152825Sdavidxu struct componentname *cnp = ap->a_cnp; 977152825Sdavidxu struct mqfs_node *pd; 978152825Sdavidxu struct mqfs_node *pn; 979152825Sdavidxu struct mqueue *mq; 980152825Sdavidxu int error; 981152825Sdavidxu 982152825Sdavidxu pd = VTON(ap->a_dvp); 983152825Sdavidxu if (pd->mn_type != mqfstype_root && pd->mn_type != mqfstype_dir) 984152825Sdavidxu return (ENOTDIR); 985152825Sdavidxu mq = mqueue_alloc(NULL); 986152825Sdavidxu if (mq == NULL) 987152825Sdavidxu return (EAGAIN); 988152825Sdavidxu sx_xlock(&mqfs->mi_lock); 989152825Sdavidxu if ((cnp->cn_flags & HASBUF) == 0) 990152825Sdavidxu panic("%s: no name", __func__); 991155889Sdavidxu pn = mqfs_create_file(pd, cnp->cn_nameptr, cnp->cn_namelen, 992155889Sdavidxu cnp->cn_cred, ap->a_vap->va_mode); 993182782Sdavidxu if (pn == NULL) { 994182782Sdavidxu sx_xunlock(&mqfs->mi_lock); 995155889Sdavidxu error = ENOSPC; 996182782Sdavidxu } else { 997182782Sdavidxu mqnode_addref(pn); 998182782Sdavidxu sx_xunlock(&mqfs->mi_lock); 999155889Sdavidxu error = mqfs_allocv(ap->a_dvp->v_mount, ap->a_vpp, pn); 1000182782Sdavidxu mqnode_release(pn); 1001155889Sdavidxu if (error) 1002155889Sdavidxu mqfs_destroy(pn); 1003155889Sdavidxu else 1004155889Sdavidxu pn->mn_data = mq; 1005155889Sdavidxu } 1006155889Sdavidxu if (error) 1007155889Sdavidxu mqueue_free(mq); 1008152825Sdavidxu return (error); 1009152825Sdavidxu} 1010152825Sdavidxu 1011152825Sdavidxu/* 1012152825Sdavidxu * Remove an entry 1013152825Sdavidxu */ 1014152825Sdavidxustatic 1015152825Sdavidxuint do_unlink(struct mqfs_node *pn, struct ucred *ucred) 1016152825Sdavidxu{ 1017152825Sdavidxu struct mqfs_node *parent; 1018152825Sdavidxu struct mqfs_vdata *vd; 1019152825Sdavidxu int error = 0; 1020152825Sdavidxu 1021152825Sdavidxu sx_assert(&pn->mn_info->mi_lock, SX_LOCKED); 1022152825Sdavidxu 1023152825Sdavidxu if (ucred->cr_uid != pn->mn_uid && 1024170587Srwatson (error = priv_check_cred(ucred, PRIV_MQ_ADMIN, 0)) != 0) 1025152825Sdavidxu error = EACCES; 1026152825Sdavidxu else if (!pn->mn_deleted) { 1027152825Sdavidxu parent = pn->mn_parent; 1028152825Sdavidxu pn->mn_parent = NULL; 1029152825Sdavidxu pn->mn_deleted = 1; 1030152825Sdavidxu LIST_REMOVE(pn, mn_sibling); 1031152825Sdavidxu LIST_FOREACH(vd, &pn->mn_vnodes, mv_link) { 1032152825Sdavidxu cache_purge(vd->mv_vnode); 1033152825Sdavidxu vhold(vd->mv_vnode); 1034152825Sdavidxu taskqueue_enqueue(taskqueue_thread, &vd->mv_task); 1035152825Sdavidxu } 1036152825Sdavidxu mqnode_release(pn); 1037152825Sdavidxu mqnode_release(parent); 1038152825Sdavidxu } else 1039152825Sdavidxu error = ENOENT; 1040152825Sdavidxu return (error); 1041152825Sdavidxu} 1042152825Sdavidxu 1043152825Sdavidxu#if 0 1044152825Sdavidxustruct vop_remove_args { 1045152825Sdavidxu struct vnode *a_dvp; 1046152825Sdavidxu struct vnode *a_vp; 1047152825Sdavidxu struct componentname *a_cnp; 1048152825Sdavidxu}; 1049152825Sdavidxu#endif 1050152825Sdavidxu 1051152825Sdavidxu/* 1052152825Sdavidxu * vnode removal operation 1053152825Sdavidxu */ 1054152825Sdavidxustatic int 1055152825Sdavidxumqfs_remove(struct vop_remove_args *ap) 1056152825Sdavidxu{ 1057152825Sdavidxu struct mqfs_info *mqfs = VFSTOMQFS(ap->a_dvp->v_mount); 1058152825Sdavidxu struct mqfs_node *pn; 1059152825Sdavidxu int error; 1060152825Sdavidxu 1061152825Sdavidxu if (ap->a_vp->v_type == VDIR) 1062152825Sdavidxu return (EPERM); 1063152825Sdavidxu pn = VTON(ap->a_vp); 1064152825Sdavidxu sx_xlock(&mqfs->mi_lock); 1065152825Sdavidxu error = do_unlink(pn, ap->a_cnp->cn_cred); 1066152825Sdavidxu sx_xunlock(&mqfs->mi_lock); 1067152825Sdavidxu return (error); 1068152825Sdavidxu} 1069152825Sdavidxu 1070152825Sdavidxu#if 0 1071152825Sdavidxustruct vop_inactive_args { 1072152825Sdavidxu struct vnode *a_vp; 1073152825Sdavidxu struct thread *a_td; 1074152825Sdavidxu}; 1075152825Sdavidxu#endif 1076152825Sdavidxu 1077152825Sdavidxustatic int 1078152825Sdavidxumqfs_inactive(struct vop_inactive_args *ap) 1079152825Sdavidxu{ 1080152825Sdavidxu struct mqfs_node *pn = VTON(ap->a_vp); 1081152825Sdavidxu 1082152825Sdavidxu if (pn->mn_deleted) 1083234607Strasz vrecycle(ap->a_vp); 1084152825Sdavidxu return (0); 1085152825Sdavidxu} 1086152825Sdavidxu 1087152825Sdavidxu#if 0 1088152825Sdavidxustruct vop_reclaim_args { 1089152825Sdavidxu struct vop_generic_args a_gen; 1090152825Sdavidxu struct vnode *a_vp; 1091152825Sdavidxu struct thread *a_td; 1092152825Sdavidxu}; 1093152825Sdavidxu#endif 1094152825Sdavidxu 1095152825Sdavidxustatic int 1096152825Sdavidxumqfs_reclaim(struct vop_reclaim_args *ap) 1097152825Sdavidxu{ 1098152825Sdavidxu struct mqfs_info *mqfs = VFSTOMQFS(ap->a_vp->v_mount); 1099152825Sdavidxu struct vnode *vp = ap->a_vp; 1100152825Sdavidxu struct mqfs_node *pn; 1101152825Sdavidxu struct mqfs_vdata *vd; 1102152825Sdavidxu 1103152825Sdavidxu vd = vp->v_data; 1104152825Sdavidxu pn = vd->mv_node; 1105152825Sdavidxu sx_xlock(&mqfs->mi_lock); 1106152825Sdavidxu vp->v_data = NULL; 1107152825Sdavidxu LIST_REMOVE(vd, mv_link); 1108152825Sdavidxu uma_zfree(mvdata_zone, vd); 1109152825Sdavidxu mqnode_release(pn); 1110152825Sdavidxu sx_xunlock(&mqfs->mi_lock); 1111152825Sdavidxu return (0); 1112152825Sdavidxu} 1113152825Sdavidxu 1114152825Sdavidxu#if 0 1115152825Sdavidxustruct vop_open_args { 1116152825Sdavidxu struct vop_generic_args a_gen; 1117152825Sdavidxu struct vnode *a_vp; 1118152825Sdavidxu int a_mode; 1119152825Sdavidxu struct ucred *a_cred; 1120152825Sdavidxu struct thread *a_td; 1121193924Skib struct file *a_fp; 1122152825Sdavidxu}; 1123152825Sdavidxu#endif 1124152825Sdavidxu 1125152825Sdavidxustatic int 1126152825Sdavidxumqfs_open(struct vop_open_args *ap) 1127152825Sdavidxu{ 1128152825Sdavidxu return (0); 1129152825Sdavidxu} 1130152825Sdavidxu 1131152825Sdavidxu#if 0 1132152825Sdavidxustruct vop_close_args { 1133152825Sdavidxu struct vop_generic_args a_gen; 1134152825Sdavidxu struct vnode *a_vp; 1135152825Sdavidxu int a_fflag; 1136152825Sdavidxu struct ucred *a_cred; 1137152825Sdavidxu struct thread *a_td; 1138152825Sdavidxu}; 1139152825Sdavidxu#endif 1140152825Sdavidxu 1141152825Sdavidxustatic int 1142152825Sdavidxumqfs_close(struct vop_close_args *ap) 1143152825Sdavidxu{ 1144152825Sdavidxu return (0); 1145152825Sdavidxu} 1146152825Sdavidxu 1147152825Sdavidxu#if 0 1148152825Sdavidxustruct vop_access_args { 1149152825Sdavidxu struct vop_generic_args a_gen; 1150152825Sdavidxu struct vnode *a_vp; 1151184413Strasz accmode_t a_accmode; 1152152825Sdavidxu struct ucred *a_cred; 1153152825Sdavidxu struct thread *a_td; 1154152825Sdavidxu}; 1155152825Sdavidxu#endif 1156152825Sdavidxu 1157152825Sdavidxu/* 1158152825Sdavidxu * Verify permissions 1159152825Sdavidxu */ 1160152825Sdavidxustatic int 1161152825Sdavidxumqfs_access(struct vop_access_args *ap) 1162152825Sdavidxu{ 1163152825Sdavidxu struct vnode *vp = ap->a_vp; 1164152825Sdavidxu struct vattr vattr; 1165152825Sdavidxu int error; 1166152825Sdavidxu 1167182371Sattilio error = VOP_GETATTR(vp, &vattr, ap->a_cred); 1168152825Sdavidxu if (error) 1169152825Sdavidxu return (error); 1170152825Sdavidxu error = vaccess(vp->v_type, vattr.va_mode, vattr.va_uid, 1171184413Strasz vattr.va_gid, ap->a_accmode, ap->a_cred, NULL); 1172152825Sdavidxu return (error); 1173152825Sdavidxu} 1174152825Sdavidxu 1175152825Sdavidxu#if 0 1176152825Sdavidxustruct vop_getattr_args { 1177152825Sdavidxu struct vop_generic_args a_gen; 1178152825Sdavidxu struct vnode *a_vp; 1179152825Sdavidxu struct vattr *a_vap; 1180152825Sdavidxu struct ucred *a_cred; 1181152825Sdavidxu}; 1182152825Sdavidxu#endif 1183152825Sdavidxu 1184152825Sdavidxu/* 1185152825Sdavidxu * Get file attributes 1186152825Sdavidxu */ 1187152825Sdavidxustatic int 1188152825Sdavidxumqfs_getattr(struct vop_getattr_args *ap) 1189152825Sdavidxu{ 1190152825Sdavidxu struct vnode *vp = ap->a_vp; 1191152825Sdavidxu struct mqfs_node *pn = VTON(vp); 1192152825Sdavidxu struct vattr *vap = ap->a_vap; 1193152825Sdavidxu int error = 0; 1194152825Sdavidxu 1195152825Sdavidxu vap->va_type = vp->v_type; 1196152825Sdavidxu vap->va_mode = pn->mn_mode; 1197152825Sdavidxu vap->va_nlink = 1; 1198152825Sdavidxu vap->va_uid = pn->mn_uid; 1199152825Sdavidxu vap->va_gid = pn->mn_gid; 1200152825Sdavidxu vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 1201152825Sdavidxu vap->va_fileid = pn->mn_fileno; 1202152825Sdavidxu vap->va_size = 0; 1203152825Sdavidxu vap->va_blocksize = PAGE_SIZE; 1204152825Sdavidxu vap->va_bytes = vap->va_size = 0; 1205152825Sdavidxu vap->va_atime = pn->mn_atime; 1206152825Sdavidxu vap->va_mtime = pn->mn_mtime; 1207152825Sdavidxu vap->va_ctime = pn->mn_ctime; 1208152825Sdavidxu vap->va_birthtime = pn->mn_birth; 1209152825Sdavidxu vap->va_gen = 0; 1210152825Sdavidxu vap->va_flags = 0; 1211183214Skib vap->va_rdev = NODEV; 1212152825Sdavidxu vap->va_bytes = 0; 1213152825Sdavidxu vap->va_filerev = 0; 1214152825Sdavidxu return (error); 1215152825Sdavidxu} 1216152825Sdavidxu 1217152825Sdavidxu#if 0 1218152825Sdavidxustruct vop_setattr_args { 1219152825Sdavidxu struct vop_generic_args a_gen; 1220152825Sdavidxu struct vnode *a_vp; 1221152825Sdavidxu struct vattr *a_vap; 1222152825Sdavidxu struct ucred *a_cred; 1223152825Sdavidxu}; 1224152825Sdavidxu#endif 1225152825Sdavidxu/* 1226152825Sdavidxu * Set attributes 1227152825Sdavidxu */ 1228152825Sdavidxustatic int 1229152825Sdavidxumqfs_setattr(struct vop_setattr_args *ap) 1230152825Sdavidxu{ 1231152825Sdavidxu struct mqfs_node *pn; 1232152825Sdavidxu struct vattr *vap; 1233152825Sdavidxu struct vnode *vp; 1234182371Sattilio struct thread *td; 1235152825Sdavidxu int c, error; 1236152825Sdavidxu uid_t uid; 1237152825Sdavidxu gid_t gid; 1238152825Sdavidxu 1239182371Sattilio td = curthread; 1240152825Sdavidxu vap = ap->a_vap; 1241152825Sdavidxu vp = ap->a_vp; 1242152825Sdavidxu if ((vap->va_type != VNON) || 1243152825Sdavidxu (vap->va_nlink != VNOVAL) || 1244152825Sdavidxu (vap->va_fsid != VNOVAL) || 1245152825Sdavidxu (vap->va_fileid != VNOVAL) || 1246152825Sdavidxu (vap->va_blocksize != VNOVAL) || 1247152825Sdavidxu (vap->va_flags != VNOVAL && vap->va_flags != 0) || 1248152825Sdavidxu (vap->va_rdev != VNOVAL) || 1249152825Sdavidxu ((int)vap->va_bytes != VNOVAL) || 1250152825Sdavidxu (vap->va_gen != VNOVAL)) { 1251152825Sdavidxu return (EINVAL); 1252152825Sdavidxu } 1253152825Sdavidxu 1254152825Sdavidxu pn = VTON(vp); 1255152825Sdavidxu 1256152825Sdavidxu error = c = 0; 1257152825Sdavidxu if (vap->va_uid == (uid_t)VNOVAL) 1258152825Sdavidxu uid = pn->mn_uid; 1259152825Sdavidxu else 1260152825Sdavidxu uid = vap->va_uid; 1261152825Sdavidxu if (vap->va_gid == (gid_t)VNOVAL) 1262152825Sdavidxu gid = pn->mn_gid; 1263152825Sdavidxu else 1264152825Sdavidxu gid = vap->va_gid; 1265152825Sdavidxu 1266152825Sdavidxu if (uid != pn->mn_uid || gid != pn->mn_gid) { 1267152825Sdavidxu /* 1268152825Sdavidxu * To modify the ownership of a file, must possess VADMIN 1269152825Sdavidxu * for that file. 1270152825Sdavidxu */ 1271182371Sattilio if ((error = VOP_ACCESS(vp, VADMIN, ap->a_cred, td))) 1272152825Sdavidxu return (error); 1273164033Srwatson 1274164033Srwatson /* 1275164033Srwatson * XXXRW: Why is there a privilege check here: shouldn't the 1276164033Srwatson * check in VOP_ACCESS() be enough? Also, are the group bits 1277164033Srwatson * below definitely right? 1278164033Srwatson */ 1279152825Sdavidxu if (((ap->a_cred->cr_uid != pn->mn_uid) || uid != pn->mn_uid || 1280152825Sdavidxu (gid != pn->mn_gid && !groupmember(gid, ap->a_cred))) && 1281182371Sattilio (error = priv_check(td, PRIV_MQ_ADMIN)) != 0) 1282152825Sdavidxu return (error); 1283152825Sdavidxu pn->mn_uid = uid; 1284152825Sdavidxu pn->mn_gid = gid; 1285152825Sdavidxu c = 1; 1286152825Sdavidxu } 1287152825Sdavidxu 1288152825Sdavidxu if (vap->va_mode != (mode_t)VNOVAL) { 1289152825Sdavidxu if ((ap->a_cred->cr_uid != pn->mn_uid) && 1290182371Sattilio (error = priv_check(td, PRIV_MQ_ADMIN))) 1291152825Sdavidxu return (error); 1292152825Sdavidxu pn->mn_mode = vap->va_mode; 1293152825Sdavidxu c = 1; 1294152825Sdavidxu } 1295152825Sdavidxu 1296152825Sdavidxu if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { 1297152825Sdavidxu /* See the comment in ufs_vnops::ufs_setattr(). */ 1298182371Sattilio if ((error = VOP_ACCESS(vp, VADMIN, ap->a_cred, td)) && 1299152825Sdavidxu ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || 1300182371Sattilio (error = VOP_ACCESS(vp, VWRITE, ap->a_cred, td)))) 1301152825Sdavidxu return (error); 1302152825Sdavidxu if (vap->va_atime.tv_sec != VNOVAL) { 1303152825Sdavidxu pn->mn_atime = vap->va_atime; 1304152825Sdavidxu } 1305152825Sdavidxu if (vap->va_mtime.tv_sec != VNOVAL) { 1306152825Sdavidxu pn->mn_mtime = vap->va_mtime; 1307152825Sdavidxu } 1308152825Sdavidxu c = 1; 1309152825Sdavidxu } 1310152825Sdavidxu if (c) { 1311152825Sdavidxu vfs_timestamp(&pn->mn_ctime); 1312152825Sdavidxu } 1313152825Sdavidxu return (0); 1314152825Sdavidxu} 1315152825Sdavidxu 1316152825Sdavidxu#if 0 1317152825Sdavidxustruct vop_read_args { 1318152825Sdavidxu struct vop_generic_args a_gen; 1319152825Sdavidxu struct vnode *a_vp; 1320152825Sdavidxu struct uio *a_uio; 1321152825Sdavidxu int a_ioflag; 1322152825Sdavidxu struct ucred *a_cred; 1323152825Sdavidxu}; 1324152825Sdavidxu#endif 1325152825Sdavidxu 1326152825Sdavidxu/* 1327152825Sdavidxu * Read from a file 1328152825Sdavidxu */ 1329152825Sdavidxustatic int 1330152825Sdavidxumqfs_read(struct vop_read_args *ap) 1331152825Sdavidxu{ 1332152825Sdavidxu char buf[80]; 1333152825Sdavidxu struct vnode *vp = ap->a_vp; 1334152825Sdavidxu struct uio *uio = ap->a_uio; 1335152825Sdavidxu struct mqfs_node *pn; 1336152825Sdavidxu struct mqueue *mq; 1337152825Sdavidxu int len, error; 1338152825Sdavidxu 1339152825Sdavidxu if (vp->v_type != VREG) 1340152825Sdavidxu return (EINVAL); 1341152825Sdavidxu 1342152825Sdavidxu pn = VTON(vp); 1343152825Sdavidxu mq = VTOMQ(vp); 1344152825Sdavidxu snprintf(buf, sizeof(buf), 1345152825Sdavidxu "QSIZE:%-10ld MAXMSG:%-10ld CURMSG:%-10ld MSGSIZE:%-10ld\n", 1346152825Sdavidxu mq->mq_totalbytes, 1347152825Sdavidxu mq->mq_maxmsg, 1348152825Sdavidxu mq->mq_curmsgs, 1349152825Sdavidxu mq->mq_msgsize); 1350152825Sdavidxu buf[sizeof(buf)-1] = '\0'; 1351152825Sdavidxu len = strlen(buf); 1352152825Sdavidxu error = uiomove_frombuf(buf, len, uio); 1353152825Sdavidxu return (error); 1354152825Sdavidxu} 1355152825Sdavidxu 1356152825Sdavidxu#if 0 1357152825Sdavidxustruct vop_readdir_args { 1358152825Sdavidxu struct vop_generic_args a_gen; 1359152825Sdavidxu struct vnode *a_vp; 1360152825Sdavidxu struct uio *a_uio; 1361152825Sdavidxu struct ucred *a_cred; 1362152825Sdavidxu int *a_eofflag; 1363152825Sdavidxu int *a_ncookies; 1364152825Sdavidxu u_long **a_cookies; 1365152825Sdavidxu}; 1366152825Sdavidxu#endif 1367152825Sdavidxu 1368152825Sdavidxu/* 1369152825Sdavidxu * Return directory entries. 1370152825Sdavidxu */ 1371152825Sdavidxustatic int 1372152825Sdavidxumqfs_readdir(struct vop_readdir_args *ap) 1373152825Sdavidxu{ 1374152825Sdavidxu struct vnode *vp; 1375152825Sdavidxu struct mqfs_info *mi; 1376152825Sdavidxu struct mqfs_node *pd; 1377152825Sdavidxu struct mqfs_node *pn; 1378152825Sdavidxu struct dirent entry; 1379152825Sdavidxu struct uio *uio; 1380297936Sjamie const void *pr_root; 1381152825Sdavidxu int *tmp_ncookies = NULL; 1382152825Sdavidxu off_t offset; 1383152825Sdavidxu int error, i; 1384152825Sdavidxu 1385152825Sdavidxu vp = ap->a_vp; 1386152825Sdavidxu mi = VFSTOMQFS(vp->v_mount); 1387152825Sdavidxu pd = VTON(vp); 1388152825Sdavidxu uio = ap->a_uio; 1389152825Sdavidxu 1390152825Sdavidxu if (vp->v_type != VDIR) 1391152825Sdavidxu return (ENOTDIR); 1392152825Sdavidxu 1393152825Sdavidxu if (uio->uio_offset < 0) 1394152825Sdavidxu return (EINVAL); 1395152825Sdavidxu 1396152825Sdavidxu if (ap->a_ncookies != NULL) { 1397152825Sdavidxu tmp_ncookies = ap->a_ncookies; 1398152825Sdavidxu *ap->a_ncookies = 0; 1399152825Sdavidxu ap->a_ncookies = NULL; 1400152825Sdavidxu } 1401152825Sdavidxu 1402152825Sdavidxu error = 0; 1403152825Sdavidxu offset = 0; 1404152825Sdavidxu 1405297936Sjamie pr_root = ap->a_cred->cr_prison->pr_root; 1406152825Sdavidxu sx_xlock(&mi->mi_lock); 1407152825Sdavidxu 1408152825Sdavidxu LIST_FOREACH(pn, &pd->mn_children, mn_sibling) { 1409152825Sdavidxu entry.d_reclen = sizeof(entry); 1410297976Sjamie 1411297936Sjamie /* 1412297936Sjamie * Only show names within the same prison root directory 1413297936Sjamie * (or not associated with a prison, e.g. "." and ".."). 1414297936Sjamie */ 1415297936Sjamie if (pn->mn_pr_root != NULL && pn->mn_pr_root != pr_root) 1416297936Sjamie continue; 1417152825Sdavidxu if (!pn->mn_fileno) 1418152825Sdavidxu mqfs_fileno_alloc(mi, pn); 1419152825Sdavidxu entry.d_fileno = pn->mn_fileno; 1420152825Sdavidxu for (i = 0; i < MQFS_NAMELEN - 1 && pn->mn_name[i] != '\0'; ++i) 1421152825Sdavidxu entry.d_name[i] = pn->mn_name[i]; 1422152825Sdavidxu entry.d_name[i] = 0; 1423152825Sdavidxu entry.d_namlen = i; 1424152825Sdavidxu switch (pn->mn_type) { 1425152825Sdavidxu case mqfstype_root: 1426152825Sdavidxu case mqfstype_dir: 1427152825Sdavidxu case mqfstype_this: 1428152825Sdavidxu case mqfstype_parent: 1429152825Sdavidxu entry.d_type = DT_DIR; 1430152825Sdavidxu break; 1431152825Sdavidxu case mqfstype_file: 1432152825Sdavidxu entry.d_type = DT_REG; 1433152825Sdavidxu break; 1434152825Sdavidxu case mqfstype_symlink: 1435152825Sdavidxu entry.d_type = DT_LNK; 1436152825Sdavidxu break; 1437152825Sdavidxu default: 1438152825Sdavidxu panic("%s has unexpected node type: %d", pn->mn_name, 1439152825Sdavidxu pn->mn_type); 1440152825Sdavidxu } 1441152825Sdavidxu if (entry.d_reclen > uio->uio_resid) 1442152825Sdavidxu break; 1443152825Sdavidxu if (offset >= uio->uio_offset) { 1444152825Sdavidxu error = vfs_read_dirent(ap, &entry, offset); 1445152825Sdavidxu if (error) 1446152825Sdavidxu break; 1447152825Sdavidxu } 1448152825Sdavidxu offset += entry.d_reclen; 1449152825Sdavidxu } 1450152825Sdavidxu sx_xunlock(&mi->mi_lock); 1451152825Sdavidxu 1452152825Sdavidxu uio->uio_offset = offset; 1453152825Sdavidxu 1454152825Sdavidxu if (tmp_ncookies != NULL) 1455152825Sdavidxu ap->a_ncookies = tmp_ncookies; 1456152825Sdavidxu 1457152825Sdavidxu return (error); 1458152825Sdavidxu} 1459152825Sdavidxu 1460152825Sdavidxu#ifdef notyet 1461152825Sdavidxu 1462152825Sdavidxu#if 0 1463152825Sdavidxustruct vop_mkdir_args { 1464152825Sdavidxu struct vnode *a_dvp; 1465152825Sdavidxu struvt vnode **a_vpp; 1466152825Sdavidxu struvt componentname *a_cnp; 1467152825Sdavidxu struct vattr *a_vap; 1468152825Sdavidxu}; 1469152825Sdavidxu#endif 1470152825Sdavidxu 1471152825Sdavidxu/* 1472152825Sdavidxu * Create a directory. 1473152825Sdavidxu */ 1474152825Sdavidxustatic int 1475152825Sdavidxumqfs_mkdir(struct vop_mkdir_args *ap) 1476152825Sdavidxu{ 1477152825Sdavidxu struct mqfs_info *mqfs = VFSTOMQFS(ap->a_dvp->v_mount); 1478152825Sdavidxu struct componentname *cnp = ap->a_cnp; 1479152825Sdavidxu struct mqfs_node *pd = VTON(ap->a_dvp); 1480152825Sdavidxu struct mqfs_node *pn; 1481152825Sdavidxu int error; 1482152825Sdavidxu 1483152825Sdavidxu if (pd->mn_type != mqfstype_root && pd->mn_type != mqfstype_dir) 1484152825Sdavidxu return (ENOTDIR); 1485152825Sdavidxu sx_xlock(&mqfs->mi_lock); 1486152825Sdavidxu if ((cnp->cn_flags & HASBUF) == 0) 1487152825Sdavidxu panic("%s: no name", __func__); 1488155889Sdavidxu pn = mqfs_create_dir(pd, cnp->cn_nameptr, cnp->cn_namelen, 1489155889Sdavidxu ap->a_vap->cn_cred, ap->a_vap->va_mode); 1490182782Sdavidxu if (pn != NULL) 1491182782Sdavidxu mqnode_addref(pn); 1492182782Sdavidxu sx_xunlock(&mqfs->mi_lock); 1493182782Sdavidxu if (pn == NULL) { 1494155889Sdavidxu error = ENOSPC; 1495182782Sdavidxu } else { 1496155889Sdavidxu error = mqfs_allocv(ap->a_dvp->v_mount, ap->a_vpp, pn); 1497182782Sdavidxu mqnode_release(pn); 1498182782Sdavidxu } 1499152825Sdavidxu return (error); 1500152825Sdavidxu} 1501152825Sdavidxu 1502152825Sdavidxu#if 0 1503152825Sdavidxustruct vop_rmdir_args { 1504152825Sdavidxu struct vnode *a_dvp; 1505152825Sdavidxu struct vnode *a_vp; 1506152825Sdavidxu struct componentname *a_cnp; 1507152825Sdavidxu}; 1508152825Sdavidxu#endif 1509152825Sdavidxu 1510152825Sdavidxu/* 1511152825Sdavidxu * Remove a directory. 1512152825Sdavidxu */ 1513152825Sdavidxustatic int 1514152825Sdavidxumqfs_rmdir(struct vop_rmdir_args *ap) 1515152825Sdavidxu{ 1516152825Sdavidxu struct mqfs_info *mqfs = VFSTOMQFS(ap->a_dvp->v_mount); 1517152825Sdavidxu struct mqfs_node *pn = VTON(ap->a_vp); 1518152825Sdavidxu struct mqfs_node *pt; 1519152825Sdavidxu 1520152825Sdavidxu if (pn->mn_type != mqfstype_dir) 1521152825Sdavidxu return (ENOTDIR); 1522152825Sdavidxu 1523152825Sdavidxu sx_xlock(&mqfs->mi_lock); 1524152825Sdavidxu if (pn->mn_deleted) { 1525152825Sdavidxu sx_xunlock(&mqfs->mi_lock); 1526152825Sdavidxu return (ENOENT); 1527152825Sdavidxu } 1528152825Sdavidxu 1529152825Sdavidxu pt = LIST_FIRST(&pn->mn_children); 1530152825Sdavidxu pt = LIST_NEXT(pt, mn_sibling); 1531152825Sdavidxu pt = LIST_NEXT(pt, mn_sibling); 1532152825Sdavidxu if (pt != NULL) { 1533152825Sdavidxu sx_xunlock(&mqfs->mi_lock); 1534152825Sdavidxu return (ENOTEMPTY); 1535152825Sdavidxu } 1536152825Sdavidxu pt = pn->mn_parent; 1537152825Sdavidxu pn->mn_parent = NULL; 1538152825Sdavidxu pn->mn_deleted = 1; 1539152825Sdavidxu LIST_REMOVE(pn, mn_sibling); 1540152825Sdavidxu mqnode_release(pn); 1541152825Sdavidxu mqnode_release(pt); 1542152825Sdavidxu sx_xunlock(&mqfs->mi_lock); 1543152825Sdavidxu cache_purge(ap->a_vp); 1544152825Sdavidxu return (0); 1545152825Sdavidxu} 1546152825Sdavidxu 1547152825Sdavidxu#endif /* notyet */ 1548152825Sdavidxu 1549152825Sdavidxu/* 1550298567Sjamie * See if this prison root is obsolete, and clean up associated queues if it is. 1551297936Sjamie */ 1552297936Sjamiestatic int 1553298567Sjamiemqfs_prison_remove(void *obj, void *data __unused) 1554297936Sjamie{ 1555298567Sjamie const struct prison *pr = obj; 1556298567Sjamie const struct prison *tpr; 1557297936Sjamie struct mqfs_node *pn, *tpn; 1558297936Sjamie int found; 1559297936Sjamie 1560297936Sjamie found = 0; 1561298567Sjamie TAILQ_FOREACH(tpr, &allprison, pr_list) { 1562298567Sjamie if (tpr->pr_root == pr->pr_root && tpr != pr && tpr->pr_ref > 0) 1563297936Sjamie found = 1; 1564297936Sjamie } 1565297936Sjamie if (!found) { 1566297936Sjamie /* 1567297936Sjamie * No jails are rooted in this directory anymore, 1568297936Sjamie * so no queues should be either. 1569297936Sjamie */ 1570297936Sjamie sx_xlock(&mqfs_data.mi_lock); 1571297936Sjamie LIST_FOREACH_SAFE(pn, &mqfs_data.mi_root->mn_children, 1572297936Sjamie mn_sibling, tpn) { 1573298567Sjamie if (pn->mn_pr_root == pr->pr_root) 1574297936Sjamie (void)do_unlink(pn, curthread->td_ucred); 1575297936Sjamie } 1576297936Sjamie sx_xunlock(&mqfs_data.mi_lock); 1577297936Sjamie } 1578298567Sjamie return (0); 1579297936Sjamie} 1580297936Sjamie 1581297936Sjamie/* 1582152825Sdavidxu * Allocate a message queue 1583152825Sdavidxu */ 1584152825Sdavidxustatic struct mqueue * 1585152825Sdavidxumqueue_alloc(const struct mq_attr *attr) 1586152825Sdavidxu{ 1587152825Sdavidxu struct mqueue *mq; 1588152825Sdavidxu 1589152825Sdavidxu if (curmq >= maxmq) 1590152825Sdavidxu return (NULL); 1591152825Sdavidxu mq = uma_zalloc(mqueue_zone, M_WAITOK | M_ZERO); 1592152825Sdavidxu TAILQ_INIT(&mq->mq_msgq); 1593152825Sdavidxu if (attr != NULL) { 1594152825Sdavidxu mq->mq_maxmsg = attr->mq_maxmsg; 1595152825Sdavidxu mq->mq_msgsize = attr->mq_msgsize; 1596152825Sdavidxu } else { 1597152825Sdavidxu mq->mq_maxmsg = default_maxmsg; 1598152825Sdavidxu mq->mq_msgsize = default_msgsize; 1599152825Sdavidxu } 1600182776Sdavidxu mtx_init(&mq->mq_mutex, "mqueue lock", NULL, MTX_DEF); 1601193951Skib knlist_init_mtx(&mq->mq_rsel.si_note, &mq->mq_mutex); 1602193951Skib knlist_init_mtx(&mq->mq_wsel.si_note, &mq->mq_mutex); 1603152825Sdavidxu atomic_add_int(&curmq, 1); 1604152825Sdavidxu return (mq); 1605152825Sdavidxu} 1606152825Sdavidxu 1607152825Sdavidxu/* 1608152825Sdavidxu * Destroy a message queue 1609152825Sdavidxu */ 1610152825Sdavidxustatic void 1611152825Sdavidxumqueue_free(struct mqueue *mq) 1612152825Sdavidxu{ 1613152825Sdavidxu struct mqueue_msg *msg; 1614152825Sdavidxu 1615152825Sdavidxu while ((msg = TAILQ_FIRST(&mq->mq_msgq)) != NULL) { 1616152825Sdavidxu TAILQ_REMOVE(&mq->mq_msgq, msg, msg_link); 1617184205Sdes free(msg, M_MQUEUEDATA); 1618152825Sdavidxu } 1619152825Sdavidxu 1620152825Sdavidxu mtx_destroy(&mq->mq_mutex); 1621225177Sattilio seldrain(&mq->mq_rsel); 1622225177Sattilio seldrain(&mq->mq_wsel); 1623152825Sdavidxu knlist_destroy(&mq->mq_rsel.si_note); 1624152825Sdavidxu knlist_destroy(&mq->mq_wsel.si_note); 1625152825Sdavidxu uma_zfree(mqueue_zone, mq); 1626152825Sdavidxu atomic_add_int(&curmq, -1); 1627152825Sdavidxu} 1628152825Sdavidxu 1629152825Sdavidxu/* 1630152825Sdavidxu * Load a message from user space 1631152825Sdavidxu */ 1632152825Sdavidxustatic struct mqueue_msg * 1633152825Sdavidxumqueue_loadmsg(const char *msg_ptr, size_t msg_size, int msg_prio) 1634152825Sdavidxu{ 1635152825Sdavidxu struct mqueue_msg *msg; 1636152825Sdavidxu size_t len; 1637152825Sdavidxu int error; 1638152825Sdavidxu 1639152825Sdavidxu len = sizeof(struct mqueue_msg) + msg_size; 1640184205Sdes msg = malloc(len, M_MQUEUEDATA, M_WAITOK); 1641152825Sdavidxu error = copyin(msg_ptr, ((char *)msg) + sizeof(struct mqueue_msg), 1642152825Sdavidxu msg_size); 1643152825Sdavidxu if (error) { 1644184205Sdes free(msg, M_MQUEUEDATA); 1645152825Sdavidxu msg = NULL; 1646152825Sdavidxu } else { 1647152825Sdavidxu msg->msg_size = msg_size; 1648152825Sdavidxu msg->msg_prio = msg_prio; 1649152825Sdavidxu } 1650152825Sdavidxu return (msg); 1651152825Sdavidxu} 1652152825Sdavidxu 1653152825Sdavidxu/* 1654152825Sdavidxu * Save a message to user space 1655152825Sdavidxu */ 1656152825Sdavidxustatic int 1657152825Sdavidxumqueue_savemsg(struct mqueue_msg *msg, char *msg_ptr, int *msg_prio) 1658152825Sdavidxu{ 1659152825Sdavidxu int error; 1660152825Sdavidxu 1661152825Sdavidxu error = copyout(((char *)msg) + sizeof(*msg), msg_ptr, 1662152825Sdavidxu msg->msg_size); 1663152948Sdavidxu if (error == 0 && msg_prio != NULL) 1664152825Sdavidxu error = copyout(&msg->msg_prio, msg_prio, sizeof(int)); 1665152825Sdavidxu return (error); 1666152825Sdavidxu} 1667152825Sdavidxu 1668152825Sdavidxu/* 1669152825Sdavidxu * Free a message's memory 1670152825Sdavidxu */ 1671152825Sdavidxustatic __inline void 1672152825Sdavidxumqueue_freemsg(struct mqueue_msg *msg) 1673152825Sdavidxu{ 1674184205Sdes free(msg, M_MQUEUEDATA); 1675152825Sdavidxu} 1676152825Sdavidxu 1677152825Sdavidxu/* 1678152825Sdavidxu * Send a message. if waitok is false, thread will not be 1679152825Sdavidxu * blocked if there is no data in queue, otherwise, absolute 1680152825Sdavidxu * time will be checked. 1681152825Sdavidxu */ 1682152825Sdavidxuint 1683152825Sdavidxumqueue_send(struct mqueue *mq, const char *msg_ptr, 1684152825Sdavidxu size_t msg_len, unsigned msg_prio, int waitok, 1685152825Sdavidxu const struct timespec *abs_timeout) 1686152825Sdavidxu{ 1687152825Sdavidxu struct mqueue_msg *msg; 1688205325Skib struct timespec ts, ts2; 1689152825Sdavidxu struct timeval tv; 1690152825Sdavidxu int error; 1691152825Sdavidxu 1692153011Sdavidxu if (msg_prio >= MQ_PRIO_MAX) 1693153011Sdavidxu return (EINVAL); 1694152825Sdavidxu if (msg_len > mq->mq_msgsize) 1695152825Sdavidxu return (EMSGSIZE); 1696152825Sdavidxu msg = mqueue_loadmsg(msg_ptr, msg_len, msg_prio); 1697152825Sdavidxu if (msg == NULL) 1698152825Sdavidxu return (EFAULT); 1699152825Sdavidxu 1700152825Sdavidxu /* O_NONBLOCK case */ 1701152825Sdavidxu if (!waitok) { 1702152825Sdavidxu error = _mqueue_send(mq, msg, -1); 1703152825Sdavidxu if (error) 1704152825Sdavidxu goto bad; 1705152825Sdavidxu return (0); 1706152825Sdavidxu } 1707152825Sdavidxu 1708152825Sdavidxu /* we allow a null timeout (wait forever) */ 1709152825Sdavidxu if (abs_timeout == NULL) { 1710152825Sdavidxu error = _mqueue_send(mq, msg, 0); 1711152825Sdavidxu if (error) 1712152825Sdavidxu goto bad; 1713152825Sdavidxu return (0); 1714152825Sdavidxu } 1715152825Sdavidxu 1716152825Sdavidxu /* send it before checking time */ 1717152825Sdavidxu error = _mqueue_send(mq, msg, -1); 1718152825Sdavidxu if (error == 0) 1719152825Sdavidxu return (0); 1720152825Sdavidxu 1721152825Sdavidxu if (error != EAGAIN) 1722152825Sdavidxu goto bad; 1723152825Sdavidxu 1724205325Skib if (abs_timeout->tv_nsec >= 1000000000 || abs_timeout->tv_nsec < 0) { 1725152825Sdavidxu error = EINVAL; 1726152825Sdavidxu goto bad; 1727152825Sdavidxu } 1728152825Sdavidxu for (;;) { 1729205325Skib ts2 = *abs_timeout; 1730153011Sdavidxu getnanotime(&ts); 1731152825Sdavidxu timespecsub(&ts2, &ts); 1732152825Sdavidxu if (ts2.tv_sec < 0 || (ts2.tv_sec == 0 && ts2.tv_nsec <= 0)) { 1733152825Sdavidxu error = ETIMEDOUT; 1734152825Sdavidxu break; 1735152825Sdavidxu } 1736152825Sdavidxu TIMESPEC_TO_TIMEVAL(&tv, &ts2); 1737152825Sdavidxu error = _mqueue_send(mq, msg, tvtohz(&tv)); 1738152825Sdavidxu if (error != ETIMEDOUT) 1739152825Sdavidxu break; 1740152825Sdavidxu } 1741152825Sdavidxu if (error == 0) 1742152825Sdavidxu return (0); 1743152825Sdavidxubad: 1744152825Sdavidxu mqueue_freemsg(msg); 1745152825Sdavidxu return (error); 1746152825Sdavidxu} 1747152825Sdavidxu 1748152825Sdavidxu/* 1749152825Sdavidxu * Common routine to send a message 1750152825Sdavidxu */ 1751152825Sdavidxustatic int 1752152825Sdavidxu_mqueue_send(struct mqueue *mq, struct mqueue_msg *msg, int timo) 1753152825Sdavidxu{ 1754152825Sdavidxu struct mqueue_msg *msg2; 1755152825Sdavidxu int error = 0; 1756152825Sdavidxu 1757152825Sdavidxu mtx_lock(&mq->mq_mutex); 1758152825Sdavidxu while (mq->mq_curmsgs >= mq->mq_maxmsg && error == 0) { 1759152825Sdavidxu if (timo < 0) { 1760152825Sdavidxu mtx_unlock(&mq->mq_mutex); 1761152825Sdavidxu return (EAGAIN); 1762152825Sdavidxu } 1763152825Sdavidxu mq->mq_senders++; 1764152825Sdavidxu error = msleep(&mq->mq_senders, &mq->mq_mutex, 1765157815Sjhb PCATCH, "mqsend", timo); 1766152825Sdavidxu mq->mq_senders--; 1767152825Sdavidxu if (error == EAGAIN) 1768152825Sdavidxu error = ETIMEDOUT; 1769152825Sdavidxu } 1770152825Sdavidxu if (mq->mq_curmsgs >= mq->mq_maxmsg) { 1771152825Sdavidxu mtx_unlock(&mq->mq_mutex); 1772152825Sdavidxu return (error); 1773152825Sdavidxu } 1774152825Sdavidxu error = 0; 1775152825Sdavidxu if (TAILQ_EMPTY(&mq->mq_msgq)) { 1776152825Sdavidxu TAILQ_INSERT_HEAD(&mq->mq_msgq, msg, msg_link); 1777152825Sdavidxu } else { 1778152825Sdavidxu if (msg->msg_prio <= TAILQ_LAST(&mq->mq_msgq, msgq)->msg_prio) { 1779152825Sdavidxu TAILQ_INSERT_TAIL(&mq->mq_msgq, msg, msg_link); 1780152825Sdavidxu } else { 1781152825Sdavidxu TAILQ_FOREACH(msg2, &mq->mq_msgq, msg_link) { 1782152825Sdavidxu if (msg2->msg_prio < msg->msg_prio) 1783152825Sdavidxu break; 1784152825Sdavidxu } 1785152825Sdavidxu TAILQ_INSERT_BEFORE(msg2, msg, msg_link); 1786152825Sdavidxu } 1787152825Sdavidxu } 1788152825Sdavidxu mq->mq_curmsgs++; 1789152825Sdavidxu mq->mq_totalbytes += msg->msg_size; 1790152825Sdavidxu if (mq->mq_receivers) 1791152825Sdavidxu wakeup_one(&mq->mq_receivers); 1792152825Sdavidxu else if (mq->mq_notifier != NULL) 1793152825Sdavidxu mqueue_send_notification(mq); 1794152825Sdavidxu if (mq->mq_flags & MQ_RSEL) { 1795152825Sdavidxu mq->mq_flags &= ~MQ_RSEL; 1796153477Sdavidxu selwakeup(&mq->mq_rsel); 1797152825Sdavidxu } 1798152825Sdavidxu KNOTE_LOCKED(&mq->mq_rsel.si_note, 0); 1799152825Sdavidxu mtx_unlock(&mq->mq_mutex); 1800152825Sdavidxu return (0); 1801152825Sdavidxu} 1802152825Sdavidxu 1803152825Sdavidxu/* 1804152825Sdavidxu * Send realtime a signal to process which registered itself 1805152825Sdavidxu * successfully by mq_notify. 1806152825Sdavidxu */ 1807152825Sdavidxustatic void 1808152825Sdavidxumqueue_send_notification(struct mqueue *mq) 1809152825Sdavidxu{ 1810152948Sdavidxu struct mqueue_notifier *nt; 1811213642Sdavidxu struct thread *td; 1812152948Sdavidxu struct proc *p; 1813213642Sdavidxu int error; 1814152825Sdavidxu 1815152825Sdavidxu mtx_assert(&mq->mq_mutex, MA_OWNED); 1816152948Sdavidxu nt = mq->mq_notifier; 1817153100Sdavidxu if (nt->nt_sigev.sigev_notify != SIGEV_NONE) { 1818153100Sdavidxu p = nt->nt_proc; 1819213642Sdavidxu error = sigev_findtd(p, &nt->nt_sigev, &td); 1820213642Sdavidxu if (error) { 1821213642Sdavidxu mq->mq_notifier = NULL; 1822213642Sdavidxu return; 1823213642Sdavidxu } 1824213642Sdavidxu if (!KSI_ONQ(&nt->nt_ksi)) { 1825213642Sdavidxu ksiginfo_set_sigev(&nt->nt_ksi, &nt->nt_sigev); 1826213642Sdavidxu tdsendsignal(p, td, nt->nt_ksi.ksi_signo, &nt->nt_ksi); 1827213642Sdavidxu } 1828153100Sdavidxu PROC_UNLOCK(p); 1829153100Sdavidxu } 1830152825Sdavidxu mq->mq_notifier = NULL; 1831152825Sdavidxu} 1832152825Sdavidxu 1833152825Sdavidxu/* 1834152825Sdavidxu * Get a message. if waitok is false, thread will not be 1835152825Sdavidxu * blocked if there is no data in queue, otherwise, absolute 1836152825Sdavidxu * time will be checked. 1837152825Sdavidxu */ 1838152825Sdavidxuint 1839152825Sdavidxumqueue_receive(struct mqueue *mq, char *msg_ptr, 1840152825Sdavidxu size_t msg_len, unsigned *msg_prio, int waitok, 1841152825Sdavidxu const struct timespec *abs_timeout) 1842152825Sdavidxu{ 1843152825Sdavidxu struct mqueue_msg *msg; 1844205325Skib struct timespec ts, ts2; 1845152825Sdavidxu struct timeval tv; 1846152825Sdavidxu int error; 1847152825Sdavidxu 1848152825Sdavidxu if (msg_len < mq->mq_msgsize) 1849152825Sdavidxu return (EMSGSIZE); 1850152825Sdavidxu 1851152825Sdavidxu /* O_NONBLOCK case */ 1852152825Sdavidxu if (!waitok) { 1853152825Sdavidxu error = _mqueue_recv(mq, &msg, -1); 1854152825Sdavidxu if (error) 1855152825Sdavidxu return (error); 1856152825Sdavidxu goto received; 1857152825Sdavidxu } 1858152825Sdavidxu 1859152825Sdavidxu /* we allow a null timeout (wait forever). */ 1860152825Sdavidxu if (abs_timeout == NULL) { 1861152825Sdavidxu error = _mqueue_recv(mq, &msg, 0); 1862152825Sdavidxu if (error) 1863152825Sdavidxu return (error); 1864152825Sdavidxu goto received; 1865152825Sdavidxu } 1866152825Sdavidxu 1867152825Sdavidxu /* try to get a message before checking time */ 1868152825Sdavidxu error = _mqueue_recv(mq, &msg, -1); 1869152825Sdavidxu if (error == 0) 1870152825Sdavidxu goto received; 1871152825Sdavidxu 1872152825Sdavidxu if (error != EAGAIN) 1873152825Sdavidxu return (error); 1874152825Sdavidxu 1875205325Skib if (abs_timeout->tv_nsec >= 1000000000 || abs_timeout->tv_nsec < 0) { 1876152825Sdavidxu error = EINVAL; 1877152825Sdavidxu return (error); 1878152825Sdavidxu } 1879152825Sdavidxu 1880152825Sdavidxu for (;;) { 1881205325Skib ts2 = *abs_timeout; 1882153011Sdavidxu getnanotime(&ts); 1883152825Sdavidxu timespecsub(&ts2, &ts); 1884152825Sdavidxu if (ts2.tv_sec < 0 || (ts2.tv_sec == 0 && ts2.tv_nsec <= 0)) { 1885152825Sdavidxu error = ETIMEDOUT; 1886152825Sdavidxu return (error); 1887152825Sdavidxu } 1888152825Sdavidxu TIMESPEC_TO_TIMEVAL(&tv, &ts2); 1889152825Sdavidxu error = _mqueue_recv(mq, &msg, tvtohz(&tv)); 1890152825Sdavidxu if (error == 0) 1891152825Sdavidxu break; 1892152825Sdavidxu if (error != ETIMEDOUT) 1893152825Sdavidxu return (error); 1894152825Sdavidxu } 1895152825Sdavidxu 1896152825Sdavidxureceived: 1897152825Sdavidxu error = mqueue_savemsg(msg, msg_ptr, msg_prio); 1898152825Sdavidxu if (error == 0) { 1899152825Sdavidxu curthread->td_retval[0] = msg->msg_size; 1900152825Sdavidxu curthread->td_retval[1] = 0; 1901152825Sdavidxu } 1902152825Sdavidxu mqueue_freemsg(msg); 1903152825Sdavidxu return (error); 1904152825Sdavidxu} 1905152825Sdavidxu 1906152825Sdavidxu/* 1907152825Sdavidxu * Common routine to receive a message 1908152825Sdavidxu */ 1909152825Sdavidxustatic int 1910152825Sdavidxu_mqueue_recv(struct mqueue *mq, struct mqueue_msg **msg, int timo) 1911152825Sdavidxu{ 1912152825Sdavidxu int error = 0; 1913152825Sdavidxu 1914152825Sdavidxu mtx_lock(&mq->mq_mutex); 1915152825Sdavidxu while ((*msg = TAILQ_FIRST(&mq->mq_msgq)) == NULL && error == 0) { 1916152825Sdavidxu if (timo < 0) { 1917152825Sdavidxu mtx_unlock(&mq->mq_mutex); 1918152825Sdavidxu return (EAGAIN); 1919152825Sdavidxu } 1920152825Sdavidxu mq->mq_receivers++; 1921152825Sdavidxu error = msleep(&mq->mq_receivers, &mq->mq_mutex, 1922157815Sjhb PCATCH, "mqrecv", timo); 1923152825Sdavidxu mq->mq_receivers--; 1924152825Sdavidxu if (error == EAGAIN) 1925152825Sdavidxu error = ETIMEDOUT; 1926152825Sdavidxu } 1927152825Sdavidxu if (*msg != NULL) { 1928152825Sdavidxu error = 0; 1929152825Sdavidxu TAILQ_REMOVE(&mq->mq_msgq, *msg, msg_link); 1930152825Sdavidxu mq->mq_curmsgs--; 1931152825Sdavidxu mq->mq_totalbytes -= (*msg)->msg_size; 1932152825Sdavidxu if (mq->mq_senders) 1933152825Sdavidxu wakeup_one(&mq->mq_senders); 1934152825Sdavidxu if (mq->mq_flags & MQ_WSEL) { 1935152825Sdavidxu mq->mq_flags &= ~MQ_WSEL; 1936153477Sdavidxu selwakeup(&mq->mq_wsel); 1937152825Sdavidxu } 1938152825Sdavidxu KNOTE_LOCKED(&mq->mq_wsel.si_note, 0); 1939152825Sdavidxu } 1940152825Sdavidxu if (mq->mq_notifier != NULL && mq->mq_receivers == 0 && 1941152825Sdavidxu !TAILQ_EMPTY(&mq->mq_msgq)) { 1942152825Sdavidxu mqueue_send_notification(mq); 1943152825Sdavidxu } 1944152825Sdavidxu mtx_unlock(&mq->mq_mutex); 1945152825Sdavidxu return (error); 1946152825Sdavidxu} 1947152825Sdavidxu 1948152948Sdavidxustatic __inline struct mqueue_notifier * 1949152948Sdavidxunotifier_alloc(void) 1950152825Sdavidxu{ 1951152948Sdavidxu return (uma_zalloc(mqnoti_zone, M_WAITOK | M_ZERO)); 1952152825Sdavidxu} 1953152825Sdavidxu 1954152825Sdavidxustatic __inline void 1955152948Sdavidxunotifier_free(struct mqueue_notifier *p) 1956152825Sdavidxu{ 1957152948Sdavidxu uma_zfree(mqnoti_zone, p); 1958152825Sdavidxu} 1959152825Sdavidxu 1960152948Sdavidxustatic struct mqueue_notifier * 1961152948Sdavidxunotifier_search(struct proc *p, int fd) 1962152948Sdavidxu{ 1963152948Sdavidxu struct mqueue_notifier *nt; 1964152948Sdavidxu 1965152948Sdavidxu LIST_FOREACH(nt, &p->p_mqnotifier, nt_link) { 1966153155Sdavidxu if (nt->nt_ksi.ksi_mqd == fd) 1967152948Sdavidxu break; 1968152948Sdavidxu } 1969152948Sdavidxu return (nt); 1970152948Sdavidxu} 1971152948Sdavidxu 1972153254Sdavidxustatic __inline void 1973152948Sdavidxunotifier_insert(struct proc *p, struct mqueue_notifier *nt) 1974152948Sdavidxu{ 1975152948Sdavidxu LIST_INSERT_HEAD(&p->p_mqnotifier, nt, nt_link); 1976152948Sdavidxu} 1977152948Sdavidxu 1978153254Sdavidxustatic __inline void 1979152948Sdavidxunotifier_delete(struct proc *p, struct mqueue_notifier *nt) 1980152948Sdavidxu{ 1981152948Sdavidxu LIST_REMOVE(nt, nt_link); 1982152948Sdavidxu notifier_free(nt); 1983152948Sdavidxu} 1984152948Sdavidxu 1985152948Sdavidxustatic void 1986152948Sdavidxunotifier_remove(struct proc *p, struct mqueue *mq, int fd) 1987152948Sdavidxu{ 1988152948Sdavidxu struct mqueue_notifier *nt; 1989152948Sdavidxu 1990152948Sdavidxu mtx_assert(&mq->mq_mutex, MA_OWNED); 1991152948Sdavidxu PROC_LOCK(p); 1992152948Sdavidxu nt = notifier_search(p, fd); 1993152948Sdavidxu if (nt != NULL) { 1994152948Sdavidxu if (mq->mq_notifier == nt) 1995152948Sdavidxu mq->mq_notifier = NULL; 1996152948Sdavidxu sigqueue_take(&nt->nt_ksi); 1997152948Sdavidxu notifier_delete(p, nt); 1998152948Sdavidxu } 1999152948Sdavidxu PROC_UNLOCK(p); 2000152948Sdavidxu} 2001152948Sdavidxu 2002205325Skibstatic int 2003205325Skibkern_kmq_open(struct thread *td, const char *upath, int flags, mode_t mode, 2004205325Skib const struct mq_attr *attr) 2005152825Sdavidxu{ 2006152948Sdavidxu char path[MQFS_NAMELEN + 1]; 2007152825Sdavidxu struct mqfs_node *pn; 2008152825Sdavidxu struct filedesc *fdp; 2009152825Sdavidxu struct file *fp; 2010152825Sdavidxu struct mqueue *mq; 2011205325Skib int fd, error, len, cmode; 2012152825Sdavidxu 2013152825Sdavidxu fdp = td->td_proc->p_fd; 2014205325Skib cmode = (((mode & ~fdp->fd_cmask) & ALLPERMS) & ~S_ISTXT); 2015152864Sdavidxu mq = NULL; 2016205325Skib if ((flags & O_CREAT) != 0 && attr != NULL) { 2017205325Skib if (attr->mq_maxmsg <= 0 || attr->mq_maxmsg > maxmsg) 2018152825Sdavidxu return (EINVAL); 2019205325Skib if (attr->mq_msgsize <= 0 || attr->mq_msgsize > maxmsgsize) 2020152825Sdavidxu return (EINVAL); 2021205325Skib } 2022152825Sdavidxu 2023205325Skib error = copyinstr(upath, path, MQFS_NAMELEN + 1, NULL); 2024152825Sdavidxu if (error) 2025152948Sdavidxu return (error); 2026152825Sdavidxu 2027152825Sdavidxu /* 2028152825Sdavidxu * The first character of name must be a slash (/) character 2029152825Sdavidxu * and the remaining characters of name cannot include any slash 2030152825Sdavidxu * characters. 2031152825Sdavidxu */ 2032152825Sdavidxu len = strlen(path); 2033229272Sed if (len < 2 || path[0] != '/' || strchr(path + 1, '/') != NULL) 2034152825Sdavidxu return (EINVAL); 2035152825Sdavidxu 2036249233Sjilles error = falloc(td, &fp, &fd, O_CLOEXEC); 2037152825Sdavidxu if (error) 2038152825Sdavidxu return (error); 2039152825Sdavidxu 2040152825Sdavidxu sx_xlock(&mqfs_data.mi_lock); 2041297936Sjamie pn = mqfs_search(mqfs_data.mi_root, path + 1, len - 1, td->td_ucred); 2042152825Sdavidxu if (pn == NULL) { 2043152825Sdavidxu if (!(flags & O_CREAT)) { 2044152825Sdavidxu error = ENOENT; 2045152825Sdavidxu } else { 2046205325Skib mq = mqueue_alloc(attr); 2047152948Sdavidxu if (mq == NULL) { 2048152948Sdavidxu error = ENFILE; 2049152948Sdavidxu } else { 2050152825Sdavidxu pn = mqfs_create_file(mqfs_data.mi_root, 2051155889Sdavidxu path + 1, len - 1, td->td_ucred, 2052155889Sdavidxu cmode); 2053152948Sdavidxu if (pn == NULL) { 2054152948Sdavidxu error = ENOSPC; 2055152825Sdavidxu mqueue_free(mq); 2056152948Sdavidxu } 2057152825Sdavidxu } 2058152825Sdavidxu } 2059152825Sdavidxu 2060152825Sdavidxu if (error == 0) { 2061152825Sdavidxu pn->mn_data = mq; 2062152825Sdavidxu } 2063152825Sdavidxu } else { 2064152825Sdavidxu if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) { 2065152825Sdavidxu error = EEXIST; 2066152825Sdavidxu } else { 2067184413Strasz accmode_t accmode = 0; 2068152825Sdavidxu 2069152825Sdavidxu if (flags & FREAD) 2070184413Strasz accmode |= VREAD; 2071152825Sdavidxu if (flags & FWRITE) 2072184413Strasz accmode |= VWRITE; 2073152825Sdavidxu error = vaccess(VREG, pn->mn_mode, pn->mn_uid, 2074184413Strasz pn->mn_gid, accmode, td->td_ucred, NULL); 2075152825Sdavidxu } 2076152825Sdavidxu } 2077152825Sdavidxu 2078152825Sdavidxu if (error) { 2079152825Sdavidxu sx_xunlock(&mqfs_data.mi_lock); 2080281436Smjg fdclose(td, fp, fd); 2081152825Sdavidxu fdrop(fp, td); 2082152825Sdavidxu return (error); 2083152825Sdavidxu } 2084152825Sdavidxu 2085152825Sdavidxu mqnode_addref(pn); 2086152825Sdavidxu sx_xunlock(&mqfs_data.mi_lock); 2087152825Sdavidxu 2088174988Sjeff finit(fp, flags & (FREAD | FWRITE | O_NONBLOCK), DTYPE_MQUEUE, pn, 2089174988Sjeff &mqueueops); 2090152825Sdavidxu 2091152825Sdavidxu td->td_retval[0] = fd; 2092152825Sdavidxu fdrop(fp, td); 2093152825Sdavidxu return (0); 2094152825Sdavidxu} 2095152825Sdavidxu 2096152825Sdavidxu/* 2097205325Skib * Syscall to open a message queue. 2098205325Skib */ 2099205325Skibint 2100225617Skmacysys_kmq_open(struct thread *td, struct kmq_open_args *uap) 2101205325Skib{ 2102205325Skib struct mq_attr attr; 2103205325Skib int flags, error; 2104205325Skib 2105254489Sjilles if ((uap->flags & O_ACCMODE) == O_ACCMODE || uap->flags & O_EXEC) 2106205325Skib return (EINVAL); 2107205325Skib flags = FFLAGS(uap->flags); 2108205325Skib if ((flags & O_CREAT) != 0 && uap->attr != NULL) { 2109205325Skib error = copyin(uap->attr, &attr, sizeof(attr)); 2110205325Skib if (error) 2111205325Skib return (error); 2112205325Skib } 2113205325Skib return (kern_kmq_open(td, uap->path, flags, uap->mode, 2114205325Skib uap->attr != NULL ? &attr : NULL)); 2115205325Skib} 2116205325Skib 2117205325Skib/* 2118167232Srwatson * Syscall to unlink a message queue. 2119152825Sdavidxu */ 2120152825Sdavidxuint 2121225617Skmacysys_kmq_unlink(struct thread *td, struct kmq_unlink_args *uap) 2122152825Sdavidxu{ 2123152825Sdavidxu char path[MQFS_NAMELEN+1]; 2124152825Sdavidxu struct mqfs_node *pn; 2125152825Sdavidxu int error, len; 2126152825Sdavidxu 2127152825Sdavidxu error = copyinstr(uap->path, path, MQFS_NAMELEN + 1, NULL); 2128152825Sdavidxu if (error) 2129152825Sdavidxu return (error); 2130152825Sdavidxu 2131152825Sdavidxu len = strlen(path); 2132229272Sed if (len < 2 || path[0] != '/' || strchr(path + 1, '/') != NULL) 2133152825Sdavidxu return (EINVAL); 2134152825Sdavidxu 2135152825Sdavidxu sx_xlock(&mqfs_data.mi_lock); 2136297936Sjamie pn = mqfs_search(mqfs_data.mi_root, path + 1, len - 1, td->td_ucred); 2137152825Sdavidxu if (pn != NULL) 2138152825Sdavidxu error = do_unlink(pn, td->td_ucred); 2139152825Sdavidxu else 2140152825Sdavidxu error = ENOENT; 2141152825Sdavidxu sx_xunlock(&mqfs_data.mi_lock); 2142152825Sdavidxu return (error); 2143152825Sdavidxu} 2144152825Sdavidxu 2145255219Spjdtypedef int (*_fgetf)(struct thread *, int, cap_rights_t *, struct file **); 2146152825Sdavidxu 2147152825Sdavidxu/* 2148152825Sdavidxu * Get message queue by giving file slot 2149152825Sdavidxu */ 2150152825Sdavidxustatic int 2151255219Spjd_getmq(struct thread *td, int fd, cap_rights_t *rightsp, _fgetf func, 2152152825Sdavidxu struct file **fpp, struct mqfs_node **ppn, struct mqueue **pmq) 2153152825Sdavidxu{ 2154152825Sdavidxu struct mqfs_node *pn; 2155152825Sdavidxu int error; 2156152825Sdavidxu 2157255219Spjd error = func(td, fd, rightsp, fpp); 2158152825Sdavidxu if (error) 2159152825Sdavidxu return (error); 2160152825Sdavidxu if (&mqueueops != (*fpp)->f_ops) { 2161152825Sdavidxu fdrop(*fpp, td); 2162152825Sdavidxu return (EBADF); 2163152825Sdavidxu } 2164152948Sdavidxu pn = (*fpp)->f_data; 2165152825Sdavidxu if (ppn) 2166152825Sdavidxu *ppn = pn; 2167152825Sdavidxu if (pmq) 2168152825Sdavidxu *pmq = pn->mn_data; 2169152825Sdavidxu return (0); 2170152825Sdavidxu} 2171152825Sdavidxu 2172152825Sdavidxustatic __inline int 2173152825Sdavidxugetmq(struct thread *td, int fd, struct file **fpp, struct mqfs_node **ppn, 2174152825Sdavidxu struct mqueue **pmq) 2175152825Sdavidxu{ 2176255219Spjd cap_rights_t rights; 2177255219Spjd 2178258181Spjd return _getmq(td, fd, cap_rights_init(&rights, CAP_EVENT), fget, 2179255219Spjd fpp, ppn, pmq); 2180152825Sdavidxu} 2181152825Sdavidxu 2182152825Sdavidxustatic __inline int 2183152825Sdavidxugetmq_read(struct thread *td, int fd, struct file **fpp, 2184152825Sdavidxu struct mqfs_node **ppn, struct mqueue **pmq) 2185152825Sdavidxu{ 2186255219Spjd cap_rights_t rights; 2187255219Spjd 2188255219Spjd return _getmq(td, fd, cap_rights_init(&rights, CAP_READ), fget_read, 2189255219Spjd fpp, ppn, pmq); 2190152825Sdavidxu} 2191152825Sdavidxu 2192152825Sdavidxustatic __inline int 2193152825Sdavidxugetmq_write(struct thread *td, int fd, struct file **fpp, 2194152825Sdavidxu struct mqfs_node **ppn, struct mqueue **pmq) 2195152825Sdavidxu{ 2196255219Spjd cap_rights_t rights; 2197255219Spjd 2198255219Spjd return _getmq(td, fd, cap_rights_init(&rights, CAP_WRITE), fget_write, 2199255219Spjd fpp, ppn, pmq); 2200152825Sdavidxu} 2201152825Sdavidxu 2202205325Skibstatic int 2203205325Skibkern_kmq_setattr(struct thread *td, int mqd, const struct mq_attr *attr, 2204205325Skib struct mq_attr *oattr) 2205152825Sdavidxu{ 2206152825Sdavidxu struct mqueue *mq; 2207152825Sdavidxu struct file *fp; 2208174988Sjeff u_int oflag, flag; 2209152825Sdavidxu int error; 2210152825Sdavidxu 2211205325Skib if (attr != NULL && (attr->mq_flags & ~O_NONBLOCK) != 0) 2212205325Skib return (EINVAL); 2213205325Skib error = getmq(td, mqd, &fp, NULL, &mq); 2214152825Sdavidxu if (error) 2215152825Sdavidxu return (error); 2216205325Skib oattr->mq_maxmsg = mq->mq_maxmsg; 2217205325Skib oattr->mq_msgsize = mq->mq_msgsize; 2218205325Skib oattr->mq_curmsgs = mq->mq_curmsgs; 2219205325Skib if (attr != NULL) { 2220174988Sjeff do { 2221174988Sjeff oflag = flag = fp->f_flag; 2222174988Sjeff flag &= ~O_NONBLOCK; 2223205325Skib flag |= (attr->mq_flags & O_NONBLOCK); 2224174988Sjeff } while (atomic_cmpset_int(&fp->f_flag, oflag, flag) == 0); 2225174988Sjeff } else 2226174988Sjeff oflag = fp->f_flag; 2227205325Skib oattr->mq_flags = (O_NONBLOCK & oflag); 2228152825Sdavidxu fdrop(fp, td); 2229205325Skib return (error); 2230205325Skib} 2231205325Skib 2232205325Skibint 2233225617Skmacysys_kmq_setattr(struct thread *td, struct kmq_setattr_args *uap) 2234205325Skib{ 2235205325Skib struct mq_attr attr, oattr; 2236205325Skib int error; 2237205325Skib 2238205325Skib if (uap->attr != NULL) { 2239205325Skib error = copyin(uap->attr, &attr, sizeof(attr)); 2240205325Skib if (error != 0) 2241205325Skib return (error); 2242205325Skib } 2243205325Skib error = kern_kmq_setattr(td, uap->mqd, uap->attr != NULL ? &attr : NULL, 2244205325Skib &oattr); 2245205325Skib if (error != 0) 2246205325Skib return (error); 2247205325Skib if (uap->oattr != NULL) 2248152825Sdavidxu error = copyout(&oattr, uap->oattr, sizeof(oattr)); 2249152825Sdavidxu return (error); 2250152825Sdavidxu} 2251152825Sdavidxu 2252152825Sdavidxuint 2253225617Skmacysys_kmq_timedreceive(struct thread *td, struct kmq_timedreceive_args *uap) 2254152825Sdavidxu{ 2255152825Sdavidxu struct mqueue *mq; 2256152825Sdavidxu struct file *fp; 2257205325Skib struct timespec *abs_timeout, ets; 2258152825Sdavidxu int error; 2259152825Sdavidxu int waitok; 2260152825Sdavidxu 2261152825Sdavidxu error = getmq_read(td, uap->mqd, &fp, NULL, &mq); 2262152825Sdavidxu if (error) 2263152825Sdavidxu return (error); 2264205325Skib if (uap->abs_timeout != NULL) { 2265205325Skib error = copyin(uap->abs_timeout, &ets, sizeof(ets)); 2266205325Skib if (error != 0) 2267205325Skib return (error); 2268205325Skib abs_timeout = &ets; 2269205325Skib } else 2270205325Skib abs_timeout = NULL; 2271152825Sdavidxu waitok = !(fp->f_flag & O_NONBLOCK); 2272152825Sdavidxu error = mqueue_receive(mq, uap->msg_ptr, uap->msg_len, 2273205325Skib uap->msg_prio, waitok, abs_timeout); 2274152825Sdavidxu fdrop(fp, td); 2275152825Sdavidxu return (error); 2276152825Sdavidxu} 2277152825Sdavidxu 2278152825Sdavidxuint 2279225617Skmacysys_kmq_timedsend(struct thread *td, struct kmq_timedsend_args *uap) 2280152825Sdavidxu{ 2281152825Sdavidxu struct mqueue *mq; 2282152825Sdavidxu struct file *fp; 2283205325Skib struct timespec *abs_timeout, ets; 2284152825Sdavidxu int error, waitok; 2285152825Sdavidxu 2286152825Sdavidxu error = getmq_write(td, uap->mqd, &fp, NULL, &mq); 2287152825Sdavidxu if (error) 2288152825Sdavidxu return (error); 2289205325Skib if (uap->abs_timeout != NULL) { 2290205325Skib error = copyin(uap->abs_timeout, &ets, sizeof(ets)); 2291205325Skib if (error != 0) 2292205325Skib return (error); 2293205325Skib abs_timeout = &ets; 2294205325Skib } else 2295205325Skib abs_timeout = NULL; 2296152825Sdavidxu waitok = !(fp->f_flag & O_NONBLOCK); 2297152825Sdavidxu error = mqueue_send(mq, uap->msg_ptr, uap->msg_len, 2298205325Skib uap->msg_prio, waitok, abs_timeout); 2299152825Sdavidxu fdrop(fp, td); 2300152825Sdavidxu return (error); 2301152825Sdavidxu} 2302152825Sdavidxu 2303253529Skibstatic int 2304253529Skibkern_kmq_notify(struct thread *td, int mqd, struct sigevent *sigev) 2305152825Sdavidxu{ 2306255239Sglebius#ifdef CAPABILITIES 2307255219Spjd cap_rights_t rights; 2308255239Sglebius#endif 2309152948Sdavidxu struct filedesc *fdp; 2310152948Sdavidxu struct proc *p; 2311152825Sdavidxu struct mqueue *mq; 2312224778Srwatson struct file *fp, *fp2; 2313152948Sdavidxu struct mqueue_notifier *nt, *newnt = NULL; 2314152825Sdavidxu int error; 2315152825Sdavidxu 2316253529Skib if (sigev != NULL) { 2317253529Skib if (sigev->sigev_notify != SIGEV_SIGNAL && 2318253529Skib sigev->sigev_notify != SIGEV_THREAD_ID && 2319253529Skib sigev->sigev_notify != SIGEV_NONE) 2320152825Sdavidxu return (EINVAL); 2321253529Skib if ((sigev->sigev_notify == SIGEV_SIGNAL || 2322253529Skib sigev->sigev_notify == SIGEV_THREAD_ID) && 2323253529Skib !_SIG_VALID(sigev->sigev_signo)) 2324152825Sdavidxu return (EINVAL); 2325152825Sdavidxu } 2326253529Skib p = td->td_proc; 2327253529Skib fdp = td->td_proc->p_fd; 2328253529Skib error = getmq(td, mqd, &fp, NULL, &mq); 2329152825Sdavidxu if (error) 2330152825Sdavidxu return (error); 2331152948Sdavidxuagain: 2332168355Srwatson FILEDESC_SLOCK(fdp); 2333253529Skib fp2 = fget_locked(fdp, mqd); 2334224778Srwatson if (fp2 == NULL) { 2335168355Srwatson FILEDESC_SUNLOCK(fdp); 2336152948Sdavidxu error = EBADF; 2337152948Sdavidxu goto out; 2338152948Sdavidxu } 2339247602Spjd#ifdef CAPABILITIES 2340255219Spjd error = cap_check(cap_rights(fdp, mqd), 2341258181Spjd cap_rights_init(&rights, CAP_EVENT)); 2342224778Srwatson if (error) { 2343224778Srwatson FILEDESC_SUNLOCK(fdp); 2344224778Srwatson goto out; 2345224778Srwatson } 2346247602Spjd#endif 2347224778Srwatson if (fp2 != fp) { 2348224778Srwatson FILEDESC_SUNLOCK(fdp); 2349224778Srwatson error = EBADF; 2350224778Srwatson goto out; 2351224778Srwatson } 2352152825Sdavidxu mtx_lock(&mq->mq_mutex); 2353168355Srwatson FILEDESC_SUNLOCK(fdp); 2354253529Skib if (sigev != NULL) { 2355152825Sdavidxu if (mq->mq_notifier != NULL) { 2356152825Sdavidxu error = EBUSY; 2357153100Sdavidxu } else { 2358152948Sdavidxu PROC_LOCK(p); 2359253529Skib nt = notifier_search(p, mqd); 2360152948Sdavidxu if (nt == NULL) { 2361152948Sdavidxu if (newnt == NULL) { 2362152948Sdavidxu PROC_UNLOCK(p); 2363152948Sdavidxu mtx_unlock(&mq->mq_mutex); 2364152948Sdavidxu newnt = notifier_alloc(); 2365152948Sdavidxu goto again; 2366152948Sdavidxu } 2367152948Sdavidxu } 2368152948Sdavidxu 2369152948Sdavidxu if (nt != NULL) { 2370152948Sdavidxu sigqueue_take(&nt->nt_ksi); 2371152948Sdavidxu if (newnt != NULL) { 2372152948Sdavidxu notifier_free(newnt); 2373152948Sdavidxu newnt = NULL; 2374152948Sdavidxu } 2375152948Sdavidxu } else { 2376152948Sdavidxu nt = newnt; 2377152948Sdavidxu newnt = NULL; 2378152948Sdavidxu ksiginfo_init(&nt->nt_ksi); 2379152948Sdavidxu nt->nt_ksi.ksi_flags |= KSI_INS | KSI_EXT; 2380152948Sdavidxu nt->nt_ksi.ksi_code = SI_MESGQ; 2381152948Sdavidxu nt->nt_proc = p; 2382253529Skib nt->nt_ksi.ksi_mqd = mqd; 2383152948Sdavidxu notifier_insert(p, nt); 2384152948Sdavidxu } 2385253529Skib nt->nt_sigev = *sigev; 2386152948Sdavidxu mq->mq_notifier = nt; 2387152948Sdavidxu PROC_UNLOCK(p); 2388152825Sdavidxu /* 2389152948Sdavidxu * if there is no receivers and message queue 2390152948Sdavidxu * is not empty, we should send notification 2391152948Sdavidxu * as soon as possible. 2392152825Sdavidxu */ 2393152825Sdavidxu if (mq->mq_receivers == 0 && 2394152825Sdavidxu !TAILQ_EMPTY(&mq->mq_msgq)) 2395152825Sdavidxu mqueue_send_notification(mq); 2396152825Sdavidxu } 2397152825Sdavidxu } else { 2398253529Skib notifier_remove(p, mq, mqd); 2399152825Sdavidxu } 2400152825Sdavidxu mtx_unlock(&mq->mq_mutex); 2401152948Sdavidxu 2402152948Sdavidxuout: 2403152825Sdavidxu fdrop(fp, td); 2404152948Sdavidxu if (newnt != NULL) 2405152948Sdavidxu notifier_free(newnt); 2406152825Sdavidxu return (error); 2407152825Sdavidxu} 2408152825Sdavidxu 2409253529Skibint 2410253529Skibsys_kmq_notify(struct thread *td, struct kmq_notify_args *uap) 2411253529Skib{ 2412253529Skib struct sigevent ev, *evp; 2413253529Skib int error; 2414253529Skib 2415253529Skib if (uap->sigev == NULL) { 2416253529Skib evp = NULL; 2417253529Skib } else { 2418253529Skib error = copyin(uap->sigev, &ev, sizeof(ev)); 2419253529Skib if (error != 0) 2420253529Skib return (error); 2421253529Skib evp = &ev; 2422253529Skib } 2423253529Skib return (kern_kmq_notify(td, uap->mqd, evp)); 2424253529Skib} 2425253529Skib 2426152948Sdavidxustatic void 2427152948Sdavidxumqueue_fdclose(struct thread *td, int fd, struct file *fp) 2428152948Sdavidxu{ 2429152948Sdavidxu struct filedesc *fdp; 2430152948Sdavidxu struct mqueue *mq; 2431152948Sdavidxu 2432152948Sdavidxu fdp = td->td_proc->p_fd; 2433168355Srwatson FILEDESC_LOCK_ASSERT(fdp); 2434168355Srwatson 2435152948Sdavidxu if (fp->f_ops == &mqueueops) { 2436152948Sdavidxu mq = FPTOMQ(fp); 2437152948Sdavidxu mtx_lock(&mq->mq_mutex); 2438152948Sdavidxu notifier_remove(td->td_proc, mq, fd); 2439152948Sdavidxu 2440152948Sdavidxu /* have to wakeup thread in same process */ 2441152948Sdavidxu if (mq->mq_flags & MQ_RSEL) { 2442152948Sdavidxu mq->mq_flags &= ~MQ_RSEL; 2443153477Sdavidxu selwakeup(&mq->mq_rsel); 2444152948Sdavidxu } 2445152948Sdavidxu if (mq->mq_flags & MQ_WSEL) { 2446152948Sdavidxu mq->mq_flags &= ~MQ_WSEL; 2447153477Sdavidxu selwakeup(&mq->mq_wsel); 2448152948Sdavidxu } 2449152948Sdavidxu mtx_unlock(&mq->mq_mutex); 2450152948Sdavidxu } 2451152948Sdavidxu} 2452152948Sdavidxu 2453152948Sdavidxustatic void 2454152948Sdavidxumq_proc_exit(void *arg __unused, struct proc *p) 2455152948Sdavidxu{ 2456152948Sdavidxu struct filedesc *fdp; 2457152948Sdavidxu struct file *fp; 2458152948Sdavidxu struct mqueue *mq; 2459152948Sdavidxu int i; 2460152948Sdavidxu 2461152948Sdavidxu fdp = p->p_fd; 2462168355Srwatson FILEDESC_SLOCK(fdp); 2463152948Sdavidxu for (i = 0; i < fdp->fd_nfiles; ++i) { 2464152948Sdavidxu fp = fget_locked(fdp, i); 2465152948Sdavidxu if (fp != NULL && fp->f_ops == &mqueueops) { 2466152948Sdavidxu mq = FPTOMQ(fp); 2467152948Sdavidxu mtx_lock(&mq->mq_mutex); 2468152948Sdavidxu notifier_remove(p, FPTOMQ(fp), i); 2469152948Sdavidxu mtx_unlock(&mq->mq_mutex); 2470152948Sdavidxu } 2471152948Sdavidxu } 2472168355Srwatson FILEDESC_SUNLOCK(fdp); 2473152948Sdavidxu KASSERT(LIST_EMPTY(&p->p_mqnotifier), ("mq notifiers left")); 2474152948Sdavidxu} 2475152948Sdavidxu 2476152825Sdavidxustatic int 2477152825Sdavidxumqf_poll(struct file *fp, int events, struct ucred *active_cred, 2478152825Sdavidxu struct thread *td) 2479152825Sdavidxu{ 2480152825Sdavidxu struct mqueue *mq = FPTOMQ(fp); 2481152825Sdavidxu int revents = 0; 2482152825Sdavidxu 2483152825Sdavidxu mtx_lock(&mq->mq_mutex); 2484152825Sdavidxu if (events & (POLLIN | POLLRDNORM)) { 2485152825Sdavidxu if (mq->mq_curmsgs) { 2486152825Sdavidxu revents |= events & (POLLIN | POLLRDNORM); 2487152825Sdavidxu } else { 2488152825Sdavidxu mq->mq_flags |= MQ_RSEL; 2489152825Sdavidxu selrecord(td, &mq->mq_rsel); 2490152825Sdavidxu } 2491152825Sdavidxu } 2492152825Sdavidxu if (events & POLLOUT) { 2493152825Sdavidxu if (mq->mq_curmsgs < mq->mq_maxmsg) 2494152825Sdavidxu revents |= POLLOUT; 2495152825Sdavidxu else { 2496152825Sdavidxu mq->mq_flags |= MQ_WSEL; 2497152825Sdavidxu selrecord(td, &mq->mq_wsel); 2498152825Sdavidxu } 2499152825Sdavidxu } 2500152825Sdavidxu mtx_unlock(&mq->mq_mutex); 2501152825Sdavidxu return (revents); 2502152825Sdavidxu} 2503152825Sdavidxu 2504152825Sdavidxustatic int 2505152825Sdavidxumqf_close(struct file *fp, struct thread *td) 2506152825Sdavidxu{ 2507152825Sdavidxu struct mqfs_node *pn; 2508152825Sdavidxu 2509152825Sdavidxu fp->f_ops = &badfileops; 2510152948Sdavidxu pn = fp->f_data; 2511152825Sdavidxu fp->f_data = NULL; 2512152825Sdavidxu sx_xlock(&mqfs_data.mi_lock); 2513152825Sdavidxu mqnode_release(pn); 2514152825Sdavidxu sx_xunlock(&mqfs_data.mi_lock); 2515152825Sdavidxu return (0); 2516152825Sdavidxu} 2517152825Sdavidxu 2518152825Sdavidxustatic int 2519152825Sdavidxumqf_stat(struct file *fp, struct stat *st, struct ucred *active_cred, 2520152825Sdavidxu struct thread *td) 2521152825Sdavidxu{ 2522152948Sdavidxu struct mqfs_node *pn = fp->f_data; 2523152825Sdavidxu 2524152825Sdavidxu bzero(st, sizeof *st); 2525224914Skib sx_xlock(&mqfs_data.mi_lock); 2526205792Sed st->st_atim = pn->mn_atime; 2527205792Sed st->st_mtim = pn->mn_mtime; 2528205792Sed st->st_ctim = pn->mn_ctime; 2529205792Sed st->st_birthtim = pn->mn_birth; 2530152825Sdavidxu st->st_uid = pn->mn_uid; 2531152825Sdavidxu st->st_gid = pn->mn_gid; 2532152825Sdavidxu st->st_mode = S_IFIFO | pn->mn_mode; 2533224914Skib sx_xunlock(&mqfs_data.mi_lock); 2534152825Sdavidxu return (0); 2535152825Sdavidxu} 2536152825Sdavidxu 2537152825Sdavidxustatic int 2538224914Skibmqf_chmod(struct file *fp, mode_t mode, struct ucred *active_cred, 2539224914Skib struct thread *td) 2540224914Skib{ 2541224914Skib struct mqfs_node *pn; 2542224914Skib int error; 2543224914Skib 2544224914Skib error = 0; 2545224914Skib pn = fp->f_data; 2546224914Skib sx_xlock(&mqfs_data.mi_lock); 2547224914Skib error = vaccess(VREG, pn->mn_mode, pn->mn_uid, pn->mn_gid, VADMIN, 2548224914Skib active_cred, NULL); 2549224914Skib if (error != 0) 2550224914Skib goto out; 2551224914Skib pn->mn_mode = mode & ACCESSPERMS; 2552224914Skibout: 2553224914Skib sx_xunlock(&mqfs_data.mi_lock); 2554224914Skib return (error); 2555224914Skib} 2556224914Skib 2557224914Skibstatic int 2558224914Skibmqf_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred, 2559224914Skib struct thread *td) 2560224914Skib{ 2561224914Skib struct mqfs_node *pn; 2562224914Skib int error; 2563224914Skib 2564224914Skib error = 0; 2565224914Skib pn = fp->f_data; 2566224914Skib sx_xlock(&mqfs_data.mi_lock); 2567224914Skib if (uid == (uid_t)-1) 2568224914Skib uid = pn->mn_uid; 2569224914Skib if (gid == (gid_t)-1) 2570224914Skib gid = pn->mn_gid; 2571224914Skib if (((uid != pn->mn_uid && uid != active_cred->cr_uid) || 2572224914Skib (gid != pn->mn_gid && !groupmember(gid, active_cred))) && 2573224914Skib (error = priv_check_cred(active_cred, PRIV_VFS_CHOWN, 0))) 2574224914Skib goto out; 2575224914Skib pn->mn_uid = uid; 2576224914Skib pn->mn_gid = gid; 2577224914Skibout: 2578224914Skib sx_xunlock(&mqfs_data.mi_lock); 2579224914Skib return (error); 2580224914Skib} 2581224914Skib 2582224914Skibstatic int 2583152825Sdavidxumqf_kqfilter(struct file *fp, struct knote *kn) 2584152825Sdavidxu{ 2585152825Sdavidxu struct mqueue *mq = FPTOMQ(fp); 2586152825Sdavidxu int error = 0; 2587152825Sdavidxu 2588152825Sdavidxu if (kn->kn_filter == EVFILT_READ) { 2589152825Sdavidxu kn->kn_fop = &mq_rfiltops; 2590152825Sdavidxu knlist_add(&mq->mq_rsel.si_note, kn, 0); 2591152825Sdavidxu } else if (kn->kn_filter == EVFILT_WRITE) { 2592152825Sdavidxu kn->kn_fop = &mq_wfiltops; 2593152825Sdavidxu knlist_add(&mq->mq_wsel.si_note, kn, 0); 2594152825Sdavidxu } else 2595152825Sdavidxu error = EINVAL; 2596152825Sdavidxu return (error); 2597152825Sdavidxu} 2598152825Sdavidxu 2599152825Sdavidxustatic void 2600152825Sdavidxufilt_mqdetach(struct knote *kn) 2601152825Sdavidxu{ 2602152825Sdavidxu struct mqueue *mq = FPTOMQ(kn->kn_fp); 2603152825Sdavidxu 2604152825Sdavidxu if (kn->kn_filter == EVFILT_READ) 2605152825Sdavidxu knlist_remove(&mq->mq_rsel.si_note, kn, 0); 2606152825Sdavidxu else if (kn->kn_filter == EVFILT_WRITE) 2607152825Sdavidxu knlist_remove(&mq->mq_wsel.si_note, kn, 0); 2608152825Sdavidxu else 2609152825Sdavidxu panic("filt_mqdetach"); 2610152825Sdavidxu} 2611152825Sdavidxu 2612152825Sdavidxustatic int 2613152825Sdavidxufilt_mqread(struct knote *kn, long hint) 2614152825Sdavidxu{ 2615152825Sdavidxu struct mqueue *mq = FPTOMQ(kn->kn_fp); 2616152825Sdavidxu 2617152825Sdavidxu mtx_assert(&mq->mq_mutex, MA_OWNED); 2618152825Sdavidxu return (mq->mq_curmsgs != 0); 2619152825Sdavidxu} 2620152825Sdavidxu 2621152825Sdavidxustatic int 2622152825Sdavidxufilt_mqwrite(struct knote *kn, long hint) 2623152825Sdavidxu{ 2624152825Sdavidxu struct mqueue *mq = FPTOMQ(kn->kn_fp); 2625152825Sdavidxu 2626152825Sdavidxu mtx_assert(&mq->mq_mutex, MA_OWNED); 2627152825Sdavidxu return (mq->mq_curmsgs < mq->mq_maxmsg); 2628152825Sdavidxu} 2629152825Sdavidxu 2630271976Sjhbstatic int 2631271976Sjhbmqf_fill_kinfo(struct file *fp, struct kinfo_file *kif, struct filedesc *fdp) 2632271976Sjhb{ 2633271976Sjhb 2634271976Sjhb kif->kf_type = KF_TYPE_MQUEUE; 2635271976Sjhb return (0); 2636271976Sjhb} 2637271976Sjhb 2638152825Sdavidxustatic struct fileops mqueueops = { 2639271489Sjhb .fo_read = invfo_rdwr, 2640271489Sjhb .fo_write = invfo_rdwr, 2641271489Sjhb .fo_truncate = invfo_truncate, 2642271489Sjhb .fo_ioctl = invfo_ioctl, 2643152825Sdavidxu .fo_poll = mqf_poll, 2644152825Sdavidxu .fo_kqfilter = mqf_kqfilter, 2645152825Sdavidxu .fo_stat = mqf_stat, 2646271489Sjhb .fo_close = mqf_close, 2647224914Skib .fo_chmod = mqf_chmod, 2648224914Skib .fo_chown = mqf_chown, 2649254356Sglebius .fo_sendfile = invfo_sendfile, 2650271976Sjhb .fo_fill_kinfo = mqf_fill_kinfo, 2651152825Sdavidxu}; 2652152825Sdavidxu 2653152825Sdavidxustatic struct vop_vector mqfs_vnodeops = { 2654152825Sdavidxu .vop_default = &default_vnodeops, 2655152825Sdavidxu .vop_access = mqfs_access, 2656152825Sdavidxu .vop_cachedlookup = mqfs_lookup, 2657152825Sdavidxu .vop_lookup = vfs_cache_lookup, 2658152825Sdavidxu .vop_reclaim = mqfs_reclaim, 2659152825Sdavidxu .vop_create = mqfs_create, 2660152825Sdavidxu .vop_remove = mqfs_remove, 2661152825Sdavidxu .vop_inactive = mqfs_inactive, 2662152825Sdavidxu .vop_open = mqfs_open, 2663152825Sdavidxu .vop_close = mqfs_close, 2664152825Sdavidxu .vop_getattr = mqfs_getattr, 2665152825Sdavidxu .vop_setattr = mqfs_setattr, 2666152825Sdavidxu .vop_read = mqfs_read, 2667152825Sdavidxu .vop_write = VOP_EOPNOTSUPP, 2668152825Sdavidxu .vop_readdir = mqfs_readdir, 2669152825Sdavidxu .vop_mkdir = VOP_EOPNOTSUPP, 2670152825Sdavidxu .vop_rmdir = VOP_EOPNOTSUPP 2671152825Sdavidxu}; 2672152825Sdavidxu 2673152825Sdavidxustatic struct vfsops mqfs_vfsops = { 2674152825Sdavidxu .vfs_init = mqfs_init, 2675152825Sdavidxu .vfs_uninit = mqfs_uninit, 2676152825Sdavidxu .vfs_mount = mqfs_mount, 2677152825Sdavidxu .vfs_unmount = mqfs_unmount, 2678152825Sdavidxu .vfs_root = mqfs_root, 2679152825Sdavidxu .vfs_statfs = mqfs_statfs, 2680152825Sdavidxu}; 2681152825Sdavidxu 2682205325Skibstatic struct vfsconf mqueuefs_vfsconf = { 2683205325Skib .vfc_version = VFS_VERSION, 2684205325Skib .vfc_name = "mqueuefs", 2685205325Skib .vfc_vfsops = &mqfs_vfsops, 2686205325Skib .vfc_typenum = -1, 2687205325Skib .vfc_flags = VFCF_SYNTHETIC 2688205325Skib}; 2689152825Sdavidxu 2690205325Skibstatic struct syscall_helper_data mq_syscalls[] = { 2691205325Skib SYSCALL_INIT_HELPER(kmq_open), 2692205325Skib SYSCALL_INIT_HELPER(kmq_setattr), 2693205325Skib SYSCALL_INIT_HELPER(kmq_timedsend), 2694205325Skib SYSCALL_INIT_HELPER(kmq_timedreceive), 2695205325Skib SYSCALL_INIT_HELPER(kmq_notify), 2696205325Skib SYSCALL_INIT_HELPER(kmq_unlink), 2697205325Skib SYSCALL_INIT_LAST 2698205325Skib}; 2699205325Skib 2700205325Skib#ifdef COMPAT_FREEBSD32 2701205325Skib#include <compat/freebsd32/freebsd32.h> 2702205325Skib#include <compat/freebsd32/freebsd32_proto.h> 2703253529Skib#include <compat/freebsd32/freebsd32_signal.h> 2704205325Skib#include <compat/freebsd32/freebsd32_syscall.h> 2705205325Skib#include <compat/freebsd32/freebsd32_util.h> 2706205325Skib 2707205325Skibstatic void 2708205325Skibmq_attr_from32(const struct mq_attr32 *from, struct mq_attr *to) 2709205325Skib{ 2710205325Skib 2711205325Skib to->mq_flags = from->mq_flags; 2712205325Skib to->mq_maxmsg = from->mq_maxmsg; 2713205325Skib to->mq_msgsize = from->mq_msgsize; 2714205325Skib to->mq_curmsgs = from->mq_curmsgs; 2715205325Skib} 2716205325Skib 2717205325Skibstatic void 2718205325Skibmq_attr_to32(const struct mq_attr *from, struct mq_attr32 *to) 2719205325Skib{ 2720205325Skib 2721205325Skib to->mq_flags = from->mq_flags; 2722205325Skib to->mq_maxmsg = from->mq_maxmsg; 2723205325Skib to->mq_msgsize = from->mq_msgsize; 2724205325Skib to->mq_curmsgs = from->mq_curmsgs; 2725205325Skib} 2726205325Skib 2727205325Skibint 2728205325Skibfreebsd32_kmq_open(struct thread *td, struct freebsd32_kmq_open_args *uap) 2729205325Skib{ 2730205325Skib struct mq_attr attr; 2731205325Skib struct mq_attr32 attr32; 2732205325Skib int flags, error; 2733205325Skib 2734254489Sjilles if ((uap->flags & O_ACCMODE) == O_ACCMODE || uap->flags & O_EXEC) 2735205325Skib return (EINVAL); 2736205325Skib flags = FFLAGS(uap->flags); 2737205325Skib if ((flags & O_CREAT) != 0 && uap->attr != NULL) { 2738205325Skib error = copyin(uap->attr, &attr32, sizeof(attr32)); 2739205325Skib if (error) 2740205325Skib return (error); 2741205325Skib mq_attr_from32(&attr32, &attr); 2742205325Skib } 2743205325Skib return (kern_kmq_open(td, uap->path, flags, uap->mode, 2744205325Skib uap->attr != NULL ? &attr : NULL)); 2745205325Skib} 2746205325Skib 2747205325Skibint 2748205325Skibfreebsd32_kmq_setattr(struct thread *td, struct freebsd32_kmq_setattr_args *uap) 2749205325Skib{ 2750205325Skib struct mq_attr attr, oattr; 2751205325Skib struct mq_attr32 attr32, oattr32; 2752205325Skib int error; 2753205325Skib 2754205325Skib if (uap->attr != NULL) { 2755205325Skib error = copyin(uap->attr, &attr32, sizeof(attr32)); 2756205325Skib if (error != 0) 2757205325Skib return (error); 2758205325Skib mq_attr_from32(&attr32, &attr); 2759205325Skib } 2760205325Skib error = kern_kmq_setattr(td, uap->mqd, uap->attr != NULL ? &attr : NULL, 2761205325Skib &oattr); 2762205325Skib if (error != 0) 2763205325Skib return (error); 2764205325Skib if (uap->oattr != NULL) { 2765205325Skib mq_attr_to32(&oattr, &oattr32); 2766205325Skib error = copyout(&oattr32, uap->oattr, sizeof(oattr32)); 2767205325Skib } 2768205325Skib return (error); 2769205325Skib} 2770205325Skib 2771205325Skibint 2772205325Skibfreebsd32_kmq_timedsend(struct thread *td, 2773205325Skib struct freebsd32_kmq_timedsend_args *uap) 2774205325Skib{ 2775205325Skib struct mqueue *mq; 2776205325Skib struct file *fp; 2777205325Skib struct timespec32 ets32; 2778205325Skib struct timespec *abs_timeout, ets; 2779205325Skib int error; 2780205325Skib int waitok; 2781205325Skib 2782240940Spjd error = getmq_write(td, uap->mqd, &fp, NULL, &mq); 2783205325Skib if (error) 2784205325Skib return (error); 2785205325Skib if (uap->abs_timeout != NULL) { 2786205325Skib error = copyin(uap->abs_timeout, &ets32, sizeof(ets32)); 2787205325Skib if (error != 0) 2788205325Skib return (error); 2789205325Skib CP(ets32, ets, tv_sec); 2790205325Skib CP(ets32, ets, tv_nsec); 2791205325Skib abs_timeout = &ets; 2792205325Skib } else 2793205325Skib abs_timeout = NULL; 2794205325Skib waitok = !(fp->f_flag & O_NONBLOCK); 2795205325Skib error = mqueue_send(mq, uap->msg_ptr, uap->msg_len, 2796205325Skib uap->msg_prio, waitok, abs_timeout); 2797205325Skib fdrop(fp, td); 2798205325Skib return (error); 2799205325Skib} 2800205325Skib 2801205325Skibint 2802205325Skibfreebsd32_kmq_timedreceive(struct thread *td, 2803205325Skib struct freebsd32_kmq_timedreceive_args *uap) 2804205325Skib{ 2805205325Skib struct mqueue *mq; 2806205325Skib struct file *fp; 2807205325Skib struct timespec32 ets32; 2808205325Skib struct timespec *abs_timeout, ets; 2809205325Skib int error, waitok; 2810205325Skib 2811240940Spjd error = getmq_read(td, uap->mqd, &fp, NULL, &mq); 2812205325Skib if (error) 2813205325Skib return (error); 2814205325Skib if (uap->abs_timeout != NULL) { 2815205325Skib error = copyin(uap->abs_timeout, &ets32, sizeof(ets32)); 2816205325Skib if (error != 0) 2817205325Skib return (error); 2818205325Skib CP(ets32, ets, tv_sec); 2819205325Skib CP(ets32, ets, tv_nsec); 2820205325Skib abs_timeout = &ets; 2821205325Skib } else 2822205325Skib abs_timeout = NULL; 2823205325Skib waitok = !(fp->f_flag & O_NONBLOCK); 2824205325Skib error = mqueue_receive(mq, uap->msg_ptr, uap->msg_len, 2825205325Skib uap->msg_prio, waitok, abs_timeout); 2826205325Skib fdrop(fp, td); 2827205325Skib return (error); 2828205325Skib} 2829205325Skib 2830253529Skibint 2831253529Skibfreebsd32_kmq_notify(struct thread *td, struct freebsd32_kmq_notify_args *uap) 2832253529Skib{ 2833253529Skib struct sigevent ev, *evp; 2834253529Skib struct sigevent32 ev32; 2835253529Skib int error; 2836253529Skib 2837253529Skib if (uap->sigev == NULL) { 2838253529Skib evp = NULL; 2839253529Skib } else { 2840253529Skib error = copyin(uap->sigev, &ev32, sizeof(ev32)); 2841253529Skib if (error != 0) 2842253529Skib return (error); 2843253529Skib error = convert_sigevent32(&ev32, &ev); 2844253529Skib if (error != 0) 2845253529Skib return (error); 2846253529Skib evp = &ev; 2847253529Skib } 2848253529Skib return (kern_kmq_notify(td, uap->mqd, evp)); 2849253529Skib} 2850253529Skib 2851205325Skibstatic struct syscall_helper_data mq32_syscalls[] = { 2852205325Skib SYSCALL32_INIT_HELPER(freebsd32_kmq_open), 2853205325Skib SYSCALL32_INIT_HELPER(freebsd32_kmq_setattr), 2854205325Skib SYSCALL32_INIT_HELPER(freebsd32_kmq_timedsend), 2855205325Skib SYSCALL32_INIT_HELPER(freebsd32_kmq_timedreceive), 2856253529Skib SYSCALL32_INIT_HELPER(freebsd32_kmq_notify), 2857225617Skmacy SYSCALL32_INIT_HELPER_COMPAT(kmq_unlink), 2858205325Skib SYSCALL_INIT_LAST 2859205325Skib}; 2860205325Skib#endif 2861205325Skib 2862205325Skibstatic int 2863205325Skibmqinit(void) 2864205325Skib{ 2865205325Skib int error; 2866205325Skib 2867273707Smjg error = syscall_helper_register(mq_syscalls, SY_THR_STATIC_KLD); 2868205325Skib if (error != 0) 2869205325Skib return (error); 2870205325Skib#ifdef COMPAT_FREEBSD32 2871273707Smjg error = syscall32_helper_register(mq32_syscalls, SY_THR_STATIC_KLD); 2872205325Skib if (error != 0) 2873205325Skib return (error); 2874205325Skib#endif 2875205325Skib return (0); 2876205325Skib} 2877205325Skib 2878205325Skibstatic int 2879205325Skibmqunload(void) 2880205325Skib{ 2881205325Skib 2882205325Skib#ifdef COMPAT_FREEBSD32 2883205325Skib syscall32_helper_unregister(mq32_syscalls); 2884205325Skib#endif 2885205325Skib syscall_helper_unregister(mq_syscalls); 2886205325Skib return (0); 2887205325Skib} 2888205325Skib 2889205325Skibstatic int 2890205325Skibmq_modload(struct module *module, int cmd, void *arg) 2891205325Skib{ 2892205325Skib int error = 0; 2893205325Skib 2894205325Skib error = vfs_modevent(module, cmd, arg); 2895205325Skib if (error != 0) 2896205325Skib return (error); 2897205325Skib 2898205325Skib switch (cmd) { 2899205325Skib case MOD_LOAD: 2900205325Skib error = mqinit(); 2901205325Skib if (error != 0) 2902205325Skib mqunload(); 2903205325Skib break; 2904205325Skib case MOD_UNLOAD: 2905205325Skib error = mqunload(); 2906205325Skib break; 2907205325Skib default: 2908205325Skib break; 2909205325Skib } 2910205325Skib return (error); 2911205325Skib} 2912205325Skib 2913205325Skibstatic moduledata_t mqueuefs_mod = { 2914205325Skib "mqueuefs", 2915205325Skib mq_modload, 2916205325Skib &mqueuefs_vfsconf 2917205325Skib}; 2918205325SkibDECLARE_MODULE(mqueuefs, mqueuefs_mod, SI_SUB_VFS, SI_ORDER_MIDDLE); 2919152853SdavidxuMODULE_VERSION(mqueuefs, 1); 2920