2 * Copyright (c) 2005 David Xu <davidxu@freebsd.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
29 * POSIX message queue implementation.
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.
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.
45 #include <sys/cdefs.h>
46 __FBSDID("$FreeBSD$");
48 #include <sys/param.h>
49 #include <sys/kernel.h>
50 #include <sys/systm.h>
51 #include <sys/limits.h>
53 #include <sys/dirent.h>
54 #include <sys/event.h>
55 #include <sys/eventhandler.h>
56 #include <sys/fcntl.h>
58 #include <sys/filedesc.h>
60 #include <sys/malloc.h>
61 #include <sys/module.h>
62 #include <sys/mount.h>
63 #include <sys/mqueue.h>
64 #include <sys/mutex.h>
65 #include <sys/namei.h>
66 #include <sys/posix4.h>
70 #include <sys/queue.h>
71 #include <sys/sysproto.h>
73 #include <sys/syscall.h>
74 #include <sys/syscallsubr.h>
75 #include <sys/sysent.h>
77 #include <sys/sysctl.h>
78 #include <sys/taskqueue.h>
79 #include <sys/unistd.h>
80 #include <sys/vnode.h>
81 #include <machine/atomic.h>
84 * Limits and constants
86 #define MQFS_NAMELEN NAME_MAX
87 #define MQFS_DELEN (8 + MQFS_NAMELEN)
103 * mqfs_info: describes a mqfs instance
107 struct mqfs_node
*mi_root
;
108 struct unrhdr
*mi_unrhdr
;
112 LIST_ENTRY(mqfs_vdata
) mv_link
;
113 struct mqfs_node
*mv_node
;
114 struct vnode
*mv_vnode
;
119 * mqfs_node: describes a node (file or directory) within a mqfs
122 char mn_name
[MQFS_NAMELEN
+1];
123 struct mqfs_info
*mn_info
;
124 struct mqfs_node
*mn_parent
;
125 LIST_HEAD(,mqfs_node
) mn_children
;
126 LIST_ENTRY(mqfs_node
) mn_sibling
;
127 LIST_HEAD(,mqfs_vdata
) mn_vnodes
;
133 struct timespec mn_birth
;
134 struct timespec mn_ctime
;
135 struct timespec mn_atime
;
136 struct timespec mn_mtime
;
142 #define VTON(vp) (((struct mqfs_vdata *)((vp)->v_data))->mv_node)
143 #define VTOMQ(vp) ((struct mqueue *)(VTON(vp)->mn_data))
144 #define VFSTOMQFS(m) ((struct mqfs_info *)((m)->mnt_data))
145 #define FPTOMQ(fp) ((struct mqueue *)(((struct mqfs_node *) \
146 (fp)->f_data)->mn_data))
148 TAILQ_HEAD(msgq
, mqueue_msg
);
152 struct mqueue_notifier
{
153 LIST_ENTRY(mqueue_notifier
) nt_link
;
154 struct sigevent nt_sigev
;
156 struct proc
*nt_proc
;
169 struct selinfo mq_rsel
;
170 struct selinfo mq_wsel
;
171 struct mqueue_notifier
*mq_notifier
;
178 TAILQ_ENTRY(mqueue_msg
) msg_link
;
179 unsigned int msg_prio
;
180 unsigned int msg_size
;
181 /* following real data... */
184 SYSCTL_NODE(_kern
, OID_AUTO
, mqueue
, CTLFLAG_RW
, 0,
185 "POSIX real time message queue");
187 static int default_maxmsg
= 10;
188 static int default_msgsize
= 1024;
190 static int maxmsg
= 100;
191 SYSCTL_INT(_kern_mqueue
, OID_AUTO
, maxmsg
, CTLFLAG_RW
,
192 &maxmsg
, 0, "Default maximum messages in queue");
193 static int maxmsgsize
= 16384;
194 SYSCTL_INT(_kern_mqueue
, OID_AUTO
, maxmsgsize
, CTLFLAG_RW
,
195 &maxmsgsize
, 0, "Default maximum message size");
196 static int maxmq
= 100;
197 SYSCTL_INT(_kern_mqueue
, OID_AUTO
, maxmq
, CTLFLAG_RW
,
198 &maxmq
, 0, "maximum message queues");
199 static int curmq
= 0;
200 SYSCTL_INT(_kern_mqueue
, OID_AUTO
, curmq
, CTLFLAG_RW
,
201 &curmq
, 0, "current message queue number");
202 static int unloadable
= 0;
203 static MALLOC_DEFINE(M_MQUEUEDATA
, "mqdata", "mqueue data");
205 static eventhandler_tag exit_tag
;
207 /* Only one instance per-system */
208 static struct mqfs_info mqfs_data
;
209 static uma_zone_t mqnode_zone
;
210 static uma_zone_t mqueue_zone
;
211 static uma_zone_t mvdata_zone
;
212 static uma_zone_t mqnoti_zone
;
213 static struct vop_vector mqfs_vnodeops
;
214 static struct fileops mqueueops
;
217 * Directory structure construction and manipulation
220 static struct mqfs_node
*mqfs_create_dir(struct mqfs_node
*parent
,
221 const char *name
, int namelen
, struct ucred
*cred
, int mode
);
222 static struct mqfs_node
*mqfs_create_link(struct mqfs_node
*parent
,
223 const char *name
, int namelen
, struct ucred
*cred
, int mode
);
226 static struct mqfs_node
*mqfs_create_file(struct mqfs_node
*parent
,
227 const char *name
, int namelen
, struct ucred
*cred
, int mode
);
228 static int mqfs_destroy(struct mqfs_node
*mn
);
229 static void mqfs_fileno_alloc(struct mqfs_info
*mi
, struct mqfs_node
*mn
);
230 static void mqfs_fileno_free(struct mqfs_info
*mi
, struct mqfs_node
*mn
);
231 static int mqfs_allocv(struct mount
*mp
, struct vnode
**vpp
, struct mqfs_node
*pn
);
234 * Message queue construction and maniplation
236 static struct mqueue
*mqueue_alloc(const struct mq_attr
*attr
);
237 static void mqueue_free(struct mqueue
*mq
);
238 static int mqueue_send(struct mqueue
*mq
, const char *msg_ptr
,
239 size_t msg_len
, unsigned msg_prio
, int waitok
,
240 const struct timespec
*abs_timeout
);
241 static int mqueue_receive(struct mqueue
*mq
, char *msg_ptr
,
242 size_t msg_len
, unsigned *msg_prio
, int waitok
,
243 const struct timespec
*abs_timeout
);
244 static int _mqueue_send(struct mqueue
*mq
, struct mqueue_msg
*msg
,
246 static int _mqueue_recv(struct mqueue
*mq
, struct mqueue_msg
**msg
,
248 static void mqueue_send_notification(struct mqueue
*mq
);
249 static void mqueue_fdclose(struct thread
*td
, int fd
, struct file
*fp
);
250 static void mq_proc_exit(void *arg
, struct proc
*p
);
255 static void filt_mqdetach(struct knote
*kn
);
256 static int filt_mqread(struct knote
*kn
, long hint
);
257 static int filt_mqwrite(struct knote
*kn
, long hint
);
259 struct filterops mq_rfiltops
=
260 { 1, NULL
, filt_mqdetach
, filt_mqread
};
261 struct filterops mq_wfiltops
=
262 { 1, NULL
, filt_mqdetach
, filt_mqwrite
};
265 * Initialize fileno bitmap
268 mqfs_fileno_init(struct mqfs_info
*mi
)
272 up
= new_unrhdr(1, INT_MAX
, NULL
);
277 * Tear down fileno bitmap
280 mqfs_fileno_uninit(struct mqfs_info
*mi
)
285 mi
->mi_unrhdr
= NULL
;
290 * Allocate a file number
293 mqfs_fileno_alloc(struct mqfs_info
*mi
, struct mqfs_node
*mn
)
295 /* make sure our parent has a file number */
296 if (mn
->mn_parent
&& !mn
->mn_parent
->mn_fileno
)
297 mqfs_fileno_alloc(mi
, mn
->mn_parent
);
299 switch (mn
->mn_type
) {
303 case mqfstype_symlink
:
304 mn
->mn_fileno
= alloc_unr(mi
->mi_unrhdr
);
307 KASSERT(mn
->mn_parent
!= NULL
,
308 ("mqfstype_this node has no parent"));
309 mn
->mn_fileno
= mn
->mn_parent
->mn_fileno
;
311 case mqfstype_parent
:
312 KASSERT(mn
->mn_parent
!= NULL
,
313 ("mqfstype_parent node has no parent"));
314 if (mn
->mn_parent
== mi
->mi_root
) {
315 mn
->mn_fileno
= mn
->mn_parent
->mn_fileno
;
318 KASSERT(mn
->mn_parent
->mn_parent
!= NULL
,
319 ("mqfstype_parent node has no grandparent"));
320 mn
->mn_fileno
= mn
->mn_parent
->mn_parent
->mn_fileno
;
324 ("mqfs_fileno_alloc() called for unknown type node: %d",
331 * Release a file number
334 mqfs_fileno_free(struct mqfs_info
*mi
, struct mqfs_node
*mn
)
336 switch (mn
->mn_type
) {
340 case mqfstype_symlink
:
341 free_unr(mi
->mi_unrhdr
, mn
->mn_fileno
);
344 case mqfstype_parent
:
345 /* ignore these, as they don't "own" their file number */
349 ("mqfs_fileno_free() called for unknown type node: %d",
355 static __inline
struct mqfs_node
*
358 return uma_zalloc(mqnode_zone
, M_WAITOK
| M_ZERO
);
362 mqnode_free(struct mqfs_node
*node
)
364 uma_zfree(mqnode_zone
, node
);
368 mqnode_addref(struct mqfs_node
*node
)
370 atomic_fetchadd_int(&node
->mn_refcount
, 1);
374 mqnode_release(struct mqfs_node
*node
)
376 struct mqfs_info
*mqfs
;
379 mqfs
= node
->mn_info
;
380 old
= atomic_fetchadd_int(&node
->mn_refcount
, -1);
381 if (node
->mn_type
== mqfstype_dir
||
382 node
->mn_type
== mqfstype_root
)
383 exp
= 3; /* include . and .. */
387 int locked
= sx_xlocked(&mqfs
->mi_lock
);
389 sx_xlock(&mqfs
->mi_lock
);
392 sx_xunlock(&mqfs
->mi_lock
);
397 * Add a node to a directory
400 mqfs_add_node(struct mqfs_node
*parent
, struct mqfs_node
*node
)
402 KASSERT(parent
!= NULL
, ("%s(): parent is NULL", __func__
));
403 KASSERT(parent
->mn_info
!= NULL
,
404 ("%s(): parent has no mn_info", __func__
));
405 KASSERT(parent
->mn_type
== mqfstype_dir
||
406 parent
->mn_type
== mqfstype_root
,
407 ("%s(): parent is not a directory", __func__
));
409 node
->mn_info
= parent
->mn_info
;
410 node
->mn_parent
= parent
;
411 LIST_INIT(&node
->mn_children
);
412 LIST_INIT(&node
->mn_vnodes
);
413 LIST_INSERT_HEAD(&parent
->mn_children
, node
, mn_sibling
);
414 mqnode_addref(parent
);
418 static struct mqfs_node
*
419 mqfs_create_node(const char *name
, int namelen
, struct ucred
*cred
, int mode
,
422 struct mqfs_node
*node
;
424 node
= mqnode_alloc();
425 strncpy(node
->mn_name
, name
, namelen
);
426 node
->mn_type
= nodetype
;
427 node
->mn_refcount
= 1;
428 vfs_timestamp(&node
->mn_birth
);
429 node
->mn_ctime
= node
->mn_atime
= node
->mn_mtime
431 node
->mn_uid
= cred
->cr_uid
;
432 node
->mn_gid
= cred
->cr_gid
;
433 node
->mn_mode
= mode
;
440 static struct mqfs_node
*
441 mqfs_create_file(struct mqfs_node
*parent
, const char *name
, int namelen
,
442 struct ucred
*cred
, int mode
)
444 struct mqfs_node
*node
;
446 node
= mqfs_create_node(name
, namelen
, cred
, mode
, mqfstype_file
);
447 if (mqfs_add_node(parent
, node
) != 0) {
455 * Add . and .. to a directory
458 mqfs_fixup_dir(struct mqfs_node
*parent
)
460 struct mqfs_node
*dir
;
462 dir
= mqnode_alloc();
463 dir
->mn_name
[0] = '.';
464 dir
->mn_type
= mqfstype_this
;
465 dir
->mn_refcount
= 1;
466 if (mqfs_add_node(parent
, dir
) != 0) {
471 dir
= mqnode_alloc();
472 dir
->mn_name
[0] = dir
->mn_name
[1] = '.';
473 dir
->mn_type
= mqfstype_parent
;
474 dir
->mn_refcount
= 1;
476 if (mqfs_add_node(parent
, dir
) != 0) {
489 static struct mqfs_node
*
490 mqfs_create_dir(struct mqfs_node
*parent
, const char *name
, int namelen
,
491 struct ucred
*cred
, int mode
)
493 struct mqfs_node
*node
;
495 node
= mqfs_create_node(name
, namelen
, cred
, mode
, mqfstype_dir
);
496 if (mqfs_add_node(parent
, node
) != 0) {
501 if (mqfs_fixup_dir(node
) != 0) {
511 static struct mqfs_node
*
512 mqfs_create_link(struct mqfs_node
*parent
, const char *name
, int namelen
,
513 struct ucred
*cred
, int mode
)
515 struct mqfs_node
*node
;
517 node
= mqfs_create_node(name
, namelen
, cred
, mode
, mqfstype_symlink
);
518 if (mqfs_add_node(parent
, node
) != 0) {
528 * Destroy a node or a tree of nodes
531 mqfs_destroy(struct mqfs_node
*node
)
533 struct mqfs_node
*parent
;
535 KASSERT(node
!= NULL
,
536 ("%s(): node is NULL", __func__
));
537 KASSERT(node
->mn_info
!= NULL
,
538 ("%s(): node has no mn_info", __func__
));
540 /* destroy children */
541 if (node
->mn_type
== mqfstype_dir
|| node
->mn_type
== mqfstype_root
)
542 while (! LIST_EMPTY(&node
->mn_children
))
543 mqfs_destroy(LIST_FIRST(&node
->mn_children
));
545 /* unlink from parent */
546 if ((parent
= node
->mn_parent
) != NULL
) {
547 KASSERT(parent
->mn_info
== node
->mn_info
,
548 ("%s(): parent has different mn_info", __func__
));
549 LIST_REMOVE(node
, mn_sibling
);
552 if (node
->mn_fileno
!= 0)
553 mqfs_fileno_free(node
->mn_info
, node
);
554 if (node
->mn_data
!= NULL
)
555 mqueue_free(node
->mn_data
);
561 * Mount a mqfs instance
564 mqfs_mount(struct mount
*mp
, struct thread
*td
)
568 if (mp
->mnt_flag
& MNT_UPDATE
)
571 mp
->mnt_data
= &mqfs_data
;
573 mp
->mnt_flag
|= MNT_LOCAL
;
574 mp
->mnt_kern_flag
|= MNTK_MPSAFE
;
579 vfs_mountedfrom(mp
, "mqueue");
580 sbp
->f_bsize
= PAGE_SIZE
;
581 sbp
->f_iosize
= PAGE_SIZE
;
591 * Unmount a mqfs instance
594 mqfs_unmount(struct mount
*mp
, int mntflags
, struct thread
*td
)
598 error
= vflush(mp
, 0, (mntflags
& MNT_FORCE
) ? FORCECLOSE
: 0, td
);
603 * Return a root vnode
606 mqfs_root(struct mount
*mp
, int flags
, struct vnode
**vpp
, struct thread
*td
)
608 struct mqfs_info
*mqfs
;
611 mqfs
= VFSTOMQFS(mp
);
612 ret
= mqfs_allocv(mp
, vpp
, mqfs
->mi_root
);
617 * Return filesystem stats
620 mqfs_statfs(struct mount
*mp
, struct statfs
*sbp
, struct thread
*td
)
622 /* XXX update statistics */
627 * Initialize a mqfs instance
630 mqfs_init(struct vfsconf
*vfc
)
632 struct mqfs_node
*root
;
633 struct mqfs_info
*mi
;
635 mqnode_zone
= uma_zcreate("mqnode", sizeof(struct mqfs_node
),
636 NULL
, NULL
, NULL
, NULL
, UMA_ALIGN_PTR
, 0);
637 mqueue_zone
= uma_zcreate("mqueue", sizeof(struct mqueue
),
638 NULL
, NULL
, NULL
, NULL
, UMA_ALIGN_PTR
, 0);
639 mvdata_zone
= uma_zcreate("mvdata",
640 sizeof(struct mqfs_vdata
), NULL
, NULL
, NULL
,
641 NULL
, UMA_ALIGN_PTR
, 0);
642 mqnoti_zone
= uma_zcreate("mqnotifier", sizeof(struct mqueue_notifier
),
643 NULL
, NULL
, NULL
, NULL
, UMA_ALIGN_PTR
, 0);
645 sx_init(&mi
->mi_lock
, "mqfs lock");
646 /* set up the root diretory */
647 root
= mqfs_create_node("/", 1, curthread
->td_ucred
, 01777,
650 LIST_INIT(&root
->mn_children
);
651 LIST_INIT(&root
->mn_vnodes
);
653 mqfs_fileno_init(mi
);
654 mqfs_fileno_alloc(mi
, root
);
655 mqfs_fixup_dir(root
);
656 exit_tag
= EVENTHANDLER_REGISTER(process_exit
, mq_proc_exit
, NULL
,
657 EVENTHANDLER_PRI_ANY
);
658 mq_fdclose
= mqueue_fdclose
;
659 p31b_setcfg(CTL_P1003_1B_MESSAGE_PASSING
, _POSIX_MESSAGE_PASSING
);
664 * Destroy a mqfs instance
667 mqfs_uninit(struct vfsconf
*vfc
)
669 struct mqfs_info
*mi
;
673 EVENTHANDLER_DEREGISTER(process_exit
, exit_tag
);
675 mqfs_destroy(mi
->mi_root
);
677 mqfs_fileno_uninit(mi
);
678 sx_destroy(&mi
->mi_lock
);
679 uma_zdestroy(mqnode_zone
);
680 uma_zdestroy(mqueue_zone
);
681 uma_zdestroy(mvdata_zone
);
682 uma_zdestroy(mqnoti_zone
);
690 do_recycle(void *context
, int pending __unused
)
692 struct vnode
*vp
= (struct vnode
*)context
;
694 vrecycle(vp
, curthread
);
702 mqfs_allocv(struct mount
*mp
, struct vnode
**vpp
, struct mqfs_node
*pn
)
704 struct mqfs_vdata
*vd
;
705 struct mqfs_info
*mqfs
;
706 struct vnode
*newvpp
;
711 sx_xlock(&mqfs
->mi_lock
);
712 LIST_FOREACH(vd
, &pn
->mn_vnodes
, mv_link
) {
713 if (vd
->mv_vnode
->v_mount
== mp
) {
722 sx_xunlock(&mqfs
->mi_lock
);
723 error
= vget(*vpp
, LK_RETRY
| LK_EXCLUSIVE
, curthread
);
727 sx_xunlock(&mqfs
->mi_lock
);
729 error
= getnewvnode("mqueue", mp
, &mqfs_vnodeops
, &newvpp
);
732 vn_lock(newvpp
, LK_EXCLUSIVE
| LK_RETRY
);
733 error
= insmntque(newvpp
, mp
);
737 sx_xlock(&mqfs
->mi_lock
);
739 * Check if it has already been allocated
740 * while we were blocked.
742 LIST_FOREACH(vd
, &pn
->mn_vnodes
, mv_link
) {
743 if (vd
->mv_vnode
->v_mount
== mp
) {
745 sx_xunlock(&mqfs
->mi_lock
);
755 vd
= uma_zalloc(mvdata_zone
, M_WAITOK
);
759 TASK_INIT(&vd
->mv_task
, 0, do_recycle
, *vpp
);
760 LIST_INSERT_HEAD(&pn
->mn_vnodes
, vd
, mv_link
);
762 switch (pn
->mn_type
) {
764 (*vpp
)->v_vflag
= VV_ROOT
;
768 case mqfstype_parent
:
769 (*vpp
)->v_type
= VDIR
;
772 (*vpp
)->v_type
= VREG
;
774 case mqfstype_symlink
:
775 (*vpp
)->v_type
= VLNK
;
778 KASSERT(0, ("mqfs_allocf called for null node\n"));
780 panic("%s has unexpected type: %d", pn
->mn_name
, pn
->mn_type
);
782 sx_xunlock(&mqfs
->mi_lock
);
787 * Search a directory entry
789 static struct mqfs_node
*
790 mqfs_search(struct mqfs_node
*pd
, const char *name
, int len
)
792 struct mqfs_node
*pn
;
794 sx_assert(&pd
->mn_info
->mi_lock
, SX_LOCKED
);
795 LIST_FOREACH(pn
, &pd
->mn_children
, mn_sibling
) {
796 if (strncmp(pn
->mn_name
, name
, len
) == 0)
803 * Look up a file or directory.
806 mqfs_lookupx(struct vop_cachedlookup_args
*ap
)
808 struct componentname
*cnp
;
809 struct vnode
*dvp
, **vpp
;
810 struct mqfs_node
*pd
;
811 struct mqfs_node
*pn
;
812 struct mqfs_info
*mqfs
;
813 int nameiop
, flags
, error
, namelen
;
820 pname
= cnp
->cn_nameptr
;
821 namelen
= cnp
->cn_namelen
;
823 flags
= cnp
->cn_flags
;
824 nameiop
= cnp
->cn_nameiop
;
830 if (dvp
->v_type
!= VDIR
)
833 error
= VOP_ACCESS(dvp
, VEXEC
, cnp
->cn_cred
, cnp
->cn_thread
);
837 /* shortcut: check if the name is too long */
838 if (cnp
->cn_namelen
>= MQFS_NAMELEN
)
842 if (namelen
== 1 && pname
[0] == '.') {
843 if ((flags
& ISLASTCN
) && nameiop
!= LOOKUP
)
852 if (cnp
->cn_flags
& ISDOTDOT
) {
853 if (dvp
->v_vflag
& VV_ROOT
)
855 if ((flags
& ISLASTCN
) && nameiop
!= LOOKUP
)
858 KASSERT(pd
->mn_parent
, ("non-root directory has no parent"));
860 error
= mqfs_allocv(dvp
->v_mount
, vpp
, pn
);
861 vn_lock(dvp
, LK_EXCLUSIVE
| LK_RETRY
);
866 sx_xlock(&mqfs
->mi_lock
);
867 pn
= mqfs_search(pd
, pname
, namelen
);
870 sx_xunlock(&mqfs
->mi_lock
);
875 if (nameiop
== DELETE
&& (flags
& ISLASTCN
)) {
876 error
= VOP_ACCESS(dvp
, VWRITE
, cnp
->cn_cred
, td
);
890 error
= mqfs_allocv(dvp
->v_mount
, vpp
, pn
);
892 if (error
== 0 && cnp
->cn_flags
& MAKEENTRY
)
893 cache_enter(dvp
, *vpp
, cnp
);
899 /* will create a new entry in the directory ? */
900 if ((nameiop
== CREATE
|| nameiop
== RENAME
) && (flags
& LOCKPARENT
)
901 && (flags
& ISLASTCN
)) {
902 error
= VOP_ACCESS(dvp
, VWRITE
, cnp
->cn_cred
, td
);
905 cnp
->cn_flags
|= SAVENAME
;
906 return (EJUSTRETURN
);
912 struct vop_lookup_args
{
913 struct vop_generic_args a_gen
;
915 struct vnode
**a_vpp
;
916 struct componentname
*a_cnp
;
921 * vnode lookup operation
924 mqfs_lookup(struct vop_cachedlookup_args
*ap
)
928 rc
= mqfs_lookupx(ap
);
933 struct vop_create_args
{
935 struct vnode
**a_vpp
;
936 struct componentname
*a_cnp
;
942 * vnode creation operation
945 mqfs_create(struct vop_create_args
*ap
)
947 struct mqfs_info
*mqfs
= VFSTOMQFS(ap
->a_dvp
->v_mount
);
948 struct componentname
*cnp
= ap
->a_cnp
;
949 struct mqfs_node
*pd
;
950 struct mqfs_node
*pn
;
954 pd
= VTON(ap
->a_dvp
);
955 if (pd
->mn_type
!= mqfstype_root
&& pd
->mn_type
!= mqfstype_dir
)
957 mq
= mqueue_alloc(NULL
);
960 sx_xlock(&mqfs
->mi_lock
);
961 if ((cnp
->cn_flags
& HASBUF
) == 0)
962 panic("%s: no name", __func__
);
963 pn
= mqfs_create_file(pd
, cnp
->cn_nameptr
, cnp
->cn_namelen
,
964 cnp
->cn_cred
, ap
->a_vap
->va_mode
);
966 sx_xunlock(&mqfs
->mi_lock
);
970 sx_xunlock(&mqfs
->mi_lock
);
971 error
= mqfs_allocv(ap
->a_dvp
->v_mount
, ap
->a_vpp
, pn
);
987 int do_unlink(struct mqfs_node
*pn
, struct ucred
*ucred
)
989 struct mqfs_node
*parent
;
990 struct mqfs_vdata
*vd
;
993 sx_assert(&pn
->mn_info
->mi_lock
, SX_LOCKED
);
995 if (ucred
->cr_uid
!= pn
->mn_uid
&&
996 (error
= priv_check_cred(ucred
, PRIV_MQ_ADMIN
, 0)) != 0)
998 else if (!pn
->mn_deleted
) {
999 parent
= pn
->mn_parent
;
1000 pn
->mn_parent
= NULL
;
1002 LIST_REMOVE(pn
, mn_sibling
);
1003 LIST_FOREACH(vd
, &pn
->mn_vnodes
, mv_link
) {
1004 cache_purge(vd
->mv_vnode
);
1005 vhold(vd
->mv_vnode
);
1006 taskqueue_enqueue(taskqueue_thread
, &vd
->mv_task
);
1009 mqnode_release(parent
);
1016 struct vop_remove_args
{
1017 struct vnode
*a_dvp
;
1019 struct componentname
*a_cnp
;
1024 * vnode removal operation
1027 mqfs_remove(struct vop_remove_args
*ap
)
1029 struct mqfs_info
*mqfs
= VFSTOMQFS(ap
->a_dvp
->v_mount
);
1030 struct mqfs_node
*pn
;
1033 if (ap
->a_vp
->v_type
== VDIR
)
1035 pn
= VTON(ap
->a_vp
);
1036 sx_xlock(&mqfs
->mi_lock
);
1037 error
= do_unlink(pn
, ap
->a_cnp
->cn_cred
);
1038 sx_xunlock(&mqfs
->mi_lock
);
1043 struct vop_inactive_args
{
1045 struct thread
*a_td
;
1050 mqfs_inactive(struct vop_inactive_args
*ap
)
1052 struct mqfs_node
*pn
= VTON(ap
->a_vp
);
1055 vrecycle(ap
->a_vp
, ap
->a_td
);
1060 struct vop_reclaim_args
{
1061 struct vop_generic_args a_gen
;
1063 struct thread
*a_td
;
1068 mqfs_reclaim(struct vop_reclaim_args
*ap
)
1070 struct mqfs_info
*mqfs
= VFSTOMQFS(ap
->a_vp
->v_mount
);
1071 struct vnode
*vp
= ap
->a_vp
;
1072 struct mqfs_node
*pn
;
1073 struct mqfs_vdata
*vd
;
1077 sx_xlock(&mqfs
->mi_lock
);
1079 LIST_REMOVE(vd
, mv_link
);
1080 uma_zfree(mvdata_zone
, vd
);
1082 sx_xunlock(&mqfs
->mi_lock
);
1087 struct vop_open_args
{
1088 struct vop_generic_args a_gen
;
1091 struct ucred
*a_cred
;
1092 struct thread
*a_td
;
1098 mqfs_open(struct vop_open_args
*ap
)
1104 struct vop_close_args
{
1105 struct vop_generic_args a_gen
;
1108 struct ucred
*a_cred
;
1109 struct thread
*a_td
;
1114 mqfs_close(struct vop_close_args
*ap
)
1120 struct vop_access_args
{
1121 struct vop_generic_args a_gen
;
1124 struct ucred
*a_cred
;
1125 struct thread
*a_td
;
1130 * Verify permissions
1133 mqfs_access(struct vop_access_args
*ap
)
1135 struct vnode
*vp
= ap
->a_vp
;
1139 error
= VOP_GETATTR(vp
, &vattr
, ap
->a_cred
);
1142 error
= vaccess(vp
->v_type
, vattr
.va_mode
, vattr
.va_uid
,
1143 vattr
.va_gid
, ap
->a_mode
, ap
->a_cred
, NULL
);
1148 struct vop_getattr_args
{
1149 struct vop_generic_args a_gen
;
1151 struct vattr
*a_vap
;
1152 struct ucred
*a_cred
;
1157 * Get file attributes
1160 mqfs_getattr(struct vop_getattr_args
*ap
)
1162 struct vnode
*vp
= ap
->a_vp
;
1163 struct mqfs_node
*pn
= VTON(vp
);
1164 struct vattr
*vap
= ap
->a_vap
;
1168 vap
->va_type
= vp
->v_type
;
1169 vap
->va_mode
= pn
->mn_mode
;
1171 vap
->va_uid
= pn
->mn_uid
;
1172 vap
->va_gid
= pn
->mn_gid
;
1173 vap
->va_fsid
= vp
->v_mount
->mnt_stat
.f_fsid
.val
[0];
1174 vap
->va_fileid
= pn
->mn_fileno
;
1176 vap
->va_blocksize
= PAGE_SIZE
;
1177 vap
->va_bytes
= vap
->va_size
= 0;
1178 vap
->va_atime
= pn
->mn_atime
;
1179 vap
->va_mtime
= pn
->mn_mtime
;
1180 vap
->va_ctime
= pn
->mn_ctime
;
1181 vap
->va_birthtime
= pn
->mn_birth
;
1186 vap
->va_filerev
= 0;
1187 vap
->va_vaflags
= 0;
1192 struct vop_setattr_args
{
1193 struct vop_generic_args a_gen
;
1195 struct vattr
*a_vap
;
1196 struct ucred
*a_cred
;
1203 mqfs_setattr(struct vop_setattr_args
*ap
)
1205 struct mqfs_node
*pn
;
1216 if ((vap
->va_type
!= VNON
) ||
1217 (vap
->va_nlink
!= VNOVAL
) ||
1218 (vap
->va_fsid
!= VNOVAL
) ||
1219 (vap
->va_fileid
!= VNOVAL
) ||
1220 (vap
->va_blocksize
!= VNOVAL
) ||
1221 (vap
->va_flags
!= VNOVAL
&& vap
->va_flags
!= 0) ||
1222 (vap
->va_rdev
!= VNOVAL
) ||
1223 ((int)vap
->va_bytes
!= VNOVAL
) ||
1224 (vap
->va_gen
!= VNOVAL
)) {
1231 if (vap
->va_uid
== (uid_t
)VNOVAL
)
1235 if (vap
->va_gid
== (gid_t
)VNOVAL
)
1240 if (uid
!= pn
->mn_uid
|| gid
!= pn
->mn_gid
) {
1242 * To modify the ownership of a file, must possess VADMIN
1245 if ((error
= VOP_ACCESS(vp
, VADMIN
, ap
->a_cred
, td
)))
1249 * XXXRW: Why is there a privilege check here: shouldn't the
1250 * check in VOP_ACCESS() be enough? Also, are the group bits
1251 * below definitely right?
1253 if (((ap
->a_cred
->cr_uid
!= pn
->mn_uid
) || uid
!= pn
->mn_uid
||
1254 (gid
!= pn
->mn_gid
&& !groupmember(gid
, ap
->a_cred
))) &&
1255 (error
= priv_check(td
, PRIV_MQ_ADMIN
)) != 0)
1262 if (vap
->va_mode
!= (mode_t
)VNOVAL
) {
1263 if ((ap
->a_cred
->cr_uid
!= pn
->mn_uid
) &&
1264 (error
= priv_check(td
, PRIV_MQ_ADMIN
)))
1266 pn
->mn_mode
= vap
->va_mode
;
1270 if (vap
->va_atime
.tv_sec
!= VNOVAL
|| vap
->va_mtime
.tv_sec
!= VNOVAL
) {
1271 /* See the comment in ufs_vnops::ufs_setattr(). */
1272 if ((error
= VOP_ACCESS(vp
, VADMIN
, ap
->a_cred
, td
)) &&
1273 ((vap
->va_vaflags
& VA_UTIMES_NULL
) == 0 ||
1274 (error
= VOP_ACCESS(vp
, VWRITE
, ap
->a_cred
, td
))))
1276 if (vap
->va_atime
.tv_sec
!= VNOVAL
) {
1277 pn
->mn_atime
= vap
->va_atime
;
1279 if (vap
->va_mtime
.tv_sec
!= VNOVAL
) {
1280 pn
->mn_mtime
= vap
->va_mtime
;
1285 vfs_timestamp(&pn
->mn_ctime
);
1291 struct vop_read_args
{
1292 struct vop_generic_args a_gen
;
1296 struct ucred
*a_cred
;
1304 mqfs_read(struct vop_read_args
*ap
)
1307 struct vnode
*vp
= ap
->a_vp
;
1308 struct uio
*uio
= ap
->a_uio
;
1309 struct mqfs_node
*pn
;
1313 if (vp
->v_type
!= VREG
)
1318 snprintf(buf
, sizeof(buf
),
1319 "QSIZE:%-10ld MAXMSG:%-10ld CURMSG:%-10ld MSGSIZE:%-10ld\n",
1324 buf
[sizeof(buf
)-1] = '\0';
1326 error
= uiomove_frombuf(buf
, len
, uio
);
1331 struct vop_readdir_args
{
1332 struct vop_generic_args a_gen
;
1335 struct ucred
*a_cred
;
1343 * Return directory entries.
1346 mqfs_readdir(struct vop_readdir_args
*ap
)
1349 struct mqfs_info
*mi
;
1350 struct mqfs_node
*pd
;
1351 struct mqfs_node
*pn
;
1352 struct dirent entry
;
1354 int *tmp_ncookies
= NULL
;
1359 mi
= VFSTOMQFS(vp
->v_mount
);
1363 if (vp
->v_type
!= VDIR
)
1366 if (uio
->uio_offset
< 0)
1369 if (ap
->a_ncookies
!= NULL
) {
1370 tmp_ncookies
= ap
->a_ncookies
;
1371 *ap
->a_ncookies
= 0;
1372 ap
->a_ncookies
= NULL
;
1378 sx_xlock(&mi
->mi_lock
);
1380 LIST_FOREACH(pn
, &pd
->mn_children
, mn_sibling
) {
1381 entry
.d_reclen
= sizeof(entry
);
1383 mqfs_fileno_alloc(mi
, pn
);
1384 entry
.d_fileno
= pn
->mn_fileno
;
1385 for (i
= 0; i
< MQFS_NAMELEN
- 1 && pn
->mn_name
[i
] != '\0'; ++i
)
1386 entry
.d_name
[i
] = pn
->mn_name
[i
];
1387 entry
.d_name
[i
] = 0;
1389 switch (pn
->mn_type
) {
1393 case mqfstype_parent
:
1394 entry
.d_type
= DT_DIR
;
1397 entry
.d_type
= DT_REG
;
1399 case mqfstype_symlink
:
1400 entry
.d_type
= DT_LNK
;
1403 panic("%s has unexpected node type: %d", pn
->mn_name
,
1406 if (entry
.d_reclen
> uio
->uio_resid
)
1408 if (offset
>= uio
->uio_offset
) {
1409 error
= vfs_read_dirent(ap
, &entry
, offset
);
1413 offset
+= entry
.d_reclen
;
1415 sx_xunlock(&mi
->mi_lock
);
1417 uio
->uio_offset
= offset
;
1419 if (tmp_ncookies
!= NULL
)
1420 ap
->a_ncookies
= tmp_ncookies
;
1428 struct vop_mkdir_args
{
1429 struct vnode
*a_dvp
;
1430 struvt vnode
**a_vpp
;
1431 struvt componentname
*a_cnp
;
1432 struct vattr
*a_vap
;
1437 * Create a directory.
1440 mqfs_mkdir(struct vop_mkdir_args
*ap
)
1442 struct mqfs_info
*mqfs
= VFSTOMQFS(ap
->a_dvp
->v_mount
);
1443 struct componentname
*cnp
= ap
->a_cnp
;
1444 struct mqfs_node
*pd
= VTON(ap
->a_dvp
);
1445 struct mqfs_node
*pn
;
1448 if (pd
->mn_type
!= mqfstype_root
&& pd
->mn_type
!= mqfstype_dir
)
1450 sx_xlock(&mqfs
->mi_lock
);
1451 if ((cnp
->cn_flags
& HASBUF
) == 0)
1452 panic("%s: no name", __func__
);
1453 pn
= mqfs_create_dir(pd
, cnp
->cn_nameptr
, cnp
->cn_namelen
,
1454 ap
->a_vap
->cn_cred
, ap
->a_vap
->va_mode
);
1457 sx_xunlock(&mqfs
->mi_lock
);
1461 error
= mqfs_allocv(ap
->a_dvp
->v_mount
, ap
->a_vpp
, pn
);
1468 struct vop_rmdir_args
{
1469 struct vnode
*a_dvp
;
1471 struct componentname
*a_cnp
;
1476 * Remove a directory.
1479 mqfs_rmdir(struct vop_rmdir_args
*ap
)
1481 struct mqfs_info
*mqfs
= VFSTOMQFS(ap
->a_dvp
->v_mount
);
1482 struct mqfs_node
*pn
= VTON(ap
->a_vp
);
1483 struct mqfs_node
*pt
;
1485 if (pn
->mn_type
!= mqfstype_dir
)
1488 sx_xlock(&mqfs
->mi_lock
);
1489 if (pn
->mn_deleted
) {
1490 sx_xunlock(&mqfs
->mi_lock
);
1494 pt
= LIST_FIRST(&pn
->mn_children
);
1495 pt
= LIST_NEXT(pt
, mn_sibling
);
1496 pt
= LIST_NEXT(pt
, mn_sibling
);
1498 sx_xunlock(&mqfs
->mi_lock
);
1502 pn
->mn_parent
= NULL
;
1504 LIST_REMOVE(pn
, mn_sibling
);
1507 sx_xunlock(&mqfs
->mi_lock
);
1508 cache_purge(ap
->a_vp
);
1515 * Allocate a message queue
1517 static struct mqueue
*
1518 mqueue_alloc(const struct mq_attr
*attr
)
1524 mq
= uma_zalloc(mqueue_zone
, M_WAITOK
| M_ZERO
);
1525 TAILQ_INIT(&mq
->mq_msgq
);
1527 mq
->mq_maxmsg
= attr
->mq_maxmsg
;
1528 mq
->mq_msgsize
= attr
->mq_msgsize
;
1530 mq
->mq_maxmsg
= default_maxmsg
;
1531 mq
->mq_msgsize
= default_msgsize
;
1533 mtx_init(&mq
->mq_mutex
, "mqueue lock", NULL
, MTX_DEF
);
1534 knlist_init(&mq
->mq_rsel
.si_note
, &mq
->mq_mutex
, NULL
, NULL
, NULL
);
1535 knlist_init(&mq
->mq_wsel
.si_note
, &mq
->mq_mutex
, NULL
, NULL
, NULL
);
1536 atomic_add_int(&curmq
, 1);
1541 * Destroy a message queue
1544 mqueue_free(struct mqueue
*mq
)
1546 struct mqueue_msg
*msg
;
1548 while ((msg
= TAILQ_FIRST(&mq
->mq_msgq
)) != NULL
) {
1549 TAILQ_REMOVE(&mq
->mq_msgq
, msg
, msg_link
);
1550 FREE(msg
, M_MQUEUEDATA
);
1553 mtx_destroy(&mq
->mq_mutex
);
1554 knlist_destroy(&mq
->mq_rsel
.si_note
);
1555 knlist_destroy(&mq
->mq_wsel
.si_note
);
1556 uma_zfree(mqueue_zone
, mq
);
1557 atomic_add_int(&curmq
, -1);
1561 * Load a message from user space
1563 static struct mqueue_msg
*
1564 mqueue_loadmsg(const char *msg_ptr
, size_t msg_size
, int msg_prio
)
1566 struct mqueue_msg
*msg
;
1570 len
= sizeof(struct mqueue_msg
) + msg_size
;
1571 MALLOC(msg
, struct mqueue_msg
*, len
, M_MQUEUEDATA
, M_WAITOK
);
1572 error
= copyin(msg_ptr
, ((char *)msg
) + sizeof(struct mqueue_msg
),
1575 FREE(msg
, M_MQUEUEDATA
);
1578 msg
->msg_size
= msg_size
;
1579 msg
->msg_prio
= msg_prio
;
1585 * Save a message to user space
1588 mqueue_savemsg(struct mqueue_msg
*msg
, char *msg_ptr
, int *msg_prio
)
1592 error
= copyout(((char *)msg
) + sizeof(*msg
), msg_ptr
,
1594 if (error
== 0 && msg_prio
!= NULL
)
1595 error
= copyout(&msg
->msg_prio
, msg_prio
, sizeof(int));
1600 * Free a message's memory
1602 static __inline
void
1603 mqueue_freemsg(struct mqueue_msg
*msg
)
1605 FREE(msg
, M_MQUEUEDATA
);
1609 * Send a message. if waitok is false, thread will not be
1610 * blocked if there is no data in queue, otherwise, absolute
1611 * time will be checked.
1614 mqueue_send(struct mqueue
*mq
, const char *msg_ptr
,
1615 size_t msg_len
, unsigned msg_prio
, int waitok
,
1616 const struct timespec
*abs_timeout
)
1618 struct mqueue_msg
*msg
;
1619 struct timespec ets
, ts
, ts2
;
1623 if (msg_prio
>= MQ_PRIO_MAX
)
1625 if (msg_len
> mq
->mq_msgsize
)
1627 msg
= mqueue_loadmsg(msg_ptr
, msg_len
, msg_prio
);
1631 /* O_NONBLOCK case */
1633 error
= _mqueue_send(mq
, msg
, -1);
1639 /* we allow a null timeout (wait forever) */
1640 if (abs_timeout
== NULL
) {
1641 error
= _mqueue_send(mq
, msg
, 0);
1647 /* send it before checking time */
1648 error
= _mqueue_send(mq
, msg
, -1);
1652 if (error
!= EAGAIN
)
1655 error
= copyin(abs_timeout
, &ets
, sizeof(ets
));
1658 if (ets
.tv_nsec
>= 1000000000 || ets
.tv_nsec
< 0) {
1665 timespecsub(&ts2
, &ts
);
1666 if (ts2
.tv_sec
< 0 || (ts2
.tv_sec
== 0 && ts2
.tv_nsec
<= 0)) {
1670 TIMESPEC_TO_TIMEVAL(&tv
, &ts2
);
1671 error
= _mqueue_send(mq
, msg
, tvtohz(&tv
));
1672 if (error
!= ETIMEDOUT
)
1678 mqueue_freemsg(msg
);
1683 * Common routine to send a message
1686 _mqueue_send(struct mqueue
*mq
, struct mqueue_msg
*msg
, int timo
)
1688 struct mqueue_msg
*msg2
;
1691 mtx_lock(&mq
->mq_mutex
);
1692 while (mq
->mq_curmsgs
>= mq
->mq_maxmsg
&& error
== 0) {
1694 mtx_unlock(&mq
->mq_mutex
);
1698 error
= msleep(&mq
->mq_senders
, &mq
->mq_mutex
,
1699 PCATCH
, "mqsend", timo
);
1701 if (error
== EAGAIN
)
1704 if (mq
->mq_curmsgs
>= mq
->mq_maxmsg
) {
1705 mtx_unlock(&mq
->mq_mutex
);
1709 if (TAILQ_EMPTY(&mq
->mq_msgq
)) {
1710 TAILQ_INSERT_HEAD(&mq
->mq_msgq
, msg
, msg_link
);
1712 if (msg
->msg_prio
<= TAILQ_LAST(&mq
->mq_msgq
, msgq
)->msg_prio
) {
1713 TAILQ_INSERT_TAIL(&mq
->mq_msgq
, msg
, msg_link
);
1715 TAILQ_FOREACH(msg2
, &mq
->mq_msgq
, msg_link
) {
1716 if (msg2
->msg_prio
< msg
->msg_prio
)
1719 TAILQ_INSERT_BEFORE(msg2
, msg
, msg_link
);
1723 mq
->mq_totalbytes
+= msg
->msg_size
;
1724 if (mq
->mq_receivers
)
1725 wakeup_one(&mq
->mq_receivers
);
1726 else if (mq
->mq_notifier
!= NULL
)
1727 mqueue_send_notification(mq
);
1728 if (mq
->mq_flags
& MQ_RSEL
) {
1729 mq
->mq_flags
&= ~MQ_RSEL
;
1730 selwakeup(&mq
->mq_rsel
);
1732 KNOTE_LOCKED(&mq
->mq_rsel
.si_note
, 0);
1733 mtx_unlock(&mq
->mq_mutex
);
1738 * Send realtime a signal to process which registered itself
1739 * successfully by mq_notify.
1742 mqueue_send_notification(struct mqueue
*mq
)
1744 struct mqueue_notifier
*nt
;
1747 mtx_assert(&mq
->mq_mutex
, MA_OWNED
);
1748 nt
= mq
->mq_notifier
;
1749 if (nt
->nt_sigev
.sigev_notify
!= SIGEV_NONE
) {
1752 if (!KSI_ONQ(&nt
->nt_ksi
))
1753 psignal_event(p
, &nt
->nt_sigev
, &nt
->nt_ksi
);
1756 mq
->mq_notifier
= NULL
;
1760 * Get a message. if waitok is false, thread will not be
1761 * blocked if there is no data in queue, otherwise, absolute
1762 * time will be checked.
1765 mqueue_receive(struct mqueue
*mq
, char *msg_ptr
,
1766 size_t msg_len
, unsigned *msg_prio
, int waitok
,
1767 const struct timespec
*abs_timeout
)
1769 struct mqueue_msg
*msg
;
1770 struct timespec ets
, ts
, ts2
;
1774 if (msg_len
< mq
->mq_msgsize
)
1777 /* O_NONBLOCK case */
1779 error
= _mqueue_recv(mq
, &msg
, -1);
1785 /* we allow a null timeout (wait forever). */
1786 if (abs_timeout
== NULL
) {
1787 error
= _mqueue_recv(mq
, &msg
, 0);
1793 /* try to get a message before checking time */
1794 error
= _mqueue_recv(mq
, &msg
, -1);
1798 if (error
!= EAGAIN
)
1801 error
= copyin(abs_timeout
, &ets
, sizeof(ets
));
1804 if (ets
.tv_nsec
>= 1000000000 || ets
.tv_nsec
< 0) {
1812 timespecsub(&ts2
, &ts
);
1813 if (ts2
.tv_sec
< 0 || (ts2
.tv_sec
== 0 && ts2
.tv_nsec
<= 0)) {
1817 TIMESPEC_TO_TIMEVAL(&tv
, &ts2
);
1818 error
= _mqueue_recv(mq
, &msg
, tvtohz(&tv
));
1821 if (error
!= ETIMEDOUT
)
1826 error
= mqueue_savemsg(msg
, msg_ptr
, msg_prio
);
1828 curthread
->td_retval
[0] = msg
->msg_size
;
1829 curthread
->td_retval
[1] = 0;
1831 mqueue_freemsg(msg
);
1836 * Common routine to receive a message
1839 _mqueue_recv(struct mqueue
*mq
, struct mqueue_msg
**msg
, int timo
)
1843 mtx_lock(&mq
->mq_mutex
);
1844 while ((*msg
= TAILQ_FIRST(&mq
->mq_msgq
)) == NULL
&& error
== 0) {
1846 mtx_unlock(&mq
->mq_mutex
);
1850 error
= msleep(&mq
->mq_receivers
, &mq
->mq_mutex
,
1851 PCATCH
, "mqrecv", timo
);
1853 if (error
== EAGAIN
)
1858 TAILQ_REMOVE(&mq
->mq_msgq
, *msg
, msg_link
);
1860 mq
->mq_totalbytes
-= (*msg
)->msg_size
;
1862 wakeup_one(&mq
->mq_senders
);
1863 if (mq
->mq_flags
& MQ_WSEL
) {
1864 mq
->mq_flags
&= ~MQ_WSEL
;
1865 selwakeup(&mq
->mq_wsel
);
1867 KNOTE_LOCKED(&mq
->mq_wsel
.si_note
, 0);
1869 if (mq
->mq_notifier
!= NULL
&& mq
->mq_receivers
== 0 &&
1870 !TAILQ_EMPTY(&mq
->mq_msgq
)) {
1871 mqueue_send_notification(mq
);
1873 mtx_unlock(&mq
->mq_mutex
);
1877 static __inline
struct mqueue_notifier
*
1878 notifier_alloc(void)
1880 return (uma_zalloc(mqnoti_zone
, M_WAITOK
| M_ZERO
));
1883 static __inline
void
1884 notifier_free(struct mqueue_notifier
*p
)
1886 uma_zfree(mqnoti_zone
, p
);
1889 static struct mqueue_notifier
*
1890 notifier_search(struct proc
*p
, int fd
)
1892 struct mqueue_notifier
*nt
;
1894 LIST_FOREACH(nt
, &p
->p_mqnotifier
, nt_link
) {
1895 if (nt
->nt_ksi
.ksi_mqd
== fd
)
1901 static __inline
void
1902 notifier_insert(struct proc
*p
, struct mqueue_notifier
*nt
)
1904 LIST_INSERT_HEAD(&p
->p_mqnotifier
, nt
, nt_link
);
1907 static __inline
void
1908 notifier_delete(struct proc
*p
, struct mqueue_notifier
*nt
)
1910 LIST_REMOVE(nt
, nt_link
);
1915 notifier_remove(struct proc
*p
, struct mqueue
*mq
, int fd
)
1917 struct mqueue_notifier
*nt
;
1919 mtx_assert(&mq
->mq_mutex
, MA_OWNED
);
1921 nt
= notifier_search(p
, fd
);
1923 if (mq
->mq_notifier
== nt
)
1924 mq
->mq_notifier
= NULL
;
1925 sigqueue_take(&nt
->nt_ksi
);
1926 notifier_delete(p
, nt
);
1932 * Syscall to open a message queue.
1935 kmq_open(struct thread
*td
, struct kmq_open_args
*uap
)
1937 char path
[MQFS_NAMELEN
+ 1];
1938 struct mq_attr attr
, *pattr
;
1939 struct mqfs_node
*pn
;
1940 struct filedesc
*fdp
;
1943 int fd
, error
, len
, flags
, cmode
;
1945 if ((uap
->flags
& O_ACCMODE
) == O_ACCMODE
)
1948 fdp
= td
->td_proc
->p_fd
;
1949 flags
= FFLAGS(uap
->flags
);
1950 cmode
= (((uap
->mode
& ~fdp
->fd_cmask
) & ALLPERMS
) & ~S_ISTXT
);
1952 if ((flags
& O_CREAT
) && (uap
->attr
!= NULL
)) {
1953 error
= copyin(uap
->attr
, &attr
, sizeof(attr
));
1956 if (attr
.mq_maxmsg
<= 0 || attr
.mq_maxmsg
> maxmsg
)
1958 if (attr
.mq_msgsize
<= 0 || attr
.mq_msgsize
> maxmsgsize
)
1964 error
= copyinstr(uap
->path
, path
, MQFS_NAMELEN
+ 1, NULL
);
1969 * The first character of name must be a slash (/) character
1970 * and the remaining characters of name cannot include any slash
1974 if (len
< 2 || path
[0] != '/' || index(path
+ 1, '/') != NULL
)
1977 error
= falloc(td
, &fp
, &fd
);
1981 sx_xlock(&mqfs_data
.mi_lock
);
1982 pn
= mqfs_search(mqfs_data
.mi_root
, path
+ 1, len
- 1);
1984 if (!(flags
& O_CREAT
)) {
1987 mq
= mqueue_alloc(pattr
);
1991 pn
= mqfs_create_file(mqfs_data
.mi_root
,
1992 path
+ 1, len
- 1, td
->td_ucred
,
2005 if ((flags
& (O_CREAT
| O_EXCL
)) == (O_CREAT
| O_EXCL
)) {
2014 error
= vaccess(VREG
, pn
->mn_mode
, pn
->mn_uid
,
2015 pn
->mn_gid
, acc_mode
, td
->td_ucred
, NULL
);
2020 sx_xunlock(&mqfs_data
.mi_lock
);
2021 fdclose(fdp
, fp
, fd
, td
);
2027 sx_xunlock(&mqfs_data
.mi_lock
);
2029 finit(fp
, flags
& (FREAD
| FWRITE
| O_NONBLOCK
), DTYPE_MQUEUE
, pn
,
2032 FILEDESC_XLOCK(fdp
);
2033 if (fdp
->fd_ofiles
[fd
] == fp
)
2034 fdp
->fd_ofileflags
[fd
] |= UF_EXCLOSE
;
2035 FILEDESC_XUNLOCK(fdp
);
2036 td
->td_retval
[0] = fd
;
2042 * Syscall to unlink a message queue.
2045 kmq_unlink(struct thread
*td
, struct kmq_unlink_args
*uap
)
2047 char path
[MQFS_NAMELEN
+1];
2048 struct mqfs_node
*pn
;
2051 error
= copyinstr(uap
->path
, path
, MQFS_NAMELEN
+ 1, NULL
);
2056 if (len
< 2 || path
[0] != '/' || index(path
+ 1, '/') != NULL
)
2059 sx_xlock(&mqfs_data
.mi_lock
);
2060 pn
= mqfs_search(mqfs_data
.mi_root
, path
+ 1, len
- 1);
2062 error
= do_unlink(pn
, td
->td_ucred
);
2065 sx_xunlock(&mqfs_data
.mi_lock
);
2069 typedef int (*_fgetf
)(struct thread
*, int, struct file
**);
2072 * Get message queue by giving file slot
2075 _getmq(struct thread
*td
, int fd
, _fgetf func
,
2076 struct file
**fpp
, struct mqfs_node
**ppn
, struct mqueue
**pmq
)
2078 struct mqfs_node
*pn
;
2081 error
= func(td
, fd
, fpp
);
2084 if (&mqueueops
!= (*fpp
)->f_ops
) {
2088 pn
= (*fpp
)->f_data
;
2097 getmq(struct thread
*td
, int fd
, struct file
**fpp
, struct mqfs_node
**ppn
,
2098 struct mqueue
**pmq
)
2100 return _getmq(td
, fd
, fget
, fpp
, ppn
, pmq
);
2104 getmq_read(struct thread
*td
, int fd
, struct file
**fpp
,
2105 struct mqfs_node
**ppn
, struct mqueue
**pmq
)
2107 return _getmq(td
, fd
, fget_read
, fpp
, ppn
, pmq
);
2111 getmq_write(struct thread
*td
, int fd
, struct file
**fpp
,
2112 struct mqfs_node
**ppn
, struct mqueue
**pmq
)
2114 return _getmq(td
, fd
, fget_write
, fpp
, ppn
, pmq
);
2118 kmq_setattr(struct thread
*td
, struct kmq_setattr_args
*uap
)
2122 struct mq_attr attr
, oattr
;
2127 error
= copyin(uap
->attr
, &attr
, sizeof(attr
));
2130 if (attr
.mq_flags
& ~O_NONBLOCK
)
2133 error
= getmq(td
, uap
->mqd
, &fp
, NULL
, &mq
);
2136 oattr
.mq_maxmsg
= mq
->mq_maxmsg
;
2137 oattr
.mq_msgsize
= mq
->mq_msgsize
;
2138 oattr
.mq_curmsgs
= mq
->mq_curmsgs
;
2141 oflag
= flag
= fp
->f_flag
;
2142 flag
&= ~O_NONBLOCK
;
2143 flag
|= (attr
.mq_flags
& O_NONBLOCK
);
2144 } while (atomic_cmpset_int(&fp
->f_flag
, oflag
, flag
) == 0);
2147 oattr
.mq_flags
= (O_NONBLOCK
& oflag
);
2150 error
= copyout(&oattr
, uap
->oattr
, sizeof(oattr
));
2155 kmq_timedreceive(struct thread
*td
, struct kmq_timedreceive_args
*uap
)
2162 error
= getmq_read(td
, uap
->mqd
, &fp
, NULL
, &mq
);
2165 waitok
= !(fp
->f_flag
& O_NONBLOCK
);
2166 error
= mqueue_receive(mq
, uap
->msg_ptr
, uap
->msg_len
,
2167 uap
->msg_prio
, waitok
, uap
->abs_timeout
);
2173 kmq_timedsend(struct thread
*td
, struct kmq_timedsend_args
*uap
)
2179 error
= getmq_write(td
, uap
->mqd
, &fp
, NULL
, &mq
);
2182 waitok
= !(fp
->f_flag
& O_NONBLOCK
);
2183 error
= mqueue_send(mq
, uap
->msg_ptr
, uap
->msg_len
,
2184 uap
->msg_prio
, waitok
, uap
->abs_timeout
);
2190 kmq_notify(struct thread
*td
, struct kmq_notify_args
*uap
)
2193 struct filedesc
*fdp
;
2197 struct mqueue_notifier
*nt
, *newnt
= NULL
;
2201 fdp
= td
->td_proc
->p_fd
;
2203 error
= copyin(uap
->sigev
, &ev
, sizeof(ev
));
2206 if (ev
.sigev_notify
!= SIGEV_SIGNAL
&&
2207 ev
.sigev_notify
!= SIGEV_THREAD_ID
&&
2208 ev
.sigev_notify
!= SIGEV_NONE
)
2210 if ((ev
.sigev_notify
== SIGEV_SIGNAL
||
2211 ev
.sigev_notify
== SIGEV_THREAD_ID
) &&
2212 !_SIG_VALID(ev
.sigev_signo
))
2215 error
= getmq(td
, uap
->mqd
, &fp
, NULL
, &mq
);
2219 FILEDESC_SLOCK(fdp
);
2220 if (fget_locked(fdp
, uap
->mqd
) != fp
) {
2221 FILEDESC_SUNLOCK(fdp
);
2225 mtx_lock(&mq
->mq_mutex
);
2226 FILEDESC_SUNLOCK(fdp
);
2227 if (uap
->sigev
!= NULL
) {
2228 if (mq
->mq_notifier
!= NULL
) {
2232 nt
= notifier_search(p
, uap
->mqd
);
2234 if (newnt
== NULL
) {
2236 mtx_unlock(&mq
->mq_mutex
);
2237 newnt
= notifier_alloc();
2243 sigqueue_take(&nt
->nt_ksi
);
2244 if (newnt
!= NULL
) {
2245 notifier_free(newnt
);
2251 ksiginfo_init(&nt
->nt_ksi
);
2252 nt
->nt_ksi
.ksi_flags
|= KSI_INS
| KSI_EXT
;
2253 nt
->nt_ksi
.ksi_code
= SI_MESGQ
;
2255 nt
->nt_ksi
.ksi_mqd
= uap
->mqd
;
2256 notifier_insert(p
, nt
);
2259 mq
->mq_notifier
= nt
;
2262 * if there is no receivers and message queue
2263 * is not empty, we should send notification
2264 * as soon as possible.
2266 if (mq
->mq_receivers
== 0 &&
2267 !TAILQ_EMPTY(&mq
->mq_msgq
))
2268 mqueue_send_notification(mq
);
2271 notifier_remove(p
, mq
, uap
->mqd
);
2273 mtx_unlock(&mq
->mq_mutex
);
2278 notifier_free(newnt
);
2283 mqueue_fdclose(struct thread
*td
, int fd
, struct file
*fp
)
2285 struct filedesc
*fdp
;
2288 fdp
= td
->td_proc
->p_fd
;
2289 FILEDESC_LOCK_ASSERT(fdp
);
2291 if (fp
->f_ops
== &mqueueops
) {
2293 mtx_lock(&mq
->mq_mutex
);
2294 notifier_remove(td
->td_proc
, mq
, fd
);
2296 /* have to wakeup thread in same process */
2297 if (mq
->mq_flags
& MQ_RSEL
) {
2298 mq
->mq_flags
&= ~MQ_RSEL
;
2299 selwakeup(&mq
->mq_rsel
);
2301 if (mq
->mq_flags
& MQ_WSEL
) {
2302 mq
->mq_flags
&= ~MQ_WSEL
;
2303 selwakeup(&mq
->mq_wsel
);
2305 mtx_unlock(&mq
->mq_mutex
);
2310 mq_proc_exit(void *arg __unused
, struct proc
*p
)
2312 struct filedesc
*fdp
;
2318 FILEDESC_SLOCK(fdp
);
2319 for (i
= 0; i
< fdp
->fd_nfiles
; ++i
) {
2320 fp
= fget_locked(fdp
, i
);
2321 if (fp
!= NULL
&& fp
->f_ops
== &mqueueops
) {
2323 mtx_lock(&mq
->mq_mutex
);
2324 notifier_remove(p
, FPTOMQ(fp
), i
);
2325 mtx_unlock(&mq
->mq_mutex
);
2328 FILEDESC_SUNLOCK(fdp
);
2329 KASSERT(LIST_EMPTY(&p
->p_mqnotifier
), ("mq notifiers left"));
2333 mqf_read(struct file
*fp
, struct uio
*uio
, struct ucred
*active_cred
,
2334 int flags
, struct thread
*td
)
2336 return (EOPNOTSUPP
);
2340 mqf_write(struct file
*fp
, struct uio
*uio
, struct ucred
*active_cred
,
2341 int flags
, struct thread
*td
)
2343 return (EOPNOTSUPP
);
2347 mqf_truncate(struct file
*fp
, off_t length
, struct ucred
*active_cred
,
2355 mqf_ioctl(struct file
*fp
, u_long cmd
, void *data
,
2356 struct ucred
*active_cred
, struct thread
*td
)
2362 mqf_poll(struct file
*fp
, int events
, struct ucred
*active_cred
,
2365 struct mqueue
*mq
= FPTOMQ(fp
);
2368 mtx_lock(&mq
->mq_mutex
);
2369 if (events
& (POLLIN
| POLLRDNORM
)) {
2370 if (mq
->mq_curmsgs
) {
2371 revents
|= events
& (POLLIN
| POLLRDNORM
);
2373 mq
->mq_flags
|= MQ_RSEL
;
2374 selrecord(td
, &mq
->mq_rsel
);
2377 if (events
& POLLOUT
) {
2378 if (mq
->mq_curmsgs
< mq
->mq_maxmsg
)
2381 mq
->mq_flags
|= MQ_WSEL
;
2382 selrecord(td
, &mq
->mq_wsel
);
2385 mtx_unlock(&mq
->mq_mutex
);
2390 mqf_close(struct file
*fp
, struct thread
*td
)
2392 struct mqfs_node
*pn
;
2394 fp
->f_ops
= &badfileops
;
2397 sx_xlock(&mqfs_data
.mi_lock
);
2399 sx_xunlock(&mqfs_data
.mi_lock
);
2404 mqf_stat(struct file
*fp
, struct stat
*st
, struct ucred
*active_cred
,
2407 struct mqfs_node
*pn
= fp
->f_data
;
2409 bzero(st
, sizeof *st
);
2410 st
->st_atimespec
= pn
->mn_atime
;
2411 st
->st_mtimespec
= pn
->mn_mtime
;
2412 st
->st_ctimespec
= pn
->mn_ctime
;
2413 st
->st_birthtimespec
= pn
->mn_birth
;
2414 st
->st_uid
= pn
->mn_uid
;
2415 st
->st_gid
= pn
->mn_gid
;
2416 st
->st_mode
= S_IFIFO
| pn
->mn_mode
;
2421 mqf_kqfilter(struct file
*fp
, struct knote
*kn
)
2423 struct mqueue
*mq
= FPTOMQ(fp
);
2426 if (kn
->kn_filter
== EVFILT_READ
) {
2427 kn
->kn_fop
= &mq_rfiltops
;
2428 knlist_add(&mq
->mq_rsel
.si_note
, kn
, 0);
2429 } else if (kn
->kn_filter
== EVFILT_WRITE
) {
2430 kn
->kn_fop
= &mq_wfiltops
;
2431 knlist_add(&mq
->mq_wsel
.si_note
, kn
, 0);
2438 filt_mqdetach(struct knote
*kn
)
2440 struct mqueue
*mq
= FPTOMQ(kn
->kn_fp
);
2442 if (kn
->kn_filter
== EVFILT_READ
)
2443 knlist_remove(&mq
->mq_rsel
.si_note
, kn
, 0);
2444 else if (kn
->kn_filter
== EVFILT_WRITE
)
2445 knlist_remove(&mq
->mq_wsel
.si_note
, kn
, 0);
2447 panic("filt_mqdetach");
2451 filt_mqread(struct knote
*kn
, long hint
)
2453 struct mqueue
*mq
= FPTOMQ(kn
->kn_fp
);
2455 mtx_assert(&mq
->mq_mutex
, MA_OWNED
);
2456 return (mq
->mq_curmsgs
!= 0);
2460 filt_mqwrite(struct knote
*kn
, long hint
)
2462 struct mqueue
*mq
= FPTOMQ(kn
->kn_fp
);
2464 mtx_assert(&mq
->mq_mutex
, MA_OWNED
);
2465 return (mq
->mq_curmsgs
< mq
->mq_maxmsg
);
2468 static struct fileops mqueueops
= {
2469 .fo_read
= mqf_read
,
2470 .fo_write
= mqf_write
,
2471 .fo_truncate
= mqf_truncate
,
2472 .fo_ioctl
= mqf_ioctl
,
2473 .fo_poll
= mqf_poll
,
2474 .fo_kqfilter
= mqf_kqfilter
,
2475 .fo_stat
= mqf_stat
,
2476 .fo_close
= mqf_close
2479 static struct vop_vector mqfs_vnodeops
= {
2480 .vop_default
= &default_vnodeops
,
2481 .vop_access
= mqfs_access
,
2482 .vop_cachedlookup
= mqfs_lookup
,
2483 .vop_lookup
= vfs_cache_lookup
,
2484 .vop_reclaim
= mqfs_reclaim
,
2485 .vop_create
= mqfs_create
,
2486 .vop_remove
= mqfs_remove
,
2487 .vop_inactive
= mqfs_inactive
,
2488 .vop_open
= mqfs_open
,
2489 .vop_close
= mqfs_close
,
2490 .vop_getattr
= mqfs_getattr
,
2491 .vop_setattr
= mqfs_setattr
,
2492 .vop_read
= mqfs_read
,
2493 .vop_write
= VOP_EOPNOTSUPP
,
2494 .vop_readdir
= mqfs_readdir
,
2495 .vop_mkdir
= VOP_EOPNOTSUPP
,
2496 .vop_rmdir
= VOP_EOPNOTSUPP
2499 static struct vfsops mqfs_vfsops
= {
2500 .vfs_init
= mqfs_init
,
2501 .vfs_uninit
= mqfs_uninit
,
2502 .vfs_mount
= mqfs_mount
,
2503 .vfs_unmount
= mqfs_unmount
,
2504 .vfs_root
= mqfs_root
,
2505 .vfs_statfs
= mqfs_statfs
,
2508 SYSCALL_MODULE_HELPER(kmq_open
);
2509 SYSCALL_MODULE_HELPER(kmq_setattr
);
2510 SYSCALL_MODULE_HELPER(kmq_timedsend
);
2511 SYSCALL_MODULE_HELPER(kmq_timedreceive
);
2512 SYSCALL_MODULE_HELPER(kmq_notify
);
2513 SYSCALL_MODULE_HELPER(kmq_unlink
);
2515 VFS_SET(mqfs_vfsops
, mqueuefs
, VFCF_SYNTHETIC
);
2516 MODULE_VERSION(mqueuefs
, 1);