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